├── CMakeLists.txt ├── LICENSE ├── README.md ├── resources ├── bluesky.mp4 └── city1.jpg ├── src ├── co_tcpserver │ ├── co_event.cc │ ├── co_event.h │ ├── co_eventloop.cc │ ├── co_eventloop.h │ ├── co_eventloop_thread.cc │ ├── co_eventloop_thread.h │ ├── co_eventloop_thread.hpp │ ├── co_scheduler.cc │ ├── co_scheduler.h │ ├── co_tcpconnection.cc │ ├── co_tcpconnection.h │ ├── co_tcpserver.cc │ ├── co_tcpserver.h │ ├── context_swap.o │ ├── context_swap.s │ ├── coroutine.cc │ ├── coroutine.h │ ├── coroutine_context.cc │ └── coroutine_context.h ├── cweb │ ├── context.cc │ ├── context.h │ ├── cweb.cc │ ├── cweb.h │ ├── router.cc │ └── router.h ├── cweb_config.h ├── db │ ├── dbconnection_pool.h │ ├── mysql.cc │ ├── mysql.h │ ├── redis.cc │ └── redis.h ├── httpserver │ ├── http_code.h │ ├── http_parser.cc │ ├── http_parser.h │ ├── httpparser.cc │ ├── httpparser.h │ ├── httprequest.cc │ ├── httprequest.h │ ├── httpresponse.cc │ ├── httpresponse.h │ ├── httpserver.cc │ ├── httpserver.h │ ├── httpsession.cc │ ├── httpsession.h │ ├── multipartparser.cc │ ├── multipartparser.h │ ├── websocket.cc │ └── websocket.h ├── log │ ├── log_appender.cc │ ├── log_appender.h │ ├── log_formatter.cc │ ├── log_formatter.h │ ├── log_info.h │ ├── log_writer.cc │ ├── log_writer.h │ ├── logfile_pipe.cc │ ├── logfile_pipe.h │ ├── logger.cc │ └── logger.h ├── main.cc ├── tcpserver │ ├── base │ │ └── poller.h │ ├── bytebuffer.cc │ ├── bytebuffer.h │ ├── bytedata.cc │ ├── bytedata.h │ ├── epoll │ │ ├── epoll_poller.cc │ │ └── epoll_poller.h │ ├── event.cc │ ├── event.h │ ├── eventloop.cc │ ├── eventloop.h │ ├── eventloop_thread.cc │ ├── eventloop_thread.h │ ├── hooks.cc │ ├── hooks.h │ ├── inetaddress.cc │ ├── inetaddress.h │ ├── kqueue │ │ ├── kqueue_poller.cc │ │ └── kqueue_poller.h │ ├── poll │ │ ├── poll_poller.cc │ │ └── poll_poller.h │ ├── scheduler.cc │ ├── scheduler.h │ ├── socket.cc │ ├── socket.h │ ├── tcpconnection.cc │ ├── tcpconnection.h │ ├── tcpserver.cc │ ├── tcpserver.h │ ├── timer.cc │ └── timer.h └── util │ ├── encode │ └── base64.h │ ├── encrypt │ └── sha1.h │ ├── json │ ├── allocator.h │ ├── assertions.h │ ├── autolink.h │ ├── config.h │ ├── features.h │ ├── forwards.h │ ├── json.h │ ├── json_reader.cc │ ├── json_tool.h │ ├── json_value.cc │ ├── json_valueiterator.inl │ ├── json_writer.cc │ ├── reader.h │ ├── value.h │ ├── version.h │ └── writer.h │ ├── linked_list.h │ ├── lockfree_queue.h │ ├── noncopyable.h │ ├── priority_queue.h │ ├── pthread_keys.h │ ├── singleton.h │ ├── threadlocal_memorypool.cc │ └── threadlocal_memorypool.h ├── test ├── coroutine_test.cc ├── linked_list_test.cc ├── lockfree_queue_test.cc ├── lockfree_queue_test.hpp ├── mysql_test.cc └── redis_test.cc └── thirdparty └── hiredis-vip ├── include └── hiredis-vip │ ├── adapters │ ├── ae.h │ ├── glib.h │ ├── libev.h │ ├── libevent.h │ └── libuv.h │ ├── adlist.h │ ├── async.h │ ├── dict.c │ ├── dict.h │ ├── fmacros.h │ ├── hiarray.h │ ├── hircluster.h │ ├── hiredis.h │ ├── hiutil.h │ ├── read.h │ └── sds.h └── lib ├── libhiredis_vip.1.0.dylib ├── libhiredis_vip.1.dylib ├── libhiredis_vip.a ├── libhiredis_vip.dylib └── pkgconfig └── hiredis_vip.pc /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | 3 | project(CWEBSERVER) 4 | 5 | option(BUILD_FLAG "build flag" TPOLL) 6 | 7 | # 添加C++11标准支持 8 | set(CMAKE_CXX_STANDARD 11) 9 | set(CMAKE_CXX_STANDARD_REQUIRED True) 10 | 11 | # 设置编译选项 12 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -w -g -O0") 13 | 14 | set(BOOST_ROOT "thirdparty/boost/1.79.0_1") 15 | set(BOOST_LIBRARYDIR "${BOOST_ROOT}/lib") 16 | 17 | file(GLOB SOURCES 18 | "src/*.cc" 19 | "src/tcpserver/*.cc" 20 | "src/tcpserver/base/*.cc" 21 | "src/util/*.cc" 22 | "src/cweb/*.cc" 23 | "src/log/*.cc" 24 | "src/httpserver/*.cc" 25 | "src/util/json/*.cc" 26 | "src/db/*.cc" 27 | ) 28 | 29 | include_directories( 30 | src 31 | src/co_tcpserver 32 | src/httpserver 33 | src/tcpserver 34 | src/tcpserver/poll 35 | src/tcpserver/epoll 36 | src/tcpserver/kqueue 37 | src/tcpserver/base 38 | src/util 39 | src/util/encode 40 | src/util/encrypt 41 | src/util/json 42 | src/cweb 43 | src/log 44 | src/db 45 | thirdparty/hiredis-vip/include 46 | /usr/local/include 47 | ) 48 | 49 | link_directories( 50 | thirdparty/hiredis-vip/lib 51 | /usr/local/lib 52 | ) 53 | 54 | # find_library(HIREDIS_LIB NAMES hiredis_vip PATHS thirdparty/hiredis-vip/lib) 55 | 56 | if(BUILD_FLAG STREQUAL TKQUEUE) 57 | add_definitions(-DKQUEUE) 58 | file(GLOB_RECURSE EXTRA_SOURCES "src/tcpserver/kqueue/*.cc") 59 | set(SOURCES 60 | ${SOURCES} 61 | ${EXTRA_SOURCES} 62 | ) 63 | add_executable(CWEBSERVER ${SOURCES}) 64 | elseif(BUILD_FLAG STREQUAL TEPOLL) 65 | add_definitions(-DEPOLL) 66 | file(GLOB_RECURSE EXTRA_SOURCES "src/tcpserver/epoll/*.cc") 67 | set(SOURCES 68 | ${SOURCES} 69 | ${EXTRA_SOURCES} 70 | ) 71 | add_executable(CWEBSERVER ${SOURCES} "src/tcpserver/epoll/*.cc") 72 | elseif(BUILD_FLAG STREQUAL CPOLL) 73 | add_definitions(-DCOROUTINE) 74 | file(GLOB_RECURSE EXTRA_SOURCES 75 | "src/tcpserver/poll/*.cc" 76 | "src/co_tcpserver/*.cc" 77 | "src/co_tcpserver/context_swap.o" 78 | ) 79 | set(SOURCES 80 | ${SOURCES} 81 | ${EXTRA_SOURCES} 82 | ) 83 | add_executable(CWEBSERVER ${SOURCES}) 84 | elseif(BUILD_FLAG STREQUAL CKQUEUE) 85 | add_definitions(-DKQUEUE) 86 | add_definitions(-DCOROUTINE) 87 | file(GLOB_RECURSE EXTRA_SOURCES 88 | "src/tcpserver/kqueue/*.cc" 89 | "src/co_tcpserver/*.cc" 90 | "src/co_tcpserver/context_swap.o" 91 | ) 92 | set(SOURCES 93 | ${SOURCES} 94 | ${EXTRA_SOURCES} 95 | ) 96 | add_executable(CWEBSERVER ${SOURCES}) 97 | elseif(BUILD_FLAG STREQUAL CEPOLL) 98 | add_definitions(-DEPOLL) 99 | add_definitions(-DCOROUTINE) 100 | file(GLOB_RECURSE EXTRA_SOURCES 101 | "src/tcpserver/epoll/*.cc" 102 | "src/co_tcpserver/*.cc" 103 | "src/co_tcpserver/context_swap.o" 104 | ) 105 | set(SOURCES 106 | ${SOURCES} 107 | ${EXTRA_SOURCES} 108 | ) 109 | add_executable(CWEBSERVER ${SOURCES}) 110 | else() 111 | file(GLOB_RECURSE EXTRA_SOURCES "src/tcpserver/poll/*.cc") 112 | set(SOURCES 113 | ${SOURCES} 114 | ${EXTRA_SOURCES} 115 | ) 116 | add_executable(CWEBSERVER ${SOURCES}) 117 | endif() 118 | target_link_libraries(CWEBSERVER hiredis_vip mysqlclient) 119 | 120 | 121 | 122 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Nodesheep 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /resources/bluesky.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nodesheep/RESTfulCweb/d22f37d5f682a99ba0d7365e1a37cff5b257c306/resources/bluesky.mp4 -------------------------------------------------------------------------------- /resources/city1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nodesheep/RESTfulCweb/d22f37d5f682a99ba0d7365e1a37cff5b257c306/resources/city1.jpg -------------------------------------------------------------------------------- /src/co_tcpserver/co_event.cc: -------------------------------------------------------------------------------- 1 | #include "co_event.h" 2 | #include "timer.h" 3 | #include "co_eventloop.h" 4 | #include "coroutine.h" 5 | #include "co_eventloop.h" 6 | 7 | namespace cweb { 8 | namespace tcpserver { 9 | namespace coroutine { 10 | 11 | CoEvent::CoEvent(std::shared_ptr loop, int fd, bool is_socket) 12 | : Event(loop, fd, is_socket) {} 13 | 14 | CoEvent::~CoEvent() {} 15 | 16 | void CoEvent::HandleEvent(Time receiveTime) { 17 | //处理读写过程中对段关闭的情况 18 | if(revents_ & (HUP_EVENT | ERR_EVENT)) { 19 | revents_ |= (READ_EVENT | WRITE_EVENT) & events_; 20 | } 21 | 22 | if(revents_ & READ_EVENT) { 23 | this->DisableReading(); 24 | if(read_coroutine_) { 25 | read_coroutine_->SetState(Coroutine::READY); 26 | }else { 27 | read_coroutine_ = new Coroutine([this, receiveTime](){ 28 | read_callback_(receiveTime); 29 | }); 30 | (std::dynamic_pointer_cast(loop_))->AddCoroutineWithState(read_coroutine_); 31 | } 32 | } 33 | 34 | if(revents_ & WRITE_EVENT) { 35 | this->DisableWriting(); 36 | if(write_coroutine_) { 37 | write_coroutine_->SetState(Coroutine::READY); 38 | }else { 39 | write_coroutine_ = new Coroutine(write_callback_); 40 | (std::dynamic_pointer_cast(loop_))->AddCoroutineWithState(write_coroutine_); 41 | } 42 | } 43 | } 44 | 45 | void CoEvent::TriggerEvent() { 46 | triggered_ = true; 47 | if(Readable() && read_coroutine_) { 48 | read_coroutine_->SetState(Coroutine::READY); 49 | } 50 | 51 | if(Writable() && write_coroutine_) { 52 | write_coroutine_->SetState(Coroutine::READY); 53 | } 54 | } 55 | 56 | void CoEvent::SetReadCoroutine(Coroutine *co) { 57 | if(read_coroutine_ == nullptr) read_coroutine_ = co; 58 | } 59 | 60 | void CoEvent::SetWriteCoroutine(Coroutine *co) { 61 | if(write_coroutine_ == nullptr) write_coroutine_ = co; 62 | } 63 | 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/co_tcpserver/co_event.h: -------------------------------------------------------------------------------- 1 | #ifndef CWEB_COROUTINE_COEVENT_H_ 2 | #define CWEB_COROUTINE_COEVENT_H_ 3 | 4 | #include "event.h" 5 | 6 | namespace cweb { 7 | namespace tcpserver { 8 | namespace coroutine { 9 | 10 | class CoEventLoop; 11 | class Coroutine; 12 | class CoEvent : public Event { 13 | 14 | public: 15 | friend CoEventLoop; 16 | CoEvent(std::shared_ptr loop, int fd, bool is_socket = false); 17 | 18 | virtual ~CoEvent(); 19 | 20 | virtual void HandleEvent(Time receiveTime) override; 21 | 22 | void SetReadCoroutine(Coroutine* co); 23 | void SetWriteCoroutine(Coroutine* co); 24 | void TriggerEvent(); 25 | bool Triggred() {return triggered_;} 26 | private: 27 | bool triggered_ = false; 28 | int flags_ = 0; 29 | Coroutine* read_coroutine_ = nullptr; 30 | Coroutine* write_coroutine_ = nullptr; 31 | }; 32 | 33 | } 34 | } 35 | } 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /src/co_tcpserver/co_eventloop.h: -------------------------------------------------------------------------------- 1 | #ifndef CWEB_COROUTINE_COEVENTLOOP_H_ 2 | #define CWEB_COROUTINE_COEVENTLOOP_H_ 3 | 4 | #include "eventloop.h" 5 | #include "linked_list.h" 6 | #include 7 | #include "coroutine.h" 8 | #include 9 | 10 | namespace cweb { 11 | namespace tcpserver { 12 | 13 | namespace coroutine { 14 | 15 | class CoEvent; 16 | class Coroutine; 17 | class CoEventLoop : public EventLoop { 18 | private: 19 | Coroutine* running_coroutine_ = nullptr; 20 | Coroutine* next_coroutine_ = nullptr; 21 | Coroutine* main_coroutine_ = nullptr; 22 | 23 | std::unordered_map events_; 24 | util::LinkedList running_coroutines_; 25 | util::LinkedList hold_coroutines_; 26 | util::LinkedList stateful_ready_coroutines_; 27 | util::LinkedList stateless_ready_coroutines_; 28 | 29 | void moveReadyCoroutines(); 30 | 31 | protected: 32 | void loop(); 33 | void handleActiveEvents(Time time); 34 | void handleTasks(); 35 | void handleTimeoutTimers(); 36 | 37 | public: 38 | CoEvent* GetEvent(int fd); 39 | virtual void Run() override; 40 | void AddTaskWithState(Functor cb, bool stateful = true); 41 | void AddCoroutineWithState(Coroutine* co, bool stateful = true); 42 | virtual void AddTask(Functor cb) override; 43 | virtual void AddTasks(std::vector& cbs) override; 44 | virtual void UpdateEvent(Event* event) override; 45 | virtual void RemoveEvent(Event* event) override; 46 | 47 | void NotifyCoroutineReady(Coroutine* co); 48 | Coroutine* GetCurrentCoroutine(); 49 | Coroutine* GetMainCoroutine(); 50 | 51 | }; 52 | 53 | } 54 | } 55 | } 56 | 57 | #endif 58 | -------------------------------------------------------------------------------- /src/co_tcpserver/co_eventloop_thread.cc: -------------------------------------------------------------------------------- 1 | #include "co_eventloop_thread.h" 2 | #include "co_eventloop.h" 3 | 4 | namespace cweb { 5 | namespace tcpserver { 6 | namespace coroutine { 7 | 8 | std::shared_ptr CoEventLoopThread::StartLoop() { 9 | stop_ = false; 10 | pthread_create(&tid_, NULL, cothreadFunc, this); 11 | 12 | { 13 | std::unique_lock lock(mutex_); 14 | while(loop_ == nullptr) { 15 | cond_.wait(lock); 16 | } 17 | } 18 | 19 | return loop_; 20 | } 21 | 22 | void* CoEventLoopThread::cothreadFunc(void *arg) { 23 | CoEventLoopThread* thread = (CoEventLoopThread*)arg; 24 | thread->createLoopAndRun(); 25 | return NULL; 26 | } 27 | 28 | void CoEventLoopThread::createLoopAndRun() { 29 | std::shared_ptrloop(new CoEventLoop()); 30 | 31 | { 32 | std::unique_lock lock(mutex_); 33 | loop_ = loop; 34 | cond_.notify_all(); 35 | } 36 | loop->Run(); 37 | } 38 | 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/co_tcpserver/co_eventloop_thread.h: -------------------------------------------------------------------------------- 1 | #ifndef CWEB_COROUTINE_COEVENTLOOPTHREAD_H_ 2 | #define CWEB_COROUTINE_COEVENTLOOPTHREAD_H_ 3 | 4 | #include 5 | #include 6 | #include "eventloop_thread.h" 7 | 8 | namespace cweb { 9 | namespace tcpserver { 10 | namespace coroutine { 11 | 12 | class CoEventLoopThread : public EventLoopThread { 13 | protected: 14 | void createLoopAndRun(); 15 | static void* cothreadFunc(void* arg); 16 | 17 | public: 18 | CoEventLoopThread(const std::string& name = "") : EventLoopThread(name) {}; 19 | ~CoEventLoopThread() {}; 20 | 21 | virtual std::shared_ptr StartLoop() override; 22 | }; 23 | 24 | } 25 | } 26 | } 27 | 28 | #endif 29 | 30 | -------------------------------------------------------------------------------- /src/co_tcpserver/co_eventloop_thread.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CWEB_COROUTINE_COEVENTLOOPTHREAD_H_ 2 | #define CWEB_COROUTINE_COEVENTLOOPTHREAD_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | namespace cweb { 9 | namespace tcpserver { 10 | 11 | class EventLoop; 12 | class EventLoopThread { 13 | private: 14 | EventLoop* loop_ = nullptr; 15 | bool stop_ = true; 16 | std::string name_; 17 | std::thread thread_; 18 | std::mutex mutex_; 19 | std::condition_variable cond_; 20 | void createLoopAndRun(); 21 | 22 | public: 23 | EventLoopThread(const std::string& name = "") : name_(name) {}; 24 | ~EventLoopThread(); 25 | 26 | EventLoop* StartLoop(); 27 | void StopLoop(); 28 | std::string Name() const {return name_;} 29 | }; 30 | 31 | } 32 | } 33 | 34 | #endif 35 | 36 | -------------------------------------------------------------------------------- /src/co_tcpserver/co_scheduler.cc: -------------------------------------------------------------------------------- 1 | #include "co_scheduler.h" 2 | #include "co_eventloop.h" 3 | #include "co_eventloop_thread.h" 4 | 5 | namespace cweb { 6 | namespace tcpserver { 7 | namespace coroutine { 8 | 9 | CoScheduler::CoScheduler(std::shared_ptr baseloop, int threadcnt) 10 | : Scheduler(baseloop, threadcnt) {} 11 | 12 | void CoScheduler::Start() { 13 | for(int i = 0; i < threadcnt_; ++i) { 14 | std::unique_ptr thread(new CoEventLoopThread()); 15 | loops_.push_back(thread->StartLoop()); 16 | threads_.push_back(std::move(thread)); 17 | } 18 | } 19 | 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/co_tcpserver/co_scheduler.h: -------------------------------------------------------------------------------- 1 | #ifndef CWEB_COROUTINE_COSCHEDULER_H_ 2 | #define CWEB_COROUTINE_COSCHEDULER_H_ 3 | 4 | #include "noncopyable.h" 5 | #include "scheduler.h" 6 | 7 | namespace cweb { 8 | namespace tcpserver { 9 | namespace coroutine { 10 | 11 | class Coroutine; 12 | class CoEventLoop; 13 | class CoScheduler : public Scheduler { 14 | private: 15 | 16 | public: 17 | CoScheduler(std::shared_ptr baseloop, int threadcnt); 18 | virtual void Start() override; 19 | 20 | }; 21 | 22 | } 23 | } 24 | } 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /src/co_tcpserver/co_tcpconnection.cc: -------------------------------------------------------------------------------- 1 | #include "co_tcpconnection.h" 2 | #include "co_event.h" 3 | #include "co_eventloop.h" 4 | #include "socket.h" 5 | #include "logger.h" 6 | 7 | using namespace cweb::log; 8 | 9 | namespace cweb { 10 | namespace tcpserver { 11 | namespace coroutine { 12 | 13 | CoTcpConnection::CoTcpConnection(std::shared_ptr loop, Socket* socket, InetAddress* addr, const std::string& id) 14 | : TcpConnection(loop, socket, addr, id) {} 15 | 16 | CoTcpConnection::~CoTcpConnection() {} 17 | 18 | void CoTcpConnection::Send(ByteData *data) { 19 | while(true) { 20 | ssize_t n = data->Writev(socket_->Fd()); 21 | if(n < 0 || !data->Remain()) { 22 | delete data; 23 | break; 24 | } 25 | } 26 | } 27 | 28 | void CoTcpConnection::Send(const void *data, size_t size) { 29 | ByteData* bdata = new ByteData(); 30 | while(true) { 31 | ssize_t n = bdata->Writev(socket_->Fd()); 32 | if(n < 0 || !bdata->Remain()) { 33 | delete bdata; 34 | break; 35 | } 36 | } 37 | } 38 | 39 | ssize_t CoTcpConnection::Recv(ByteBuffer* buf) { 40 | return buf->Readv(socket_->Fd()); 41 | } 42 | 43 | void CoTcpConnection::ForceClose() { 44 | if(connect_state_ != CLOSED) { 45 | if(ownerloop_->isInLoopThread()) { 46 | forceCloseInLoop(); 47 | }else { 48 | ownerloop_->AddTask(std::bind(&CoTcpConnection::forceCloseInLoop, this)); 49 | } 50 | } 51 | } 52 | 53 | void CoTcpConnection::forceCloseInLoop() { 54 | if(connect_state_ != CLOSED) { 55 | handleClose(); 56 | } 57 | } 58 | 59 | void CoTcpConnection::handleClose() { 60 | LOG(LOGLEVEL_INFO, CWEB_MODULE, "cotcpconnection", "连接关闭,id: %s", id_.c_str()); 61 | connect_state_ = CLOSED; 62 | ((CoEvent*)event_.get())->TriggerEvent(); 63 | event_->DisableAll(); 64 | event_->Remove(); 65 | connected_callback_(shared_from_this()); 66 | close_callback_(shared_from_this()); 67 | } 68 | 69 | void CoTcpConnection::handleTimeout() { 70 | LOG(LOGLEVEL_INFO, CWEB_MODULE, "cotcpconnection", "连接超时,socketfd: %d, id: %s", socket_->Fd() ,id_.c_str()); 71 | handleClose(); 72 | } 73 | 74 | void CoTcpConnection::handleMessage() { 75 | event_.reset(new CoEvent(std::dynamic_pointer_cast(ownerloop_), socket_->Fd(), true)); 76 | event_->SetTimeoutCallback(std::bind(&CoTcpConnection::handleTimeout, this)); 77 | ownerloop_->UpdateEvent(event_.get()); 78 | connect_state_ = CONNECT; 79 | connected_callback_(shared_from_this()); 80 | while(Connected()) { 81 | ssize_t n = inputbuffer_->Readv(socket_->Fd()); 82 | if(n > 0) { 83 | Time time = Time::Now(); 84 | LOG(LOGLEVEL_INFO, CWEB_MODULE, "cotcpconnection", "conn: %s 获取数据", id_.c_str()); 85 | //sleep(3); 86 | LOG(LOGLEVEL_INFO, CWEB_MODULE, "cotcpconnection", "conn: %s 睡醒", id_.c_str()); 87 | if(message_callback_) { 88 | MessageState state = message_callback_(shared_from_this(), inputbuffer_.get(), time); 89 | if(state == BAD) { 90 | break; 91 | } 92 | } 93 | }else if(n == 0) { 94 | LOG(LOGLEVEL_INFO, CWEB_MODULE, "cotcpconnection", "conn: %s 对端主动关闭", id_.c_str()); 95 | handleClose(); 96 | break; 97 | }else { 98 | LOG(LOGLEVEL_WARN, CWEB_MODULE, "cotcpconnection", "conn: %s 数据读取时出错", id_.c_str()); 99 | handleClose(); 100 | break; 101 | } 102 | } 103 | } 104 | 105 | } 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src/co_tcpserver/co_tcpconnection.h: -------------------------------------------------------------------------------- 1 | #ifndef CWEB_COROUTINE_COTCPCONNECTION_H_ 2 | #define CWEB_COROUTINE_COTCPCONNECTION_H_ 3 | 4 | #include "tcpconnection.h" 5 | 6 | namespace cweb { 7 | namespace tcpserver { 8 | namespace coroutine { 9 | 10 | class CoEventLoop; 11 | class CoSocket; 12 | class CoEvent; 13 | class CoTcpConnection : public TcpConnection { 14 | protected: 15 | void handleMessage(); 16 | void handleClose(); 17 | void handleTimeout(); 18 | void forceCloseInLoop(); 19 | 20 | public: 21 | friend class CoTcpServer; 22 | CoTcpConnection(std::shared_ptr loop, Socket* socket, InetAddress* addr, const std::string& id); 23 | virtual ~CoTcpConnection(); 24 | 25 | virtual void ForceClose() override; 26 | virtual void Send(const void* data, size_t size) override; 27 | virtual void Send(ByteData* data) override; 28 | virtual ssize_t Recv(ByteBuffer* buf) override; 29 | }; 30 | 31 | } 32 | } 33 | } 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /src/co_tcpserver/co_tcpserver.cc: -------------------------------------------------------------------------------- 1 | #include "co_tcpserver.h" 2 | #include "co_scheduler.h" 3 | #include "co_tcpconnection.h" 4 | #include "co_eventloop.h" 5 | #include "co_event.h" 6 | #include "socket.h" 7 | #include "logger.h" 8 | #include 9 | #include 10 | 11 | using namespace cweb::log; 12 | 13 | namespace cweb { 14 | namespace tcpserver { 15 | namespace coroutine { 16 | 17 | CoTcpServer::CoTcpServer(std::shared_ptr loop, uint16_t port, bool loopbackonly, bool ipv6) 18 | : TcpServer(loop, port, loopbackonly, ipv6) {} 19 | 20 | CoTcpServer::CoTcpServer(std::shared_ptr loop, const std::string& ip, uint16_t port, bool ipv6) 21 | : TcpServer(loop, ip, port, ipv6) {} 22 | 23 | CoTcpServer::~CoTcpServer() { 24 | 25 | } 26 | 27 | void CoTcpServer::Start(int threadcnt) { 28 | init(); 29 | running_ = true; 30 | scheduler_.reset(new CoScheduler(std::dynamic_pointer_cast(accept_loop_), threadcnt)); 31 | scheduler_->Start(); 32 | accept_socket_->Listen(); 33 | accept_event_->EnableReading(); 34 | accept_loop_->Run(); 35 | } 36 | 37 | void CoTcpServer::init() { 38 | accept_socket_.reset(Socket::CreateFdAndBind(addr_.get(), true)); 39 | accept_event_.reset(new CoEvent(std::dynamic_pointer_cast(accept_loop_), accept_socket_->Fd())); 40 | accept_event_->SetReadCallback(std::bind(&CoTcpServer::handleAccept, this)); 41 | } 42 | 43 | void CoTcpServer::handleAccept() { 44 | while (running_) { 45 | InetAddress* peeraddr = new InetAddress(); 46 | 47 | int connfd = accept_socket_->Accept(peeraddr); 48 | 49 | Socket* socket = nullptr; 50 | if(connfd > 0) socket = new Socket(connfd); 51 | else { 52 | LOG(LOGLEVEL_WARN, CWEB_MODULE, "cotcpserver", "创建连接失败"); 53 | delete peeraddr; 54 | continue; 55 | } 56 | 57 | socket->SetNonBlock(); 58 | std::shared_ptr loop = std::dynamic_pointer_cast(scheduler_->GetNextLoop()); 59 | //底层会调用read 60 | std::string id = boost::uuids::to_string(random_generator_()); 61 | std::shared_ptr conn = std::make_shared(loop, socket, peeraddr, id); 62 | LOG(LOGLEVEL_INFO, CWEB_MODULE, "cotcpserver", "创建连接,connfd: %d, id: %s", connfd, id.c_str()); 63 | conn->SetCloseCallback(std::bind(&CoTcpServer::handleConnectionClose, this, std::placeholders::_1)); 64 | conn->SetConnectedCallback(connected_callback_); 65 | living_connections_[id] = conn; 66 | loop->AddTask(std::bind(&CoTcpConnection::handleMessage, conn.get())); 67 | } 68 | } 69 | 70 | void CoTcpServer::handleConnectionClose(std::shared_ptr conn) { 71 | accept_loop_->AddTask(std::bind(&CoTcpServer::removeConnectionInLoop, this, conn)); 72 | } 73 | 74 | void CoTcpServer::removeConnectionInLoop(std::shared_ptr conn) { 75 | LOG(LOGLEVEL_INFO, CWEB_MODULE, "cotcpserver", "移出连接,id: %s", std::dynamic_pointer_cast(conn) ->id_.c_str()); 76 | living_connections_.erase(std::dynamic_pointer_cast(conn) ->id_); 77 | } 78 | 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/co_tcpserver/co_tcpserver.h: -------------------------------------------------------------------------------- 1 | #ifndef CWEB_COROUTINE_COTCPSERVER_H_ 2 | #define CWEB_COROUTINE_COTCPSERVER_H_ 3 | 4 | #include "event.h" 5 | #include "tcpserver.h" 6 | #include "inetaddress.h" 7 | 8 | namespace cweb { 9 | namespace tcpserver { 10 | namespace coroutine { 11 | 12 | class CoSocket; 13 | class CoEventLoop; 14 | class CoEvent; 15 | class CoScheduler; 16 | class CoTcpServer : public TcpServer { 17 | 18 | protected: 19 | void handleAccept(); 20 | void handleConnectionClose(std::shared_ptr conn); 21 | void removeConnectionInLoop(std::shared_ptr conn); 22 | void init(); 23 | 24 | public: 25 | CoTcpServer(std::shared_ptr loop, uint16_t port = 0, bool loopbackonly = false, bool ipv6 = false); 26 | CoTcpServer(std::shared_ptr loop, const std::string& ip, uint16_t port, bool ipv6 = false); 27 | virtual ~CoTcpServer(); 28 | 29 | virtual void Start(int threadcnt) override; 30 | }; 31 | 32 | } 33 | } 34 | } 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /src/co_tcpserver/context_swap.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nodesheep/RESTfulCweb/d22f37d5f682a99ba0d7365e1a37cff5b257c306/src/co_tcpserver/context_swap.o -------------------------------------------------------------------------------- /src/co_tcpserver/context_swap.s: -------------------------------------------------------------------------------- 1 | .global __ZN4cweb9tcpserver9coroutine12context_swapEPNS1_16CoroutineContextES3_ 2 | 3 | __ZN4cweb9tcpserver9coroutine12context_swapEPNS1_16CoroutineContextES3_: 4 | leaq (%rsp), %rax 5 | movq %rax, 56(%rdi) 6 | movq %rbx, 48(%rdi) 7 | movq 0(%rax), %rax 8 | movq %rax, 40(%rdi) 9 | movq %rbp, 32(%rdi) 10 | movq %r12, 24(%rdi) 11 | movq %r13, 16(%rdi) 12 | movq %r14, 8(%rdi) 13 | movq %r15, (%rdi) 14 | xorq %rax, %rax 15 | 16 | movq 32(%rsi), %rbp 17 | movq 56(%rsi), %rsp 18 | movq (%rsi), %r15 19 | movq 8(%rsi), %r14 20 | movq 16(%rsi), %r13 21 | movq 24(%rsi), %r12 22 | movq 48(%rsi), %rbx 23 | movq 64(%rsi), %rdi 24 | leaq 8(%rsp), %rsp 25 | pushq 40(%rsi) 26 | 27 | ret 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /src/co_tcpserver/coroutine.cc: -------------------------------------------------------------------------------- 1 | #include "coroutine.h" 2 | #include "co_eventloop.h" 3 | #include "coroutine_context.h" 4 | #include "pthread_keys.h" 5 | 6 | namespace cweb { 7 | namespace tcpserver { 8 | namespace coroutine { 9 | 10 | static const size_t kCoroutineContextSize = 4096 * 1024; 11 | 12 | void Coroutine::coroutineFunc(void *vp) { 13 | Coroutine* co = (Coroutine*)vp; 14 | co->run(); 15 | } 16 | 17 | Coroutine::Coroutine(std::function func, std::shared_ptr loop) : func_(std::move(func)), context_(new CoroutineContext(kCoroutineContextSize, coroutineFunc, this)), loop_(loop) {} 18 | 19 | Coroutine::~Coroutine() { 20 | delete context_; 21 | } 22 | 23 | void Coroutine::SwapIn() { 24 | state_ = EXEC; 25 | CoroutineContext::ContextSwap(((CoEventLoop*)pthread_getspecific(util::PthreadKeysSingleton::GetInstance()->TLSEventLoop))->GetMainCoroutine()->context_, context_); 26 | } 27 | 28 | void Coroutine::SwapOut() { 29 | CoroutineContext::ContextSwap(context_, ((CoEventLoop*)pthread_getspecific(util::PthreadKeysSingleton::GetInstance()->TLSEventLoop))->GetMainCoroutine()->context_); 30 | } 31 | 32 | void Coroutine::SwapTo(Coroutine *co) { 33 | co->SetState(EXEC); 34 | CoroutineContext::ContextSwap(context_, co->context_); 35 | } 36 | 37 | void Coroutine::SetState(enum State state) { 38 | if(state_ != READY && state == READY) { 39 | loop_->NotifyCoroutineReady(this); 40 | } 41 | state_ = state; 42 | } 43 | 44 | void Coroutine::run() { 45 | if(func_) func_(); 46 | state_ = TERM; 47 | SwapOut(); 48 | } 49 | 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/co_tcpserver/coroutine.h: -------------------------------------------------------------------------------- 1 | #ifndef CWEB_COROUTINE_COROUTINE_H_ 2 | #define CWEB_COROUTINE_COROUTINE_H_ 3 | 4 | #include 5 | #include 6 | #include "linked_list.h" 7 | #include "co_event.h" 8 | 9 | namespace cweb { 10 | namespace tcpserver { 11 | namespace coroutine { 12 | 13 | class CoroutineContext; 14 | class CoEventLoop; 15 | class CoEvent; 16 | class Coroutine : public util::LinkedListNode { 17 | 18 | public: 19 | enum State { 20 | READY, 21 | HOLD, 22 | EXEC, 23 | TERM 24 | }; 25 | 26 | Coroutine(std::function func, std::shared_ptr loop = nullptr); 27 | ~Coroutine(); 28 | void SwapIn(); 29 | void SwapOut(); 30 | void SwapTo(Coroutine* co); 31 | 32 | void SetState(State state); 33 | State State() const {return state_;} 34 | void SetLoop(std::shared_ptr loop) {loop_ = loop;} 35 | 36 | private: 37 | enum State state_ = READY; 38 | CoroutineContext* context_; 39 | std::function func_; 40 | std::shared_ptr loop_; 41 | CoEvent* event_ = nullptr; 42 | void run(); 43 | static void coroutineFunc(void* vp); 44 | }; 45 | 46 | } 47 | } 48 | } 49 | 50 | #endif 51 | -------------------------------------------------------------------------------- /src/co_tcpserver/coroutine_context.cc: -------------------------------------------------------------------------------- 1 | #include "coroutine_context.h" 2 | #include 3 | 4 | #define R15 0 5 | #define R14 1 6 | #define R13 2 7 | #define R12 3 8 | #define RBP 4 9 | #define RET 5 10 | #define RBX 6 11 | #define RSP 7 12 | #define RDI 8 13 | 14 | namespace cweb { 15 | namespace tcpserver { 16 | namespace coroutine { 17 | 18 | void context_swap(CoroutineContext* from, CoroutineContext* to); 19 | 20 | CoroutineContext::CoroutineContext() {} 21 | 22 | CoroutineContext::CoroutineContext(size_t size, void (*fn)(void*), const void* vp) : ss_size(size) { 23 | Init(size, fn, vp); 24 | } 25 | 26 | CoroutineContext::~CoroutineContext() { 27 | free(ss_sp); 28 | } 29 | 30 | void CoroutineContext::Init(size_t size, void (*fn)(void*), const void* vp) { 31 | ss_sp = (char*)malloc(size); //堆 低->高 32 | //移动到高地址 栈 高->低 33 | char* sp = ss_sp + ss_size - sizeof(void*); 34 | 35 | //对齐 移动(16 - ss_size % 16) 36 | sp = (char*)((unsigned long)sp & -16LL); 37 | 38 | memset(regs, 0, sizeof(regs)); 39 | 40 | *(void**)sp = (void*)fn; 41 | 42 | //初始时栈顶位置 43 | regs[RBP] = sp + sizeof(void*); 44 | regs[RSP] = sp; //栈顶指针存储函数地址 函数运行过程栈指针向高地址增长 45 | regs[RDI] = (void*)vp; 46 | 47 | regs[RET] = (void*)fn; //函数返回地址 48 | } 49 | 50 | void CoroutineContext::ContextSwap(CoroutineContext *from, CoroutineContext *to) { 51 | context_swap(from, to); 52 | } 53 | 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/co_tcpserver/coroutine_context.h: -------------------------------------------------------------------------------- 1 | #ifndef CWEB_COROUTINE_COROUTINECONTEXT_H_ 2 | #define CWEB_COROUTINE_COROUTINECONTEXT_H_ 3 | 4 | //目前只支持x86_64 5 | #include 6 | #include 7 | 8 | namespace cweb { 9 | namespace tcpserver { 10 | namespace coroutine { 11 | 12 | class CoroutineContext { 13 | public: 14 | void* regs[9]; 15 | size_t ss_size = 0; 16 | char* ss_sp = nullptr; 17 | 18 | CoroutineContext(); 19 | ~CoroutineContext(); 20 | CoroutineContext(size_t size, void (*fn)(void*), const void* vp); 21 | void Init(size_t size, void (*fn)(void*), const void* vp); 22 | static void ContextSwap(CoroutineContext *from, CoroutineContext *to); 23 | }; 24 | 25 | } 26 | } 27 | } 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /src/cweb/context.cc: -------------------------------------------------------------------------------- 1 | #include "context.h" 2 | #include "httpserver.h" 3 | #include "httpsession.h" 4 | #include "bytedata.h" 5 | #include 6 | #include 7 | 8 | namespace cweb { 9 | 10 | Context::~Context() { 11 | if(redis_) { 12 | RedisPoolSingleton::GetInstance()->ReleaseConnection(redis_); 13 | } 14 | 15 | if(mysql_) { 16 | MySQLPoolSingleton::GetInstance()->ReleaseConnection(mysql_); 17 | } 18 | } 19 | 20 | const std::string& Context::Method() const { 21 | return request_->Method(); 22 | } 23 | 24 | const std::string& Context::Path() const { 25 | return request_->Path(); 26 | } 27 | 28 | const std::string& Context::Param(const std::string &key) { 29 | static std::string empty; 30 | auto iter = params_.find(key); 31 | if(iter != params_.end()) { 32 | return iter->second; 33 | } 34 | return empty; 35 | } 36 | 37 | const std::string& Context::Query(const std::string &key) const { 38 | return request_->Query(key); 39 | } 40 | 41 | const std::string& Context::PostForm(const std::string &key) const { 42 | return request_->PostForm(key); 43 | } 44 | 45 | MultipartPart* Context::MultipartForm(const std::string& key) const { 46 | return request_->MultipartForm(key); 47 | } 48 | 49 | const Json::Value& Context::JsonValue() const { 50 | return request_->JsonValue(); 51 | } 52 | 53 | const BinaryData& Context::BinaryValue() const { 54 | return request_->BinaryValue(); 55 | } 56 | 57 | void Context::SaveUploadedFile(const BinaryData &file, const std::string &path, const std::string& filename) { 58 | std::ofstream ofs; 59 | ofs.open(path + filename, std::ofstream::out | std::ofstream::app); 60 | ofs.write(file.data, file.size); 61 | ofs.close(); 62 | } 63 | 64 | std::shared_ptr Context::Redis() { 65 | if(redis_) return redis_; 66 | redis_ = RedisPoolSingleton::GetInstance()->GetConnection(); 67 | return redis_; 68 | } 69 | 70 | std::shared_ptr Context::MySQL() { 71 | if(mysql_) return mysql_; 72 | mysql_ = MySQLPoolSingleton::GetInstance()->GetConnection(); 73 | return mysql_; 74 | } 75 | 76 | std::shared_ptr Context::Upgrade() const { 77 | return std::dynamic_pointer_cast(session_); 78 | } 79 | 80 | void Context::STRING(HttpStatusCode code, const std::string& data) { 81 | session_->SendString(code, data); 82 | } 83 | 84 | void Context::JSON(HttpStatusCode code, const std::string& data) { 85 | session_->SendJson(code, data); 86 | } 87 | 88 | //单文件传输 89 | void Context::FILE(HttpStatusCode code, const std::string &filepath, std::string filename) { 90 | session_->SendFile(code, filepath, filename); 91 | } 92 | 93 | //MULTIPART 数据 94 | /* 95 | POST /upload HTTP/1.1 96 | Host: example.com 97 | Content-Type: multipart/form-data; boundary=----BOUNDARY_STRING 98 | 99 | ------BOUNDARY_STRING 100 | Content-Disposition: form-data; name="file"; filename="test.jpg" 101 | Content-Type: image/jpeg 102 | 103 | 104 | ------BOUNDARY_STRING--*/ 105 | void Context::MULTIPART(HttpStatusCode code, const std::vector& parts) { 106 | session_->SendMultipart(code, parts); 107 | } 108 | 109 | 110 | } 111 | -------------------------------------------------------------------------------- /src/cweb/context.h: -------------------------------------------------------------------------------- 1 | #ifndef CWEB_CWEB_CONTEXT_H_ 2 | #define CWEB_CWEB_CONTEXT_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include "router.h" 8 | #include "bytebuffer.h" 9 | #include "http_code.h" 10 | #include "httpserver.h" 11 | #include "httprequest.h" 12 | #include "websocket.h" 13 | #include "redis.h" 14 | #include "mysql.h" 15 | 16 | using namespace cweb::tcpserver; 17 | using namespace cweb::httpserver; 18 | using namespace cweb::util; 19 | using namespace cweb::db; 20 | 21 | namespace cweb { 22 | 23 | class Context : public std::enable_shared_from_this { 24 | private: 25 | int index_ = -1; 26 | std::vector handlers_; 27 | std::unique_ptr request_; 28 | //shared 避免下层通道关闭后 上层无感知导致send空指针 29 | std::shared_ptr session_; 30 | std::unordered_map params_; 31 | std::shared_ptr redis_ = nullptr; 32 | std::shared_ptr mysql_ = nullptr; 33 | 34 | public: 35 | friend class Router; 36 | Context(std::shared_ptr session, std::unique_ptr req) : session_(session), request_(std::move(req)) {} 37 | ~Context(); 38 | 39 | void Next() { 40 | ++index_; 41 | if(index_ < handlers_.size()) { 42 | (handlers_[index_])(shared_from_this()); 43 | } 44 | } 45 | 46 | void AddHandler(ContextHandler handler) { 47 | handlers_.push_back(std::move(handler)); 48 | } 49 | 50 | const std::string& Method() const; 51 | const std::string& Path() const; 52 | const std::string& Query(const std::string& key) const; 53 | const std::string& Param(const std::string& key); 54 | const std::string& PostForm(const std::string& key) const; 55 | MultipartPart* MultipartForm(const std::string& key) const; 56 | const Json::Value& JsonValue() const; 57 | const BinaryData& BinaryValue() const; 58 | 59 | std::shared_ptr Redis(); 60 | std::shared_ptr MySQL(); 61 | 62 | std::shared_ptr Upgrade() const; 63 | 64 | void SaveUploadedFile(const BinaryData& file, const std::string& path, const std::string& filename); 65 | 66 | void STRING(HttpStatusCode code, const std::string& data); 67 | void JSON(HttpStatusCode code, const std::string& data); 68 | void FILE(HttpStatusCode code, const std::string& filepath, std::string filename = ""); 69 | void MULTIPART(HttpStatusCode code, const std::vector& parts); 70 | }; 71 | 72 | } 73 | #endif /* context_hpp */ 74 | -------------------------------------------------------------------------------- /src/cweb/cweb.cc: -------------------------------------------------------------------------------- 1 | #include "cweb.h" 2 | #include "context.h" 3 | #include "httpserver.h" 4 | #include "redis.h" 5 | #include "mysql.h" 6 | #include "logger.h" 7 | #ifdef COROUTINE 8 | #include "co_eventloop.h" 9 | #else 10 | #include "eventloop.h" 11 | #endif 12 | 13 | #ifdef COROUTINE 14 | using namespace cweb::tcpserver::coroutine; 15 | #endif 16 | 17 | using namespace cweb::db; 18 | using namespace cweb::log; 19 | 20 | namespace cweb { 21 | 22 | #ifdef COROUTINE 23 | std::shared_ptr mainloop(new CoEventLoop()); 24 | #else 25 | std::shared_ptr mainloop(new EventLoop()); 26 | #endif 27 | 28 | Cweb::Cweb(uint16_t port, bool loopbackonly, bool ipv6) { 29 | LoggerManagerSingleton::GetInstance(); 30 | if(!RedisPoolSingleton::GetInstance()->Init()) { 31 | LOG(LOGLEVEL_DEBUG, CWEB_MODULE, "cweb", "redis init error"); 32 | } 33 | if(!MySQLPoolSingleton::GetInstance()->Init()) { 34 | LOG(LOGLEVEL_DEBUG, CWEB_MODULE, "cweb", "mysql init error"); 35 | } 36 | LoggerManagerSingleton::GetInstance(); 37 | router_.reset(new Router()); 38 | httpserver_.reset(new HttpServer(mainloop, port, loopbackonly, ipv6)); 39 | httpserver_->SetRequestCallback(std::bind(&Cweb::serverHTTP, this, std::placeholders::_1, std::placeholders::_2)); 40 | } 41 | 42 | Cweb::Cweb(const std::string& ip, uint16_t port, bool ipv6) { 43 | LoggerManagerSingleton::GetInstance(); 44 | if(!RedisPoolSingleton::GetInstance()->Init()) { 45 | LOG(LOGLEVEL_DEBUG, CWEB_MODULE, "cweb", "redis init error"); 46 | } 47 | if(!MySQLPoolSingleton::GetInstance()->Init()) { 48 | LOG(LOGLEVEL_DEBUG, CWEB_MODULE, "cweb", "mysql init error"); 49 | } 50 | router_.reset(new Router()); 51 | httpserver_.reset(new HttpServer(mainloop, ip, port, ipv6)); 52 | httpserver_->SetRequestCallback(std::bind(&Cweb::serverHTTP, this, std::placeholders::_1, std::placeholders::_2)); 53 | } 54 | 55 | Cweb::~Cweb() { 56 | for(class Group* group : groups_) { 57 | delete group; 58 | } 59 | } 60 | 61 | void Cweb::serverHTTP(std::shared_ptr session, std::unique_ptr req) { 62 | std::shared_ptr c = std::make_shared(session, std::move(req)); 63 | 64 | //全局中间件 65 | for(ContextHandler handler : global_handlers_) { 66 | //验证有无问题 67 | c->AddHandler(std::move(handler)); 68 | } 69 | 70 | for(class Group* group : groups_) { 71 | if(c->Path().find(group->prefix_) == 0) { 72 | for(ContextHandler handler : group->middlewares_) { 73 | c->AddHandler(std::move(handler)); 74 | } 75 | } 76 | } 77 | 78 | router_->Handle(c); 79 | } 80 | 81 | void Cweb::Run(int threadcnt) { 82 | LOG(LOGLEVEL_DEBUG, CWEB_MODULE, "cweb", "server start success"); 83 | httpserver_->Start(threadcnt); 84 | } 85 | 86 | void Cweb::Quit() { 87 | httpserver_->Quit(); 88 | } 89 | 90 | } 91 | -------------------------------------------------------------------------------- /src/cweb/cweb.h: -------------------------------------------------------------------------------- 1 | #ifndef CWEB_CWEB_CWEB_H_ 2 | #define CWEB_CWEB_CWEB_H_ 3 | 4 | #include 5 | #include "router.h" 6 | #include "httpsession.h" 7 | #include "httpserver.h" 8 | 9 | using namespace cweb::tcpserver; 10 | using namespace cweb::httpserver; 11 | 12 | namespace cweb { 13 | 14 | class Group { 15 | private: 16 | const std::string prefix_; 17 | std::vector middlewares_; 18 | Router* router_ = nullptr; 19 | 20 | public: 21 | friend class Cweb; 22 | Group(const std::string& prefix, Router* router) : prefix_(prefix), router_(router) {} 23 | 24 | void Use(ContextHandler handler) { 25 | middlewares_.push_back(std::move(handler)); 26 | } 27 | 28 | void GET(const std::string& path, ContextHandler handler) { 29 | router_->AddRouter("GET", prefix_ + path, handler); 30 | } 31 | 32 | void POST(const std::string& path, ContextHandler handler) { 33 | router_->AddRouter("POST", prefix_ + path, handler); 34 | } 35 | 36 | void PUT(const std::string& path, ContextHandler handler) { 37 | router_->AddRouter("PUT", prefix_ + path, handler); 38 | } 39 | 40 | void DELETE(const std::string& path, ContextHandler handler) { 41 | router_->AddRouter("DELETE", prefix_ + path, handler); 42 | } 43 | }; 44 | 45 | class Cweb { 46 | private: 47 | std::unique_ptr router_; 48 | std::vector global_handlers_; 49 | std::vector groups_; 50 | std::unique_ptr httpserver_; 51 | 52 | void serverHTTP(std::shared_ptr session, std::unique_ptr req); 53 | 54 | public: 55 | Cweb(uint16_t port, bool loopbackonly = false, bool ipv6 = false); 56 | Cweb(const std::string& ip, uint16_t port, bool ipv6 = false); 57 | 58 | ~Cweb(); 59 | 60 | void Use(ContextHandler handler) { 61 | global_handlers_.push_back(std::move(handler)); 62 | } 63 | 64 | void GET(const std::string& path, ContextHandler handler) { 65 | router_->AddRouter("GET", path, handler); 66 | } 67 | 68 | void POST(const std::string& path, ContextHandler handler) { 69 | router_->AddRouter("POST", path, handler); 70 | } 71 | 72 | void PUT(const std::string& path, ContextHandler handler) { 73 | router_->AddRouter("PUT", path, handler); 74 | } 75 | 76 | void DELETE(const std::string& path, ContextHandler handler) { 77 | router_->AddRouter("DELETE", path, handler); 78 | } 79 | 80 | class Group* Group(const std::string& prefix) { 81 | class Group* group = new class Group(prefix, router_.get()); 82 | groups_.push_back(std::move(group)); 83 | return group; 84 | } 85 | 86 | void Run(int threadcnt); 87 | void Quit(); 88 | }; 89 | 90 | } 91 | 92 | #endif 93 | -------------------------------------------------------------------------------- /src/cweb/router.cc: -------------------------------------------------------------------------------- 1 | #include "router.h" 2 | #include "context.h" 3 | #include "logger.h" 4 | 5 | using namespace cweb::log; 6 | namespace cweb { 7 | 8 | void Router::AddRouter(const std::string &method, const std::string &pattern, ContextHandler handler) { 9 | std::vector parts; 10 | Trie::ParsePattern(pattern, parts); 11 | 12 | if(roots_.find(method) == roots_.end()) { 13 | roots_[method] = new Trie(); 14 | } 15 | 16 | roots_[method]->Insert(pattern, handler); 17 | } 18 | 19 | void Router::Handle(std::shared_ptr c) { 20 | if(findRoute(c.get())) { 21 | LOG(LOGLEVEL_INFO, CWEB_MODULE, "router", "请求命中路由: %s", c->Path().c_str()); 22 | c->Next(); 23 | }else { 24 | LOG(LOGLEVEL_WARN, CWEB_MODULE, "router", "请求未命中路由: %s", c->Path().c_str()); 25 | c->STRING(StatusNotFound, "NOT FOUND!"); 26 | } 27 | } 28 | 29 | bool Router::findRoute(Context *c) { 30 | if(roots_.find(c->Method()) == roots_.end()) return false; 31 | 32 | std::vector parts; 33 | Trie::ParsePattern(c->Path(), parts); 34 | 35 | Node* node = roots_[c->Method()]->Search(parts); 36 | 37 | if(node != nullptr) { 38 | std::vector node_parts; 39 | Trie::ParsePattern(node->pattern_, node_parts); 40 | for(int i = 0; i < node_parts.size(); ++i) { 41 | if(node_parts[i][0] == ':') { 42 | c->params_[node_parts[i].substr(1)] = parts[i]; 43 | } 44 | } 45 | c->AddHandler(node->handler_); 46 | return true; 47 | } 48 | 49 | return false; 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /src/cweb_config.h: -------------------------------------------------------------------------------- 1 | #ifndef CWEB_CWEBCONFIG_H_ 2 | #define CWEB_CWEBCONFIG_H_ 3 | 4 | #include 5 | #include 6 | #include "log_info.h" 7 | 8 | namespace cweb { 9 | 10 | class EnvConfig { 11 | public: 12 | static void Init() { 13 | signal(SIGPIPE, SIG_IGN); 14 | } 15 | }; 16 | 17 | class LogConfig { 18 | public: 19 | std::string log_pattern = "[%d][%l][%T][%m][%t][%c]%n"; 20 | std::string log_filepath = "../logfile"; 21 | cweb::log::LogLevel log_level = cweb::log::LogLevel::LOGLEVEL_DEBUG; 22 | int writer_capcity = 2000; 23 | //是否控制台打印日志 24 | bool need_console = true; 25 | }; 26 | 27 | class RedisConfig { 28 | public: 29 | enum Type { 30 | Standalone, 31 | Cluster 32 | }; 33 | 34 | Type type = Standalone; 35 | std::string host = "127.0.0.1"; 36 | int port = 8300; 37 | std::string addrs = "127.0.0.1:8306,127.0.0.1:8307,127.0.0.1:8308"; 38 | std::string password = "12345678"; 39 | int capcity = 5; 40 | uint64_t timeout_ms = 100; 41 | 42 | }; 43 | 44 | class MysqlConfig { 45 | public: 46 | std::string host = "127.0.0.1"; 47 | int port = 3306; 48 | std::string user = "root"; 49 | std::string password = "ccw257yej"; 50 | std::string dbname = "test"; 51 | int capcity = 5; 52 | uint64_t timeout_ms = 100; 53 | }; 54 | 55 | class ElasticSearchConfig { 56 | 57 | }; 58 | 59 | } 60 | 61 | 62 | #endif 63 | -------------------------------------------------------------------------------- /src/db/dbconnection_pool.h: -------------------------------------------------------------------------------- 1 | #ifndef CWEB_DATABASE_CONNECTIONPOOL_H_ 2 | #define CWEB_DATABASE_CONNECTIONPOOL_H_ 3 | 4 | #include "lockfree_queue.h" 5 | #include 6 | #include 7 | 8 | using namespace cweb::util; 9 | 10 | template 11 | class DBConnectionPool { 12 | protected: 13 | std::shared_ptr>> connections_; 14 | std::mutex mutex_; 15 | std::condition_variable cond_; 16 | 17 | public: 18 | DBConnectionPool() {} 19 | DBConnectionPool(int capcity) : connections_(std::make_shared>>(capcity)) {} 20 | 21 | virtual ~DBConnectionPool(){} 22 | 23 | std::shared_ptr GetConnection() { 24 | std::shared_ptr conn; 25 | std::unique_lock lock(mutex_); 26 | while(!connections_->MultiplePop(conn)) { 27 | cond_.wait(lock); 28 | } 29 | 30 | return conn; 31 | } 32 | 33 | bool ReleaseConnection(std::shared_ptr conn) { 34 | connections_->MultiplePush(conn); 35 | cond_.notify_all(); 36 | return true; 37 | } 38 | }; 39 | 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /src/db/mysql.cc: -------------------------------------------------------------------------------- 1 | #include "mysql.h" 2 | #include "logger.h" 3 | 4 | using namespace cweb::log; 5 | 6 | namespace cweb { 7 | namespace db { 8 | 9 | MySQLReply::MySQLReply(MYSQL_RES* res) { 10 | if(res) { 11 | data_.reset(res, mysql_free_result); 12 | } 13 | } 14 | 15 | int MySQLReply::Rows() { 16 | return (int)mysql_num_rows(data_.get()); 17 | } 18 | 19 | int MySQLReply::Columns() { 20 | return (int)mysql_num_fields(data_.get()); 21 | } 22 | 23 | std::string MySQLReply::ColumnName(int idx) { 24 | MYSQL_FIELD* filed = mysql_fetch_field_direct(data_.get(), idx); 25 | return filed->name; 26 | } 27 | 28 | bool MySQLReply::Next() { 29 | current_row_ = mysql_fetch_row(data_.get()); 30 | current_row_len_ = mysql_fetch_lengths(data_.get()); 31 | return current_row_; 32 | } 33 | 34 | bool MySQLReply::isNull(int idx) { 35 | return current_row_[idx] == nullptr; 36 | } 37 | 38 | int MySQLReply::IntValue(int idx) { 39 | return std::stoi(current_row_[idx]); 40 | } 41 | 42 | uint MySQLReply::UIntValue(int idx) { 43 | return std::stoi(current_row_[idx]); 44 | } 45 | 46 | int64_t MySQLReply::Int64Value(int idx) { 47 | return std::stoll(current_row_[idx]); 48 | } 49 | 50 | uint64_t MySQLReply::UInt64Value(int idx) { 51 | return std::stoull(current_row_[idx]); 52 | } 53 | 54 | float MySQLReply::FloatValue(int idx) { 55 | return std::stof(current_row_[idx]); 56 | } 57 | 58 | double MySQLReply::DoubleValue(int idx) { 59 | return std::stod(current_row_[idx]); 60 | } 61 | 62 | std::string MySQLReply::StringValue(int idx) { 63 | return std::string(current_row_[idx], current_row_len_[idx]); 64 | } 65 | 66 | std::string MySQLReply::BlobValue(int idx) { 67 | return std::string(current_row_[idx], current_row_len_[idx]); 68 | } 69 | 70 | bool MySQL::Connect(const std::string &host, int port, const std::string &user, const std::string &password, const std::string &dbname, int timeout_ms) { 71 | MYSQL* mysql = mysql_init(nullptr); 72 | if(!mysql) { 73 | LOG(LOGLEVEL_ERROR, CWEB_MODULE, "mysql", "connect init error"); 74 | return false; 75 | } 76 | 77 | if(timeout_ms > 0) mysql_options(mysql, MYSQL_OPT_CONNECT_TIMEOUT, &timeout_ms); 78 | 79 | if(!mysql_real_connect(mysql, host.c_str(), user.c_str(), password.c_str(), dbname.c_str(), port, NULL, 0)) { 80 | LOG(LOGLEVEL_ERROR, CWEB_MODULE, "mysql", "connect error"); 81 | mysql_close(mysql); 82 | return false; 83 | } 84 | 85 | mysql_.reset(mysql, mysql_close); 86 | return true; 87 | } 88 | 89 | bool MySQL::Use(const std::string &dbname) { 90 | return mysql_select_db(mysql_.get(), dbname.c_str()) == 0; 91 | } 92 | 93 | /* 94 | row[0] row[1] row[2] 95 | "1" "Alice" "100" 96 | "2" "Bob" "200" 97 | "3" "Carol" "300" 98 | */ 99 | MySQLReplyPtr MySQL::Cmd(const char *format, ...) { 100 | va_list ap; 101 | va_start(ap, format); 102 | 103 | char* buf = nullptr; 104 | if(vasprintf(&buf, format, ap) < 0) { 105 | LOG(LOGLEVEL_ERROR, CWEB_MODULE, "mysql", "cmd format error"); 106 | return nullptr; 107 | } 108 | MySQLReplyPtr r = cmd(buf); 109 | va_end(ap); 110 | free(buf); 111 | 112 | return r; 113 | } 114 | 115 | MySQLReplyPtr MySQL::Cmd(const std::string &sql) { 116 | return cmd(sql.c_str()); 117 | } 118 | 119 | MySQLReplyPtr MySQL::cmd(const char *sql) { 120 | if(mysql_query(mysql_.get(), sql) != 0) { 121 | LOG(LOGLEVEL_ERROR, CWEB_MODULE, "mysql", "cmd query error"); 122 | return nullptr; 123 | } 124 | 125 | MYSQL_RES* res = mysql_store_result(mysql_.get()); 126 | if(!res) { 127 | LOG(LOGLEVEL_ERROR, CWEB_MODULE, "mysql", "cmd result store error"); 128 | return nullptr; 129 | } 130 | 131 | MySQLReplyPtr rt(new MySQLReply(res)); 132 | 133 | return rt; 134 | } 135 | 136 | bool MySQLPool::Init() { 137 | connections_ = std::make_shared>>(config_.capcity); 138 | for(int i = 0; i < config_.capcity; ++i) { 139 | std::shared_ptr sql = std::make_shared(); 140 | if(!sql->Connect(config_.host, config_.port, config_.user, config_.password, config_.dbname)) { 141 | LOG(LOGLEVEL_ERROR, CWEB_MODULE, "mysql", "mysql pool init error"); 142 | return false; 143 | } 144 | ReleaseConnection(sql); 145 | } 146 | 147 | return true; 148 | } 149 | 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /src/db/mysql.h: -------------------------------------------------------------------------------- 1 | #ifndef CWEB_DATABASE_MYSQL_H_ 2 | #define CWEB_DATABASE_MYSQL_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "dbconnection_pool.h" 9 | #include "cweb_config.h" 10 | #include "singleton.h" 11 | 12 | namespace cweb { 13 | namespace db { 14 | 15 | class MySQLReply { 16 | private: 17 | std::shared_ptr data_; 18 | MYSQL_ROW current_row_; 19 | unsigned long* current_row_len_; 20 | 21 | public: 22 | MySQLReply(MYSQL_RES* res); 23 | 24 | int Rows(); 25 | int Columns(); 26 | std::string ColumnName(int idx); 27 | bool Next(); 28 | 29 | bool isNull(int idx); 30 | int IntValue(int idx); 31 | uint UIntValue(int idx); 32 | int64_t Int64Value(int idx); 33 | uint64_t UInt64Value(int idx); 34 | float FloatValue(int idx); 35 | double DoubleValue(int idx); 36 | std::string StringValue(int idx); 37 | std::string BlobValue(int idx); 38 | }; 39 | 40 | typedef std::shared_ptr MySQLReplyPtr; 41 | 42 | class MySQL { 43 | private: 44 | std::shared_ptr mysql_; 45 | MySQLReplyPtr cmd(const char* sql); 46 | 47 | public: 48 | bool Connect(const std::string& host, int port, const std::string& user, const std::string& password, const std::string& dbname, int timeout_ms = 0); 49 | bool Use(const std::string& dbname); 50 | 51 | MySQLReplyPtr Cmd(const char* format, ...); 52 | MySQLReplyPtr Cmd(const std::string& sql); 53 | }; 54 | 55 | class MySQLPool : public DBConnectionPool { 56 | private: 57 | MysqlConfig config_; 58 | 59 | public: 60 | MySQLPool() : DBConnectionPool() {} 61 | bool Init(); 62 | }; 63 | 64 | typedef cweb::util::Singleton MySQLPoolSingleton; 65 | 66 | } 67 | } 68 | 69 | #endif 70 | -------------------------------------------------------------------------------- /src/db/redis.h: -------------------------------------------------------------------------------- 1 | #ifndef CWEB_DATABASE_REDIS_H_ 2 | #define CWEB_DATABASE_REDIS_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "dbconnection_pool.h" 9 | #include "cweb_config.h" 10 | #include "singleton.h" 11 | 12 | namespace cweb { 13 | namespace db { 14 | 15 | typedef std::shared_ptr RedisReplyPtr; 16 | 17 | class Redis { 18 | private: 19 | std::shared_ptr context_; 20 | 21 | public: 22 | bool Connect(const std::string& ip, int port, uint64_t ms = 100); 23 | bool Auth(const std::string& password); 24 | bool ConnectAndAuth(const std::string& ip, int port, const std::string& password, uint64_t ms = 100); 25 | 26 | virtual RedisReplyPtr Cmd(const char* fmt, ...); 27 | virtual int AppendCmd(const char* fmt, ...); 28 | virtual RedisReplyPtr GetReply(); 29 | 30 | std::string Lock(const std::string& key, uint64_t ms); 31 | bool Unlock(const std::string& key, const std::string& value); 32 | }; 33 | 34 | class RedisCluster : public Redis { 35 | private: 36 | std::shared_ptr context_; 37 | 38 | public: 39 | bool ConnectAndAuth(const std::string& addrs, const std::string& password, uint64_t ms = 100); 40 | 41 | virtual RedisReplyPtr Cmd(const char* fmt, ...) override; 42 | virtual int AppendCmd(const char* fmt, ...) override; 43 | virtual RedisReplyPtr GetReply() override; 44 | 45 | //virtual std::string Lock(const std::string& key, uint64_t ms) override; 46 | //virtual bool Unlock(const std::string& key, const std::string& value) override; 47 | }; 48 | 49 | 50 | class RedisPool : public DBConnectionPool { 51 | private: 52 | RedisConfig config_; 53 | 54 | public: 55 | RedisPool() : DBConnectionPool() {} 56 | bool Init(); 57 | }; 58 | 59 | typedef cweb::util::Singleton RedisPoolSingleton; 60 | 61 | } 62 | } 63 | 64 | #endif 65 | -------------------------------------------------------------------------------- /src/httpserver/http_code.h: -------------------------------------------------------------------------------- 1 | #ifndef CWEB_CWEB_HTTPCODE_H_ 2 | #define CWEB_CWEB_HTTPCODE_H_ 3 | 4 | #include 5 | #include 6 | 7 | namespace cweb { 8 | 9 | enum HttpStatusCode { 10 | StatusOK = 200, 11 | StatusMovedPermanently = 301, 12 | StatusBadRequest = 400, 13 | StatusNotFound = 404, 14 | }; 15 | 16 | } 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /src/httpserver/httpparser.cc: -------------------------------------------------------------------------------- 1 | #include "httpparser.h" 2 | #include "httpsession.h" 3 | #include "httprequest.h" 4 | #include 5 | 6 | namespace cweb { 7 | namespace httpserver { 8 | 9 | static std::string header_key_temp_ = ""; 10 | 11 | static std::unordered_map Methods = { 12 | {0, "DELETE"}, 13 | {1, "GET"}, 14 | {2, "HEAD"}, 15 | {3, "POST"}, 16 | {4, "PUT"} 17 | }; 18 | 19 | HttpParser::HttpParser(std::weak_ptr session) : session_(session) { 20 | parser_.reset(new http_parser()); 21 | parser_settings_.reset(new http_parser_settings()); 22 | http_parser_init(parser_.get(), HTTP_REQUEST); 23 | request_.reset(new HttpRequest()); 24 | parser_->data = this; 25 | http_parser_settings_init(parser_settings_.get()); 26 | parser_settings_->on_message_begin = handleMessageBegin; 27 | parser_settings_->on_url = handleURL; 28 | parser_settings_->on_header_field = handleHeaderField; 29 | parser_settings_->on_header_value = handleHeaderValue; 30 | parser_settings_->on_body = handleBody; 31 | parser_settings_->on_message_complete = handleMessageComplete; 32 | } 33 | 34 | HttpParser::ParserProcess HttpParser::Parse(const void *data, size_t len) { 35 | size_t n = http_parser_execute(parser_.get(), parser_settings_.get(), (const char*)data, len); 36 | if(n != len) { 37 | parser_process_ = FAIL; 38 | } 39 | return parser_process_; 40 | } 41 | 42 | bool HttpParser::CheckVersion(int major, int minor) const { 43 | return parser_->http_major == major && parser_->http_minor == minor; 44 | } 45 | 46 | bool HttpParser::IsUpgrade() const { 47 | return parser_->upgrade; 48 | } 49 | 50 | 51 | int HttpParser::handleMessageBegin(http_parser* parser) { 52 | ((HttpParser*)(parser->data))->parser_process_ = PROCESS; 53 | ((HttpParser*)(parser->data))->request_.reset(new HttpRequest()); 54 | return 0; 55 | } 56 | 57 | int HttpParser::handleURL(http_parser* parser, const char *at, size_t length) { 58 | HttpParser* self = (HttpParser*)(parser->data); 59 | self->request_->method_ = Methods[parser->method]; 60 | self->request_->url_.assign(at, length); 61 | const char* start = at; 62 | const char* end = at + length; 63 | const char* flag = std::find(start, end, '?'); 64 | if(start != flag) { 65 | self->request_->path_.assign(start, flag); 66 | } 67 | 68 | const char* equal = nullptr; 69 | start = flag + 1; 70 | 71 | if(start >= end) return 0; 72 | 73 | do { 74 | flag = std::find(start, end, '&'); 75 | equal = std::find(start, flag, '='); 76 | if(flag == end && equal == flag) { 77 | self->parser_process_ = FAIL; 78 | return 0; 79 | } 80 | self->request_->querys_[std::string(start, equal)] = std::string(equal+1, flag); 81 | start = flag + 1; 82 | }while(flag != end); 83 | return 0; 84 | } 85 | 86 | int HttpParser::handleHeaderField(http_parser* parser, const char *at, size_t length) { 87 | header_key_temp_.assign(at, length); 88 | return 0; 89 | } 90 | 91 | int HttpParser::handleHeaderValue(http_parser* parser, const char *at, size_t length) { 92 | HttpParser* self = (HttpParser*)(parser->data); 93 | self->request_->headers_[header_key_temp_] = std::string(at, length); 94 | header_key_temp_.clear(); 95 | return 0; 96 | } 97 | 98 | int HttpParser::handleBody(http_parser* parser, const char *at, size_t length) { 99 | HttpParser* self = (HttpParser*)(parser->data); 100 | //TODO 文件上传场景 缓存到磁盘中 multipart场景 101 | //copy 102 | self->request_->raw_body_->Append(at, length); 103 | return 0; 104 | } 105 | 106 | int HttpParser::handleMessageComplete(http_parser* parser) { 107 | HttpParser* self = (HttpParser*)(parser->data); 108 | self->parser_process_ = SUCCESS; 109 | if(auto session = self->session_.lock()) { 110 | session->handleParsedMessage(std::move(self->request_)); 111 | } 112 | return 0; 113 | } 114 | 115 | 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /src/httpserver/httpparser.h: -------------------------------------------------------------------------------- 1 | #ifndef CWEB_HTTP_HTTPPARSER_H_ 2 | #define CWEB_HTTP_HTTPPARSER_H_ 3 | 4 | #include "http_parser.h" 5 | #include 6 | 7 | namespace cweb { 8 | namespace httpserver { 9 | 10 | class HttpSession; 11 | class HttpRequest; 12 | class HttpParser { 13 | private: 14 | enum ParserProcess { 15 | PROCESS, 16 | SUCCESS, 17 | FAIL 18 | }; 19 | 20 | std::weak_ptr session_; 21 | std::unique_ptr parser_; 22 | std::unique_ptr parser_settings_; 23 | std::unique_ptr request_; 24 | ParserProcess parser_process_ = PROCESS; 25 | //wsparser 26 | 27 | public: 28 | HttpParser(std::weak_ptr session); 29 | ParserProcess Parse(const void* data, size_t len); 30 | bool CheckVersion(int major, int minor) const; 31 | bool IsUpgrade() const; 32 | 33 | private: 34 | static int handleMessageBegin(http_parser* parser); 35 | static int handleURL(http_parser* parser, const char *at, size_t length); 36 | static int handleHeaderField(http_parser* parser, const char *at, size_t length); 37 | static int handleHeaderValue(http_parser* parser, const char *at, size_t length); 38 | static int handleBody(http_parser* parser, const char *at, size_t length); 39 | static int handleMessageComplete(http_parser* parser); 40 | 41 | }; 42 | 43 | } 44 | } 45 | 46 | #endif 47 | 48 | -------------------------------------------------------------------------------- /src/httpserver/httpresponse.cc: -------------------------------------------------------------------------------- 1 | #include "httpresponse.h" 2 | 3 | namespace cweb { 4 | namespace httpserver { 5 | 6 | HttpResponse::HttpResponse() {} 7 | HttpResponse::~HttpResponse() {} 8 | 9 | void HttpResponse::SetStatusCode(HttpStatusCode code, std::string& stream) { 10 | static std::unordered_map http_status_code = { 11 | {200 ,"OK"}, 12 | {301, "Moved Permanently"}, 13 | {400, "Bad Request"}, 14 | {404, "Not Found"} 15 | }; 16 | 17 | stream += "HTTP/1.1 " + std::to_string(code) + " " + http_status_code[code] + "\r\n"; 18 | } 19 | 20 | void HttpResponse::SetHeader(const std::string &key, const std::string &value, std::string& stream) { 21 | stream += key + ": " + value + "\r\n"; 22 | } 23 | 24 | void HttpResponse::SetBody(StringPiece body, std::string& stream) { 25 | stream += "\r\n"; 26 | stream += body.Data(); 27 | } 28 | 29 | 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/httpserver/httpresponse.h: -------------------------------------------------------------------------------- 1 | #ifndef CWEB_HTTP_HTTPRESPONSE_H_ 2 | #define CWEB_HTTP_HTTPRESPONSE_H_ 3 | 4 | #include 5 | #include 6 | #include "http_code.h" 7 | #include "bytebuffer.h" 8 | 9 | using namespace cweb::tcpserver; 10 | 11 | namespace cweb { 12 | namespace httpserver { 13 | 14 | class HttpResponse { 15 | private: 16 | std::unordered_map headers_; 17 | std::string body_; 18 | 19 | 20 | public: 21 | HttpResponse(); 22 | ~HttpResponse(); 23 | void SetHeader(const void* data, size_t size); 24 | void SetBody(const void* data, size_t size); 25 | 26 | 27 | static void SetHeader(const std::string& key, const std::string& value, std::string& stream); 28 | static void SetStatusCode(HttpStatusCode code, std::string& stream); 29 | static void SetBody(StringPiece body, std::string& stream); 30 | }; 31 | 32 | } 33 | } 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /src/httpserver/httpserver.cc: -------------------------------------------------------------------------------- 1 | #include "httpserver.h" 2 | #include "tcpconnection.h" 3 | #include "logger.h" 4 | #include "http_parser.h" 5 | #include "httpsession.h" 6 | #ifdef COROUTINE 7 | #include "co_tcpserver.h" 8 | #else 9 | #include "tcpserver.h" 10 | #endif 11 | 12 | #ifdef COROUTINE 13 | using namespace cweb::tcpserver::coroutine; 14 | #endif 15 | 16 | using namespace cweb::log; 17 | 18 | namespace cweb { 19 | namespace httpserver { 20 | 21 | HttpServer::HttpServer(std::shared_ptr loop, uint16_t port, bool loopbackonly, bool ipv6) { 22 | #ifdef COROUTINE 23 | tcpserver_.reset(new CoTcpServer(loop, port, loopbackonly, ipv6)); 24 | #else 25 | tcpserver_.reset(new TcpServer(loop, port, loopbackonly, ipv6)); 26 | #endif 27 | tcpserver_->SetConnectedCallback(std::bind(&HttpServer::handleConnected, this, std::placeholders::_1)); 28 | } 29 | 30 | HttpServer::HttpServer(std::shared_ptr loop, const std::string& ip, uint16_t port, bool ipv6) { 31 | #ifdef COROUTINE 32 | tcpserver_.reset(new CoTcpServer(loop, ip, port, ipv6)); 33 | #else 34 | tcpserver_.reset(new TcpServer(loop, ip, port, ipv6)); 35 | #endif 36 | tcpserver_->SetConnectedCallback(std::bind(&HttpServer::handleConnected, this, std::placeholders::_1)); 37 | } 38 | 39 | HttpServer::~HttpServer() {} 40 | 41 | void HttpServer::Start(int threadcnt) { 42 | tcpserver_->Start(threadcnt); 43 | } 44 | 45 | void HttpServer::Quit() { 46 | tcpserver_->Quit(); 47 | } 48 | 49 | void HttpServer::handleConnected(std::shared_ptr conn) { 50 | if(conn->Connected()) { 51 | std::shared_ptr session(new HttpSession(conn, request_callback_)); 52 | session->Init(); 53 | conn->SetMessageCallback(std::bind(&HttpSession::handleMessage, session.get(), std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); 54 | while(lock_.test_and_set(std::memory_order_acquire)) {} 55 | httpsessions_[conn] = session; 56 | lock_.clear(std::memory_order_release); 57 | }else { 58 | handleDisconnected(conn); 59 | } 60 | } 61 | 62 | void HttpServer::handleDisconnected(std::shared_ptr conn) { 63 | auto iter = httpsessions_.find(conn); 64 | if(iter != httpsessions_.end()) { 65 | while(lock_.test_and_set(std::memory_order_acquire)) {} 66 | httpsessions_.erase(conn); 67 | lock_.clear(std::memory_order_release); 68 | } 69 | } 70 | 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/httpserver/httpserver.h: -------------------------------------------------------------------------------- 1 | #ifndef CWEB_HTTP_HTTPSERVER_H_ 2 | #define CWEB_HTTP_HTTPSERVER_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include "http_parser.h" 8 | #include "timer.h" 9 | #include "bytebuffer.h" 10 | #include "tcpserver.h" 11 | #include "tcpconnection.h" 12 | #include "eventloop.h" 13 | #include "http_code.h" 14 | 15 | using namespace cweb::util; 16 | using namespace cweb::tcpserver; 17 | 18 | namespace cweb { 19 | namespace httpserver { 20 | 21 | class HttpSession; 22 | class HttpRequest; 23 | class HttpServer { 24 | private: 25 | typedef std::function, std::unique_ptr)> RequestCallback; 26 | std::unique_ptr tcpserver_; 27 | std::unordered_map, std::shared_ptr> httpsessions_; 28 | RequestCallback request_callback_; 29 | std::atomic_flag lock_ = ATOMIC_FLAG_INIT; 30 | 31 | void handleConnected(std::shared_ptr conn); 32 | void handleDisconnected(std::shared_ptr conn); 33 | 34 | public: 35 | HttpServer(std::shared_ptr loop, uint16_t port = 0, bool loopbackonly = false, bool ipv6 = false); 36 | HttpServer(std::shared_ptr loop, const std::string& ip, uint16_t port, bool ipv6 = false); 37 | 38 | ~HttpServer(); 39 | 40 | void Start(int threadcnt); 41 | void Quit(); 42 | void SetRequestCallback(RequestCallback cb) {request_callback_ = std::move(cb);} 43 | }; 44 | 45 | } 46 | } 47 | 48 | #endif 49 | 50 | -------------------------------------------------------------------------------- /src/httpserver/httpsession.h: -------------------------------------------------------------------------------- 1 | #ifndef CWEB_HTTP_HTTPSESSION_H_ 2 | #define CWEB_HTTP_HTTPSESSION_H_ 3 | 4 | #include "tcpconnection.h" 5 | #include "httpparser.h" 6 | #include "http_code.h" 7 | #include "httprequest.h" 8 | 9 | using namespace cweb::tcpserver; 10 | 11 | namespace cweb { 12 | namespace httpserver { 13 | 14 | class WebSocket; 15 | class HttpSession : public std::enable_shared_from_this { 16 | public: 17 | virtual ~HttpSession(); 18 | typedef std::function, std::unique_ptr)> RequestCallback; 19 | friend class HttpServer; 20 | HttpSession(std::shared_ptr conn, RequestCallback cb); 21 | void Init(); 22 | 23 | void SendString(HttpStatusCode code, const std::string& data); 24 | void SendJson(HttpStatusCode code, const std::string& data); 25 | void SendFile(HttpStatusCode code, const std::string& filepath, std::string filename = ""); 26 | //void SendMedia(HttpStatusCode code, const std::string& filepath, //type) 27 | //void SendBinary() 28 | //void SendHtml(); 29 | void SendMultipart(HttpStatusCode code, const std::vector& parts); 30 | void Send(ByteData* data); 31 | 32 | protected: 33 | std::shared_ptr connection_; 34 | RequestCallback request_callback_; 35 | 36 | private: 37 | friend class HttpParser; 38 | std::unique_ptr http_parser_; 39 | std::shared_ptr websocket_ ; 40 | bool need_close_ = true; 41 | bool upgrade_ = false; 42 | virtual TcpConnection::MessageState handleMessage(std::shared_ptr conn, ByteBuffer* buf, Time time); 43 | void handleParsedMessage(std::unique_ptr request); 44 | static std::string generateBoundary(size_t len); 45 | }; 46 | 47 | } 48 | } 49 | 50 | #endif 51 | -------------------------------------------------------------------------------- /src/httpserver/multipartparser.h: -------------------------------------------------------------------------------- 1 | #ifndef MULTIPARTPARSER_H 2 | #define MULTIPARTPARSER_H 3 | #ifdef __cplusplus 4 | extern "C" { 5 | #endif 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | typedef struct multipartparser multipartparser; 12 | typedef struct multipartparser_callbacks multipartparser_callbacks; 13 | 14 | typedef int (*multipart_cb) (multipartparser*); 15 | typedef int (*multipart_data_cb) (multipartparser*, const char* data, size_t size); 16 | 17 | struct multipartparser { 18 | /** PRIVATE **/ 19 | char boundary[70]; 20 | int boundary_length; 21 | int index; 22 | uint16_t state; 23 | 24 | /** PUBLIC **/ 25 | void* data; 26 | }; 27 | 28 | struct multipartparser_callbacks { 29 | multipart_cb on_body_begin; 30 | multipart_cb on_part_begin; 31 | multipart_data_cb on_header_field; 32 | multipart_data_cb on_header_value; 33 | multipart_cb on_headers_complete; 34 | multipart_data_cb on_data; 35 | multipart_cb on_part_end; 36 | multipart_cb on_body_end; 37 | }; 38 | 39 | void multipartparser_init(multipartparser* parser, const char* boundary); 40 | 41 | void multipartparser_callbacks_init(multipartparser_callbacks* callbacks); 42 | 43 | size_t multipartparser_execute(multipartparser* parser, 44 | multipartparser_callbacks* callbacks, 45 | const char* data, 46 | size_t size); 47 | 48 | #ifdef __cplusplus 49 | } 50 | #endif 51 | #endif // MULTIPARTPARSER_H 52 | -------------------------------------------------------------------------------- /src/httpserver/websocket.h: -------------------------------------------------------------------------------- 1 | #ifndef CWEB_HTTP_WEBSOCKET_H_ 2 | #define CWEB_HTTP_WEBSOCKET_H_ 3 | 4 | #include "httpsession.h" 5 | 6 | namespace cweb { 7 | namespace httpserver { 8 | 9 | enum MessageType { 10 | Text, 11 | Binary 12 | }; 13 | 14 | class WebSocket : public HttpSession { 15 | 16 | private: 17 | typedef std::function, const char*, size_t, MessageType)> MessageCallback; 18 | typedef std::function)> CloseCallback; 19 | enum ParseState { 20 | MiniHeader, 21 | Len16, 22 | Len64, 23 | Mask, 24 | Payload, 25 | }; 26 | 27 | uint32_t mask_; 28 | uint16_t mini_header_; 29 | uint16_t length16_needrecv_; 30 | uint64_t length_needrecv_; 31 | std::unique_ptr data_buffer_; 32 | int recv_begin_index_ = 0; 33 | int recv_end_index = 0; 34 | ParseState parse_state_ = MiniHeader; 35 | MessageType type_ = Binary; 36 | MessageCallback message_callback_; 37 | CloseCallback close_callback_; 38 | bool recv_close_ = false; 39 | bool sent_close = false; 40 | void sendPong(); 41 | bool isFIN(); 42 | int opcode(); 43 | void handleFragment(); 44 | std::string buildHeader(int opcode, size_t size); 45 | void fragmentFIN(); 46 | public: 47 | WebSocket(std::shared_ptr conn, RequestCallback cb); 48 | virtual ~WebSocket(); 49 | virtual TcpConnection::MessageState handleMessage(std::shared_ptr conn, ByteBuffer* buf, Time time) override; 50 | void Start(std::unique_ptr req); 51 | void SetMessageCallback(MessageCallback cb) {message_callback_ = std::move(cb);} 52 | void SetCloseCallback(CloseCallback cb) {close_callback_ = std::move(cb);} 53 | void SendBinary(const char* data, size_t size); 54 | void SendText(const StringPiece& str); 55 | void Close(const char* data = "", size_t size = 0); 56 | void HandleClose(); 57 | 58 | #ifdef COROUTINE 59 | void Send(const void* data, size_t size); 60 | ssize_t Recv(ByteBuffer* buf); 61 | private: 62 | std::unique_ptr buffer_; 63 | #endif 64 | 65 | }; 66 | 67 | } 68 | } 69 | 70 | #endif 71 | -------------------------------------------------------------------------------- /src/log/log_appender.cc: -------------------------------------------------------------------------------- 1 | #include "log_appender.h" 2 | #include "logfile_pipe.h" 3 | #include "log_formatter.h" 4 | #include "pthread_keys.h" 5 | #include 6 | #include 7 | 8 | namespace cweb { 9 | 10 | namespace log { 11 | 12 | static const size_t kMaxLogCapacity = 2000; 13 | 14 | void ConsoleAppender::Log(LogInfo *logInfo) { 15 | std::unique_lock lock(mutex_); 16 | std::cout << formatter_->Format(logInfo); 17 | 18 | } 19 | 20 | FileAppender::FileAppender(LogFormatter* formatter, LogWriter* writer, const std::string& module, const std::string& filepath) : LogAppender(formatter), writer_(writer), module_(module), filepath_(filepath) { 21 | logging_pipe_ = new LogfilePipe(kMaxLogCapacity); 22 | createFilepath(); 23 | ofs_.open(filepath_, std::ofstream::out | std::ofstream::app); 24 | writer_->AddTask(std::bind(&FileAppender::writeLogsfile, this)); 25 | } 26 | 27 | FileAppender::~FileAppender() { 28 | writeLogsfile(); 29 | ofs_.close(); 30 | } 31 | 32 | void FileAppender::Log(LogInfo* logInfo) { 33 | 34 | while(!logging_pipe_->MultiplePush(logInfo)) { 35 | writer_->Wakeup(); 36 | std::unique_lock lock(mutex_); 37 | cond_.wait(lock); 38 | } 39 | writer_->Wakeup(); 40 | } 41 | 42 | bool FileAppender::createFilepath() { 43 | char timeStr[20]; 44 | struct timeval tv; 45 | gettimeofday(&tv, NULL); 46 | time_t seconds = tv.tv_sec; 47 | struct tm* tm = localtime(&seconds); 48 | strftime(timeStr, 20, "%Y-%m-%d", tm); 49 | std::string filepath = filepath_ + "/LOG_" + std::string(timeStr) + "_" + module_ + ".txt"; 50 | 51 | if(filepath_.compare(filepath) != 0) { 52 | filepath_ = filepath; 53 | return true; 54 | } 55 | 56 | return false; 57 | } 58 | 59 | //单线程写文件 60 | void FileAppender::writeLogsfile() { 61 | writing_ = true; 62 | if(createFilepath()) { 63 | ofs_.close(); 64 | ofs_.open(filepath_, std::ofstream::out | std::ofstream::app); 65 | } 66 | 67 | if(!ofs_.is_open()) { 68 | ofs_.open(filepath_, std::ofstream::out | std::ofstream::app); 69 | } 70 | 71 | LogInfo *loginfo = logging_pipe_->SinglePop(); 72 | while(loginfo) { 73 | ofs_ << formatter_->Format(loginfo); 74 | writer_->DeallocLogInfo(loginfo); 75 | loginfo = logging_pipe_->SinglePop(); 76 | cond_.notify_all(); 77 | ofs_.flush(); 78 | } 79 | writing_ = false; 80 | } 81 | 82 | 83 | 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /src/log/log_appender.h: -------------------------------------------------------------------------------- 1 | #ifndef CWEB_LOG_LOGAPPENDER_H_ 2 | #define CWEB_LOG_LOGAPPENDER_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "log_writer.h" 11 | 12 | namespace cweb { 13 | 14 | namespace log { 15 | 16 | struct LogInfo; 17 | class LogfilePipe; 18 | class LogFormatter; 19 | 20 | class LogAppender { 21 | protected: 22 | LogFormatter* formatter_; 23 | 24 | public: 25 | LogAppender(LogFormatter* formatter) : formatter_(formatter) {} 26 | virtual ~LogAppender() {} 27 | virtual void Log(LogInfo* logInfo) = 0; 28 | 29 | }; 30 | 31 | class ConsoleAppender : public LogAppender { 32 | 33 | private: 34 | std::mutex mutex_; 35 | 36 | public: 37 | ConsoleAppender(LogFormatter* formatter) : LogAppender(formatter) {} 38 | virtual ~ConsoleAppender() {} 39 | virtual void Log(LogInfo* logInfo) override; 40 | 41 | }; 42 | 43 | class FileAppender : public LogAppender { 44 | 45 | private: 46 | std::string filepath_ = ""; 47 | //写入时是多写单读 48 | LogfilePipe* logging_pipe_; 49 | LogWriter* writer_; 50 | std::string module_; 51 | std::mutex mutex_; 52 | std::condition_variable cond_; 53 | std::ofstream ofs_; 54 | bool writing_ = false; 55 | 56 | bool createFilepath(); 57 | void writeLogsfile(); 58 | 59 | public: 60 | FileAppender(LogFormatter* formatter, LogWriter* writer, const std::string& module, const std::string& filepath = "../logfile"); 61 | virtual ~FileAppender(); 62 | virtual void Log(LogInfo* logInfo) override; 63 | 64 | }; 65 | 66 | class DailyFileAppender : public FileAppender { 67 | 68 | }; 69 | 70 | class LimitSizeFileAppender : public FileAppender { 71 | 72 | }; 73 | 74 | } 75 | } 76 | 77 | #endif 78 | -------------------------------------------------------------------------------- /src/log/log_formatter.h: -------------------------------------------------------------------------------- 1 | #ifndef CWEB_LOG_LOGFORMATTER_H_ 2 | #define CWEB_LOG_LOGFORMATTER_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | namespace cweb { 9 | 10 | namespace log { 11 | 12 | struct LogInfo; 13 | 14 | class LogFormatItem { 15 | public: 16 | virtual ~LogFormatItem() {}; 17 | virtual void Format(std::ostream& os, LogInfo* info) = 0; 18 | }; 19 | 20 | class LogFormatItemFactory { 21 | public: 22 | static LogFormatItem* GetFormatItem(const std::string& type, const std::string str = ""); 23 | }; 24 | 25 | class LogFormatter { 26 | private: 27 | std::string log_pattern_; 28 | std::vector format_items_; 29 | 30 | void parseLogpattern(); 31 | public: 32 | //[%d][%l][%T][%C][%m][%t][%c]%n 33 | LogFormatter(const std::string& pattern = "[%d][%l][%T][%m][%t][%c]%n"); 34 | 35 | std::string Format(LogInfo* loginfo); 36 | }; 37 | 38 | } 39 | } 40 | 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /src/log/log_info.h: -------------------------------------------------------------------------------- 1 | #ifndef CWB_LOG_LOGINFO_H_ 2 | #define CWB_LOG_LOGINFO_H_ 3 | 4 | #include 5 | #include 6 | 7 | namespace cweb { 8 | 9 | namespace log { 10 | 11 | enum LogLevel { 12 | LOGLEVEL_DEBUG, 13 | LOGLEVEL_INFO, 14 | LOGLEVEL_WARN, 15 | LOGLEVEL_ERROR, 16 | LOGLEVEL_FATAL, 17 | LOGLEVEL_OFF 18 | }; 19 | 20 | struct LogInfo { 21 | public: 22 | //%n 换行 23 | uint64_t time = 0; //%d 24 | LogLevel log_level; //%l 25 | unsigned long int thread_id; //&T 26 | std::string log_module; //%m 27 | std::string log_tag; //%t 28 | std::string log_content; //%c 29 | }; 30 | 31 | } 32 | } 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /src/log/log_writer.cc: -------------------------------------------------------------------------------- 1 | #include "log_writer.h" 2 | 3 | namespace cweb { 4 | namespace log { 5 | 6 | LogWriter::LogWriter(int capacity) { 7 | size_t size = sizeof(LogInfo); 8 | logfilepipe_ = new LogfilePipe(capacity); 9 | for(int i = 0; i < capacity; ++i) { 10 | logfilepipe_->SinglePush((LogInfo*)(memorypool_->Allocate(size))); 11 | } 12 | } 13 | 14 | void LogWriter::AddTask(Functor cb) { 15 | std::unique_lock lock(mutex_); 16 | tasks_.push_back(std::move(cb)); 17 | } 18 | 19 | void LogWriter::Run() { 20 | running_ = true; 21 | loop(); 22 | } 23 | 24 | void LogWriter::Stop() { 25 | running_ = false; 26 | } 27 | 28 | void LogWriter::Wakeup() { 29 | cond_.notify_all(); 30 | } 31 | 32 | void LogWriter::Sleep() { 33 | std::unique_lock lock(mutex_); 34 | cond_.wait(lock); 35 | } 36 | 37 | LogInfo* LogWriter::AllocLogInfo() { 38 | LogInfo* info = logfilepipe_->MultiplePop(); 39 | while(!info) { 40 | Wakeup(); 41 | info = logfilepipe_->MultiplePop(); 42 | } 43 | return info; 44 | } 45 | 46 | void LogWriter::DeallocLogInfo(LogInfo *info) { 47 | logfilepipe_->MultiplePush(info); 48 | } 49 | 50 | void LogWriter::loop() { 51 | while(running_) { 52 | std::unique_lock lock(mutex_); 53 | cond_.wait_for(lock, std::chrono::seconds(60)); 54 | for(auto task : tasks_) { 55 | task(); 56 | } 57 | } 58 | } 59 | 60 | 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/log/log_writer.h: -------------------------------------------------------------------------------- 1 | #ifndef CWEB_LOG_LOGWRITER_H_ 2 | #define CWEB_LOG_LOGWRITER_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include "threadlocal_memorypool.h" 8 | #include "logfile_pipe.h" 9 | 10 | namespace cweb { 11 | namespace log { 12 | 13 | class LogWriter { 14 | 15 | private: 16 | typedef std::function Functor; 17 | bool running_ = false; 18 | std::mutex mutex_; 19 | std::condition_variable cond_; 20 | std::vector tasks_; 21 | util::MemoryPool* memorypool_ = new util::MemoryPool(); 22 | LogfilePipe* logfilepipe_ = nullptr; 23 | 24 | void loop(); 25 | 26 | public: 27 | LogWriter(int capacity = 2000); 28 | void AddTask(Functor cb); 29 | void Run(); 30 | void Stop(); 31 | void Wakeup(); 32 | void Sleep(); 33 | LogInfo* AllocLogInfo(); 34 | void DeallocLogInfo(LogInfo* info); 35 | }; 36 | 37 | } 38 | } 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /src/log/logfile_pipe.cc: -------------------------------------------------------------------------------- 1 | #include "logfile_pipe.h" 2 | 3 | namespace cweb { 4 | namespace log { 5 | 6 | LogfilePipe::LogfilePipe(int capacity) : logs_(LockfreeQueue(capacity)){ 7 | } 8 | 9 | bool LogfilePipe::MultiplePush(LogInfo *log) { 10 | return logs_.MultiplePush(log); 11 | } 12 | 13 | bool LogfilePipe::SinglePush(LogInfo *log) { 14 | return logs_.SinglePush(log); 15 | } 16 | 17 | LogInfo* LogfilePipe::MultiplePop() { 18 | LogInfo* info = nullptr; 19 | if(logs_.MultiplePop(info)) { 20 | return info; 21 | }else { 22 | return nullptr; 23 | } 24 | } 25 | 26 | LogInfo* LogfilePipe::SinglePop() { 27 | LogInfo* info = nullptr; 28 | if(logs_.SinglePop(info)) { 29 | return info; 30 | }else { 31 | return nullptr; 32 | } 33 | return info; 34 | } 35 | 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/log/logfile_pipe.h: -------------------------------------------------------------------------------- 1 | #ifndef CWEB_LOG_LOGFILEPIPE_H_ 2 | #define CWEB_LOG_LOGFILEPIPE_H_ 3 | 4 | #include 5 | #include "log_info.h" 6 | #include "lockfree_queue.h" 7 | 8 | using namespace cweb::util; 9 | 10 | namespace cweb { 11 | 12 | namespace log { 13 | 14 | class LogfilePipe { 15 | private: 16 | LockfreeQueue logs_; 17 | 18 | public: 19 | LogfilePipe(int capacity); 20 | 21 | bool MultiplePush(LogInfo *log); 22 | bool SinglePush(LogInfo *log); 23 | 24 | LogInfo* MultiplePop(); 25 | LogInfo* SinglePop(); 26 | 27 | }; 28 | 29 | } 30 | } 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /src/log/logger.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include "logger.h" 3 | #include "pthread_keys.h" 4 | 5 | namespace cweb { 6 | 7 | namespace log { 8 | 9 | static const size_t kMaxLogContentLength = 256; 10 | 11 | Logger::Logger(const std::string& module, LogWriter* writer, LogLevel loglevel) : module_(module), writer_(writer), log_level_(loglevel) {} 12 | 13 | Logger::~Logger() { 14 | for(LogAppender* appender : appenders_) { 15 | delete appender; 16 | } 17 | } 18 | 19 | void Logger::Log(LogLevel level, const std::string &module, const std::string &tag, const char *format, ...) { 20 | if(level >= log_level_) { 21 | LogInfo* info = writer_->AllocLogInfo(); 22 | struct timeval tv; 23 | gettimeofday(&tv, NULL); 24 | int64_t seconds = tv.tv_sec; 25 | info->log_level = level; 26 | info->time = seconds * 1000 * 1000 + tv.tv_usec; 27 | info->thread_id = (unsigned long int)pthread_self(); 28 | info->log_module = module; 29 | info->log_tag = tag; 30 | char content[kMaxLogContentLength]; 31 | va_list valst; 32 | va_start(valst, format); 33 | int n = vsnprintf(content, kMaxLogContentLength, format, valst); 34 | content[n] = '\0'; 35 | info->log_content = std::string(content); 36 | va_end(valst); 37 | 38 | log(level, info); 39 | } 40 | } 41 | 42 | void Logger::log(LogLevel level, LogInfo* loginfo) { 43 | for(auto& appender : appenders_) { 44 | appender->Log(loginfo); 45 | } 46 | } 47 | 48 | void Logger::AddAppender(LogAppender* appender) { 49 | appenders_.push_back(appender); 50 | } 51 | 52 | LoggerManager::LoggerManager() { 53 | formatter_ = new LogFormatter(config_.log_pattern); 54 | writer_ = new LogWriter(config_.writer_capcity); 55 | writer_thread_ = std::thread([this](){ 56 | writer_->Run(); 57 | }); 58 | } 59 | 60 | LoggerManager::~LoggerManager() { 61 | writer_->Stop(); 62 | for(std::unordered_map::iterator iter = loggers_.begin(); iter != loggers_.end(); ++iter) { 63 | delete iter->second; 64 | } 65 | delete formatter_; 66 | } 67 | 68 | Logger* LoggerManager::GetLogger(const std::string& module) { 69 | auto iter = loggers_.find(module); 70 | if(iter == loggers_.end()) { 71 | Logger* logger = new Logger(module, writer_, config_.log_level); 72 | if(config_.need_console) { 73 | logger->AddAppender(new ConsoleAppender(formatter_)); 74 | } 75 | logger->AddAppender(new FileAppender(formatter_, writer_, module, config_.log_filepath)); 76 | std::unique_lock lock(mutex_); 77 | loggers_[module] = logger; 78 | return logger; 79 | } 80 | return iter->second; 81 | } 82 | 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/log/logger.h: -------------------------------------------------------------------------------- 1 | #ifndef CWEB_LOG_LOGGER_H_ 2 | #define CWEB_LOG_LOGGER_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "log_appender.h" 11 | #include "log_info.h" 12 | #include "log_formatter.h" 13 | #include "log_writer.h" 14 | #include "singleton.h" 15 | #include "cweb_config.h" 16 | 17 | namespace cweb { 18 | namespace log { 19 | 20 | class Logger { 21 | public: 22 | 23 | Logger(const std::string& module = "root", LogWriter* writer = nullptr, LogLevel loglevel = LOGLEVEL_DEBUG); 24 | ~Logger(); 25 | 26 | void Log(LogLevel level, const std::string& module, const std::string& tag, const char *format, ...); 27 | 28 | void AddAppender(LogAppender* appender); 29 | 30 | private: 31 | const std::string module_; 32 | std::vector appenders_; 33 | LogWriter* writer_ = nullptr; 34 | LogLevel log_level_ = LOGLEVEL_DEBUG; 35 | 36 | void log(LogLevel level, LogInfo* loginfo); 37 | 38 | }; 39 | 40 | //单例 41 | class LoggerManager { 42 | public: 43 | //formatter共享 loop共享 44 | LoggerManager(); 45 | ~LoggerManager(); 46 | Logger* GetLogger(const std::string& module); 47 | void log(); 48 | 49 | private: 50 | LogFormatter* formatter_; 51 | LogWriter* writer_; 52 | std::unordered_map loggers_; 53 | std::mutex mutex_; 54 | std::thread writer_thread_; 55 | 56 | LogConfig config_; 57 | }; 58 | 59 | typedef cweb::util::Singleton LoggerManagerSingleton; 60 | 61 | #define CWEB_MODULE "CWEB" 62 | 63 | #define LOG(level, module, tag, format, ...) \ 64 | LoggerManagerSingleton::GetInstance()->GetLogger(module)->Log(level, module, tag, format, ##__VA_ARGS__) 65 | 66 | } 67 | } 68 | 69 | #endif 70 | -------------------------------------------------------------------------------- /src/tcpserver/base/poller.h: -------------------------------------------------------------------------------- 1 | #ifndef CWEB_TCP_POLLER_H_ 2 | #define CWEB_TCP_POLLER_H_ 3 | 4 | #include 5 | #include 6 | 7 | namespace cweb { 8 | namespace tcpserver { 9 | 10 | 11 | const int kMaxEventsSize = 1024; 12 | 13 | class EventLoop; 14 | class Event; 15 | class Time; 16 | class Poller { 17 | 18 | public: 19 | Poller(EventLoop* loop) : ownerloop_(loop) {} 20 | virtual ~Poller() = default; 21 | 22 | virtual void UpdateEvent(Event* event) = 0; 23 | virtual void RemoveEvent(Event* event) = 0; 24 | 25 | virtual Time Poll(int timeout, std::vector& activeEvents) = 0; 26 | 27 | protected: 28 | std::unordered_map events_map_; 29 | 30 | private: 31 | EventLoop* ownerloop_; 32 | 33 | }; 34 | 35 | } 36 | } 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /src/tcpserver/bytebuffer.cc: -------------------------------------------------------------------------------- 1 | #include "bytebuffer.h" 2 | #include "hooks.h" 3 | 4 | namespace cweb { 5 | namespace tcpserver { 6 | 7 | 8 | int ByteBuffer::Readv(int fd) { 9 | char extrabuf[65536]; 10 | 11 | struct iovec vec[2]; 12 | size_t writable = WritableBytes(); 13 | 14 | vec[0].iov_base = buffer_ + writeindex_; 15 | vec[0].iov_len = writable; 16 | 17 | vec[1].iov_base = extrabuf; 18 | vec[1].iov_len = sizeof(extrabuf); 19 | 20 | int iovcnt = (writable < sizeof extrabuf) ? 2 : 1; 21 | 22 | ssize_t n = readv(fd, vec, iovcnt); 23 | 24 | if(n < 0) { 25 | return -1; 26 | }else if(n <= writable) { 27 | writeindex_ += n; 28 | }else { 29 | writeindex_ = size_; 30 | 31 | Append(extrabuf, n - writable); 32 | } 33 | 34 | return (int)n; 35 | } 36 | 37 | void ByteBuffer::Append(const char *data, size_t len) { 38 | if(WritableBytes() < len) { 39 | extendSpace(len); 40 | } 41 | memcpy(buffer_ + writeindex_, data, len); 42 | writeindex_ += len; 43 | } 44 | 45 | void ByteBuffer::Append(const StringPiece& str) { 46 | Append(str.Data(), str.Size()); 47 | } 48 | 49 | void ByteBuffer::ReadUtil(const char *end) { 50 | size_t len = end - Peek(); 51 | ReadBytes(len); 52 | } 53 | 54 | void ByteBuffer::ReadBytes(size_t len) { 55 | if(len < ReadableBytes()) { 56 | readindex_ += len; 57 | }else { 58 | readindex_ = kCheapPrepend; 59 | writeindex_ = kCheapPrepend; 60 | } 61 | } 62 | 63 | void ByteBuffer::WriteBytes(size_t len) { 64 | writeindex_ += len; 65 | } 66 | 67 | void ByteBuffer::ReadAll() { 68 | readindex_ = kCheapPrepend; 69 | writeindex_ = kCheapPrepend; 70 | } 71 | 72 | const char* ByteBuffer::ReadJSON() { 73 | int n = 0; 74 | if(*Peek() == '{') { 75 | n = 1; 76 | for(char* iter = buffer_ + readindex_ + 1; iter < buffer_ + writeindex_; ++iter) { 77 | if(*iter == '}') n--; 78 | if(*iter == '{') n++; 79 | if(n == 0) { 80 | return iter; 81 | } 82 | } 83 | } 84 | return Peek(); 85 | } 86 | 87 | const char* ByteBuffer::FindCRLF() { 88 | for(char* iter = buffer_ + readindex_; iter < buffer_ + writeindex_; ++iter) { 89 | if(*iter == '\r') { 90 | if(iter + 1 == buffer_ + writeindex_) { 91 | return NULL; 92 | }else if(*(iter + 1) == '\n') { 93 | return iter; 94 | } 95 | } 96 | } 97 | return NULL; 98 | } 99 | 100 | 101 | void ByteBuffer::extendSpace(size_t len) { 102 | if(WritableBytes() + PrependableBytes() < len + kCheapPrepend) { 103 | 104 | char* newbuffer = (char*)malloc(size_ + len); 105 | memset(newbuffer, 0, size_ + len); 106 | size_ += len; 107 | size_t readable = ReadableBytes(); 108 | memcpy(newbuffer + kCheapPrepend, Peek(), readable); 109 | free(buffer_); 110 | readindex_ = kCheapPrepend; 111 | writeindex_ = kCheapPrepend + readable; 112 | buffer_ = newbuffer; 113 | }else { 114 | 115 | size_t readable = ReadableBytes(); 116 | memmove(buffer_ + kCheapPrepend, buffer_ + readindex_, ReadableBytes()); 117 | readindex_ = kCheapPrepend; 118 | writeindex_ = readindex_ + readable; 119 | } 120 | } 121 | 122 | int ByteBuffer::ReadSome(void *data, size_t len) { 123 | if(len <= 0 || ReadableBytes() < len) return 0; 124 | memcpy(data, Peek(), len); 125 | ReadBytes(len); 126 | return (int)len; 127 | } 128 | 129 | int ByteBuffer::ReadToBuffer(ByteBuffer *buf, size_t len) { 130 | if(len <= 0 || ReadableBytes() < len) return 0; 131 | buf->Append(Peek(), len); 132 | ReadBytes(len); 133 | return (int)len; 134 | } 135 | 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /src/tcpserver/bytebuffer.h: -------------------------------------------------------------------------------- 1 | #ifndef CWEB_UTIL_BYTEBUFFER_H_ 2 | #define CWEB_UTIL_BYTEBUFFER_H_ 3 | 4 | #include 5 | #include 6 | 7 | namespace cweb { 8 | namespace tcpserver { 9 | 10 | static const size_t kCheapPrepend = 8; 11 | static const size_t kInitialSize = 1024; 12 | 13 | class StringPiece { 14 | private: 15 | const char* ptr_; 16 | size_t length_; 17 | 18 | public: 19 | StringPiece() : ptr_(nullptr), length_(0) {} 20 | StringPiece(const char* str) 21 | : ptr_(str), length_(static_cast(strlen(ptr_))) {} 22 | StringPiece(const char* bytes, size_t len) : ptr_(bytes), length_(len) {} 23 | StringPiece(const std::string& str) 24 | : ptr_(str.data()), length_(static_cast(str.size())) {} 25 | 26 | const char* Data() const {return ptr_;} 27 | 28 | size_t Size() const {return length_;} 29 | 30 | }; 31 | 32 | class ByteBuffer { 33 | private: 34 | size_t readindex_; 35 | size_t writeindex_; 36 | char* buffer_; 37 | size_t size_; 38 | 39 | void extendSpace(size_t len); 40 | 41 | public: 42 | explicit ByteBuffer(size_t initialSize = kInitialSize) 43 | :readindex_(kCheapPrepend), 44 | writeindex_(kCheapPrepend), 45 | size_(kCheapPrepend + kInitialSize){ 46 | buffer_ = (char *)malloc((kCheapPrepend + kInitialSize) * sizeof(char)); 47 | memset(buffer_, 0, kCheapPrepend + kInitialSize); 48 | } 49 | 50 | ~ByteBuffer() { 51 | free(buffer_); 52 | } 53 | 54 | size_t WritableBytes() const {return size_ - writeindex_;} 55 | size_t ReadableBytes() const {return writeindex_ - readindex_;} 56 | size_t PrependableBytes() const {return readindex_;} 57 | 58 | char& operator[](int index) { 59 | return *(buffer_ + kCheapPrepend + index); 60 | } 61 | 62 | const char* Peek() const {return buffer_ + readindex_;} 63 | const char* Back() const {return buffer_ + writeindex_;} 64 | 65 | int Readv(int fd); 66 | void ReadUtil(const char* end); 67 | void ReadBytes(size_t len); 68 | void WriteBytes(size_t len); 69 | void ReadAll(); 70 | 71 | int ReadSome(void* data, size_t len); 72 | int ReadToBuffer(ByteBuffer* buf, size_t len); 73 | 74 | const char* ReadJSON(); 75 | const char* FindCRLF(); 76 | 77 | void Append(const char* data, size_t len); 78 | void Append(const StringPiece& str); 79 | }; 80 | 81 | } 82 | } 83 | 84 | #endif 85 | -------------------------------------------------------------------------------- /src/tcpserver/bytedata.cc: -------------------------------------------------------------------------------- 1 | #include "bytedata.h" 2 | #include "hooks.h" 3 | //#include 4 | #include 5 | #include 6 | #include 7 | 8 | namespace cweb { 9 | namespace tcpserver { 10 | 11 | void ByteData::AddDataZeroCopy(const StringPiece& data) { 12 | AddDataZeroCopy(data.Data(), data.Size()); 13 | } 14 | 15 | void ByteData::AddDataZeroCopy(const void *data, size_t size) { 16 | DataPacket* dp = new DataPacket(); 17 | dp->copy_ = false; 18 | dp->zero_copy_data_ = (char*)data; 19 | dp->size_ += size; 20 | datas_.push_back(dp); 21 | } 22 | 23 | void ByteData::AddDataCopy(const StringPiece &data) { 24 | AddDataCopy(data.Data(), data.Size()); 25 | } 26 | 27 | void ByteData::AddDataCopy(const void *data, size_t size) { 28 | DataPacket* dp = new DataPacket(); 29 | dp->copy_ = true; 30 | dp->copy_data_ = new ByteBuffer(size * 2); 31 | dp->copy_data_->Append((const char*)data, size); 32 | dp->size_ += size; 33 | datas_.push_back(dp); 34 | } 35 | 36 | void ByteData::AppendData(const void *data, size_t size) { 37 | int len = (int)datas_.size(); 38 | assert(len != 0 && !datas_[len-1]->copy_); 39 | datas_[len-1]->copy_data_->Append((const char*)data, size); 40 | datas_[len-1]->size_ += size; 41 | } 42 | 43 | void ByteData::AddFile(const std::string &filepath) { 44 | int fd = open(filepath.c_str(), O_RDONLY); 45 | assert(fd > 0); 46 | struct stat st; 47 | fstat(fd, &st); 48 | DataPacket* dp = new DataPacket(); 49 | dp->fd_ = fd; 50 | dp->copy_ = false; 51 | dp->size_ += st.st_size; 52 | dp->zero_copy_data_ = (char*)mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); 53 | assert(dp->zero_copy_data_ != MAP_FAILED); 54 | datas_.push_back(dp); 55 | } 56 | 57 | void ByteData::AddFile(int fd, size_t size) { 58 | assert(fd > 0); 59 | DataPacket* dp = new DataPacket(); 60 | dp->fd_ = fd; 61 | dp->copy_ = false; 62 | dp->size_ += size; 63 | dp->zero_copy_data_ = (char*)mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0); 64 | assert(dp->zero_copy_data_ != MAP_FAILED); 65 | datas_.push_back(dp); 66 | } 67 | 68 | ssize_t ByteData::Writev(int fd) { 69 | if(!Remain()) return 0; 70 | std::vector iovs; 71 | for(int i = (int)current_index_; i < datas_.size(); ++i) { 72 | struct iovec iov; 73 | DataPacket* data = datas_[i]; 74 | if(i == (int)current_index_) { 75 | iov.iov_base = (void*)(data->Data() + offset_); 76 | iov.iov_len = data->size_ - offset_; 77 | }else { 78 | iov.iov_base = (void*)data->Data(); 79 | iov.iov_len = data->size_; 80 | } 81 | iovs.push_back(iov); 82 | } 83 | 84 | ssize_t n = writev(fd, (struct iovec*)(&*iovs.begin()), (int)iovs.size()); 85 | if(n > 0) { 86 | offset_ += n; 87 | modifyIndexAndOffset(); 88 | } 89 | return n; 90 | } 91 | 92 | bool ByteData::Remain() { 93 | return !(current_index_ == datas_.size() - 1 && offset_ == datas_[datas_.size() - 1]->size_); 94 | } 95 | 96 | void ByteData::CopyDataIfNeed() { 97 | if(Remain()) { 98 | for(int i = (int)current_index_; i < datas_.size(); ++i) { 99 | if(i == (int)current_index_) { 100 | if(datas_[i]->CopyIfNeed(offset_)) offset_ = 0; 101 | }else { 102 | datas_[i]->CopyIfNeed(); 103 | } 104 | } 105 | } 106 | } 107 | 108 | void ByteData::modifyIndexAndOffset() { 109 | int size = (int)datas_.size(); 110 | for(int i = (int)current_index_; i < size; ++i) { 111 | offset_ -= datas_[i]->size_; 112 | if(offset_ < 0) { 113 | offset_ += datas_[i]->size_; 114 | current_index_ = i; 115 | return; 116 | } 117 | } 118 | current_index_ = size - 1; 119 | offset_ = (int)datas_[current_index_]->size_; 120 | return; 121 | } 122 | 123 | 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /src/tcpserver/bytedata.h: -------------------------------------------------------------------------------- 1 | #ifndef CWEB_UTIL_BYTEDATA_H_ 2 | #define CWEB_UTIL_BYTEDATA_H_ 3 | 4 | #include "bytebuffer.h" 5 | #include 6 | #include 7 | #include 8 | 9 | namespace cweb { 10 | namespace tcpserver { 11 | 12 | class DataPacket { 13 | private: 14 | ByteBuffer* copy_data_ = nullptr; 15 | char* zero_copy_data_ = nullptr; 16 | 17 | size_t size_ = 0; 18 | int fd_ = -1; 19 | bool copy_ = false; 20 | 21 | public: 22 | friend class ByteData; 23 | ~DataPacket() { 24 | if(copy_) { 25 | delete copy_data_; 26 | }else { 27 | if(fd_ > 0) { 28 | munmap(zero_copy_data_, size_); 29 | close(fd_); 30 | } 31 | } 32 | } 33 | 34 | const char* Data() const { 35 | if(!copy_) return zero_copy_data_; 36 | else return copy_data_->Peek(); 37 | } 38 | 39 | bool CopyIfNeed(size_t offset = 0) { 40 | if(copy_ || fd_ > 0) return false; 41 | copy_ = true; 42 | size_ -= offset; 43 | copy_data_ = new ByteBuffer(size_); 44 | copy_data_->Append(zero_copy_data_ + offset, size_); 45 | zero_copy_data_ = nullptr; 46 | return true; 47 | } 48 | }; 49 | 50 | class ByteData { 51 | private: 52 | std::vector datas_; 53 | size_t current_index_ = 0; 54 | int offset_ = 0; 55 | 56 | void modifyIndexAndOffset(); 57 | 58 | public: 59 | ~ByteData() { 60 | for(DataPacket* data : datas_) delete data; 61 | } 62 | 63 | //内部不拷贝,注意不要提前释放数据,如果一次性没有发完的数据需要手动调用CopyDataIfNeed方法对数据进行缓存 64 | void AddDataZeroCopy(const StringPiece& data); 65 | void AddDataZeroCopy(const void* data, size_t size); 66 | 67 | //内部会存在一次拷贝 68 | void AddDataCopy(const StringPiece& data); 69 | void AddDataCopy(const void* data, size_t size); 70 | void AppendData(const void* data, size_t size); 71 | void AddFile(const std::string& filepath); 72 | void AddFile(int fd, size_t size); 73 | 74 | ssize_t Writev(int fd); 75 | bool Remain(); 76 | void CopyDataIfNeed(); 77 | }; 78 | 79 | } 80 | } 81 | 82 | #endif 83 | -------------------------------------------------------------------------------- /src/tcpserver/epoll/epoll_poller.cc: -------------------------------------------------------------------------------- 1 | /*#include "epoll_poller.h" 2 | #include "event.h" 3 | #include "timer.h" 4 | #include 5 | 6 | namespace cweb { 7 | namespace tcpserver { 8 | 9 | EPollPoller::EPollPoller(EventLoop* loop) : Poller(loop), epollfd_(::epoll_create1(EPOLL_CLOEXEC)), epoll_events_(1024) {} 10 | 11 | EPollPoller::~EPollPoller() { 12 | ::close(epollfd_); 13 | } 14 | 15 | void EPollPoller::UpdateEvent(Event* event) { 16 | if(event->index_ < 0) { 17 | if (events_map_.find(event->fd_) != events_map_.end()) { 18 | return; 19 | } 20 | event->index_ = 1; 21 | events_map_[event->Fd()] = event; 22 | update(EPOLL_CTL_ADD, event); 23 | }else { 24 | if(events_map_.find(event->fd_) == events_map_.end()) { 25 | return; 26 | } 27 | 28 | if(event->events_ == 0) { 29 | update(EPOLL_CTL_DEL, event); 30 | event->index_ = 2; 31 | }else { 32 | update(EPOLL_CTL_MOD, event); 33 | } 34 | } 35 | } 36 | 37 | void EPollPoller::RemoveEvent(Event* event) { 38 | events_map_.erase(event->Fd()); 39 | if(event->index_ == 1) { 40 | update(EPOLL_CTL_DEL, event); 41 | } 42 | event->index_ = -1; 43 | } 44 | 45 | Time EPollPoller::Poll(int timeout, std::vector& activeEvents) { 46 | int n = ::epoll_wait(epollfd_, 47 | &*epoll_events_.begin(), 48 | static_cast(epoll_events_.size()), 49 | timeout); 50 | 51 | Time now = Time::Now(); 52 | 53 | for(int i = 0; i < n; ++i) { 54 | Event* event = static_cast(epoll_events_[i].data.ptr); 55 | event->revents_ = epoll_events_[i].events; 56 | activeEvents.push_back(event); 57 | } 58 | 59 | return now; 60 | } 61 | 62 | void EPollPoller::update(int operation, Event *event) { 63 | struct epoll_event ev; 64 | memZero(&ev, sizeof ev); 65 | ev.events = event->events_; 66 | ev.data.ptr = event; 67 | int fd = event->fd(); 68 | 69 | ::epoll_ctl(epollfd_, operation, fd, &ev) 70 | } 71 | 72 | } 73 | }*/ 74 | -------------------------------------------------------------------------------- /src/tcpserver/epoll/epoll_poller.h: -------------------------------------------------------------------------------- 1 | /*#ifndef CWEB_TCP_EPOLLPOLLER_H_ 2 | #define CWEB_TCP_EPOLLPOLLER_H_ 3 | 4 | #include "poller.h" 5 | #include 6 | #include 7 | #include 8 | 9 | namespace cweb { 10 | namespace tcpserver { 11 | 12 | class EPollPoller : public Poller { 13 | public: 14 | EPollPoller(EventLoop* loop); 15 | virtual ~EPollPoller(); 16 | 17 | virtual void UpdateEvent(Event* event) override; 18 | virtual void RemoveEvent(Event* event) override; 19 | 20 | virtual Time Poll(int timeout, std::vector& activeEvents) override; 21 | 22 | private: 23 | int epollfd_; 24 | std::vector epoll_events_; 25 | void update(int operation, Event* event); 26 | 27 | }; 28 | 29 | } 30 | } 31 | 32 | #endif*/ 33 | -------------------------------------------------------------------------------- /src/tcpserver/event.cc: -------------------------------------------------------------------------------- 1 | #include "event.h" 2 | #include "eventloop.h" 3 | #include "timer.h" 4 | 5 | namespace cweb { 6 | namespace tcpserver { 7 | 8 | void Event::EnableReading() { 9 | events_ |= READ_EVENT; 10 | update(); 11 | } 12 | 13 | void Event::EnableWriting() { 14 | events_ |= WRITE_EVENT; 15 | update(); 16 | } 17 | 18 | void Event::DisableReading() { 19 | events_ &= ~READ_EVENT; 20 | update(); 21 | } 22 | 23 | void Event::DisableWriting() { 24 | events_ &= ~WRITE_EVENT; 25 | update(); 26 | } 27 | 28 | void Event::DisableAll() { 29 | events_ = 0; 30 | update(); 31 | } 32 | 33 | void Event::HandleEvent(Time receiveTime) { 34 | if(revents_ & (READ_EVENT | HUP_EVENT | ERR_EVENT)) { 35 | read_callback_(receiveTime); 36 | } 37 | 38 | if(revents_ & WRITE_EVENT) { 39 | write_callback_(); 40 | } 41 | } 42 | 43 | void Event::HandleTimeout() { 44 | if(timeout_callback_) { 45 | timeout_callback_(); 46 | } 47 | } 48 | 49 | void Event::Remove() { 50 | loop_->RemoveEvent(this); 51 | } 52 | 53 | void Event::update() { 54 | loop_->UpdateEvent(this); 55 | } 56 | 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/tcpserver/event.h: -------------------------------------------------------------------------------- 1 | #ifndef CWEB_TCP_EVENT_H_ 2 | #define CWEB_TCP_EVENT_H_ 3 | 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | namespace cweb { 10 | namespace tcpserver { 11 | 12 | #define NONE_EVENT 0x0000 13 | #define READ_EVENT 0x0001 14 | #define WRITE_EVENT 0x0004 15 | #define HUP_EVENT 0x0010 16 | #define ERR_EVENT 0x0008 17 | 18 | class EventLoop; 19 | class Time; 20 | class KqueuePoller; 21 | 22 | class Event { 23 | public: 24 | friend KqueuePoller; 25 | friend class PollPoller; 26 | friend class EPollPoller; 27 | friend EventLoop; 28 | Event(std::shared_ptr loop, int fd, bool is_socket = false) : loop_(loop), fd_(fd), is_socket_(is_socket) { 29 | flags_ = ::fcntl(fd_, F_GETFL, 0); 30 | } 31 | 32 | typedef std::function EventCallback; 33 | typedef std::function ReadEventCallback; 34 | 35 | void SetRevents(short revents) {revents_ = revents;} 36 | void AddRevents(short revents) {revents_ |= revents;} 37 | 38 | void EnableReading(); 39 | void EnableWriting(); 40 | void DisableReading(); 41 | void DisableWriting(); 42 | void DisableAll(); 43 | 44 | virtual void HandleEvent(Time receiveTime); 45 | 46 | bool Readable() const {return events_ & READ_EVENT;} 47 | bool Writable() const {return events_ & WRITE_EVENT;} 48 | 49 | void HandleTimeout(); 50 | void Remove(); 51 | 52 | void SetReadCallback(ReadEventCallback cb) { read_callback_ = std::move(cb); } 53 | void SetWriteCallback(EventCallback cb) { write_callback_ = std::move(cb); } 54 | void SetTimeoutCallback(EventCallback cb) { timeout_callback_ = std::move(cb); } 55 | void SetErrorCallback(EventCallback cb) { error_callback_ = std::move(cb); } 56 | 57 | int Fd() const {return fd_;} 58 | int Flags() const {return flags_;} 59 | bool IsSocket() const {return is_socket_;} 60 | 61 | protected: 62 | int fd_ = 0; 63 | int events_ = 0; 64 | int revents_ = 0; 65 | int index_ = -1; 66 | int flags_ = 0; 67 | bool is_socket_ = false; 68 | std::shared_ptr loop_; 69 | ReadEventCallback read_callback_; 70 | EventCallback write_callback_; 71 | EventCallback timeout_callback_; 72 | EventCallback error_callback_; 73 | 74 | void update(); 75 | }; 76 | 77 | } 78 | } 79 | 80 | #endif 81 | -------------------------------------------------------------------------------- /src/tcpserver/eventloop.cc: -------------------------------------------------------------------------------- 1 | #include "eventloop.h" 2 | #include "event.h" 3 | #include "timer.h" 4 | #ifdef KQUEUE 5 | #include "kqueue_poller.h" 6 | #elif EPOLL 7 | #include "epoll_poller.h" 8 | #else 9 | #include "poll_poller.h" 10 | #endif 11 | #include "pthread_keys.h" 12 | 13 | #include 14 | #include 15 | 16 | namespace cweb { 17 | namespace tcpserver { 18 | 19 | EventLoop::EventLoop() 20 | :tid_(pthread_self()) { 21 | #ifdef KQUEUE 22 | poller_.reset(new KqueuePoller(this)); 23 | #elif EPOLL 24 | poller_.reset(new EPollPoller(this)); 25 | #else 26 | poller_.reset(new PollPoller(this)); 27 | #endif 28 | timermanager_.reset(new TimerWheelManager()); 29 | memorypool_.reset(new util::MemoryPool()); 30 | } 31 | 32 | EventLoop::~EventLoop() {} 33 | 34 | void EventLoop::Run() { 35 | createWakeupfd(); 36 | pthread_setspecific(util::PthreadKeysSingleton::GetInstance()->TLSMemoryPool, memorypool_.get()); 37 | running_ = true; 38 | loop(); 39 | } 40 | 41 | void EventLoop::Quit() { 42 | running_ = false; 43 | if(!isInLoopThread()) { 44 | wakeup(); 45 | } 46 | } 47 | 48 | void EventLoop::AddTask(Functor cb) { 49 | if(isInLoopThread()) { 50 | cb(); 51 | }else { 52 | std::unique_lock lock(mutex_); 53 | tasks_.push_back(std::move(cb)); 54 | wakeup(); 55 | } 56 | } 57 | 58 | void EventLoop::AddTasks(std::vector& cbs) { 59 | if(isInLoopThread()) { 60 | for(Functor cb : cbs) { 61 | cb(); 62 | } 63 | }else { 64 | std::unique_lock lock(mutex_); 65 | for(Functor cb : cbs) { 66 | tasks_.push_back(std::move(cb)); 67 | } 68 | } 69 | } 70 | 71 | Timer* EventLoop::AddTimer(uint64_t s, Functor cb, int repeats) { 72 | Timer* timer = new Timer(s, cb, repeats); 73 | //线程安全 74 | timermanager_->AddTimer(timer); 75 | return timer; 76 | } 77 | 78 | void EventLoop::RemoveTimer(Timer *timer) { 79 | timermanager_->RemoveTimer(timer); 80 | } 81 | 82 | void EventLoop::UpdateEvent(Event *event) { 83 | poller_->UpdateEvent(event); 84 | } 85 | 86 | void EventLoop::RemoveEvent(Event *event) { 87 | poller_->RemoveEvent(event); 88 | } 89 | 90 | void EventLoop::loop() { 91 | Time now = Time::Now(); 92 | while(running_) { 93 | active_events_.clear(); 94 | int timeout = timermanager_->NextTimeoutInterval(); 95 | now = poller_->Poll(timeout, active_events_); 96 | handleActiveEvents(now); 97 | handleTasks(); 98 | handleTimeoutTimers(); 99 | } 100 | } 101 | 102 | void EventLoop::handleActiveEvents(Time time) { 103 | for(Event* event : active_events_) { 104 | event->HandleEvent(time); 105 | } 106 | } 107 | 108 | void EventLoop::handleTasks() { 109 | std::vector tasks; 110 | { 111 | std::unique_lock lock(mutex_); 112 | tasks.swap(tasks_); 113 | } 114 | 115 | for(Functor& task : tasks) { 116 | task(); 117 | } 118 | } 119 | 120 | void EventLoop::handleTimeoutTimers() { 121 | std::vector timeouts; 122 | if(timermanager_->PopAllTimeoutTimer(timeouts)) { 123 | for(Timer* timeout : timeouts) { 124 | timeout->Execute(); 125 | } 126 | } 127 | } 128 | 129 | void EventLoop::createWakeupfd() { 130 | ::pipe(wakeup_fd_); 131 | wakeup_event_.reset(new Event(shared_from_this(), wakeup_fd_[0])); 132 | wakeup_event_->EnableReading(); 133 | wakeup_event_->SetReadCallback(std::bind(&EventLoop::handleWakeup, this)); 134 | } 135 | 136 | void EventLoop::wakeup() { 137 | char c = 'w'; 138 | ::write(wakeup_fd_[1], &c, sizeof(c)); 139 | } 140 | 141 | void EventLoop::handleWakeup() { 142 | char c; 143 | ::read(wakeup_fd_[0], &c, sizeof(c)); 144 | } 145 | 146 | 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /src/tcpserver/eventloop.h: -------------------------------------------------------------------------------- 1 | #ifndef CWEB_TCP_EVENTLOOP_H_ 2 | #define CWEB_TCP_EVENTLOOP_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "threadlocal_memorypool.h" 10 | 11 | namespace cweb { 12 | 13 | namespace tcpserver { 14 | 15 | class Poller; 16 | class Event; 17 | class Timer; 18 | class Time; 19 | class TimerManager; 20 | class EventLoop : public std::enable_shared_from_this { 21 | 22 | public: 23 | typedef std::function Functor; 24 | 25 | EventLoop(); 26 | ~EventLoop(); 27 | 28 | virtual void Run(); 29 | virtual void Quit(); 30 | 31 | virtual void AddTask(Functor cb); 32 | virtual void AddTasks(std::vector& cbs); 33 | virtual Timer* AddTimer(uint64_t s, Functor cb, int repeats = 1); 34 | void RemoveTimer(Timer* timer); 35 | virtual void UpdateEvent(Event* event); 36 | virtual void RemoveEvent(Event* event); 37 | 38 | bool isInLoopThread() const {return tid_ == pthread_self();} 39 | 40 | protected: 41 | bool running_ = false; 42 | std::unique_ptr poller_; 43 | std::unique_ptr memorypool_; 44 | std::mutex mutex_; 45 | std::unique_ptr timermanager_; 46 | std::vector active_events_; 47 | 48 | void loop(); 49 | void wakeup(); 50 | 51 | void createWakeupfd(); 52 | void handleActiveEvents(Time time); 53 | void handleTasks(); 54 | void handleTimeoutTimers(); 55 | void handleWakeup(); 56 | 57 | private: 58 | std::vector tasks_; 59 | std::vector timeout_timers_; 60 | 61 | int wakeup_fd_[2]; 62 | std::unique_ptr wakeup_event_; 63 | pthread_t tid_; 64 | 65 | }; 66 | 67 | 68 | } 69 | } 70 | 71 | #endif 72 | -------------------------------------------------------------------------------- /src/tcpserver/eventloop_thread.cc: -------------------------------------------------------------------------------- 1 | #include "eventloop_thread.h" 2 | #include "eventloop.h" 3 | 4 | namespace cweb { 5 | namespace tcpserver { 6 | 7 | EventLoopThread::~EventLoopThread() { 8 | if(!stop_) { 9 | StopLoop(); 10 | } 11 | } 12 | 13 | std::shared_ptr EventLoopThread::StartLoop() { 14 | stop_ = false; 15 | pthread_create(&tid_, NULL, threadFunc, this); 16 | //thread_ = std::thread(std::bind(&EventLoopThread::createLoopAndRun, this)); 17 | 18 | { 19 | std::unique_lock lock(mutex_); 20 | while(loop_ == nullptr) { 21 | cond_.wait(lock); 22 | } 23 | } 24 | 25 | return loop_; 26 | } 27 | 28 | void EventLoopThread::StopLoop() { 29 | stop_ = true; 30 | if(loop_ != nullptr) { 31 | loop_->Quit(); 32 | pthread_join(tid_, NULL); 33 | } 34 | } 35 | 36 | void* EventLoopThread::threadFunc(void* arg) { 37 | EventLoopThread* thread = (EventLoopThread*)arg; 38 | thread->createLoopAndRun(); 39 | return NULL; 40 | } 41 | 42 | void EventLoopThread::createLoopAndRun() { 43 | std::shared_ptr loop(new EventLoop()); 44 | 45 | { 46 | std::unique_lock lock(mutex_); 47 | loop_ = loop; 48 | cond_.notify_all(); 49 | } 50 | 51 | loop->Run(); 52 | } 53 | 54 | 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/tcpserver/eventloop_thread.h: -------------------------------------------------------------------------------- 1 | #ifndef CWEB_TCP_EVENTLOOPTHREAD_H_ 2 | #define CWEB_TCP_EVENTLOOPTHREAD_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | namespace cweb { 9 | namespace tcpserver { 10 | 11 | class EventLoop; 12 | class EventLoopThread { 13 | protected: 14 | std::shared_ptr loop_; 15 | bool stop_ = true; 16 | std::string name_; 17 | pthread_t tid_; 18 | std::mutex mutex_; 19 | std::condition_variable cond_; 20 | void createLoopAndRun(); 21 | static void* threadFunc(void* arg); 22 | 23 | public: 24 | EventLoopThread(const std::string& name = "") : name_(name) {}; 25 | ~EventLoopThread(); 26 | 27 | virtual std::shared_ptr StartLoop(); 28 | virtual void StopLoop(); 29 | std::string Name() const {return name_;} 30 | }; 31 | 32 | } 33 | } 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /src/tcpserver/hooks.h: -------------------------------------------------------------------------------- 1 | #ifndef CWEB_TCP_HOOKS_H_ 2 | #define CWEB_TCP_HOOKS_H_ 3 | 4 | #include 5 | 6 | namespace cweb { 7 | namespace tcpserver { 8 | 9 | //去除name mangling 10 | extern "C" { 11 | 12 | ssize_t read(int fd, void *buf, size_t nbyte); 13 | ssize_t readv(int fd, const struct iovec *iov, int iovcnt); 14 | ssize_t write(int fd, const void *buf, size_t nbyte); 15 | ssize_t writev(int fd, const struct iovec *iov, int iovcnt); 16 | 17 | int accept(int fd, struct sockaddr *addr, socklen_t *len); 18 | unsigned int sleep(unsigned int seconds); 19 | 20 | } 21 | 22 | } 23 | } 24 | #endif 25 | -------------------------------------------------------------------------------- /src/tcpserver/inetaddress.cc: -------------------------------------------------------------------------------- 1 | #include "inetaddress.h" 2 | #include 3 | 4 | namespace cweb { 5 | namespace tcpserver { 6 | 7 | InetAddress::InetAddress(uint16_t port, bool loopbackonly, bool ipv6) { 8 | ipv6_ = ipv6; 9 | if(ipv6) { 10 | memset(&addrv6_, 0, sizeof(addrv6_)); 11 | addrv6_.sin6_family = AF_INET6; 12 | addrv6_.sin6_addr = loopbackonly ? in6addr_loopback : in6addr_any; 13 | addrv6_.sin6_port = htons(port); 14 | }else { 15 | memset(&addrv4_, 0, sizeof(addrv4_)); 16 | addrv4_.sin_family = AF_INET; 17 | addrv4_.sin_addr.s_addr = htonl(loopbackonly ? INADDR_LOOPBACK : INADDR_ANY); 18 | addrv4_.sin_port = htons(port); 19 | } 20 | } 21 | 22 | InetAddress::InetAddress(const std::string& ip, uint16_t port, bool ipv6) { 23 | ipv6_ = ipv6; 24 | if(ipv6) { 25 | memset(&addrv6_, 0, sizeof(addrv6_)); 26 | addrv6_.sin6_family = AF_INET6; 27 | addrv6_.sin6_port = htons(port); 28 | ::inet_pton(AF_INET6, ip.c_str(), &addrv6_.sin6_addr); 29 | }else { 30 | memset(&addrv4_, 0, sizeof(addrv4_)); 31 | addrv4_.sin_family = AF_INET; 32 | addrv4_.sin_port = htons(port); 33 | addrv4_.sin_addr.s_addr = htonl(INADDR_ANY); 34 | //::inet_pton(AF_INET, ip.c_str(), &addrv4_.sin_addr); 35 | } 36 | } 37 | 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/tcpserver/inetaddress.h: -------------------------------------------------------------------------------- 1 | #ifndef CWEB_TCP_INETADDRESS_H_ 2 | #define CWEB_TCP_INETADDRESS_H_ 3 | 4 | #include 5 | #include 6 | 7 | namespace cweb { 8 | namespace tcpserver { 9 | 10 | class InetAddress { 11 | public: 12 | friend class Socket; 13 | InetAddress() {} 14 | InetAddress(uint16_t port, bool loopbackonly = false, bool ipv6 = false); 15 | InetAddress(const std::string& ip, uint16_t port, bool ipv6 = false); 16 | InetAddress(const struct sockaddr_in addr) : addrv4_(addr) {} 17 | InetAddress(const struct sockaddr_in6 addr) : addrv6_(addr) {} 18 | 19 | //验证加不加&的效果 20 | void SetSockaddr(const struct sockaddr_in addr) {addrv4_ = addr;} 21 | void SetSockaddr(const struct sockaddr_in6 addr) {addrv6_ = addr;} 22 | 23 | bool IsIPv6() const {return ipv6_;} 24 | struct sockaddr_in* Addrv4() {return &addrv4_;} 25 | struct sockaddr_in6* Addrv6() {return &addrv6_;} 26 | 27 | private: 28 | union { 29 | struct sockaddr_in addrv4_; 30 | struct sockaddr_in6 addrv6_; 31 | }; 32 | bool ipv6_ = false; 33 | }; 34 | 35 | } 36 | } 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /src/tcpserver/kqueue/kqueue_poller.cc: -------------------------------------------------------------------------------- 1 | #include "kqueue_poller.h" 2 | #include "timer.h" 3 | #include "event.h" 4 | #include 5 | 6 | namespace cweb { 7 | namespace tcpserver { 8 | 9 | KqueuePoller::KqueuePoller(EventLoop* loop) : Poller(loop) { 10 | events_ = (struct kevent*)malloc(sizeof(struct kevent) * kMaxEventsSize); 11 | kqfd_ = kqueue(); 12 | } 13 | 14 | KqueuePoller::~KqueuePoller() { 15 | free(events_); 16 | ::close(kqfd_); 17 | } 18 | 19 | Time KqueuePoller::Poll(int timeout, std::vector& activeEvents) { 20 | 21 | int ret = 0; 22 | if(timeout < 0) { 23 | ret = kevent(kqfd_, NULL, 0, events_, 1024, NULL); 24 | }else { 25 | struct timespec time; 26 | time.tv_sec = timeout / 1000; 27 | time.tv_nsec = timeout - time.tv_sec * 1000; 28 | ret = kevent(kqfd_, NULL, 0, events_, 1024, &time); 29 | } 30 | 31 | Time now = Time::Now(); 32 | 33 | if(ret > 0) { 34 | std::unordered_map active_events; 35 | for(int i = 0; i < ret; ++i) { 36 | struct kevent* ev = events_ + i; 37 | //kqueue读写事件是分开的,避免重复添加 38 | std::unordered_map::iterator evptr = active_events.find((int)(ev->ident)); 39 | 40 | if(evptr != active_events.end()) { 41 | Event* event = evptr->second; 42 | if(ev->filter == EVFILT_READ) event->AddRevents(READ_EVENT); 43 | else if(ev->filter == EVFILT_WRITE) event->AddRevents(WRITE_EVENT); 44 | continue; 45 | } 46 | 47 | evptr = events_map_.find((int)(ev->ident)); 48 | 49 | if(evptr != events_map_.end()) { 50 | Event* event = evptr->second; 51 | if(ev->filter == EVFILT_READ) event->SetRevents(READ_EVENT); 52 | else if(ev->filter == EVFILT_WRITE) event->SetRevents(WRITE_EVENT); 53 | active_events[event->fd_] = event; 54 | } 55 | } 56 | 57 | for(std::unordered_map::iterator ptr = active_events.begin(); ptr != active_events.end(); ++ptr) { 58 | activeEvents.push_back(ptr->second); 59 | } 60 | } 61 | 62 | return now; 63 | } 64 | 65 | void KqueuePoller::UpdateEvent(Event* event) { 66 | 67 | struct kevent ke; 68 | if(event->events_ & READ_EVENT) { 69 | EV_SET(&ke, event->fd_, EVFILT_READ, EV_ADD, 0, 0, NULL); 70 | kevent(kqfd_, &ke, 1, NULL, 0, NULL); 71 | }else { 72 | EV_SET(&ke, event->fd_, EVFILT_READ, EV_DELETE, 0, 0, NULL); 73 | kevent(kqfd_, &ke, 1, NULL, 0, NULL); 74 | } 75 | 76 | if(event->events_ & WRITE_EVENT) { 77 | EV_SET(&ke, event->fd_, EVFILT_WRITE, EV_ADD, 0, 0, NULL); 78 | kevent(kqfd_, &ke, 1, NULL, 0, NULL); 79 | }else { 80 | EV_SET(&ke, event->fd_, EVFILT_WRITE, EV_DELETE, 0, 0, NULL); 81 | kevent(kqfd_, &ke, 1, NULL, 0, NULL); 82 | } 83 | events_map_[event->fd_] = event; 84 | } 85 | 86 | void KqueuePoller::RemoveEvent(Event* event) { 87 | 88 | struct kevent ke; 89 | if(event->events_ & READ_EVENT) { 90 | EV_SET(&ke, event->fd_, EVFILT_READ, EV_DELETE, 0, 0, NULL); 91 | kevent(kqfd_, &ke, 1, NULL, 0, NULL); 92 | } 93 | 94 | if(event->events_ & WRITE_EVENT) { 95 | EV_SET(&ke, event->fd_, EVFILT_WRITE, EV_DELETE, 0, 0, NULL); 96 | kevent(kqfd_, &ke, 1, NULL, 0, NULL); 97 | } 98 | 99 | if(events_map_.find(event->fd_) != events_map_.end()) { 100 | events_map_.erase(event->fd_); 101 | } 102 | } 103 | 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /src/tcpserver/kqueue/kqueue_poller.h: -------------------------------------------------------------------------------- 1 | #ifndef CWEB_TCP_KQUEUEPOLLER_H_ 2 | #define CWEB_TCP_KQUEUEPOLLER_H_ 3 | 4 | #include "poller.h" 5 | #include 6 | 7 | namespace cweb { 8 | namespace tcpserver { 9 | 10 | class EventLoop; 11 | class KqueuePoller : public Poller { 12 | 13 | public: 14 | KqueuePoller(EventLoop* loop); 15 | ~KqueuePoller(); 16 | 17 | virtual void UpdateEvent(Event* event) override; 18 | virtual void RemoveEvent(Event* event) override; 19 | 20 | virtual Time Poll(int timeout, std::vector& activeEvents) override; 21 | 22 | private: 23 | int kqfd_; 24 | struct kevent* events_; 25 | }; 26 | 27 | } 28 | } 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /src/tcpserver/poll/poll_poller.cc: -------------------------------------------------------------------------------- 1 | #include "poll_poller.h" 2 | #include "timer.h" 3 | #include "event.h" 4 | 5 | namespace cweb { 6 | namespace tcpserver { 7 | 8 | void PollPoller::UpdateEvent(Event* event) { 9 | if(event->index_ < 0) { 10 | if (events_map_.find(event->fd_) != events_map_.end()) { 11 | return; 12 | } 13 | 14 | struct pollfd pfd; 15 | pfd.fd = event->fd_; 16 | pfd.events = static_cast(event->events_); 17 | pfd.revents = 0; 18 | 19 | int idx = static_cast(pollfds_.size()); 20 | event->index_ = idx; 21 | 22 | pollfds_.push_back(pfd); 23 | events_map_[pfd.fd] = event; 24 | }else{ 25 | if(events_map_.find(event->fd_) == events_map_.end()) { 26 | return; 27 | } 28 | 29 | int idx = event->index_; 30 | 31 | struct pollfd& pfd = pollfds_[idx]; 32 | pfd.events = static_cast(event->events_); 33 | pfd.revents = 0; 34 | } 35 | } 36 | 37 | void PollPoller::RemoveEvent(Event* event) { 38 | int idx = event->index_; 39 | if(idx >= 0 && idx < pollfds_.size()) { 40 | events_map_.erase(event->fd_); 41 | if((size_t)idx == pollfds_.size()-1) { 42 | pollfds_.pop_back(); 43 | }else { 44 | int lastFd = pollfds_.back().fd; 45 | std::iter_swap(pollfds_.begin() + idx, pollfds_.end() - 1); 46 | if(lastFd < 0) {lastFd = -lastFd - 1;} 47 | events_map_[lastFd]->index_ = idx; 48 | pollfds_.pop_back(); 49 | } 50 | } 51 | 52 | } 53 | 54 | Time PollPoller::Poll(int timeout, std::vector& activeEvents) { 55 | int n = ::poll(&(*pollfds_.begin()), pollfds_.size(), timeout); 56 | Time now = Time::Now(); 57 | 58 | if(n > 0) { 59 | for (std::vector::const_iterator pfd = pollfds_.begin(); pfd != pollfds_.end() && n > 0; ++pfd) 60 | { 61 | if (pfd->revents > 0) 62 | { 63 | --n; 64 | std::unordered_map::iterator evptr = events_map_.find(pfd->fd); 65 | if(evptr != events_map_.end()) { 66 | Event* ev = evptr->second; 67 | ev->revents_ = pfd->revents; 68 | activeEvents.push_back(ev); 69 | } 70 | } 71 | } 72 | } 73 | return now; 74 | } 75 | 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/tcpserver/poll/poll_poller.h: -------------------------------------------------------------------------------- 1 | #ifndef CWEB_TCP_POLLPOLLER_H_ 2 | #define CWEB_TCP_POLLPOLLER_H_ 3 | 4 | #include "poller.h" 5 | #include 6 | #include 7 | 8 | namespace cweb { 9 | namespace tcpserver { 10 | 11 | class PollPoller : public Poller { 12 | public: 13 | PollPoller(EventLoop* loop) : Poller(loop){}; 14 | virtual ~PollPoller() {}; 15 | 16 | virtual void UpdateEvent(Event* event) override; 17 | virtual void RemoveEvent(Event* event) override; 18 | 19 | virtual Time Poll(int timeout, std::vector& activeEvents) override; 20 | 21 | private: 22 | std::vector pollfds_; 23 | 24 | }; 25 | 26 | } 27 | } 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /src/tcpserver/scheduler.cc: -------------------------------------------------------------------------------- 1 | #include "scheduler.h" 2 | #include "eventloop_thread.h" 3 | #include "eventloop.h" 4 | 5 | namespace cweb { 6 | namespace tcpserver { 7 | 8 | Scheduler::Scheduler(std::shared_ptr baseloop, int threadcnt) : baseloop_(baseloop), threadcnt_(threadcnt) {} 9 | 10 | Scheduler::~Scheduler() { 11 | //不要回收loop 外部创建的临时变量 12 | } 13 | 14 | void Scheduler::Start() { 15 | for(int i = 0; i < threadcnt_; ++i) { 16 | std::unique_ptr thread(new EventLoopThread()); 17 | loops_.push_back(thread->StartLoop()); 18 | threads_.push_back(std::move(thread)); 19 | } 20 | } 21 | 22 | void Scheduler::Stop() { 23 | for (auto loop : loops_) { 24 | loop->Quit(); 25 | } 26 | } 27 | 28 | std::shared_ptr Scheduler::GetNextLoop() { 29 | ++next_; 30 | next_ %= threadcnt_; 31 | //单线程 32 | return loops_[next_]; 33 | } 34 | 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/tcpserver/scheduler.h: -------------------------------------------------------------------------------- 1 | #ifndef CWEB_TCP_SCHEDULER_H_ 2 | #define CWEB_TCP_SCHEDULER_H_ 3 | 4 | #include 5 | #include 6 | #include "noncopyable.h" 7 | 8 | namespace cweb { 9 | namespace tcpserver { 10 | 11 | class EventLoop; 12 | class EventLoopThread; 13 | class Scheduler : public util::Noncopyable { 14 | protected: 15 | std::shared_ptr baseloop_; 16 | int next_ = -1; 17 | int threadcnt_ = 0; 18 | std::vector> loops_; 19 | std::vector> threads_; 20 | 21 | public: 22 | Scheduler(std::shared_ptr baseloop, int threadcnt); 23 | ~Scheduler(); 24 | std::shared_ptr GetNextLoop(); 25 | virtual void Start(); 26 | virtual void Stop(); 27 | }; 28 | 29 | } 30 | } 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /src/tcpserver/socket.cc: -------------------------------------------------------------------------------- 1 | #include "socket.h" 2 | #include "inetaddress.h" 3 | #include "eventloop.h" 4 | #include "hooks.h" 5 | #include 6 | #include 7 | #include 8 | 9 | static const int kMaxConnCount = 128; 10 | namespace cweb { 11 | namespace tcpserver { 12 | 13 | Socket* Socket::CreateFdAndBind(InetAddress* addr, bool nonblock) { 14 | int fd = -1; 15 | if(addr->ipv6_) { 16 | fd = ::socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP); 17 | }else { 18 | fd = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 19 | } 20 | 21 | int ret = 0; 22 | 23 | if(addr->ipv6_) { 24 | ret = ::bind(fd, (struct sockaddr*)&addr->addrv6_, static_cast(sizeof(struct sockaddr_in6))); 25 | }else { 26 | ret = ::bind(fd, (struct sockaddr*)&addr->addrv4_, static_cast(sizeof(struct sockaddr_in))); 27 | } 28 | 29 | if(ret < 0) return nullptr; 30 | 31 | Socket* socket = new Socket(fd); 32 | 33 | if(nonblock) { 34 | socket->SetNonBlock(); 35 | } 36 | 37 | return socket; 38 | } 39 | 40 | Socket::~Socket() { 41 | if(connected_) { 42 | Close(); 43 | } 44 | } 45 | 46 | int Socket::Listen() { 47 | int ret = ::listen(fd_, kMaxConnCount); 48 | return ret; 49 | } 50 | 51 | int Socket::Accept(InetAddress* peeraddr) { 52 | sockaddr addr; 53 | memset(&addr, 0, sizeof(addr)); 54 | socklen_t len = static_cast(sizeof(addr)); 55 | int connfd = accept(fd_, &addr, &len); 56 | 57 | if(connfd < 0) return -1; 58 | 59 | if(addr.sa_family == AF_INET) { 60 | peeraddr->SetSockaddr(*(sockaddr_in*)&addr); 61 | }else { 62 | peeraddr->SetSockaddr(*(sockaddr_in6*)&addr); 63 | } 64 | 65 | return connfd; 66 | } 67 | 68 | void Socket::Close() { 69 | if(!connected_ || fd_ == -1) return; 70 | ::close(fd_); 71 | fd_ = -1; 72 | connected_ = false; 73 | } 74 | 75 | ssize_t Socket::Read(void *buffer, size_t len) { 76 | return read(fd_, buffer, len); 77 | } 78 | 79 | ssize_t Socket::Write(const void *buffer, size_t len) { 80 | return write(fd_, buffer, len); 81 | } 82 | 83 | ssize_t Socket::Readv(const struct iovec *iov, int iovcnt) { 84 | return readv(fd_, iov, iovcnt); 85 | } 86 | 87 | ssize_t Socket::Writev(const struct iovec *iov,int iovcnt) { 88 | return writev(fd_, iov, iovcnt); 89 | } 90 | 91 | //ssize_t Socket::Recv(void *buffer, size_t len, int flags) { 92 | // return ::recv(fd_, buffer, len, flags); 93 | //} 94 | // 95 | //ssize_t Socket::Send(const void *buffer, size_t len, int flags) { 96 | // return ::send(fd_, buffer, len, flags); 97 | //} 98 | 99 | int Socket::SetNonBlock() { 100 | if(nonblock_) return 0; 101 | else { 102 | int flags = ::fcntl(fd_, F_GETFL, 0); 103 | flags |= O_NONBLOCK; 104 | int ret = ::fcntl(fd_, F_SETFL, flags); 105 | if(ret < 0) return -1; 106 | else { 107 | nonblock_ = true; 108 | return 0; 109 | } 110 | } 111 | } 112 | 113 | int Socket::Bind(InetAddress *addr) { 114 | return 0; 115 | } 116 | 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /src/tcpserver/socket.h: -------------------------------------------------------------------------------- 1 | #ifndef CWEB_TCP_SOCKET_H_ 2 | #define CWEB_TCP_SOCKET_H_ 3 | 4 | #include "noncopyable.h" 5 | #include "hooks.h" 6 | 7 | namespace cweb { 8 | namespace tcpserver { 9 | 10 | class InetAddress; 11 | class Socket : public util::Noncopyable { 12 | public: 13 | Socket(int fd) : fd_(fd) {connected_ = true;} 14 | virtual ~Socket(); 15 | 16 | int Fd() const {return fd_;} 17 | 18 | int Listen(); 19 | virtual int Accept(InetAddress* peeraddr); 20 | void Close(); 21 | int SetNonBlock(); 22 | int Bind(InetAddress* addr); 23 | 24 | virtual ssize_t Read(void* buffer, size_t len); 25 | virtual ssize_t Write(const void* buffer, size_t len); 26 | virtual ssize_t Readv(const struct iovec* iov, int iovcnt); 27 | virtual ssize_t Writev(const struct iovec* iov, int iovcnt); 28 | //virtual ssize_t Recv(void* buffer, size_t len, int flags); 29 | //virtual ssize_t Send(const void* buffer, size_t len, int flags); 30 | 31 | static Socket* CreateFdAndBind(InetAddress* addr, bool nonblock = true); 32 | 33 | protected: 34 | int fd_ = -1; 35 | bool connected_ = false; 36 | bool nonblock_ = false; 37 | }; 38 | 39 | } 40 | } 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /src/tcpserver/tcpconnection.h: -------------------------------------------------------------------------------- 1 | #ifndef CWEB_TCP_TCPCONNECTION_H_ 2 | #define CWEB_TCP_TCPCONNECTION_H_ 3 | 4 | #include "bytebuffer.h" 5 | #include "bytedata.h" 6 | #include "inetaddress.h" 7 | #include "timer.h" 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | namespace cweb { 16 | namespace tcpserver { 17 | 18 | class EventLoop; 19 | class Socket; 20 | class Event; 21 | class InetAddress; 22 | class Time; 23 | class Timer; 24 | class TcpConnection : public std::enable_shared_from_this { 25 | public: 26 | friend class TcpServer; 27 | enum MessageState { 28 | PROCESS, 29 | FINISH, 30 | BAD 31 | }; 32 | 33 | typedef std::function)> ConnectedCallback; 34 | typedef std::function)> CloseCallback; 35 | typedef std::function, ByteBuffer*, Time)> MessageCallback; 36 | 37 | protected: 38 | enum ConnectState { 39 | INIT, 40 | CONNECT, 41 | CLOSED 42 | }; 43 | 44 | std::string id_ = ""; 45 | std::unique_ptr iaddr_; 46 | bool keep_alive_ = false; 47 | ConnectState connect_state_ = INIT; 48 | std::unique_ptr outputbuffer_; 49 | std::unique_ptr inputbuffer_; 50 | CloseCallback close_callback_; 51 | MessageCallback message_callback_; 52 | ConnectedCallback connected_callback_; 53 | std::queue send_datas_; 54 | std::shared_ptr ownerloop_; 55 | std::unique_ptr socket_; 56 | std::unique_ptr event_; 57 | Timer* timeout_timer_; 58 | 59 | void handleRead(Time time); 60 | void handleWrite(); 61 | void handleClose(); 62 | void handleTimeout(); 63 | void sendInLoop(ByteData* data); 64 | void connectEstablished(); 65 | void forceCloseInLoop(); 66 | void cancelTimer(); 67 | void resumeTimer(); 68 | 69 | public: 70 | 71 | std::string Id() const {return id_;} 72 | bool KeepAlive() const {return keep_alive_;} 73 | bool Connected() const {return connect_state_ == CONNECT;} 74 | void SetConnectedCallback(ConnectedCallback cb) {connected_callback_ = std::move(cb);} 75 | void SetCloseCallback(CloseCallback cb) {close_callback_ = std::move(cb);} 76 | void SetMessageCallback(MessageCallback cb) {message_callback_ = std::move(cb);} 77 | 78 | TcpConnection(std::shared_ptr loop, Socket* socket, InetAddress* addr, const std::string& id); 79 | virtual ~TcpConnection(); 80 | 81 | EventLoop* Ownerloop() const {return ownerloop_.get();} 82 | 83 | /* 84 | virtual void Send(util::ByteBuffer* buf) override; 85 | virtual void Send(const util::StringPiece& data) override; 86 | virtual void Send(std::iostream* stream) override; 87 | virtual void Send(const std::vector& streams) override; 88 | */ 89 | virtual void ForceClose(); 90 | virtual void Send(const void* data, size_t size); 91 | virtual void Send(ByteData* data); 92 | virtual ssize_t Recv(ByteBuffer* buf); 93 | 94 | }; 95 | 96 | } 97 | } 98 | 99 | #endif 100 | -------------------------------------------------------------------------------- /src/tcpserver/tcpserver.cc: -------------------------------------------------------------------------------- 1 | #include "tcpserver.h" 2 | #include "inetaddress.h" 3 | #include "socket.h" 4 | #include "event.h" 5 | #include "timer.h" 6 | #include "tcpconnection.h" 7 | #include "eventloop.h" 8 | #include "scheduler.h" 9 | #include "logger.h" 10 | #include 11 | #include 12 | 13 | using namespace cweb::log; 14 | namespace cweb { 15 | namespace tcpserver { 16 | 17 | TcpServer::TcpServer(std::shared_ptr loop, uint16_t port, bool loopbackonly, bool ipv6) 18 | : accept_loop_(loop), 19 | addr_(new InetAddress(port, loopbackonly, ipv6)) {} 20 | 21 | TcpServer::TcpServer(std::shared_ptr loop, const std::string& ip, uint16_t port, bool ipv6) 22 | : accept_loop_(loop), 23 | addr_(new InetAddress(ip, port, ipv6)) {} 24 | 25 | TcpServer::~TcpServer() { 26 | if(running_) { 27 | Quit(); 28 | } 29 | } 30 | 31 | void TcpServer::init() { 32 | accept_socket_.reset(Socket::CreateFdAndBind(addr_.get())); 33 | if(!accept_socket_) {} 34 | accept_event_.reset(new Event(accept_loop_, accept_socket_->Fd())); 35 | accept_event_->SetReadCallback(std::bind(&TcpServer::handleAccept, this)); 36 | } 37 | 38 | void TcpServer::Start(int threadcnt) { 39 | init(); 40 | running_ = true; 41 | scheduler_.reset(new Scheduler(accept_loop_, threadcnt)); 42 | scheduler_->Start(); 43 | if(accept_socket_->Listen() < 0) {} 44 | accept_event_->EnableReading(); 45 | accept_loop_->Run(); 46 | } 47 | 48 | void TcpServer::Quit() { 49 | running_ = false; 50 | accept_event_->DisableAll(); 51 | accept_event_->Remove(); 52 | scheduler_->Stop(); 53 | } 54 | 55 | void TcpServer::handleAccept() { 56 | InetAddress* peeraddr = new InetAddress(); 57 | int connfd = accept_socket_->Accept(peeraddr); 58 | 59 | Socket* socket = nullptr; 60 | if(connfd > 0) socket = new Socket(connfd); 61 | else { 62 | LOG(LOGLEVEL_WARN, CWEB_MODULE, "tcpserver", "创建连接失败"); 63 | return; 64 | } 65 | 66 | socket->SetNonBlock(); 67 | std::shared_ptr loop = scheduler_->GetNextLoop(); 68 | std::string id = boost::uuids::to_string(random_generator_()); 69 | LOG(LOGLEVEL_INFO, CWEB_MODULE, "tcpserver", "创建连接,connfd: %d, id: %s", connfd, id.c_str()); 70 | std::shared_ptr conn(new TcpConnection(loop, socket, peeraddr, id)); 71 | conn->SetCloseCallback(std::bind(&TcpServer::handleConnectionClose, this, std::placeholders::_1)); 72 | conn->SetConnectedCallback(connected_callback_); 73 | living_connections_[id] = conn; 74 | loop->AddTask(std::bind(&TcpConnection::connectEstablished, conn)); 75 | } 76 | 77 | void TcpServer::handleConnectionClose(std::shared_ptr conn) { 78 | accept_loop_->AddTask(std::bind(&TcpServer::removeConnectionInLoop, this, conn)); 79 | } 80 | 81 | void TcpServer::removeConnectionInLoop(std::shared_ptr conn) { 82 | living_connections_.erase(conn.get()->id_); 83 | } 84 | 85 | 86 | 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/tcpserver/tcpserver.h: -------------------------------------------------------------------------------- 1 | #ifndef CWEB_TCP_TCPSERVER_H_ 2 | #define CWEB_TCP_TCPSERVER_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "bytebuffer.h" 9 | #include "tcpconnection.h" 10 | 11 | namespace cweb { 12 | namespace tcpserver { 13 | 14 | class InetAddress; 15 | class EventLoop; 16 | class Event; 17 | class Socket; 18 | class Time; 19 | class TcpConnection; 20 | class Scheduler; 21 | class TcpServer { 22 | 23 | protected: 24 | std::shared_ptr accept_loop_; 25 | std::unique_ptr accept_socket_; 26 | std::unique_ptr accept_event_; 27 | std::unique_ptr scheduler_; 28 | boost::uuids::random_generator random_generator_; 29 | 30 | bool running_ = false; 31 | std::unique_ptr addr_; 32 | TcpConnection::ConnectedCallback connected_callback_; 33 | std::unordered_map> living_connections_; 34 | 35 | void handleAccept(); 36 | void handleConnectionClose(std::shared_ptr conn); 37 | void removeConnectionInLoop(std::shared_ptr conn); 38 | void init(); 39 | 40 | public: 41 | TcpServer(std::shared_ptr loop, uint16_t port = 0, bool loopbackonly = false, bool ipv6 = false); 42 | TcpServer(std::shared_ptr loop, const std::string& ip, uint16_t port, bool ipv6 = false); 43 | 44 | virtual ~TcpServer(); 45 | void SetConnectedCallback(TcpConnection::ConnectedCallback cb) {connected_callback_ = std::move(cb);} 46 | 47 | virtual void Start(int threadcnt); 48 | virtual void Quit(); 49 | }; 50 | 51 | } 52 | } 53 | 54 | #endif 55 | -------------------------------------------------------------------------------- /src/tcpserver/timer.h: -------------------------------------------------------------------------------- 1 | #ifndef CWEB_TCP_TIMER_H_ 2 | #define CWEB_TCP_TIMER_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "priority_queue.h" 10 | #include "linked_list.h" 11 | 12 | 13 | //TODO 堆定时器导致cancel时timer无法被立即销毁,后续改用时间轮 14 | namespace cweb { 15 | namespace tcpserver { 16 | 17 | class Time { 18 | private: 19 | uint64_t microseconds_since_epoch_; 20 | 21 | public: 22 | Time(int64_t microseconds) : microseconds_since_epoch_(microseconds) {} 23 | 24 | inline int64_t MicroSecondsSinceEpoch() const{ 25 | return microseconds_since_epoch_; 26 | } 27 | 28 | inline Time& operator += (int64_t interval) { 29 | microseconds_since_epoch_ += interval; 30 | return *this; 31 | } 32 | 33 | inline Time& operator -= (int64_t interval) { 34 | microseconds_since_epoch_ -= interval; 35 | return *this; 36 | } 37 | 38 | inline uint64_t operator - (const Time& time) { 39 | return microseconds_since_epoch_ - time.microseconds_since_epoch_; 40 | } 41 | 42 | friend bool operator < (const Time& lt, const Time& rt) { 43 | return lt.MicroSecondsSinceEpoch() < rt.MicroSecondsSinceEpoch(); 44 | } 45 | 46 | friend bool operator > (const Time& lt, const Time& rt) { 47 | return lt.MicroSecondsSinceEpoch() > rt.MicroSecondsSinceEpoch(); 48 | } 49 | 50 | std::string ToString(const std::string& fmt = "%Y-%m-%d %H:%M:%S"); 51 | static Time Now(); 52 | }; 53 | 54 | class TimerManager; 55 | class TimerWheelManager; 56 | class Timer : public util::LinkedListNode { 57 | private: 58 | bool cancel_ = false; 59 | Time executionTime_; 60 | uint64_t interval_; 61 | int repeats_; 62 | std::function timer_callback_; 63 | int position_[2]; 64 | bool poped_ = false; 65 | 66 | public: 67 | friend TimerManager; 68 | friend TimerWheelManager; 69 | //毫秒 70 | Timer(uint64_t interval, std::function cb, int repeats = 1); 71 | 72 | Time ExecutionTime() const {return executionTime_;} 73 | uint64_t ExecutionInterval() {return executionTime_ - Time::Now();} 74 | bool Execute(); 75 | bool PretendExecute(); 76 | void Cancel() {cancel_ = true;} 77 | 78 | void setPosition(int layers, int step) { 79 | position_[0] = layers; 80 | position_[1] = step; 81 | } 82 | 83 | friend bool operator < (const Timer& lt, const Timer& rt) { 84 | return lt.executionTime_ < rt.executionTime_; 85 | } 86 | 87 | friend bool operator > (const Timer& lt, const Timer& rt) { 88 | return lt.executionTime_ > rt.executionTime_; 89 | } 90 | 91 | Timer& operator=(const Timer& task) { 92 | cancel_ = task.cancel_; 93 | executionTime_ = task.executionTime_; 94 | interval_ = task.interval_; 95 | repeats_ = task.repeats_; 96 | return *this; 97 | } 98 | 99 | }; 100 | 101 | //小顶堆弃用 102 | class TimerManager { 103 | private: 104 | util::PriorityQueue timers_; 105 | std::vector timeout_timers_; 106 | std::mutex mutex_; 107 | 108 | public: 109 | TimerManager(); 110 | virtual ~TimerManager(); 111 | virtual void AddTimer(Timer* timer); 112 | //获取超时事件 113 | virtual void ExecuteAllTimeoutTimer(); 114 | virtual bool PopOneTimeoutTimer(Timer*& timer); 115 | virtual bool PopAllTimeoutTimer(std::vector& timers); 116 | virtual bool PopAllTimeoutFunctor(std::vector>& funcs); 117 | virtual int NextTimeoutInterval(); 118 | virtual void RemoveTimer(Timer* timer) = 0; 119 | }; 120 | 121 | class TimerWheelManager : public TimerManager { 122 | private: 123 | uint64_t tickms_; 124 | int wheel_size_; 125 | int layers_; 126 | std::vector steps_; 127 | std::vector timers_cnts_; 128 | std::vector>> timers_wheels_; 129 | std::mutex mutex_; 130 | Time last_rotate_time_; 131 | void addTimer(Timer* timer); 132 | 133 | public: 134 | TimerWheelManager(uint64_t tickms = 1, int wheelsize = 100, int layers = 3); 135 | virtual ~TimerWheelManager(); 136 | 137 | virtual void AddTimer(Timer* timer) override; 138 | virtual bool PopAllTimeoutFunctor(std::vector>& funcs) override; 139 | virtual bool PopAllTimeoutTimer(std::vector& timers) override; 140 | virtual int NextTimeoutInterval() override; 141 | virtual void RemoveTimer(Timer* timer) override; 142 | }; 143 | 144 | } 145 | } 146 | 147 | #endif 148 | -------------------------------------------------------------------------------- /src/util/encode/base64.h: -------------------------------------------------------------------------------- 1 | #ifndef CWEB_UTIL_ENCODE_H_ 2 | #define CWEB_UTIL_ENCODE_H_ 3 | 4 | #include 5 | 6 | namespace cweb { 7 | namespace util { 8 | namespace encode { 9 | 10 | inline static std::string base64encode(const char* data, size_t size, const char* key = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/") { 11 | std::string ret; 12 | ret.resize((size+2) / 3 * 4); 13 | auto it = ret.begin(); 14 | while(size >= 3) 15 | { 16 | *it++ = key[(((unsigned char)*data)&0xFC)>>2]; 17 | unsigned char h = (((unsigned char)*data++) & 0x03) << 4; 18 | *it++ = key[h|((((unsigned char)*data)&0xF0)>>4)]; 19 | h = (((unsigned char)*data++) & 0x0F) << 2; 20 | *it++ = key[h|((((unsigned char)*data)&0xC0)>>6)]; 21 | *it++ = key[((unsigned char)*data++)&0x3F]; 22 | 23 | size -= 3; 24 | } 25 | if (size == 1) 26 | { 27 | *it++ = key[(((unsigned char)*data)&0xFC)>>2]; 28 | unsigned char h = (((unsigned char)*data++) & 0x03) << 4; 29 | *it++ = key[h]; 30 | *it++ = '='; 31 | *it++ = '='; 32 | } 33 | else if (size == 2) 34 | { 35 | *it++ = key[(((unsigned char)*data)&0xFC)>>2]; 36 | unsigned char h = (((unsigned char)*data++) & 0x03) << 4; 37 | *it++ = key[h|((((unsigned char)*data)&0xF0)>>4)]; 38 | h = (((unsigned char)*data++) & 0x0F) << 2; 39 | *it++ = key[h]; 40 | *it++ = '='; 41 | } 42 | return ret; 43 | } 44 | 45 | } 46 | } 47 | } 48 | 49 | #endif 50 | -------------------------------------------------------------------------------- /src/util/json/allocator.h: -------------------------------------------------------------------------------- 1 | // Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors 2 | // Distributed under MIT license, or public domain if desired and 3 | // recognized in your jurisdiction. 4 | // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE 5 | 6 | #ifndef CPPTL_JSON_ALLOCATOR_H_INCLUDED 7 | #define CPPTL_JSON_ALLOCATOR_H_INCLUDED 8 | 9 | #include 10 | #include 11 | 12 | #pragma pack(push, 8) 13 | 14 | namespace Json { 15 | template class SecureAllocator { 16 | public: 17 | // Type definitions 18 | using value_type = T; 19 | using pointer = T*; 20 | using const_pointer = const T*; 21 | using reference = T&; 22 | using const_reference = const T&; 23 | using size_type = std::size_t; 24 | using difference_type = std::ptrdiff_t; 25 | 26 | /** 27 | * Allocate memory for N items using the standard allocator. 28 | */ 29 | pointer allocate(size_type n) { 30 | // allocate using "global operator new" 31 | return static_cast(::operator new(n * sizeof(T))); 32 | } 33 | 34 | /** 35 | * Release memory which was allocated for N items at pointer P. 36 | * 37 | * The memory block is filled with zeroes before being released. 38 | * The pointer argument is tagged as "volatile" to prevent the 39 | * compiler optimizing out this critical step. 40 | */ 41 | void deallocate(volatile pointer p, size_type n) { 42 | std::memset(p, 0, n * sizeof(T)); 43 | // free using "global operator delete" 44 | ::operator delete(p); 45 | } 46 | 47 | /** 48 | * Construct an item in-place at pointer P. 49 | */ 50 | template void construct(pointer p, Args&&... args) { 51 | // construct using "placement new" and "perfect forwarding" 52 | ::new (static_cast(p)) T(std::forward(args)...); 53 | } 54 | 55 | size_type max_size() const { return size_t(-1) / sizeof(T); } 56 | 57 | pointer address(reference x) const { return std::addressof(x); } 58 | 59 | const_pointer address(const_reference x) const { return std::addressof(x); } 60 | 61 | /** 62 | * Destroy an item in-place at pointer P. 63 | */ 64 | void destroy(pointer p) { 65 | // destroy using "explicit destructor" 66 | p->~T(); 67 | } 68 | 69 | // Boilerplate 70 | SecureAllocator() {} 71 | template SecureAllocator(const SecureAllocator&) {} 72 | template struct rebind { using other = SecureAllocator; }; 73 | }; 74 | 75 | template 76 | bool operator==(const SecureAllocator&, const SecureAllocator&) { 77 | return true; 78 | } 79 | 80 | template 81 | bool operator!=(const SecureAllocator&, const SecureAllocator&) { 82 | return false; 83 | } 84 | 85 | } // namespace Json 86 | 87 | #pragma pack(pop) 88 | 89 | #endif // CPPTL_JSON_ALLOCATOR_H_INCLUDED 90 | -------------------------------------------------------------------------------- /src/util/json/assertions.h: -------------------------------------------------------------------------------- 1 | // Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors 2 | // Distributed under MIT license, or public domain if desired and 3 | // recognized in your jurisdiction. 4 | // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE 5 | 6 | #ifndef CPPTL_JSON_ASSERTIONS_H_INCLUDED 7 | #define CPPTL_JSON_ASSERTIONS_H_INCLUDED 8 | 9 | #include 10 | #include 11 | 12 | #if !defined(JSON_IS_AMALGAMATION) 13 | #include "config.h" 14 | #endif // if !defined(JSON_IS_AMALGAMATION) 15 | 16 | /** It should not be possible for a maliciously designed file to 17 | * cause an abort() or seg-fault, so these macros are used only 18 | * for pre-condition violations and internal logic errors. 19 | */ 20 | #if JSON_USE_EXCEPTION 21 | 22 | // @todo <= add detail about condition in exception 23 | #define JSON_ASSERT(condition) \ 24 | { \ 25 | if (!(condition)) { \ 26 | Json::throwLogicError("assert json failed"); \ 27 | } \ 28 | } 29 | 30 | #define JSON_FAIL_MESSAGE(message) \ 31 | { \ 32 | OStringStream oss; \ 33 | oss << message; \ 34 | Json::throwLogicError(oss.str()); \ 35 | abort(); \ 36 | } 37 | 38 | #else // JSON_USE_EXCEPTION 39 | 40 | #define JSON_ASSERT(condition) assert(condition) 41 | 42 | // The call to assert() will show the failure message in debug builds. In 43 | // release builds we abort, for a core-dump or debugger. 44 | #define JSON_FAIL_MESSAGE(message) \ 45 | { \ 46 | OStringStream oss; \ 47 | oss << message; \ 48 | assert(false && oss.str().c_str()); \ 49 | abort(); \ 50 | } 51 | 52 | #endif 53 | 54 | #define JSON_ASSERT_MESSAGE(condition, message) \ 55 | if (!(condition)) { \ 56 | JSON_FAIL_MESSAGE(message); \ 57 | } 58 | 59 | #endif // CPPTL_JSON_ASSERTIONS_H_INCLUDED 60 | -------------------------------------------------------------------------------- /src/util/json/autolink.h: -------------------------------------------------------------------------------- 1 | // Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors 2 | // Distributed under MIT license, or public domain if desired and 3 | // recognized in your jurisdiction. 4 | // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE 5 | 6 | #ifndef JSON_AUTOLINK_H_INCLUDED 7 | #define JSON_AUTOLINK_H_INCLUDED 8 | 9 | #include "config.h" 10 | 11 | #ifdef JSON_IN_CPPTL 12 | #include 13 | #endif 14 | 15 | #if !defined(JSON_NO_AUTOLINK) && !defined(JSON_DLL_BUILD) && \ 16 | !defined(JSON_IN_CPPTL) 17 | #define CPPTL_AUTOLINK_NAME "json" 18 | #undef CPPTL_AUTOLINK_DLL 19 | #ifdef JSON_DLL 20 | #define CPPTL_AUTOLINK_DLL 21 | #endif 22 | #include "autolink.h" 23 | #endif 24 | 25 | #endif // JSON_AUTOLINK_H_INCLUDED 26 | -------------------------------------------------------------------------------- /src/util/json/features.h: -------------------------------------------------------------------------------- 1 | // Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors 2 | // Distributed under MIT license, or public domain if desired and 3 | // recognized in your jurisdiction. 4 | // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE 5 | 6 | #ifndef CPPTL_JSON_FEATURES_H_INCLUDED 7 | #define CPPTL_JSON_FEATURES_H_INCLUDED 8 | 9 | #if !defined(JSON_IS_AMALGAMATION) 10 | #include "forwards.h" 11 | #endif // if !defined(JSON_IS_AMALGAMATION) 12 | 13 | #pragma pack(push, 8) 14 | 15 | namespace Json { 16 | 17 | /** \brief Configuration passed to reader and writer. 18 | * This configuration object can be used to force the Reader or Writer 19 | * to behave in a standard conforming way. 20 | */ 21 | class JSON_API Features { 22 | public: 23 | /** \brief A configuration that allows all features and assumes all strings 24 | * are UTF-8. 25 | * - C & C++ comments are allowed 26 | * - Root object can be any JSON value 27 | * - Assumes Value strings are encoded in UTF-8 28 | */ 29 | static Features all(); 30 | 31 | /** \brief A configuration that is strictly compatible with the JSON 32 | * specification. 33 | * - Comments are forbidden. 34 | * - Root object must be either an array or an object value. 35 | * - Assumes Value strings are encoded in UTF-8 36 | */ 37 | static Features strictMode(); 38 | 39 | /** \brief Initialize the configuration like JsonConfig::allFeatures; 40 | */ 41 | Features(); 42 | 43 | /// \c true if comments are allowed. Default: \c true. 44 | bool allowComments_{true}; 45 | 46 | /// \c true if root must be either an array or an object value. Default: \c 47 | /// false. 48 | bool strictRoot_{false}; 49 | 50 | /// \c true if dropped null placeholders are allowed. Default: \c false. 51 | bool allowDroppedNullPlaceholders_{false}; 52 | 53 | /// \c true if numeric object key are allowed. Default: \c false. 54 | bool allowNumericKeys_{false}; 55 | }; 56 | 57 | } // namespace Json 58 | 59 | #pragma pack(pop) 60 | 61 | #endif // CPPTL_JSON_FEATURES_H_INCLUDED 62 | -------------------------------------------------------------------------------- /src/util/json/forwards.h: -------------------------------------------------------------------------------- 1 | // Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors 2 | // Distributed under MIT license, or public domain if desired and 3 | // recognized in your jurisdiction. 4 | // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE 5 | 6 | #ifndef JSON_FORWARDS_H_INCLUDED 7 | #define JSON_FORWARDS_H_INCLUDED 8 | 9 | #if !defined(JSON_IS_AMALGAMATION) 10 | #include "config.h" 11 | #endif // if !defined(JSON_IS_AMALGAMATION) 12 | 13 | namespace Json { 14 | 15 | // writer.h 16 | class FastWriter; 17 | class StyledWriter; 18 | 19 | // reader.h 20 | class Reader; 21 | 22 | // features.h 23 | class Features; 24 | 25 | // value.h 26 | typedef unsigned int ArrayIndex; 27 | class StaticString; 28 | class Path; 29 | class PathArgument; 30 | class Value; 31 | class ValueIteratorBase; 32 | class ValueIterator; 33 | class ValueConstIterator; 34 | 35 | } // namespace Json 36 | 37 | #endif // JSON_FORWARDS_H_INCLUDED 38 | -------------------------------------------------------------------------------- /src/util/json/json.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nodesheep/RESTfulCweb/d22f37d5f682a99ba0d7365e1a37cff5b257c306/src/util/json/json.h -------------------------------------------------------------------------------- /src/util/json/json_tool.h: -------------------------------------------------------------------------------- 1 | // Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors 2 | // Distributed under MIT license, or public domain if desired and 3 | // recognized in your jurisdiction. 4 | // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE 5 | 6 | #ifndef LIB_JSONCPP_JSON_TOOL_H_INCLUDED 7 | #define LIB_JSONCPP_JSON_TOOL_H_INCLUDED 8 | 9 | #if !defined(JSON_IS_AMALGAMATION) 10 | #include "config.h" 11 | #endif 12 | 13 | // Also support old flag NO_LOCALE_SUPPORT 14 | #ifdef NO_LOCALE_SUPPORT 15 | #define JSONCPP_NO_LOCALE_SUPPORT 16 | #endif 17 | 18 | #ifndef JSONCPP_NO_LOCALE_SUPPORT 19 | #include 20 | #endif 21 | 22 | /* This header provides common string manipulation support, such as UTF-8, 23 | * portable conversion from/to string... 24 | * 25 | * It is an internal header that must not be exposed. 26 | */ 27 | 28 | namespace Json { 29 | static inline char getDecimalPoint() { 30 | #ifdef JSONCPP_NO_LOCALE_SUPPORT 31 | return '\0'; 32 | #else 33 | struct lconv* lc = localeconv(); 34 | return lc ? *(lc->decimal_point) : '\0'; 35 | #endif 36 | } 37 | 38 | /// Converts a unicode code-point to UTF-8. 39 | static inline String codePointToUTF8(unsigned int cp) { 40 | String result; 41 | 42 | // based on description from http://en.wikipedia.org/wiki/UTF-8 43 | 44 | if (cp <= 0x7f) { 45 | result.resize(1); 46 | result[0] = static_cast(cp); 47 | } else if (cp <= 0x7FF) { 48 | result.resize(2); 49 | result[1] = static_cast(0x80 | (0x3f & cp)); 50 | result[0] = static_cast(0xC0 | (0x1f & (cp >> 6))); 51 | } else if (cp <= 0xFFFF) { 52 | result.resize(3); 53 | result[2] = static_cast(0x80 | (0x3f & cp)); 54 | result[1] = static_cast(0x80 | (0x3f & (cp >> 6))); 55 | result[0] = static_cast(0xE0 | (0xf & (cp >> 12))); 56 | } else if (cp <= 0x10FFFF) { 57 | result.resize(4); 58 | result[3] = static_cast(0x80 | (0x3f & cp)); 59 | result[2] = static_cast(0x80 | (0x3f & (cp >> 6))); 60 | result[1] = static_cast(0x80 | (0x3f & (cp >> 12))); 61 | result[0] = static_cast(0xF0 | (0x7 & (cp >> 18))); 62 | } 63 | 64 | return result; 65 | } 66 | 67 | enum { 68 | /// Constant that specify the size of the buffer that must be passed to 69 | /// uintToString. 70 | uintToStringBufferSize = 3 * sizeof(LargestUInt) + 1 71 | }; 72 | 73 | // Defines a char buffer for use with uintToString(). 74 | typedef char UIntToStringBuffer[uintToStringBufferSize]; 75 | 76 | /** Converts an unsigned integer to string. 77 | * @param value Unsigned integer to convert to string 78 | * @param current Input/Output string buffer. 79 | * Must have at least uintToStringBufferSize chars free. 80 | */ 81 | static inline void uintToString(LargestUInt value, char*& current) { 82 | *--current = 0; 83 | do { 84 | *--current = static_cast(value % 10U + static_cast('0')); 85 | value /= 10; 86 | } while (value != 0); 87 | } 88 | 89 | /** Change ',' to '.' everywhere in buffer. 90 | * 91 | * We had a sophisticated way, but it did not work in WinCE. 92 | * @see https://github.com/open-source-parsers/jsoncpp/pull/9 93 | */ 94 | template Iter fixNumericLocale(Iter begin, Iter end) { 95 | for (; begin != end; ++begin) { 96 | if (*begin == ',') { 97 | *begin = '.'; 98 | } 99 | } 100 | return begin; 101 | } 102 | 103 | template void fixNumericLocaleInput(Iter begin, Iter end) { 104 | char decimalPoint = getDecimalPoint(); 105 | if (decimalPoint == '\0' || decimalPoint == '.') { 106 | return; 107 | } 108 | for (; begin != end; ++begin) { 109 | if (*begin == '.') { 110 | *begin = decimalPoint; 111 | } 112 | } 113 | } 114 | 115 | /** 116 | * Return iterator that would be the new end of the range [begin,end), if we 117 | * were to delete zeros in the end of string, but not the last zero before '.'. 118 | */ 119 | template Iter fixZerosInTheEnd(Iter begin, Iter end) { 120 | for (; begin != end; --end) { 121 | if (*(end - 1) != '0') { 122 | return end; 123 | } 124 | // Don't delete the last zero before the decimal point. 125 | if (begin != (end - 1) && *(end - 2) == '.') { 126 | return end; 127 | } 128 | } 129 | return end; 130 | } 131 | 132 | } // namespace Json 133 | 134 | #endif // LIB_JSONCPP_JSON_TOOL_H_INCLUDED 135 | -------------------------------------------------------------------------------- /src/util/json/version.h: -------------------------------------------------------------------------------- 1 | // DO NOT EDIT. This file (and "version") is generated by CMake. 2 | // Run CMake configure step to update it. 3 | #ifndef JSON_VERSION_H_INCLUDED 4 | # define JSON_VERSION_H_INCLUDED 5 | 6 | # define JSONCPP_VERSION_STRING "1.9.0" 7 | # define JSONCPP_VERSION_MAJOR 1 8 | # define JSONCPP_VERSION_MINOR 9 9 | # define JSONCPP_VERSION_PATCH 0 10 | # define JSONCPP_VERSION_QUALIFIER 11 | # define JSONCPP_VERSION_HEXA ((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | (JSONCPP_VERSION_PATCH << 8)) 12 | 13 | #ifdef JSONCPP_USING_SECURE_MEMORY 14 | #undef JSONCPP_USING_SECURE_MEMORY 15 | #endif 16 | #define JSONCPP_USING_SECURE_MEMORY 0 17 | // If non-zero, the library zeroes any memory that it has allocated before 18 | // it frees its memory. 19 | 20 | #endif // JSON_VERSION_H_INCLUDED 21 | -------------------------------------------------------------------------------- /src/util/linked_list.h: -------------------------------------------------------------------------------- 1 | #ifndef CWEB_UTIL_LINKEDLIST_H_ 2 | #define CWEB_UTIL_LINKEDLIST_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | namespace cweb { 9 | namespace util { 10 | 11 | class LinkedListNode { 12 | public: 13 | LinkedListNode* pre = nullptr; 14 | LinkedListNode* next = nullptr; 15 | }; 16 | 17 | template 18 | class LinkedList { 19 | static_assert((std::is_base_of::value), "T must inherit LinkedListNode"); 20 | private: 21 | T* head_ = nullptr; 22 | T* tail_ = nullptr; 23 | size_t size_; 24 | 25 | void push(T* begin, T* end, size_t size) { 26 | if(size_ == 0) { 27 | head_ = begin; 28 | tail_ = end; 29 | size_ = size; 30 | }else { 31 | tail_->next = begin; 32 | begin->pre = tail_; 33 | end->next = nullptr; 34 | tail_ = end; 35 | size_ += size; 36 | } 37 | } 38 | 39 | public: 40 | LinkedList() : size_(0) {} 41 | 42 | T* Pop() { 43 | T* value = head_ ? head_ : nullptr; 44 | if(value == nullptr) return value; 45 | if(size_ == 1) { 46 | Clear(); 47 | }else { 48 | head_ = (T*)(head_->next); 49 | head_->pre = tail_; 50 | tail_->next = head_; 51 | --size_; 52 | } 53 | return value; 54 | } 55 | 56 | void Push(T* val) { 57 | if(val == nullptr) return; 58 | 59 | if(size_ == 0) { 60 | head_ = tail_ = val; 61 | tail_->next = nullptr; 62 | head_->pre = nullptr; 63 | }else { 64 | tail_->next = val; 65 | val->pre = tail_; 66 | val->next = nullptr; 67 | tail_ = val; 68 | } 69 | ++size_; 70 | } 71 | 72 | void Push(LinkedList& list) { 73 | push(list.Front(), list.Back(), list.Size()); 74 | list.Clear(); 75 | } 76 | 77 | T* Front() { 78 | return head_ ? head_ : nullptr; 79 | } 80 | 81 | T* Back() { 82 | return tail_ ? tail_ : nullptr; 83 | } 84 | 85 | void Clear() { 86 | head_ = tail_ = nullptr; 87 | size_ = 0; 88 | } 89 | 90 | void Erase(T* val) { 91 | assert(val != nullptr); 92 | if(size_ == 0) return; 93 | if(val->pre == nullptr) { 94 | head_ = (T*)head_->next; 95 | if(head_) head_->pre = nullptr; 96 | }else if(val->next == nullptr){ 97 | tail_ = (T*)val->pre; 98 | if(tail_) tail_->next = nullptr; 99 | }else { 100 | val->pre->next = val->next; 101 | val->next->pre = val->pre; 102 | } 103 | --size_; 104 | } 105 | 106 | T* Next(T* current) { 107 | return current->next ? (T*)current->next : nullptr; 108 | } 109 | 110 | size_t Size() {return size_;} 111 | 112 | }; 113 | 114 | } 115 | } 116 | 117 | #endif 118 | -------------------------------------------------------------------------------- /src/util/lockfree_queue.h: -------------------------------------------------------------------------------- 1 | #ifndef CWEB_UTIL_LOCKFREEQUEUE_H_ 2 | #define CWEB_UTIL_LOCKFREEQUEUE_H_ 3 | 4 | #include 5 | #include 6 | 7 | namespace cweb { 8 | 9 | namespace util { 10 | 11 | template 12 | class LockfreeQueue { 13 | 14 | private: 15 | std::vector data_; 16 | std::atomic front_ = {0}; 17 | std::atomic back_ = {0}; 18 | std::atomic write_ = {0}; 19 | int capacity_; 20 | 21 | public: 22 | LockfreeQueue(int capacity = 100) : capacity_(capacity), data_(std::vector(capacity)){} 23 | LockfreeQueue(const LockfreeQueue& queue) { 24 | capacity_ = queue.capacity_; 25 | data_ = queue.data_; 26 | } 27 | 28 | bool MultiplePush(const T val) { 29 | int write, back; 30 | 31 | do { 32 | write = write_.load(std::memory_order_relaxed); 33 | if((write + 1) % capacity_ == front_.load(std::memory_order_acquire)) return false; 34 | }while(!write_.compare_exchange_strong(write, (write + 1) % capacity_, std::memory_order_relaxed)); 35 | 36 | data_[write] = val; 37 | 38 | do { 39 | back = write; 40 | }while(!back_.compare_exchange_strong(back, (back + 1) % capacity_ , std::memory_order_release)); 41 | 42 | return true; 43 | } 44 | 45 | bool MultiplePop(T& val) { 46 | int front; 47 | do { 48 | front = front_.load(std::memory_order_relaxed); 49 | if(front == back_.load(std::memory_order_acquire)) return false; 50 | val = data_[front]; 51 | }while(!front_.compare_exchange_strong(front, (front + 1) % capacity_, std::memory_order_release)); 52 | 53 | return true; 54 | } 55 | 56 | bool SinglePush(const T val) { 57 | int back = back_.load(std::memory_order_relaxed); 58 | 59 | if((back + 1) % capacity_ == front_.load(std::memory_order_acquire)) return false; 60 | 61 | data_[back] = val; 62 | back_.store((back + 1) % capacity_, std::memory_order_release); 63 | return true; 64 | } 65 | 66 | bool SinglePop(T& val) { 67 | int front = front_.load(std::memory_order_relaxed); 68 | if(front == back_.load(std::memory_order_acquire)) return false; 69 | val = data_[front]; 70 | front_.store((front + 1) % capacity_, std::memory_order_release); 71 | return true; 72 | } 73 | 74 | }; 75 | 76 | } 77 | } 78 | 79 | #endif 80 | -------------------------------------------------------------------------------- /src/util/noncopyable.h: -------------------------------------------------------------------------------- 1 | #ifndef CWEB_UTIL_NONCOPYABLE_H_ 2 | #define CWEB_UTIL_NONCOPYABLE_H_ 3 | 4 | namespace cweb { 5 | 6 | namespace util { 7 | 8 | class Noncopyable { 9 | public: 10 | Noncopyable(const Noncopyable&) = delete; 11 | void operator=(const Noncopyable&) = delete; 12 | 13 | protected: 14 | Noncopyable() = default; 15 | ~Noncopyable() = default; 16 | }; 17 | 18 | } 19 | 20 | } 21 | 22 | #endif -------------------------------------------------------------------------------- /src/util/priority_queue.h: -------------------------------------------------------------------------------- 1 | #ifndef CWEB_UTIL_PRIORITYQUEUE_H_ 2 | #define CWEB_UTIL_PRIORITYQUEUE_H_ 3 | 4 | #include 5 | 6 | namespace cweb { 7 | namespace util { 8 | 9 | template 10 | struct less { 11 | bool operator()(const T& left, const T& right) { 12 | return left < right; //存的指针比较的就是指针 13 | } 14 | }; 15 | 16 | template 17 | struct greater { 18 | bool operator()(const T& left, const T& right) { 19 | return left > right; 20 | } 21 | }; 22 | 23 | template > 24 | class PriorityQueue { 25 | 26 | public: 27 | 28 | void Push(T* const elem) { 29 | container_.push_back(elem); 30 | upturn(Size() - 1); 31 | } 32 | 33 | void Pop() { 34 | if(!Empty()) { 35 | std::swap(container_.front(), container_.back()); 36 | container_.pop_back(); 37 | downturn(0); 38 | } 39 | } 40 | 41 | size_t Size() const { 42 | return container_.size(); 43 | } 44 | 45 | T* Front() const { 46 | return container_.front(); 47 | } 48 | 49 | bool Empty() const { 50 | return container_.empty(); 51 | } 52 | 53 | private: 54 | std::vector container_; 55 | Compare compare_; 56 | //移除时下渗 57 | void downturn(size_t n) { 58 | size_t child = n * 2 + 1; 59 | while(child < Size()) { 60 | if(child + 1 < Size() && compare_(*container_[child], *container_[child + 1])) { 61 | child++; 62 | } 63 | 64 | if(compare_(*container_[n], *container_[child])) { 65 | std::swap(container_[n], container_[child]); 66 | n = child; 67 | child = n * 2 + 1; 68 | }else { 69 | break; 70 | } 71 | 72 | 73 | } 74 | } 75 | //插入时上渗 76 | void upturn(size_t n) { 77 | //找到父节点 78 | size_t parent = (n - 1) / 2; 79 | while(n) { 80 | if(compare_(*container_[parent], *container_[n])) { 81 | std::swap(container_[parent], container_[n]); 82 | //T temp = _container[parent]; 83 | //_container[parent] = _container[n]; 84 | //_container[n] = temp; //swap底层会调用复制构造函数和=运算符,所以对应类必须进行显示实现!!! 85 | n = parent; 86 | parent = (n - 1) / 2; 87 | }else { 88 | break; 89 | } 90 | } 91 | } 92 | }; 93 | 94 | } 95 | } 96 | 97 | #endif 98 | -------------------------------------------------------------------------------- /src/util/pthread_keys.h: -------------------------------------------------------------------------------- 1 | #ifndef CWEB_UTIL_PTHREADKEYS_H_ 2 | #define CWEB_UTIL_PTHREADKEYS_H_ 3 | 4 | #include 5 | #include "singleton.h" 6 | 7 | namespace cweb { 8 | namespace util { 9 | 10 | class PthreadKeys { 11 | public: 12 | pthread_key_t TLSEventLoop; 13 | pthread_key_t TLSMainCoroutine; 14 | pthread_key_t TLSMemoryPool; 15 | PthreadKeys() { 16 | pthread_key_create(&TLSEventLoop, NULL); 17 | pthread_key_create(&TLSMainCoroutine, NULL); 18 | pthread_key_create(&TLSMemoryPool, NULL); 19 | } 20 | }; 21 | 22 | typedef cweb::util::Singleton PthreadKeysSingleton; 23 | 24 | } 25 | } 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /src/util/singleton.h: -------------------------------------------------------------------------------- 1 | #ifndef CWEB_UTIL_SINGLETON_H_ 2 | #define CWEB_UTIL_SINGLETON_H_ 3 | 4 | #include "noncopyable.h" 5 | 6 | namespace cweb { 7 | 8 | namespace util { 9 | 10 | template 11 | class Singleton : public Noncopyable { 12 | 13 | public: 14 | 15 | static T* GetInstance() { 16 | static T v; 17 | return &v; 18 | } 19 | 20 | }; 21 | } 22 | 23 | } 24 | 25 | #endif -------------------------------------------------------------------------------- /src/util/threadlocal_memorypool.cc: -------------------------------------------------------------------------------- 1 | #include "threadlocal_memorypool.h" 2 | #include 3 | 4 | namespace cweb { 5 | 6 | namespace util { 7 | 8 | static const size_t kMemoryListsLength = 8; 9 | static const size_t kMaxMemeorySize = 1024; 10 | static const size_t kMemoryBlockSize = 4096; 11 | 12 | void MemoryList::PushFront(void* obj) { 13 | //前4/8个字节存储下一节点的地址 14 | *(void**)obj = head_; 15 | head_ = obj; 16 | ++nodes_remaining_; 17 | } 18 | 19 | void* MemoryList::PopFront() { 20 | if(nodes_remaining_ == 0) { 21 | return nullptr; 22 | } 23 | 24 | void* head = head_; 25 | head_ = *(void**)head_; 26 | --nodes_remaining_; 27 | return head; 28 | } 29 | 30 | bool MemoryList::Empty() { 31 | return nodes_remaining_ == 0; 32 | } 33 | 34 | MemoryPool::MemoryPool() : memorylists_(std::vector(kMemoryListsLength)) {} 35 | 36 | MemoryPool::~MemoryPool() { 37 | for(size_t i = 0; i < memoryblocks_.size(); ++i) { 38 | delete[] memoryblocks_[i]; 39 | } 40 | } 41 | 42 | void* MemoryPool::Allocate(size_t bytes) { 43 | if(bytes <= kMaxMemeorySize) { 44 | size_t index = memorylistsIndex(bytes); 45 | 46 | if(memorylists_[index].Empty()) { 47 | return allocateInMemoryblocks(bytes); 48 | }else { 49 | return memorylists_[index].PopFront(); 50 | } 51 | }else { 52 | return malloc(bytes); 53 | } 54 | } 55 | 56 | void MemoryPool::Deallocate(void* ptr, size_t bytes) { 57 | if(bytes <= kMaxMemeorySize) { 58 | size_t index = memorylistsIndex(bytes); 59 | memorylists_[index].PushFront(ptr); 60 | }else { 61 | free(ptr); 62 | } 63 | } 64 | 65 | size_t MemoryPool::memorylistsIndex(size_t bytes) { 66 | size_t index = 0; 67 | size_t bytes_canuse = 8; 68 | while(bytes_canuse < bytes) { 69 | ++index; 70 | bytes_canuse *= 2; 71 | } 72 | return index; 73 | } 74 | 75 | void* MemoryPool::allocateInMemoryblocks (size_t bytes) { 76 | const int align = (sizeof(void*) > 8) ? sizeof(void*) : 8; 77 | size_t current_mod = reinterpret_cast(alloc_ptr_) & (align - 1); 78 | size_t slop = (current_mod == 0 ? 0 : align - current_mod); 79 | size_t bytesneed = bytes + slop; 80 | char* allocptr; 81 | if(bytesneed <= bytes_remaining_) { 82 | allocptr = alloc_ptr_ + slop; 83 | alloc_ptr_ += bytesneed; 84 | bytes_remaining_ -= bytesneed; 85 | }else { 86 | alloc_ptr_ = new char[kMemoryBlockSize]; 87 | memoryblocks_.push_back(alloc_ptr_); 88 | bytes_remaining_ = kMemoryBlockSize; 89 | allocptr = alloc_ptr_; 90 | alloc_ptr_ += bytes; 91 | bytes_remaining_ -= bytes; 92 | } 93 | return allocptr; 94 | } 95 | 96 | } 97 | 98 | } 99 | -------------------------------------------------------------------------------- /src/util/threadlocal_memorypool.h: -------------------------------------------------------------------------------- 1 | #ifndef CWEB_UTIL_THREADLOCALMEMORYPOOL_H_ 2 | #define CWEB_UTIL_THREADLOCALMEMORYPOOL_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "noncopyable.h" 9 | 10 | //小内存管理,小于4k 11 | namespace cweb { 12 | 13 | namespace util { 14 | 15 | class MemoryList { 16 | 17 | public: 18 | void PushFront(void* obj); 19 | void* PopFront(); 20 | bool Empty(); 21 | 22 | private: 23 | void* head_ = nullptr; 24 | size_t nodes_remaining_ = 0; 25 | }; 26 | 27 | class MemoryPool : public Noncopyable { 28 | 29 | public: 30 | MemoryPool(); 31 | ~MemoryPool(); 32 | 33 | void* Allocate(size_t bytes); 34 | void Deallocate(void* ptr, size_t bytes); 35 | 36 | private: 37 | std::vector memorylists_; 38 | char* alloc_ptr_ = nullptr; 39 | size_t bytes_remaining_ = 0; 40 | size_t real_used_ = 0; 41 | std::vector memoryblocks_; 42 | 43 | size_t memorylistsIndex(size_t bytes); 44 | void* allocateInMemoryblocks(size_t bytes); 45 | }; 46 | 47 | } 48 | } 49 | 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /test/coroutine_test.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "coroutine_context.h" 4 | #include "coroutine.h" 5 | 6 | using namespace cweb::tcpserver::coroutine; 7 | 8 | void f1(); 9 | void f2(); 10 | 11 | 12 | Coroutine c1([](){ 13 | f1(); 14 | }); 15 | 16 | Coroutine c2([](){ 17 | f2(); 18 | }); 19 | 20 | int f3(int a, int b) { 21 | return a + b; 22 | } 23 | 24 | void f1() { 25 | // while(1) { 26 | int a = 0; 27 | int b = 6; 28 | std::cout << a + b << std::endl; 29 | for(int i = 0;i < 5; i++){ 30 | std::cout << "我是f1" << f3(i, i*i) << std::endl; 31 | c1.SwapTo(&c2); 32 | } 33 | //} 34 | } 35 | 36 | void f2() { 37 | 38 | //while(1) { 39 | std::string s("hello my world"); 40 | for(int i = 0; i < s.size(); ++i) { 41 | std::cout << s[i] << std::endl; 42 | } 43 | 44 | for(int i = 0;i < 5; i++){ 45 | std::cout << "我是f2" << std::endl; 46 | //CoroutineContext::ContextSwap(&c2, &c1); 47 | c2.SwapTo(&c1); 48 | } 49 | //} 50 | } 51 | 52 | //int main(int argc, const char * argv[]) { 53 | // // insert code here... 54 | // //std::cout << "hello" << std::endl; 55 | // f1(); 56 | // 57 | // return 0; 58 | //} 59 | -------------------------------------------------------------------------------- /test/linked_list_test.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "linked_list.h" 4 | 5 | using namespace cweb::util; 6 | 7 | class Base : public LinkedListNode { 8 | private: 9 | int index_; 10 | public: 11 | Base(int index) : index_(index) {} 12 | void Say() { 13 | std::cout << "my index is " << index_ << std::endl; 14 | } 15 | 16 | }; 17 | 18 | /* 19 | int main() { 20 | LinkedList lists; 21 | 22 | 23 | lists.Push(new Base(2)); 24 | lists.Push(new Base(3)); 25 | lists.Push(new Base(4)); 26 | lists.Push(new Base(5)); 27 | lists.Push(new Base(6)); 28 | lists.Push(new Base(7)); 29 | 30 | Base* front = lists.Front(); 31 | if(front) { 32 | front->Say(); 33 | std::cout << "size: " << lists.Size() << std::endl; 34 | } 35 | int i = 100; 36 | while (front && i) { 37 | front = lists.Pop(); 38 | lists.Push(front); 39 | if(front) front->Say(); 40 | if(i % 5 == 0) { 41 | lists.Erase(front); 42 | std::cout << "size: " << lists.Size() << std::endl; 43 | } 44 | --i; 45 | } 46 | 47 | LinkedList lists1; 48 | 49 | 50 | lists1.Push(new Base(8)); 51 | lists1.Push(new Base(9)); 52 | lists1.Push(new Base(10)); 53 | lists1.Push(new Base(11)); 54 | lists1.Push(new Base(12)); 55 | lists1.Push(new Base(13)); 56 | 57 | std::cout << "lists1 size: " << lists1.Size() << std::endl; 58 | lists.Push(lists1); 59 | std::cout << "lists size: " << lists.Size() << std::endl; 60 | std::cout << "lists1 size: " << lists1.Size() << std::endl; 61 | 62 | i = 100; 63 | front = lists.Front(); 64 | while (front && i) { 65 | front = lists.Pop(); 66 | lists.Push(front); 67 | if(front) front->Say(); 68 | if(i % 5 == 0) { 69 | lists.Erase(front); 70 | std::cout << "size: " << lists.Size() << std::endl; 71 | } 72 | --i; 73 | } 74 | 75 | lists1.Push(new Base(8)); 76 | lists1.Push(new Base(9)); 77 | lists1.Push(new Base(10)); 78 | lists1.Push(new Base(11)); 79 | lists1.Push(new Base(12)); 80 | lists1.Push(new Base(13)); 81 | front = lists1.Front(); 82 | while(front = lists1.Next(front)) { 83 | front->Say(); 84 | } 85 | 86 | return 0; 87 | } 88 | */ 89 | -------------------------------------------------------------------------------- /test/lockfree_queue_test.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "lockfree_queue.h" 5 | 6 | using namespace cweb::util; 7 | 8 | LockfreeQueue queue1(1000); 9 | LockfreeQueue queue2(100010); 10 | 11 | void func1() { 12 | for(int i = 0; i < 100000;) { 13 | if(!queue1.MultiplePush(i)) { 14 | std::cout << "failed:" << i << std::endl; 15 | }else { 16 | i += 4; 17 | } 18 | } 19 | } 20 | 21 | void func2() { 22 | for(int i = 1; i < 100000;) { 23 | if(!queue1.MultiplePush(i)) { 24 | std::cout << "failed:" << i << std::endl; 25 | }else { 26 | i += 4; 27 | } 28 | } 29 | } 30 | 31 | void func3() { 32 | for(int i = 2; i < 100000;) { 33 | if(!queue1.MultiplePush(i)) { 34 | std::cout << "failed:" << i << std::endl; 35 | }else { 36 | i += 4; 37 | } 38 | } 39 | } 40 | 41 | void func4() { 42 | for(int i = 3; i < 100000;) { 43 | if(!queue1.MultiplePush(i)) { 44 | std::cout << "failed:" << i << std::endl; 45 | }else { 46 | i += 4; 47 | } 48 | } 49 | } 50 | 51 | 52 | void func5() { 53 | int val = 0; 54 | int count = 200000; 55 | int ref = 0; 56 | while(count) { 57 | if(queue1.MultiplePop(val)) { 58 | ++ref; 59 | queue2.MultiplePush(val); 60 | } 61 | --count; 62 | } 63 | std::cout << "ref = " << ref << std::endl; 64 | } 65 | 66 | 67 | int main() { 68 | std::thread t1(func1); 69 | std::thread t2(func2); 70 | std::thread t3(func3); 71 | std::thread t4(func4); 72 | 73 | //sleep(3); 74 | std::thread t5(func5); 75 | std::thread t6(func5); 76 | std::thread t7(func5); 77 | std::thread t8(func5); 78 | t1.join(); 79 | t2.join(); 80 | t3.join(); 81 | t4.join(); 82 | t5.join(); 83 | t6.join(); 84 | t7.join(); 85 | t8.join(); 86 | 87 | int val = 0; 88 | int i = 0; 89 | std::vector map(100000, 0); 90 | while(queue2.MultiplePop(val)) { 91 | ++i; 92 | map[val] = 1; 93 | } 94 | 95 | std::cout << "i = " << i << std::endl; 96 | 97 | for(int i = 0; i < 100000; ++i) { 98 | if(!map[i]) { 99 | std::cout << "lose:" << i << std::endl; 100 | } 101 | } 102 | return 0; 103 | } 104 | -------------------------------------------------------------------------------- /test/lockfree_queue_test.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // lockfree_queue_test.hpp 3 | // cweb 4 | // 5 | // Created by yangerjun on 2023/7/11. 6 | // 7 | 8 | #ifndef lockfree_queue_test_hpp 9 | #define lockfree_queue_test_hpp 10 | 11 | #include 12 | 13 | #endif /* lockfree_queue_test_hpp */ 14 | -------------------------------------------------------------------------------- /test/mysql_test.cc: -------------------------------------------------------------------------------- 1 | #include "mysql.h" 2 | #include "logger.h" 3 | #include "json.h" 4 | 5 | using namespace cweb::db; 6 | using namespace cweb::log; 7 | 8 | /* 9 | int main() { 10 | 11 | if(!MySQLPoolSingleton::GetInstance()->Init()) { 12 | LOG(LOGLEVEL_DEBUG, CWEB_MODULE, "mysql", "init error"); 13 | return 0; 14 | } 15 | 16 | std::shared_ptr sql = MySQLPoolSingleton::GetInstance()->GetConnection(); 17 | 18 | MySQLReplyPtr r = sql->Cmd("SELECT * FROM person"); 19 | 20 | int rows = r->Rows(); 21 | 22 | Json::Value root; 23 | root["cout"] = rows; 24 | for(int i = 0; i < rows; ++i) { 25 | r->Next(); 26 | Json::Value p; 27 | p["id"] = r->IntValue(0); 28 | p["name"] = r->StringValue(1); 29 | p["age"] = r->IntValue(2); 30 | root["people"].append(p); 31 | } 32 | 33 | std::stringstream body; 34 | Json::StreamWriterBuilder writerBuilder; 35 | writerBuilder["emitUTF8"] = true; 36 | std::unique_ptr jsonWriter(writerBuilder.newStreamWriter()); 37 | jsonWriter->write(root, &body); 38 | 39 | LOG(LOGLEVEL_DEBUG, CWEB_MODULE, "mysql", "mysql res: %s", body.str().c_str()); 40 | 41 | return 0; 42 | }*/ 43 | -------------------------------------------------------------------------------- /test/redis_test.cc: -------------------------------------------------------------------------------- 1 | #include "logger.h" 2 | #include "redis.h" 3 | 4 | using namespace cweb::db; 5 | using namespace cweb::log; 6 | 7 | /* 8 | int main() { 9 | 10 | cweb::db::Redis r; 11 | bool res = r.Connect("127.0.0.1", 8300); 12 | if(res) { 13 | std::cout << "连接成功" << std::endl; 14 | }else { 15 | std::cout << "连接失败" << std::endl; 16 | } 17 | 18 | sleep(3); 19 | r.Cmd("set foo hello"); 20 | r.Cmd("auth 12345678"); 21 | r.Cmd("set foo hello"); 22 | RedisReplyPtr rp = r.Cmd("get foo"); 23 | std::cout << "rp:" << rp->str << std::endl; 24 | sleep(3); 25 | 26 | 27 | bool res = RedisPoolSingleton::GetInstance()->Init(); 28 | 29 | if(!res) { 30 | LOG(LOGLEVEL_DEBUG, CWEB_MODULE, "redis", "init error"); 31 | } 32 | 33 | std::shared_ptr redis = RedisPoolSingleton::GetInstance()->GetConnection(); 34 | 35 | RedisReplyPtr r = redis->Cmd("ping"); 36 | if(r) { 37 | LOG(LOGLEVEL_DEBUG, CWEB_MODULE, "redis", "ping reply: %s", r->str); 38 | } 39 | 40 | r = redis->Cmd("SET %s %s", "foo", "testfoo"); 41 | 42 | if(r) { 43 | LOG(LOGLEVEL_DEBUG, CWEB_MODULE, "redis", "set reply: %s", r->str); 44 | } 45 | 46 | r = redis->Cmd("SET %s %s", "key_htl_hlea", "first"); 47 | 48 | if(r) { 49 | LOG(LOGLEVEL_DEBUG, CWEB_MODULE, "redis", "set reply: %s", r->str); 50 | } 51 | 52 | r = redis->Cmd("SET %s %s", "tlyyyy_ghhtl_aseghlea", "second"); 53 | 54 | if(r) { 55 | LOG(LOGLEVEL_DEBUG, CWEB_MODULE, "redis", "set reply: %s", r->str); 56 | } 57 | 58 | r = redis->Cmd("SET %s %s", "key_htl_hlea_tlyyyy_ghhtl_aseghlea", "third"); 59 | 60 | if(r) { 61 | LOG(LOGLEVEL_DEBUG, CWEB_MODULE, "redis", "set reply: %s", r->str); 62 | } 63 | 64 | r = redis->Cmd("GET foo"); 65 | if(r) { 66 | LOG(LOGLEVEL_DEBUG, CWEB_MODULE, "redis", "get reply: %s", r->str); 67 | } 68 | 69 | r = redis->Cmd("GET key_htl_hlea"); 70 | if(r) { 71 | LOG(LOGLEVEL_DEBUG, CWEB_MODULE, "redis", "get reply: %s", r->str); 72 | } 73 | 74 | r = redis->Cmd("GET tlyyyy_ghhtl_aseghlea"); 75 | if(r) { 76 | LOG(LOGLEVEL_DEBUG, CWEB_MODULE, "redis", "get reply: %s", r->str); 77 | } 78 | 79 | r = redis->Cmd("GET key_htl_hlea_tlyyyy_ghhtl_aseghlea"); 80 | if(r) { 81 | LOG(LOGLEVEL_DEBUG, CWEB_MODULE, "redis", "get reply: %s", r->str); 82 | } 83 | 84 | return 0; 85 | } 86 | */ 87 | -------------------------------------------------------------------------------- /thirdparty/hiredis-vip/include/hiredis-vip/adapters/glib.h: -------------------------------------------------------------------------------- 1 | #ifndef __HIREDIS_GLIB_H__ 2 | #define __HIREDIS_GLIB_H__ 3 | 4 | #include 5 | 6 | #include "../hiredis.h" 7 | #include "../async.h" 8 | 9 | typedef struct 10 | { 11 | GSource source; 12 | redisAsyncContext *ac; 13 | GPollFD poll_fd; 14 | } RedisSource; 15 | 16 | static void 17 | redis_source_add_read (gpointer data) 18 | { 19 | RedisSource *source = data; 20 | g_return_if_fail(source); 21 | source->poll_fd.events |= G_IO_IN; 22 | g_main_context_wakeup(g_source_get_context(data)); 23 | } 24 | 25 | static void 26 | redis_source_del_read (gpointer data) 27 | { 28 | RedisSource *source = data; 29 | g_return_if_fail(source); 30 | source->poll_fd.events &= ~G_IO_IN; 31 | g_main_context_wakeup(g_source_get_context(data)); 32 | } 33 | 34 | static void 35 | redis_source_add_write (gpointer data) 36 | { 37 | RedisSource *source = data; 38 | g_return_if_fail(source); 39 | source->poll_fd.events |= G_IO_OUT; 40 | g_main_context_wakeup(g_source_get_context(data)); 41 | } 42 | 43 | static void 44 | redis_source_del_write (gpointer data) 45 | { 46 | RedisSource *source = data; 47 | g_return_if_fail(source); 48 | source->poll_fd.events &= ~G_IO_OUT; 49 | g_main_context_wakeup(g_source_get_context(data)); 50 | } 51 | 52 | static void 53 | redis_source_cleanup (gpointer data) 54 | { 55 | RedisSource *source = data; 56 | 57 | g_return_if_fail(source); 58 | 59 | redis_source_del_read(source); 60 | redis_source_del_write(source); 61 | /* 62 | * It is not our responsibility to remove ourself from the 63 | * current main loop. However, we will remove the GPollFD. 64 | */ 65 | if (source->poll_fd.fd >= 0) { 66 | g_source_remove_poll(data, &source->poll_fd); 67 | source->poll_fd.fd = -1; 68 | } 69 | } 70 | 71 | static gboolean 72 | redis_source_prepare (GSource *source, 73 | gint *timeout_) 74 | { 75 | RedisSource *redis = (RedisSource *)source; 76 | *timeout_ = -1; 77 | return !!(redis->poll_fd.events & redis->poll_fd.revents); 78 | } 79 | 80 | static gboolean 81 | redis_source_check (GSource *source) 82 | { 83 | RedisSource *redis = (RedisSource *)source; 84 | return !!(redis->poll_fd.events & redis->poll_fd.revents); 85 | } 86 | 87 | static gboolean 88 | redis_source_dispatch (GSource *source, 89 | GSourceFunc callback, 90 | gpointer user_data) 91 | { 92 | RedisSource *redis = (RedisSource *)source; 93 | 94 | if ((redis->poll_fd.revents & G_IO_OUT)) { 95 | redisAsyncHandleWrite(redis->ac); 96 | redis->poll_fd.revents &= ~G_IO_OUT; 97 | } 98 | 99 | if ((redis->poll_fd.revents & G_IO_IN)) { 100 | redisAsyncHandleRead(redis->ac); 101 | redis->poll_fd.revents &= ~G_IO_IN; 102 | } 103 | 104 | if (callback) { 105 | return callback(user_data); 106 | } 107 | 108 | return TRUE; 109 | } 110 | 111 | static void 112 | redis_source_finalize (GSource *source) 113 | { 114 | RedisSource *redis = (RedisSource *)source; 115 | 116 | if (redis->poll_fd.fd >= 0) { 117 | g_source_remove_poll(source, &redis->poll_fd); 118 | redis->poll_fd.fd = -1; 119 | } 120 | } 121 | 122 | static GSource * 123 | redis_source_new (redisAsyncContext *ac) 124 | { 125 | static GSourceFuncs source_funcs = { 126 | .prepare = redis_source_prepare, 127 | .check = redis_source_check, 128 | .dispatch = redis_source_dispatch, 129 | .finalize = redis_source_finalize, 130 | }; 131 | redisContext *c = &ac->c; 132 | RedisSource *source; 133 | 134 | g_return_val_if_fail(ac != NULL, NULL); 135 | 136 | source = (RedisSource *)g_source_new(&source_funcs, sizeof *source); 137 | source->ac = ac; 138 | source->poll_fd.fd = c->fd; 139 | source->poll_fd.events = 0; 140 | source->poll_fd.revents = 0; 141 | g_source_add_poll((GSource *)source, &source->poll_fd); 142 | 143 | ac->ev.addRead = redis_source_add_read; 144 | ac->ev.delRead = redis_source_del_read; 145 | ac->ev.addWrite = redis_source_add_write; 146 | ac->ev.delWrite = redis_source_del_write; 147 | ac->ev.cleanup = redis_source_cleanup; 148 | ac->ev.data = source; 149 | 150 | return (GSource *)source; 151 | } 152 | 153 | #endif /* __HIREDIS_GLIB_H__ */ 154 | -------------------------------------------------------------------------------- /thirdparty/hiredis-vip/include/hiredis-vip/adapters/libev.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010-2011, Pieter Noordhuis 3 | * 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are met: 8 | * 9 | * * Redistributions of source code must retain the above copyright notice, 10 | * this list of conditions and the following disclaimer. 11 | * * Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * * Neither the name of Redis nor the names of its contributors may be used 15 | * to endorse or promote products derived from this software without 16 | * specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 22 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | * POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #ifndef __HIREDIS_LIBEV_H__ 32 | #define __HIREDIS_LIBEV_H__ 33 | #include 34 | #include 35 | #include 36 | #include "../hiredis.h" 37 | #include "../async.h" 38 | 39 | typedef struct redisLibevEvents { 40 | redisAsyncContext *context; 41 | struct ev_loop *loop; 42 | int reading, writing; 43 | ev_io rev, wev; 44 | } redisLibevEvents; 45 | 46 | static void redisLibevReadEvent(EV_P_ ev_io *watcher, int revents) { 47 | #if EV_MULTIPLICITY 48 | ((void)loop); 49 | #endif 50 | ((void)revents); 51 | 52 | redisLibevEvents *e = (redisLibevEvents*)watcher->data; 53 | redisAsyncHandleRead(e->context); 54 | } 55 | 56 | static void redisLibevWriteEvent(EV_P_ ev_io *watcher, int revents) { 57 | #if EV_MULTIPLICITY 58 | ((void)loop); 59 | #endif 60 | ((void)revents); 61 | 62 | redisLibevEvents *e = (redisLibevEvents*)watcher->data; 63 | redisAsyncHandleWrite(e->context); 64 | } 65 | 66 | static void redisLibevAddRead(void *privdata) { 67 | redisLibevEvents *e = (redisLibevEvents*)privdata; 68 | struct ev_loop *loop = e->loop; 69 | ((void)loop); 70 | if (!e->reading) { 71 | e->reading = 1; 72 | ev_io_start(EV_A_ &e->rev); 73 | } 74 | } 75 | 76 | static void redisLibevDelRead(void *privdata) { 77 | redisLibevEvents *e = (redisLibevEvents*)privdata; 78 | struct ev_loop *loop = e->loop; 79 | ((void)loop); 80 | if (e->reading) { 81 | e->reading = 0; 82 | ev_io_stop(EV_A_ &e->rev); 83 | } 84 | } 85 | 86 | static void redisLibevAddWrite(void *privdata) { 87 | redisLibevEvents *e = (redisLibevEvents*)privdata; 88 | struct ev_loop *loop = e->loop; 89 | ((void)loop); 90 | if (!e->writing) { 91 | e->writing = 1; 92 | ev_io_start(EV_A_ &e->wev); 93 | } 94 | } 95 | 96 | static void redisLibevDelWrite(void *privdata) { 97 | redisLibevEvents *e = (redisLibevEvents*)privdata; 98 | struct ev_loop *loop = e->loop; 99 | ((void)loop); 100 | if (e->writing) { 101 | e->writing = 0; 102 | ev_io_stop(EV_A_ &e->wev); 103 | } 104 | } 105 | 106 | static void redisLibevCleanup(void *privdata) { 107 | redisLibevEvents *e = (redisLibevEvents*)privdata; 108 | redisLibevDelRead(privdata); 109 | redisLibevDelWrite(privdata); 110 | free(e); 111 | } 112 | 113 | static int redisLibevAttach(EV_P_ redisAsyncContext *ac) { 114 | redisContext *c = &(ac->c); 115 | redisLibevEvents *e; 116 | 117 | /* Nothing should be attached when something is already attached */ 118 | if (ac->ev.data != NULL) 119 | return REDIS_ERR; 120 | 121 | /* Create container for context and r/w events */ 122 | e = (redisLibevEvents*)malloc(sizeof(*e)); 123 | e->context = ac; 124 | #if EV_MULTIPLICITY 125 | e->loop = loop; 126 | #else 127 | e->loop = NULL; 128 | #endif 129 | e->reading = e->writing = 0; 130 | e->rev.data = e; 131 | e->wev.data = e; 132 | 133 | /* Register functions to start/stop listening for events */ 134 | ac->ev.addRead = redisLibevAddRead; 135 | ac->ev.delRead = redisLibevDelRead; 136 | ac->ev.addWrite = redisLibevAddWrite; 137 | ac->ev.delWrite = redisLibevDelWrite; 138 | ac->ev.cleanup = redisLibevCleanup; 139 | ac->ev.data = e; 140 | 141 | /* Initialize read/write events */ 142 | ev_io_init(&e->rev,redisLibevReadEvent,c->fd,EV_READ); 143 | ev_io_init(&e->wev,redisLibevWriteEvent,c->fd,EV_WRITE); 144 | return REDIS_OK; 145 | } 146 | 147 | #endif 148 | -------------------------------------------------------------------------------- /thirdparty/hiredis-vip/include/hiredis-vip/adapters/libevent.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010-2011, Pieter Noordhuis 3 | * 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are met: 8 | * 9 | * * Redistributions of source code must retain the above copyright notice, 10 | * this list of conditions and the following disclaimer. 11 | * * Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * * Neither the name of Redis nor the names of its contributors may be used 15 | * to endorse or promote products derived from this software without 16 | * specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 22 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | * POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #ifndef __HIREDIS_LIBEVENT_H__ 32 | #define __HIREDIS_LIBEVENT_H__ 33 | #include 34 | #include "../hiredis.h" 35 | #include "../async.h" 36 | 37 | #if 1 //shenzheng 2015-9-21 redis cluster 38 | #include "../hircluster.h" 39 | #endif //shenzheng 2015-9-21 redis cluster 40 | 41 | typedef struct redisLibeventEvents { 42 | redisAsyncContext *context; 43 | struct event rev, wev; 44 | } redisLibeventEvents; 45 | 46 | static void redisLibeventReadEvent(int fd, short event, void *arg) { 47 | ((void)fd); ((void)event); 48 | redisLibeventEvents *e = (redisLibeventEvents*)arg; 49 | redisAsyncHandleRead(e->context); 50 | } 51 | 52 | static void redisLibeventWriteEvent(int fd, short event, void *arg) { 53 | ((void)fd); ((void)event); 54 | redisLibeventEvents *e = (redisLibeventEvents*)arg; 55 | redisAsyncHandleWrite(e->context); 56 | } 57 | 58 | static void redisLibeventAddRead(void *privdata) { 59 | redisLibeventEvents *e = (redisLibeventEvents*)privdata; 60 | event_add(&e->rev,NULL); 61 | } 62 | 63 | static void redisLibeventDelRead(void *privdata) { 64 | redisLibeventEvents *e = (redisLibeventEvents*)privdata; 65 | event_del(&e->rev); 66 | } 67 | 68 | static void redisLibeventAddWrite(void *privdata) { 69 | redisLibeventEvents *e = (redisLibeventEvents*)privdata; 70 | event_add(&e->wev,NULL); 71 | } 72 | 73 | static void redisLibeventDelWrite(void *privdata) { 74 | redisLibeventEvents *e = (redisLibeventEvents*)privdata; 75 | event_del(&e->wev); 76 | } 77 | 78 | static void redisLibeventCleanup(void *privdata) { 79 | redisLibeventEvents *e = (redisLibeventEvents*)privdata; 80 | event_del(&e->rev); 81 | event_del(&e->wev); 82 | free(e); 83 | } 84 | 85 | static int redisLibeventAttach(redisAsyncContext *ac, struct event_base *base) { 86 | redisContext *c = &(ac->c); 87 | redisLibeventEvents *e; 88 | 89 | /* Nothing should be attached when something is already attached */ 90 | if (ac->ev.data != NULL) 91 | return REDIS_ERR; 92 | 93 | /* Create container for context and r/w events */ 94 | e = (redisLibeventEvents*)malloc(sizeof(*e)); 95 | e->context = ac; 96 | 97 | /* Register functions to start/stop listening for events */ 98 | ac->ev.addRead = redisLibeventAddRead; 99 | ac->ev.delRead = redisLibeventDelRead; 100 | ac->ev.addWrite = redisLibeventAddWrite; 101 | ac->ev.delWrite = redisLibeventDelWrite; 102 | ac->ev.cleanup = redisLibeventCleanup; 103 | ac->ev.data = e; 104 | 105 | /* Initialize and install read/write events */ 106 | event_set(&e->rev,c->fd,EV_READ,redisLibeventReadEvent,e); 107 | event_set(&e->wev,c->fd,EV_WRITE,redisLibeventWriteEvent,e); 108 | event_base_set(base,&e->rev); 109 | event_base_set(base,&e->wev); 110 | return REDIS_OK; 111 | } 112 | 113 | #if 1 //shenzheng 2015-9-21 redis cluster 114 | 115 | static int redisLibeventAttach_link(redisAsyncContext *ac, void *base) 116 | { 117 | return redisLibeventAttach(ac, (struct event_base *)base); 118 | } 119 | 120 | static int redisClusterLibeventAttach(redisClusterAsyncContext *acc, struct event_base *base) { 121 | 122 | if(acc == NULL || base == NULL) 123 | { 124 | return REDIS_ERR; 125 | } 126 | 127 | acc->adapter = base; 128 | acc->attach_fn = redisLibeventAttach_link; 129 | 130 | return REDIS_OK; 131 | } 132 | 133 | #endif //shenzheng 2015-9-21 redis cluster 134 | 135 | #endif 136 | -------------------------------------------------------------------------------- /thirdparty/hiredis-vip/include/hiredis-vip/adapters/libuv.h: -------------------------------------------------------------------------------- 1 | #ifndef __HIREDIS_LIBUV_H__ 2 | #define __HIREDIS_LIBUV_H__ 3 | #include 4 | #include 5 | #include "../hiredis.h" 6 | #include "../async.h" 7 | #include 8 | 9 | typedef struct redisLibuvEvents { 10 | redisAsyncContext* context; 11 | uv_poll_t handle; 12 | int events; 13 | } redisLibuvEvents; 14 | 15 | 16 | static void redisLibuvPoll(uv_poll_t* handle, int status, int events) { 17 | redisLibuvEvents* p = (redisLibuvEvents*)handle->data; 18 | 19 | if (status != 0) { 20 | return; 21 | } 22 | 23 | if (events & UV_READABLE) { 24 | redisAsyncHandleRead(p->context); 25 | } 26 | if (events & UV_WRITABLE) { 27 | redisAsyncHandleWrite(p->context); 28 | } 29 | } 30 | 31 | 32 | static void redisLibuvAddRead(void *privdata) { 33 | redisLibuvEvents* p = (redisLibuvEvents*)privdata; 34 | 35 | p->events |= UV_READABLE; 36 | 37 | uv_poll_start(&p->handle, p->events, redisLibuvPoll); 38 | } 39 | 40 | 41 | static void redisLibuvDelRead(void *privdata) { 42 | redisLibuvEvents* p = (redisLibuvEvents*)privdata; 43 | 44 | p->events &= ~UV_READABLE; 45 | 46 | if (p->events) { 47 | uv_poll_start(&p->handle, p->events, redisLibuvPoll); 48 | } else { 49 | uv_poll_stop(&p->handle); 50 | } 51 | } 52 | 53 | 54 | static void redisLibuvAddWrite(void *privdata) { 55 | redisLibuvEvents* p = (redisLibuvEvents*)privdata; 56 | 57 | p->events |= UV_WRITABLE; 58 | 59 | uv_poll_start(&p->handle, p->events, redisLibuvPoll); 60 | } 61 | 62 | 63 | static void redisLibuvDelWrite(void *privdata) { 64 | redisLibuvEvents* p = (redisLibuvEvents*)privdata; 65 | 66 | p->events &= ~UV_WRITABLE; 67 | 68 | if (p->events) { 69 | uv_poll_start(&p->handle, p->events, redisLibuvPoll); 70 | } else { 71 | uv_poll_stop(&p->handle); 72 | } 73 | } 74 | 75 | 76 | static void on_close(uv_handle_t* handle) { 77 | redisLibuvEvents* p = (redisLibuvEvents*)handle->data; 78 | 79 | free(p); 80 | } 81 | 82 | 83 | static void redisLibuvCleanup(void *privdata) { 84 | redisLibuvEvents* p = (redisLibuvEvents*)privdata; 85 | 86 | uv_close((uv_handle_t*)&p->handle, on_close); 87 | } 88 | 89 | 90 | static int redisLibuvAttach(redisAsyncContext* ac, uv_loop_t* loop) { 91 | redisContext *c = &(ac->c); 92 | 93 | if (ac->ev.data != NULL) { 94 | return REDIS_ERR; 95 | } 96 | 97 | ac->ev.addRead = redisLibuvAddRead; 98 | ac->ev.delRead = redisLibuvDelRead; 99 | ac->ev.addWrite = redisLibuvAddWrite; 100 | ac->ev.delWrite = redisLibuvDelWrite; 101 | ac->ev.cleanup = redisLibuvCleanup; 102 | 103 | redisLibuvEvents* p = (redisLibuvEvents*)malloc(sizeof(*p)); 104 | 105 | if (!p) { 106 | return REDIS_ERR; 107 | } 108 | 109 | memset(p, 0, sizeof(*p)); 110 | 111 | if (uv_poll_init(loop, &p->handle, c->fd) != 0) { 112 | return REDIS_ERR; 113 | } 114 | 115 | ac->ev.data = p; 116 | p->handle.data = p; 117 | p->context = ac; 118 | 119 | return REDIS_OK; 120 | } 121 | 122 | #endif 123 | -------------------------------------------------------------------------------- /thirdparty/hiredis-vip/include/hiredis-vip/adlist.h: -------------------------------------------------------------------------------- 1 | /* adlist.h - A generic doubly linked list implementation 2 | * 3 | * Copyright (c) 2006-2012, Salvatore Sanfilippo 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are met: 8 | * 9 | * * Redistributions of source code must retain the above copyright notice, 10 | * this list of conditions and the following disclaimer. 11 | * * Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * * Neither the name of Redis nor the names of its contributors may be used 15 | * to endorse or promote products derived from this software without 16 | * specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 22 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | * POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #ifndef __ADLIST_H__ 32 | #define __ADLIST_H__ 33 | 34 | /* Node, List, and Iterator are the only data structures used currently. */ 35 | 36 | typedef struct listNode { 37 | struct listNode *prev; 38 | struct listNode *next; 39 | void *value; 40 | } listNode; 41 | 42 | typedef struct listIter { 43 | listNode *next; 44 | int direction; 45 | } listIter; 46 | 47 | typedef struct hilist { 48 | listNode *head; 49 | listNode *tail; 50 | void *(*dup)(void *ptr); 51 | void (*free)(void *ptr); 52 | int (*match)(void *ptr, void *key); 53 | unsigned long len; 54 | } hilist; 55 | 56 | /* Functions implemented as macros */ 57 | #define listLength(l) ((l)->len) 58 | #define listFirst(l) ((l)->head) 59 | #define listLast(l) ((l)->tail) 60 | #define listPrevNode(n) ((n)->prev) 61 | #define listNextNode(n) ((n)->next) 62 | #define listNodeValue(n) ((n)->value) 63 | 64 | #define listSetDupMethod(l,m) ((l)->dup = (m)) 65 | #define listSetFreeMethod(l,m) ((l)->free = (m)) 66 | #define listSetMatchMethod(l,m) ((l)->match = (m)) 67 | 68 | #define listGetDupMethod(l) ((l)->dup) 69 | #define listGetFree(l) ((l)->free) 70 | #define listGetMatchMethod(l) ((l)->match) 71 | 72 | /* Prototypes */ 73 | hilist *listCreate(void); 74 | void listRelease(hilist *list); 75 | hilist *listAddNodeHead(hilist *list, void *value); 76 | hilist *listAddNodeTail(hilist *list, void *value); 77 | hilist *listInsertNode(hilist *list, listNode *old_node, void *value, int after); 78 | void listDelNode(hilist *list, listNode *node); 79 | listIter *listGetIterator(hilist *list, int direction); 80 | listNode *listNext(listIter *iter); 81 | void listReleaseIterator(listIter *iter); 82 | hilist *listDup(hilist *orig); 83 | listNode *listSearchKey(hilist *list, void *key); 84 | listNode *listIndex(hilist *list, long index); 85 | void listRewind(hilist *list, listIter *li); 86 | void listRewindTail(hilist *list, listIter *li); 87 | void listRotate(hilist *list); 88 | 89 | /* Directions for iterators */ 90 | #define AL_START_HEAD 0 91 | #define AL_START_TAIL 1 92 | 93 | #endif /* __ADLIST_H__ */ 94 | -------------------------------------------------------------------------------- /thirdparty/hiredis-vip/include/hiredis-vip/dict.h: -------------------------------------------------------------------------------- 1 | /* Hash table implementation. 2 | * 3 | * This file implements in memory hash tables with insert/del/replace/find/ 4 | * get-random-element operations. Hash tables will auto resize if needed 5 | * tables of power of two in size are used, collisions are handled by 6 | * chaining. See the source code for more information... :) 7 | * 8 | * Copyright (c) 2006-2010, Salvatore Sanfilippo 9 | * All rights reserved. 10 | * 11 | * Redistribution and use in source and binary forms, with or without 12 | * modification, are permitted provided that the following conditions are met: 13 | * 14 | * * Redistributions of source code must retain the above copyright notice, 15 | * this list of conditions and the following disclaimer. 16 | * * Redistributions in binary form must reproduce the above copyright 17 | * notice, this list of conditions and the following disclaimer in the 18 | * documentation and/or other materials provided with the distribution. 19 | * * Neither the name of Redis nor the names of its contributors may be used 20 | * to endorse or promote products derived from this software without 21 | * specific prior written permission. 22 | * 23 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 24 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 27 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 28 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 29 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 30 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 31 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 32 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33 | * POSSIBILITY OF SUCH DAMAGE. 34 | */ 35 | 36 | #ifndef __DICT_H 37 | #define __DICT_H 38 | 39 | #define DICT_OK 0 40 | #define DICT_ERR 1 41 | 42 | /* Unused arguments generate annoying warnings... */ 43 | #define DICT_NOTUSED(V) ((void) V) 44 | 45 | typedef struct dictEntry { 46 | void *key; 47 | void *val; 48 | struct dictEntry *next; 49 | } dictEntry; 50 | 51 | typedef struct dictType { 52 | unsigned int (*hashFunction)(const void *key); 53 | void *(*keyDup)(void *privdata, const void *key); 54 | void *(*valDup)(void *privdata, const void *obj); 55 | int (*keyCompare)(void *privdata, const void *key1, const void *key2); 56 | void (*keyDestructor)(void *privdata, void *key); 57 | void (*valDestructor)(void *privdata, void *obj); 58 | } dictType; 59 | 60 | typedef struct dict { 61 | dictEntry **table; 62 | dictType *type; 63 | unsigned long size; 64 | unsigned long sizemask; 65 | unsigned long used; 66 | void *privdata; 67 | } dict; 68 | 69 | typedef struct dictIterator { 70 | dict *ht; 71 | int index; 72 | dictEntry *entry, *nextEntry; 73 | } dictIterator; 74 | 75 | /* This is the initial size of every hash table */ 76 | #define DICT_HT_INITIAL_SIZE 4 77 | 78 | /* ------------------------------- Macros ------------------------------------*/ 79 | #define dictFreeEntryVal(ht, entry) \ 80 | if ((ht)->type->valDestructor) \ 81 | (ht)->type->valDestructor((ht)->privdata, (entry)->val) 82 | 83 | #define dictSetHashVal(ht, entry, _val_) do { \ 84 | if ((ht)->type->valDup) \ 85 | entry->val = (ht)->type->valDup((ht)->privdata, _val_); \ 86 | else \ 87 | entry->val = (_val_); \ 88 | } while(0) 89 | 90 | #define dictFreeEntryKey(ht, entry) \ 91 | if ((ht)->type->keyDestructor) \ 92 | (ht)->type->keyDestructor((ht)->privdata, (entry)->key) 93 | 94 | #define dictSetHashKey(ht, entry, _key_) do { \ 95 | if ((ht)->type->keyDup) \ 96 | entry->key = (ht)->type->keyDup((ht)->privdata, _key_); \ 97 | else \ 98 | entry->key = (_key_); \ 99 | } while(0) 100 | 101 | #define dictCompareHashKeys(ht, key1, key2) \ 102 | (((ht)->type->keyCompare) ? \ 103 | (ht)->type->keyCompare((ht)->privdata, key1, key2) : \ 104 | (key1) == (key2)) 105 | 106 | #define dictHashKey(ht, key) (ht)->type->hashFunction(key) 107 | 108 | #define dictGetEntryKey(he) ((he)->key) 109 | #define dictGetEntryVal(he) ((he)->val) 110 | #define dictSlots(ht) ((ht)->size) 111 | #define dictSize(ht) ((ht)->used) 112 | 113 | /* API */ 114 | static unsigned int dictGenHashFunction(const unsigned char *buf, int len); 115 | static dict *dictCreate(dictType *type, void *privDataPtr); 116 | static int dictExpand(dict *ht, unsigned long size); 117 | static int dictAdd(dict *ht, void *key, void *val); 118 | static int dictReplace(dict *ht, void *key, void *val); 119 | static int dictDelete(dict *ht, const void *key); 120 | static void dictRelease(dict *ht); 121 | static dictEntry * dictFind(dict *ht, const void *key); 122 | static dictIterator *dictGetIterator(dict *ht); 123 | static dictEntry *dictNext(dictIterator *iter); 124 | static void dictReleaseIterator(dictIterator *iter); 125 | 126 | #endif /* __DICT_H */ 127 | -------------------------------------------------------------------------------- /thirdparty/hiredis-vip/include/hiredis-vip/fmacros.h: -------------------------------------------------------------------------------- 1 | #ifndef __HIREDIS_FMACRO_H 2 | #define __HIREDIS_FMACRO_H 3 | 4 | #if defined(__linux__) 5 | #ifndef _BSD_SOURCE 6 | #define _BSD_SOURCE 7 | #endif 8 | #define _DEFAULT_SOURCE 9 | #endif 10 | 11 | #if defined(__sun__) 12 | #define _POSIX_C_SOURCE 200112L 13 | #elif defined(__linux__) || defined(__OpenBSD__) || defined(__NetBSD__) 14 | #define _XOPEN_SOURCE 600 15 | #else 16 | #define _XOPEN_SOURCE 17 | #endif 18 | 19 | #if __APPLE__ && __MACH__ 20 | #define _OSX 21 | #endif 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /thirdparty/hiredis-vip/include/hiredis-vip/hiarray.h: -------------------------------------------------------------------------------- 1 | #ifndef __HIARRAY_H_ 2 | #define __HIARRAY_H_ 3 | 4 | #include 5 | 6 | typedef int (*hiarray_compare_t)(const void *, const void *); 7 | typedef int (*hiarray_each_t)(void *, void *); 8 | 9 | struct hiarray { 10 | uint32_t nelem; /* # element */ 11 | void *elem; /* element */ 12 | size_t size; /* element size */ 13 | uint32_t nalloc; /* # allocated element */ 14 | }; 15 | 16 | #define null_hiarray { 0, NULL, 0, 0 } 17 | 18 | static inline void 19 | hiarray_null(struct hiarray *a) 20 | { 21 | a->nelem = 0; 22 | a->elem = NULL; 23 | a->size = 0; 24 | a->nalloc = 0; 25 | } 26 | 27 | static inline void 28 | hiarray_set(struct hiarray *a, void *elem, size_t size, uint32_t nalloc) 29 | { 30 | a->nelem = 0; 31 | a->elem = elem; 32 | a->size = size; 33 | a->nalloc = nalloc; 34 | } 35 | 36 | static inline uint32_t 37 | hiarray_n(const struct hiarray *a) 38 | { 39 | return a->nelem; 40 | } 41 | 42 | struct hiarray *hiarray_create(uint32_t n, size_t size); 43 | void hiarray_destroy(struct hiarray *a); 44 | int hiarray_init(struct hiarray *a, uint32_t n, size_t size); 45 | void hiarray_deinit(struct hiarray *a); 46 | 47 | uint32_t hiarray_idx(struct hiarray *a, void *elem); 48 | void *hiarray_push(struct hiarray *a); 49 | void *hiarray_pop(struct hiarray *a); 50 | void *hiarray_get(struct hiarray *a, uint32_t idx); 51 | void *hiarray_top(struct hiarray *a); 52 | void hiarray_swap(struct hiarray *a, struct hiarray *b); 53 | void hiarray_sort(struct hiarray *a, hiarray_compare_t compare); 54 | int hiarray_each(struct hiarray *a, hiarray_each_t func, void *data); 55 | 56 | #endif 57 | -------------------------------------------------------------------------------- /thirdparty/hiredis-vip/include/hiredis-vip/sds.h: -------------------------------------------------------------------------------- 1 | /* SDS (Simple Dynamic Strings), A C dynamic strings library. 2 | * 3 | * Copyright (c) 2006-2014, Salvatore Sanfilippo 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are met: 8 | * 9 | * * Redistributions of source code must retain the above copyright notice, 10 | * this list of conditions and the following disclaimer. 11 | * * Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * * Neither the name of Redis nor the names of its contributors may be used 15 | * to endorse or promote products derived from this software without 16 | * specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 22 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | * POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #ifndef __SDS_H 32 | #define __SDS_H 33 | 34 | #define SDS_MAX_PREALLOC (1024*1024) 35 | 36 | #include 37 | #include 38 | #ifdef _MSC_VER 39 | #include "win32.h" 40 | #endif 41 | 42 | typedef char *sds; 43 | 44 | struct sdshdr { 45 | int len; 46 | int free; 47 | char buf[]; 48 | }; 49 | 50 | static inline size_t sdslen(const sds s) { 51 | struct sdshdr *sh = (struct sdshdr *)(s-sizeof *sh); 52 | return sh->len; 53 | } 54 | 55 | static inline size_t sdsavail(const sds s) { 56 | struct sdshdr *sh = (struct sdshdr *)(s-sizeof *sh); 57 | return sh->free; 58 | } 59 | 60 | sds sdsnewlen(const void *init, size_t initlen); 61 | sds sdsnew(const char *init); 62 | sds sdsempty(void); 63 | size_t sdslen(const sds s); 64 | sds sdsdup(const sds s); 65 | void sdsfree(sds s); 66 | size_t sdsavail(const sds s); 67 | sds sdsgrowzero(sds s, size_t len); 68 | sds sdscatlen(sds s, const void *t, size_t len); 69 | sds sdscat(sds s, const char *t); 70 | sds sdscatsds(sds s, const sds t); 71 | sds sdscpylen(sds s, const char *t, size_t len); 72 | sds sdscpy(sds s, const char *t); 73 | 74 | sds sdscatvprintf(sds s, const char *fmt, va_list ap); 75 | #ifdef __GNUC__ 76 | sds sdscatprintf(sds s, const char *fmt, ...) 77 | __attribute__((format(printf, 2, 3))); 78 | #else 79 | sds sdscatprintf(sds s, const char *fmt, ...); 80 | #endif 81 | 82 | sds sdscatfmt(sds s, char const *fmt, ...); 83 | void sdstrim(sds s, const char *cset); 84 | void sdsrange(sds s, int start, int end); 85 | void sdsupdatelen(sds s); 86 | void sdsclear(sds s); 87 | int sdscmp(const sds s1, const sds s2); 88 | sds *sdssplitlen(const char *s, int len, const char *sep, int seplen, int *count); 89 | void sdsfreesplitres(sds *tokens, int count); 90 | void sdstolower(sds s); 91 | void sdstoupper(sds s); 92 | sds sdsfromlonglong(long long value); 93 | sds sdscatrepr(sds s, const char *p, size_t len); 94 | sds *sdssplitargs(const char *line, int *argc); 95 | sds sdsmapchars(sds s, const char *from, const char *to, size_t setlen); 96 | sds sdsjoin(char **argv, int argc, char *sep, size_t seplen); 97 | sds sdsjoinsds(sds *argv, int argc, const char *sep, size_t seplen); 98 | 99 | /* Low level functions exposed to the user API */ 100 | sds sdsMakeRoomFor(sds s, size_t addlen); 101 | void sdsIncrLen(sds s, int incr); 102 | sds sdsRemoveFreeSpace(sds s); 103 | size_t sdsAllocSize(sds s); 104 | 105 | #endif 106 | -------------------------------------------------------------------------------- /thirdparty/hiredis-vip/lib/libhiredis_vip.1.0.dylib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nodesheep/RESTfulCweb/d22f37d5f682a99ba0d7365e1a37cff5b257c306/thirdparty/hiredis-vip/lib/libhiredis_vip.1.0.dylib -------------------------------------------------------------------------------- /thirdparty/hiredis-vip/lib/libhiredis_vip.1.dylib: -------------------------------------------------------------------------------- 1 | libhiredis_vip.1.0.dylib -------------------------------------------------------------------------------- /thirdparty/hiredis-vip/lib/libhiredis_vip.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nodesheep/RESTfulCweb/d22f37d5f682a99ba0d7365e1a37cff5b257c306/thirdparty/hiredis-vip/lib/libhiredis_vip.a -------------------------------------------------------------------------------- /thirdparty/hiredis-vip/lib/libhiredis_vip.dylib: -------------------------------------------------------------------------------- 1 | libhiredis_vip.1.dylib -------------------------------------------------------------------------------- /thirdparty/hiredis-vip/lib/pkgconfig/hiredis_vip.pc: -------------------------------------------------------------------------------- 1 | prefix=/usr/local 2 | exec_prefix=${prefix} 3 | libdir=/usr/local/lib 4 | includedir=/usr/local/include/hiredis-vip 5 | 6 | Name: hiredis-vip 7 | Description: Minimalistic C client library for Redis and Redis Cluster. 8 | Version: 1.0.0 9 | Libs: -L${libdir} -lhiredis_vip 10 | Cflags: -I${includedir} -D_FILE_OFFSET_BITS=64 11 | --------------------------------------------------------------------------------