├── .gitmodules ├── BUILD ├── CMakeLists.txt ├── LICENSE ├── Makefile ├── README.md ├── contributors.txt ├── examples ├── client.cc └── server.cc ├── src └── cnetpp │ ├── base │ ├── csonpp.h │ ├── csonpp_impl.cc │ ├── csonpp_impl.h │ ├── end_point.cc │ ├── end_point.h │ ├── ip_address.cc │ ├── ip_address.h │ ├── log.cc │ ├── log.h │ ├── memory_cache.cc │ ├── memory_cache.h │ ├── socket.cc │ ├── socket.h │ ├── string_piece.cc │ ├── string_piece.h │ ├── string_utils.cc │ ├── string_utils.h │ ├── uri.cc │ └── uri.h │ ├── concurrency │ ├── priority_queue.h │ ├── queue_base.cc │ ├── queue_base.h │ ├── rwlock.cc │ ├── rwlock.h │ ├── spin_lock.h │ ├── task.h │ ├── this_thread.cc │ ├── this_thread.h │ ├── thread.cc │ ├── thread.h │ ├── thread_pool.cc │ └── thread_pool.h │ ├── http │ ├── http_base.cc │ ├── http_base.h │ ├── http_callbacks.h │ ├── http_client.cc │ ├── http_client.h │ ├── http_connection.cc │ ├── http_connection.h │ ├── http_options.h │ ├── http_packet.cc │ ├── http_packet.h │ ├── http_request.cc │ ├── http_request.h │ ├── http_response.cc │ ├── http_response.h │ ├── http_server.cc │ └── http_server.h │ └── tcp │ ├── command.h │ ├── connection_base.h │ ├── connection_factory.h │ ├── connection_id.cc │ ├── connection_id.h │ ├── epoll_event_poller_impl.cc │ ├── epoll_event_poller_impl.h │ ├── event.h │ ├── event_center.cc │ ├── event_center.h │ ├── event_poller.cc │ ├── event_poller.h │ ├── eventfd_interrupter_impl.cc │ ├── eventfd_interrupter_impl.h │ ├── interrupter.cc │ ├── interrupter.h │ ├── listen_connection.cc │ ├── listen_connection.h │ ├── pipe_interrupter_impl.cc │ ├── pipe_interrupter_impl.h │ ├── poll_event_poller_impl.cc │ ├── poll_event_poller_impl.h │ ├── ring_buffer.cc │ ├── ring_buffer.h │ ├── select_event_poller_impl.cc │ ├── select_event_poller_impl.h │ ├── tcp_callbacks.h │ ├── tcp_client.cc │ ├── tcp_client.h │ ├── tcp_connection.cc │ ├── tcp_connection.h │ ├── tcp_options.h │ ├── tcp_server.cc │ └── tcp_server.h └── unittests ├── base ├── csonpp_unittest.cc ├── end_point_unittest.cc ├── memory_cache_uinttest.cc ├── string_piece_unittest.cc ├── string_utils_test.cc └── uri_unittest.cc ├── concurrency ├── priority_queue_unittest.cc ├── thread_pool_unittest.cc └── thread_unittest.cc └── tcp ├── ring_buffer_unittest.cc └── tcp_client_unittest.cc /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "third_party/gtest-1.7.0"] 2 | path = third_party/gtest-1.7.0 3 | url = https://github.com/wulaxx/gtest-1.7.0.git 4 | -------------------------------------------------------------------------------- /BUILD: -------------------------------------------------------------------------------- 1 | cc_library( 2 | name="cnetpp", 3 | srcs=[ 4 | "src/cnetpp/base/*.cc", 5 | "src/cnetpp/concurrency/*.cc", 6 | "src/cnetpp/http/*.cc", 7 | "src/cnetpp/tcp/*.cc", 8 | ], 9 | incs=["src"], 10 | export_incs=["src"], 11 | deps=[ 12 | "#pthread" 13 | ], 14 | extra_cppflags=["-Wextra -Wno-unused-local-typedefs -std=c++14 -Werror"] 15 | ) 16 | 17 | cc_binary( 18 | name="cnetpp_server_test", 19 | srcs=[ 20 | "examples/server.cc", 21 | ], 22 | incs=[ 23 | "src" 24 | ], 25 | deps=[ 26 | "#pthread", 27 | ":cnetpp", 28 | ], 29 | extra_cppflags=["-Wextra -Wno-unused-local-typedefs -std=c++14 -Werror"] 30 | ) 31 | 32 | cc_binary( 33 | name="cnetpp_client_test", 34 | srcs=[ 35 | "examples/client.cc", 36 | ], 37 | incs=[ 38 | "src", 39 | ], 40 | deps=[ 41 | "#pthread", 42 | ":cnetpp", 43 | ], 44 | extra_cppflags=["-Wextra -Wno-unused-local-typedefs -std=c++14"] 45 | ) 46 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #cmake_minimum_required(VERSION 3.1) 2 | cmake_minimum_required(VERSION 2.8) 3 | project(cnetpp) 4 | include_directories("${CMAKE_SOURCE_DIR}/src") 5 | SET(CMAKE_VERBOSE_MAKEFILE ON) 6 | 7 | IF (${CMAKE_SYSTEM_NAME} MATCHES "Linux") 8 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -std=c++14 -Werror -Wall -ldl -Wno-unused-function") 9 | ELSE() 10 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -std=c++14 -Werror -Wall -Wno-unused-function") 11 | ENDIF() 12 | 13 | file(GLOB HTTP_HEADER_FILES "src/cnetpp/http/*.h") 14 | file(GLOB HTTP_SOURCE_FILES "src/cnetpp/http/*.cc") 15 | file(GLOB TCP_HEADER_FILES "src/cnetpp/tcp/*.h") 16 | file(GLOB TCP_SOURCE_FILES "src/cnetpp/tcp/*.cc") 17 | file(GLOB BASE_HEADER_FILES "src/cnetpp/base/*.h") 18 | file(GLOB BASE_SOURCE_FILES "src/cnetpp/base/*.cc") 19 | file(GLOB CONCURRENCY_HEADER_FILES "src/cnetpp/concurrency/*.h") 20 | file(GLOB CONCURRENCY_SOURCE_FILES "src/cnetpp/concurrency/*.cc") 21 | 22 | set(SOURCE_FILES 23 | ${BASE_SOURCE_FILES} 24 | ${CONCURRENCY_SOURCE_FILES} 25 | ${HTTP_SOURCE_FILES} 26 | ${TCP_SOURCE_FILES}) 27 | 28 | # build shared library 29 | add_library(cnetpp SHARED ${SOURCE_FILES}) 30 | set_target_properties(cnetpp PROPERTIES VERSION 1.0 SOVERSION 1) 31 | 32 | # build static library 33 | add_library(cnetpp_s STATIC ${SOURCE_FILES}) 34 | set_target_properties(cnetpp_s PROPERTIES OUTPUT_NAME "cnetpp") 35 | 36 | link_directories("${PROJECT_BINARY_DIR}") 37 | set(TEST_SERVER_SOURCE_FILES examples/server.cc) 38 | add_executable(cnetpp_server_test ${TEST_SERVER_SOURCE_FILES}) 39 | target_link_libraries(cnetpp_server_test cnetpp pthread) 40 | 41 | set(TEST_CLIENT_SOURCE_FILES examples/client.cc) 42 | add_executable(cnetpp_client_test ${TEST_CLIENT_SOURCE_FILES}) 43 | target_link_libraries(cnetpp_client_test cnetpp pthread) 44 | 45 | # Add unittests 46 | add_subdirectory(third_party/gtest-1.7.0) 47 | aux_source_directory(unittests/base UNITTEST_FILES) 48 | aux_source_directory(unittests/concurrency UNITTEST_FILES) 49 | aux_source_directory(unittests/tcp UNITTEST_FILES) 50 | add_executable(cnetpp_unittest ${UNITTEST_FILES} unittests/tcp/tcp_client_unittest.cc) 51 | target_include_directories(cnetpp_unittest PRIVATE third_party/gtest-1.7.0/include unittest) 52 | target_link_libraries(cnetpp_unittest cnetpp gtest gtest_main pthread) 53 | 54 | enable_testing() 55 | add_test(unittest cnetpp_unittest) 56 | 57 | 58 | install(TARGETS cnetpp cnetpp_s 59 | LIBRARY DESTINATION lib 60 | ARCHIVE DESTINATION lib) 61 | 62 | install(FILES ${BASE_HEADER_FILES} DESTINATION include/cnetpp/base) 63 | install(FILES ${CONCURRENCY_HEADER_FILES} DESTINATION include/cnetpp/concurrency) 64 | install(FILES ${HTTP_HEADER_FILES} DESTINATION include/cnetpp/http) 65 | install(FILES ${TCP_HEADER_FILES} DESTINATION include/cnetpp/tcp) 66 | 67 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 myjfm(mwxjmmyjfm@gmail.com) 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 | 23 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all test clean 2 | 3 | all: 4 | blade build . --verbose -p debug --bundle debug 2>&1 | tee build.log 5 | 6 | test: all 7 | blade test . --verbos 8 | 9 | clean: 10 | blade clean . -p debug 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## What is cnetpp? ## 2 | 3 | a ligthweight asynchronous network library focused on backend c++ development 4 | 5 | ## Dependancies: ## 6 | 7 | * linux2.6 or higher, mac osx 10.10 or higher (will support more platforms in the future) 8 | * gcc4.9.0 or higher, clang-703.0.29 or higher 9 | 10 | ## Includes: ## 11 | 12 | * a simple json parser, named csonpp 13 | * a simple thread framework 14 | * the asynchronous Tcp network framework based on epoll(or select or poll) 15 | * the asynchronous Http server and client module based on our Tcp network framework 16 | 17 | ## Install: ## 18 | 19 | cd $CNETPP_ROOT_PATH 20 | mkdir build/ 21 | cd build/ 22 | cmake -DCMAKE_INSTALL_PREFIX=/usr/local .. (modify the value of option CMAKE_INSTALL_PREFIX if you want to change the install directory) 23 | make 24 | sudo make install 25 | 26 | -------------------------------------------------------------------------------- /contributors.txt: -------------------------------------------------------------------------------- 1 | myjfm mwxjmmyjfm@gmail.com 2 | wulaxx xu_chu@163.com 3 | -------------------------------------------------------------------------------- /examples/client.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | 11 | #include 12 | 13 | int main(int argc, const char **argv) { 14 | if(argc != 2) { 15 | std::cout << "Usage: " << argv[0] << " " << std::endl; 16 | return 1; 17 | } 18 | 19 | std::unordered_map counts; 20 | using HttpConnectionPtr = std::shared_ptr; 21 | 22 | cnetpp::http::HttpClientOptions http_options; 23 | http_options.set_send_buffer_size(1024 * 1024); 24 | http_options.set_receive_buffer_size(1024 * 1024); 25 | 26 | auto send_func = [] (HttpConnectionPtr c) -> bool { 27 | std::shared_ptr http_request( 28 | new cnetpp::http::HttpRequest); 29 | http_request->set_method(cnetpp::http::HttpRequest::MethodType::kGet); 30 | http_request->set_uri("/"); 31 | // http_request->SetHttpHeader("Content-Length", "0"); 32 | if (!c->remote_hostname().empty()) { 33 | http_request->SetHttpHeader("Host", c->remote_hostname()); 34 | } else { 35 | auto tc = c->tcp_connection(); 36 | http_request->SetHttpHeader( 37 | "Host", 38 | tc->remote_end_point().ToStringWithoutPort()); 39 | } 40 | http_request->SetHttpHeader("User-Agent", "cnetpp/1.0"); 41 | return c->SendPacket(http_request->ToString()); 42 | }; 43 | 44 | http_options.set_connected_callback([&send_func] (HttpConnectionPtr c) -> bool { 45 | CnetppInfo("Connected to the server"); 46 | return send_func(c); 47 | }); 48 | 49 | http_options.set_closed_callback([] (HttpConnectionPtr c) -> bool { 50 | CnetppInfo("Connection closed"); 51 | (void) c; 52 | return true; 53 | }); 54 | 55 | http_options.set_received_callback([&send_func, &counts] ( 56 | HttpConnectionPtr c) -> bool { 57 | auto http_response = 58 | std::static_pointer_cast(c->http_packet()); 59 | std::string headers; 60 | http_response->HttpHeadersToString(&headers); 61 | CnetppInfo("headers: %s", headers.c_str()); 62 | if (http_response->http_body().length() > 0) { 63 | CnetppInfo("body: %s", http_response->http_body().c_str()); 64 | } 65 | if (counts[c->id()]++ == 10) { 66 | c->MarkAsClosed(); 67 | CnetppInfo("MarkAsClosed"); 68 | return true; 69 | } else { 70 | return send_func(c); 71 | } 72 | }); 73 | 74 | http_options.set_sent_callback([] (bool success, HttpConnectionPtr c) -> bool { 75 | (void) c; 76 | CnetppInfo("Send packet successfully"); 77 | return success; 78 | }); 79 | 80 | cnetpp::http::HttpClient http_client; 81 | cnetpp::http::HttpClientOptions options; 82 | options.set_worker_count(1); 83 | if (!http_client.Launch(options)) { 84 | CnetppFatal("Failed to launch http client, exiting..."); 85 | return 1; 86 | } 87 | 88 | for (auto i = 0; i < 8; ++i) { 89 | auto connection_id = http_client.Connect(argv[1], http_options); 90 | if (connection_id == cnetpp::tcp::kInvalidConnectionId) { 91 | CnetppInfo("Failed to connect to server"); 92 | return 1; 93 | } 94 | } 95 | 96 | sleep(2); 97 | 98 | http_client.Shutdown(); 99 | 100 | return 0; 101 | } 102 | 103 | -------------------------------------------------------------------------------- /examples/server.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | 12 | #include 13 | #include 14 | 15 | class HttpServerHandler final { 16 | public: 17 | HttpServerHandler() = default; 18 | ~HttpServerHandler() = default; 19 | 20 | bool OnConnected(std::shared_ptr c) { 21 | CnetppInfo("A new connection arrived"); 22 | assert(c.get()); 23 | (void) c; 24 | return true; 25 | } 26 | 27 | bool OnReceived(std::shared_ptr c) { 28 | assert(c.get()); 29 | auto http_request = 30 | static_cast(c->http_packet().get()); 31 | if (!http_request) { 32 | return false; 33 | } 34 | CnetppInfo("uri: %s", http_request->uri().c_str()); 35 | CnetppInfo("method: %d", static_cast(http_request->method())); 36 | std::shared_ptr http_response( 37 | new cnetpp::http::HttpResponse); 38 | http_response->set_status( 39 | static_cast(200)); 40 | http_response->SetHttpHeader("Content-Length", "10"); 41 | http_response->set_http_body("1234567890"); 42 | std::string str_response; 43 | http_response->ToString(&str_response); 44 | c->SendPacket(str_response); 45 | //c->MarkAsClosed(false); 46 | return true; 47 | } 48 | 49 | bool OnClosed(std::shared_ptr c) { 50 | assert(c.get()); 51 | (void) c; 52 | CnetppInfo("Connection closed"); 53 | return true; 54 | } 55 | 56 | bool OnSent(bool success, std::shared_ptr c) { 57 | (void) c; 58 | CnetppInfo("Message has been sent"); 59 | return success; 60 | } 61 | }; 62 | 63 | int main() { 64 | cnetpp::base::IPAddress listen_ip("127.0.0.1"); 65 | cnetpp::base::EndPoint listen_end_point(listen_ip, 12346); 66 | 67 | HttpServerHandler http_handler; 68 | cnetpp::http::HttpServerOptions options; 69 | options.set_connected_callback( 70 | [&http_handler] ( 71 | std::shared_ptr c) -> bool { 72 | return http_handler.OnConnected(c); 73 | }); 74 | options.set_closed_callback( 75 | [&http_handler] ( 76 | std::shared_ptr c) -> bool { 77 | return http_handler.OnClosed(c); 78 | }); 79 | options.set_received_callback( 80 | [&http_handler] ( 81 | std::shared_ptr c) -> bool { 82 | return http_handler.OnReceived(c); 83 | }); 84 | options.set_sent_callback( 85 | [&http_handler] ( 86 | bool success, 87 | std::shared_ptr c) -> bool { 88 | return http_handler.OnSent(success, c); 89 | }); 90 | 91 | cnetpp::http::HttpServer http_server; 92 | if (!http_server.Launch(listen_end_point, options)) { 93 | CnetppFatal("Failed to launch http server, exiting..."); 94 | } 95 | 96 | ::sleep(1000); 97 | 98 | return 0; 99 | } 100 | 101 | -------------------------------------------------------------------------------- /src/cnetpp/base/end_point.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, myjfm(mwxjmmyjfm@gmail.com). All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are met: 5 | // 6 | // * Redistributions of source code must retain the above copyright notice, 7 | // this list of conditions and the following disclaimer. 8 | // * Redistributions in binary form must reproduce the above copyright notice, 9 | // this list of conditions and the following disclaimer in the documentation 10 | // and/or other materials provided with the distribution. 11 | // * Neither the name of myjfm nor the names of other contributors may be 12 | // used to endorse or promote products derived from this software without 13 | // specific prior written permission. 14 | // 15 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | // CONTRACT, STRICT LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) 24 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | // POSSIBILITY OF SUCH DAMAGE. 26 | // 27 | #include 28 | #include 29 | 30 | #include 31 | #include 32 | #include 33 | 34 | namespace cnetpp { 35 | namespace base { 36 | 37 | bool EndPoint::ToSockAddr(struct sockaddr* address, 38 | socklen_t* address_len) const { 39 | assert(address); 40 | assert(address_len); 41 | 42 | if (port_ <= 0) { 43 | return false; 44 | } 45 | 46 | switch (address_.Family()) { 47 | case AF_INET: { 48 | //*address_len = IPAddress::kIPv4AddressSize; 49 | *address_len = sizeof(struct sockaddr_in); 50 | auto in_address = reinterpret_cast(address); 51 | in_address->sin_family = AF_INET; 52 | in_address->sin_port = htons(port_); 53 | ::memcpy(&(in_address->sin_addr), 54 | &((address_.address())[0]), 55 | IPAddress::kIPv4AddressSize); 56 | break; 57 | } 58 | case AF_INET6: { 59 | //*address_len = IPAddress::kIPv6AddressSize; 60 | *address_len = sizeof(struct sockaddr_in6); 61 | auto in6_address = reinterpret_cast(address); 62 | in6_address->sin6_family = AF_INET6; 63 | in6_address->sin6_port = htons(port_); 64 | memcpy(&(in6_address->sin6_addr), 65 | &((address_.address())[0]), 66 | IPAddress::kIPv6AddressSize); 67 | break; 68 | } 69 | default: 70 | return false; 71 | } 72 | return true; 73 | } 74 | 75 | bool EndPoint::FromSockAddr(const struct sockaddr& address, 76 | socklen_t address_len) { 77 | auto error = [this] { 78 | address_.mutable_address().clear(); 79 | port_ = 0; 80 | return false; 81 | }; 82 | switch (address_len) { 83 | // case IPAddress::kIPv4AddressSize: { 84 | case sizeof(struct sockaddr_in): { 85 | if (address_len < static_cast(sizeof(struct sockaddr_in))) { 86 | return error(); 87 | } 88 | auto in_address = reinterpret_cast(&address); 89 | if (in_address->sin_family != AF_INET) { 90 | return error(); 91 | } 92 | port_ = ntohs(in_address->sin_port); 93 | address_.mutable_address().resize(IPAddress::kIPv4AddressSize); 94 | memcpy(&((address_.mutable_address())[0]), 95 | &(in_address->sin_addr), 96 | IPAddress::kIPv4AddressSize); 97 | break; 98 | } 99 | // case IPAddress::kIPv6AddressSize: { 100 | case sizeof(struct sockaddr_in6): { 101 | if (address_len < static_cast(sizeof(struct sockaddr_in6))) { 102 | return error(); 103 | } 104 | auto in6_address = reinterpret_cast(&address); 105 | if (in6_address->sin6_family != AF_INET6) { 106 | return error(); 107 | } 108 | port_ = ntohs(in6_address->sin6_port); 109 | address_.mutable_address().resize(IPAddress::kIPv6AddressSize); 110 | memcpy(&((address_.mutable_address())[0]), 111 | &(in6_address->sin6_addr), 112 | IPAddress::kIPv6AddressSize); 113 | break; 114 | } 115 | default: 116 | return error(); 117 | } 118 | return true; 119 | } 120 | 121 | } // namespace base 122 | } // namespace cnetpp 123 | 124 | namespace std { 125 | 126 | void swap(cnetpp::base::EndPoint& a, cnetpp::base::EndPoint& b) { 127 | a.Swap(b); 128 | } 129 | 130 | } // namespace std 131 | 132 | -------------------------------------------------------------------------------- /src/cnetpp/base/end_point.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, myjfm(mwxjmmyjfm@gmail.com). All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are met: 5 | // 6 | // * Redistributions of source code must retain the above copyright notice, 7 | // this list of conditions and the following disclaimer. 8 | // * Redistributions in binary form must reproduce the above copyright notice, 9 | // this list of conditions and the following disclaimer in the documentation 10 | // and/or other materials provided with the distribution. 11 | // * Neither the name of myjfm nor the names of other contributors may be 12 | // used to endorse or promote products derived from this software without 13 | // specific prior written permission. 14 | // 15 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | // CONTRACT, STRICT LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) 24 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | // POSSIBILITY OF SUCH DAMAGE. 26 | // 27 | #ifndef CNETPP_BASE_END_POINT_H_ 28 | #define CNETPP_BASE_END_POINT_H_ 29 | 30 | #include 31 | 32 | #include 33 | 34 | #include 35 | 36 | namespace cnetpp { 37 | namespace base { 38 | 39 | class EndPoint final { 40 | public: 41 | EndPoint() = default; 42 | ~EndPoint() = default; 43 | 44 | EndPoint(const IPAddress& address, int port) 45 | : address_(address), 46 | port_(port) { 47 | } 48 | 49 | EndPoint(IPAddress&& address, int port) 50 | : address_(std::move(address)), 51 | port_(port) { 52 | } 53 | 54 | EndPoint(const StringPiece& address, int port) 55 | : address_(address), port_(port) { 56 | } 57 | 58 | EndPoint(const struct sockaddr& address, socklen_t address_length) { 59 | bool res = FromSockAddr(address, address_length); 60 | (void) res; 61 | assert(res); 62 | } 63 | 64 | EndPoint(const EndPoint&) = default; 65 | EndPoint& operator=(const EndPoint&) = default; 66 | 67 | EndPoint(EndPoint&&) = default; 68 | EndPoint& operator=(EndPoint&&) = default; 69 | 70 | int Family() const { 71 | return address_.Family(); 72 | } 73 | 74 | int port() const { 75 | return port_; 76 | } 77 | 78 | IPAddress& mutable_address() { 79 | return address_; 80 | } 81 | 82 | const IPAddress& address() const { 83 | return address_; 84 | } 85 | 86 | bool ToSockAddr(struct sockaddr* address, 87 | socklen_t* address_len) const; 88 | 89 | bool FromSockAddr(const struct sockaddr& address, 90 | socklen_t address_len); 91 | 92 | std::string ToString(bool colon_delimited = true) const { 93 | std::string res; 94 | res.reserve(64); 95 | res.append(address_.ToString()); 96 | if (colon_delimited) { 97 | res.append(1, ':'); 98 | } else { 99 | res.append(1, ','); 100 | } 101 | res.append(std::to_string(static_cast(port_))); 102 | return res; 103 | } 104 | 105 | std::string ToStringWithoutPort() const { 106 | return address_.ToString(); 107 | } 108 | 109 | void Swap(EndPoint& end_point) { 110 | std::swap(address_, end_point.address_); 111 | std::swap(port_, end_point.port_); 112 | } 113 | 114 | private: 115 | IPAddress address_; 116 | int port_ { 0 }; 117 | }; 118 | 119 | } // namespace base 120 | } // namespace cnetpp 121 | 122 | namespace std { 123 | 124 | void swap(cnetpp::base::EndPoint& a, cnetpp::base::EndPoint& b); 125 | 126 | } // namespace std 127 | 128 | #endif // CNETPP_BASE_END_POINT_H_ 129 | 130 | -------------------------------------------------------------------------------- /src/cnetpp/base/ip_address.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, myjfm(mwxjmmyjfm@gmail.com). All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are met: 5 | // 6 | // * Redistributions of source code must retain the above copyright notice, 7 | // this list of conditions and the following disclaimer. 8 | // * Redistributions in binary form must reproduce the above copyright notice, 9 | // this list of conditions and the following disclaimer in the documentation 10 | // and/or other materials provided with the distribution. 11 | // * Neither the name of myjfm nor the names of other contributors may be 12 | // used to endorse or promote products derived from this software without 13 | // specific prior written permission. 14 | // 15 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | // CONTRACT, STRICT LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) 24 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | // POSSIBILITY OF SUCH DAMAGE. 26 | // 27 | #ifndef CNETPP_BASE_IP_ADDRESS_H_ 28 | #define CNETPP_BASE_IP_ADDRESS_H_ 29 | 30 | #include 31 | 32 | #include 33 | 34 | #include 35 | #include 36 | #include 37 | 38 | namespace cnetpp { 39 | namespace base { 40 | 41 | class IPAddress final { 42 | public: 43 | static const size_t kIPv4AddressSize = 4; // 4 bytes 44 | static const int kIPv6AddressSize = 16; // 16 bytes 45 | 46 | // convert IPv4 address like '192.168.1.1', or 47 | // IPv6 address like 48 | // '2001:0DB8:02de:0000:0000:0000:0000:0e13', 49 | // or '2001:DB8:2de:0000:0000:0000:0000:e13', 50 | // or '2001:0DB8:02de::0e13', 51 | // or '::e13:2001', 52 | // or 'abcd:0001::', 53 | // or '::ffff:192.168.1.1' 54 | // to number, in network byte order 55 | // return false if the str_addr is invalid 56 | static bool LiteralToNumber(StringPiece str_addr, IPAddress* number); 57 | 58 | // convert IPv4 or IPv6 address with binary format to string format 59 | static bool NumberToLiteral(const IPAddress& number, std::string* str_addr); 60 | 61 | IPAddress() = default; 62 | ~IPAddress() = default; 63 | 64 | explicit IPAddress(StringPiece str_addr); 65 | 66 | IPAddress(const IPAddress&) = default; 67 | IPAddress& operator=(const IPAddress&) = default; 68 | IPAddress(IPAddress&&) = default; 69 | IPAddress& operator=(IPAddress&&) = default; 70 | 71 | int Family() const; 72 | 73 | std::vector& mutable_address() { 74 | return address_; 75 | } 76 | 77 | const std::vector& address() const { 78 | return address_; 79 | } 80 | 81 | size_t Size() const { 82 | return address_.size(); 83 | } 84 | 85 | // onlu ipv4 86 | // ipv6 -> 255.255.255.255 87 | // unspec -> 255.255.255.255 88 | uint32_t ToIPv4ID() const; 89 | 90 | std::string ToString() const; 91 | 92 | void Swap(IPAddress& ip_address) { 93 | std::swap(address_, ip_address.address_); 94 | } 95 | 96 | private: 97 | static bool IPv4LiteralToNumber(StringPiece str_addr, 98 | IPAddress* number); 99 | static bool IPv6LiteralToNumber(StringPiece str_addr, 100 | IPAddress* number); 101 | 102 | static bool IPv4NumberToLiteral(const IPAddress& number, 103 | std::string* str_addr); 104 | static bool IPv6NumberToLiteral(const IPAddress& number, 105 | std::string* str_addr); 106 | 107 | std::vector address_; 108 | }; 109 | 110 | class IPAddressList { 111 | public: 112 | std::vector addresses_; 113 | }; 114 | 115 | } // namespace base 116 | } // namespace cnetpp 117 | 118 | namespace std { 119 | 120 | void swap(cnetpp::base::IPAddress& a, cnetpp::base::IPAddress& b); 121 | 122 | } // namespace std 123 | 124 | #endif // CNETPP_BASE_IP_ADDRESS_H_ 125 | 126 | -------------------------------------------------------------------------------- /src/cnetpp/base/log.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, myjfm(mwxjmmyjfm@gmail.com). All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are met: 5 | // 6 | // * Redistributions of source code must retain the above copyright notice, 7 | // this list of conditions and the following disclaimer. 8 | // * Redistributions in binary form must reproduce the above copyright notice, 9 | // this list of conditions and the following disclaimer in the documentation 10 | // and/or other materials provided with the distribution. 11 | // * Neither the name of myjfm nor the names of other contributors may be 12 | // used to endorse or promote products derived from this software without 13 | // specific prior written permission. 14 | // 15 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | // CONTRACT, STRICT LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) 24 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | // POSSIBILITY OF SUCH DAMAGE. 26 | // 27 | #ifndef CNETPP_BASE_LOG_H_ 28 | #define CNETPP_BASE_LOG_H_ 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | namespace cnetpp { 36 | namespace base { 37 | 38 | class Log { 39 | public: 40 | enum class Level : uint8_t { 41 | kDebug, 42 | kInfo, 43 | kWarn, 44 | kError, 45 | kFatal, 46 | }; 47 | 48 | Log() : func_(&DefaultFunc), level_(Level::kDebug) {} 49 | 50 | inline void set_func(void (*func)(Level level, const char*)) { 51 | func_ = func; 52 | } 53 | 54 | void set_level(Log::Level level) { 55 | level_ = level; 56 | } 57 | 58 | Log::Level get_level() const { return level_; } 59 | 60 | inline void Debug(const char* fmt, ...) { 61 | if (level_ < Level::kDebug) return; 62 | va_list ap; 63 | va_start(ap, fmt); 64 | VPrintf(Level::kDebug, fmt, ap); 65 | va_end(ap); 66 | } 67 | inline void Info(const char* fmt, ...) { 68 | if (level_ < Level::kInfo) return; 69 | va_list ap; 70 | va_start(ap, fmt); 71 | VPrintf(Level::kInfo, fmt, ap); 72 | va_end(ap); 73 | } 74 | inline void Warn(const char* fmt, ...) { 75 | if (level_ < Level::kWarn) return; 76 | va_list ap; 77 | va_start(ap, fmt); 78 | VPrintf(Level::kWarn, fmt, ap); 79 | va_end(ap); 80 | } 81 | inline void Error(const char* fmt, ...) { 82 | if (level_ < Level::kError) return; 83 | va_list ap; 84 | va_start(ap, fmt); 85 | VPrintf(Level::kError, fmt, ap); 86 | va_end(ap); 87 | } 88 | inline void Fatal(const char* fmt, ...) { 89 | if (level_ < Level::kFatal) return; 90 | va_list ap; 91 | va_start(ap, fmt); 92 | VPrintf(Level::kFatal, fmt, ap); 93 | va_end(ap); 94 | } 95 | 96 | static void DefaultFunc(Level level, const char* msg); 97 | static void DefaultEmptyFunc(Level level, const char* msg); 98 | 99 | private: 100 | void VPrintf(Level level, const char* fmt, va_list ap); 101 | 102 | static int FormatTime(char* buffer, size_t size); 103 | 104 | void (*func_)(Level level, const char*); 105 | Log::Level level_; 106 | }; 107 | 108 | extern Log LOG; 109 | 110 | #ifdef NDEBUG 111 | #define CnetppDebug(fmt, ...) 112 | #else 113 | #define CnetppDebug(fmt, ...) \ 114 | cnetpp::base::LOG.Debug(" %s:%d] " fmt, __FILE__, __LINE__, ##__VA_ARGS__); 115 | #endif 116 | 117 | #define CnetppInfo(fmt, ...) \ 118 | cnetpp::base::LOG.Info(" %s:%d] " fmt, __FILE__, __LINE__, ##__VA_ARGS__); 119 | 120 | #define CnetppWarn(fmt, ...) \ 121 | cnetpp::base::LOG.Warn(" %s:%d] " fmt, __FILE__, __LINE__, ##__VA_ARGS__); 122 | 123 | #define CnetppError(fmt, ...) \ 124 | cnetpp::base::LOG.Error(" %s:%d] " fmt, __FILE__, __LINE__, ##__VA_ARGS__); 125 | 126 | #define CnetppFatal(fmt, ...) \ 127 | cnetpp::base::LOG.Fatal(" %s:%d] " fmt, __FILE__, __LINE__, ##__VA_ARGS__); 128 | 129 | extern std::string BacktraceString(int skip = 1); 130 | } // namespace base 131 | 132 | } // namespace cnetpp 133 | 134 | #endif // CNETPP_BASE_LOG_H_ 135 | 136 | -------------------------------------------------------------------------------- /src/cnetpp/base/memory_cache.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, myjfm(mwxjmmyjfm@gmail.com). All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are met: 5 | // 6 | // * Redistributions of source code must retain the above copyright notice, 7 | // this list of conditions and the following disclaimer. 8 | // * Redistributions in binary form must reproduce the above copyright notice, 9 | // this list of conditions and the following disclaimer in the documentation 10 | // and/or other materials provided with the distribution. 11 | // * Neither the name of myjfm nor the names of other contributors may be 12 | // used to endorse or promote products derived from this software without 13 | // specific prior written permission. 14 | // 15 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | // CONTRACT, STRICT LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) 24 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | // POSSIBILITY OF SUCH DAMAGE. 26 | // 27 | #ifndef CNETPP_BASE_MEMORY_CACHE_H_ 28 | #define CNETPP_BASE_MEMORY_CACHE_H_ 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | namespace cnetpp { 39 | namespace base { 40 | 41 | class MemoryCacheTLS; 42 | 43 | typedef struct MemoryCacheHead { 44 | MemoryCacheHead() : head_(nullptr) {} 45 | std::mutex mtx_; 46 | MemoryCacheTLS* head_; 47 | } MemoryCacheHead; 48 | 49 | class MemoryCache { 50 | public: 51 | using Stats = 52 | std::deque>>; 53 | 54 | static MemoryCache* Instance(); 55 | 56 | ~MemoryCache(); 57 | 58 | void* Allocate(uint32_t n); 59 | void Deallocate(void* ptr); 60 | void* Recycle(void* ptr, uint32_t* len); 61 | 62 | void max_cache_normal(uint32_t n) { 63 | max_cache_normal_ = n; 64 | } 65 | uint32_t max_cache_normal() const { 66 | return max_cache_normal_; 67 | } 68 | 69 | void max_cache_large(uint32_t n) { 70 | max_cache_large_ = n; 71 | } 72 | uint32_t max_cache_large() const { 73 | return max_cache_large_; 74 | } 75 | 76 | void EnsureHasMemoryCacheTLS(); 77 | MemoryCache::Stats GetStats() const; 78 | 79 | private: 80 | MemoryCache(); 81 | 82 | static void PrepareCleanupTLSAtThreadExit(); 83 | static void CleanupAtThreadExit(void* argv __attribute__((unused))); 84 | static void CleanupAtMainExit(); 85 | static void CleanupMemoryCacheTLS(MemoryCacheTLS* pool); 86 | 87 | static uint32_t max_cache_normal_; 88 | static uint32_t max_cache_large_; 89 | static pthread_key_t tls_key_; 90 | static MemoryCacheHead h_; 91 | static __thread MemoryCacheTLS* pool_; 92 | }; 93 | 94 | } // namespace base 95 | } // namespace cnetpp 96 | 97 | #endif // CNETPP_BASE_MEMORY_CACHE_H_ 98 | -------------------------------------------------------------------------------- /src/cnetpp/base/uri.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, myjfm(mwxjmmyjfm@gmail.com). All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are met: 5 | // 6 | // * Redistributions of source code must retain the above copyright notice, 7 | // this list of conditions and the following disclaimer. 8 | // * Redistributions in binary form must reproduce the above copyright notice, 9 | // this list of conditions and the following disclaimer in the documentation 10 | // and/or other materials provided with the distribution. 11 | // * Neither the name of myjfm nor the names of other contributors may be 12 | // used to endorse or promote products derived from this software without 13 | // specific prior written permission. 14 | // 15 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | // CONTRACT, STRICT LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) 24 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | // POSSIBILITY OF SUCH DAMAGE. 26 | // 27 | #ifndef CNETPP_BASE_URI_H_ 28 | #define CNETPP_BASE_URI_H_ 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | namespace cnetpp { 36 | namespace base { 37 | 38 | class Uri { 39 | public: 40 | Uri() = default; 41 | ~Uri() = default; 42 | 43 | // whether it's a valid uri, false by default 44 | bool Valid() const noexcept { 45 | return valid_; 46 | } 47 | 48 | // given a string, parse it into uri 49 | // e.g. http://www.baidu.com/search/error.html?key=hello#anchor 50 | // The string is broken down into these parts: 51 | // scheme: "http", 52 | // authority: "www.baidu.com", 53 | // path: "/search/error.html", 54 | // query "key=hello", and, 55 | // fragment "anchor" 56 | // return true if the string is a valid uri, else false 57 | bool Parse(const std::string& uri); 58 | 59 | bool ParseUriPath(const std::string& path, bool decoded = false); 60 | 61 | // get the uri with string format 62 | std::string String() const; 63 | 64 | // get the authority: [username:password@]host[:port] 65 | std::string Authority() const; 66 | 67 | std::string Scheme() const { 68 | return scheme_; 69 | } 70 | 71 | std::string Username() const { 72 | return username_; 73 | } 74 | 75 | std::string Password() const { 76 | return password_; 77 | } 78 | 79 | // get host part of Uri. 80 | // If host is an IPv6 address, square brackets will be returned, 81 | // e.g. [::ffff:192.168.89.9] 82 | // for more information, please refer to rfc3986 83 | std::string Host() const { 84 | return host_; 85 | } 86 | 87 | // This method is the same as Host(), except that when the host is an IPv6 88 | // address. This method will return raw IPv6 address without square brackets, 89 | // because some APIs only understands host without square brackets 90 | std::string Hostname() const; 91 | 92 | uint16_t Port() const noexcept { 93 | return port_; 94 | } 95 | 96 | std::string Path() const { 97 | return path_; 98 | } 99 | 100 | std::string Query() const { 101 | return query_; 102 | } 103 | 104 | std::string Fragment() const { 105 | return fragment_; 106 | } 107 | 108 | // get query parameters as key-value pairs 109 | // e.g. for the uri that contains query string: key1=foo&key2=&key3&=bar&=bar= 110 | // It returns a vector that contains 3 entries: 111 | // "key1" => "foo", 112 | // "key2" => "" 113 | // "key3" => "" 114 | // Parts "=bar" and "=bar=" are ignored, as they are not valid query parameters. 115 | // "=bar" is missing parameter name, while "=bar=" has more than one equal signs, 116 | // we don't know which one is the delimiter for key and value. It returns query 117 | // parameter key-value pairs in a vector, each element is a pair of which the 118 | // first element is parameter name and the second one is parameter value. 119 | std::vector> QueryParams() const { 120 | return query_params_; 121 | } 122 | 123 | private: 124 | static const std::regex kUriRegex; 125 | static const std::regex kAuthorityAndPathRegex; 126 | static const std::regex kAuthorityRegex; 127 | static const std::regex kQueryParamRegex; 128 | 129 | bool valid_ { false }; 130 | std::string scheme_; 131 | std::string username_; 132 | std::string password_; 133 | std::string host_; 134 | uint16_t port_ { 0 }; 135 | std::string port_str_; 136 | std::string path_; 137 | std::string query_; 138 | std::string fragment_; 139 | std::vector> query_params_; 140 | }; 141 | 142 | } // namespace base 143 | } // namespace cnetpp 144 | 145 | #endif // CNETPP_BASE_URI_H_ 146 | 147 | -------------------------------------------------------------------------------- /src/cnetpp/concurrency/priority_queue.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, myjfm(mwxjmmyjfm@gmail.com). All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are met: 5 | // 6 | // * Redistributions of source code must retain the above copyright notice, 7 | // this list of conditions and the following disclaimer. 8 | // * Redistributions in binary form must reproduce the above copyright notice, 9 | // this list of conditions and the following disclaimer in the documentation 10 | // and/or other materials provided with the distribution. 11 | // * Neither the name of myjfm nor the names of other contributors may be 12 | // used to endorse or promote products derived from this software without 13 | // specific prior written permission. 14 | // 15 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | // CONTRACT, STRICT LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) 24 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | // POSSIBILITY OF SUCH DAMAGE. 26 | // 27 | #ifndef CNETPP_CONCURRENCY_PRIORITY_QUEUE_H_ 28 | #define CNETPP_CONCURRENCY_PRIORITY_QUEUE_H_ 29 | 30 | #include 31 | 32 | #include 33 | 34 | namespace cnetpp { 35 | namespace concurrency { 36 | 37 | template 38 | class PriorityQueue final : public QueueBase { 39 | public: 40 | PriorityQueue(size_t capacity = 0) : capacity_(capacity) { 41 | } 42 | virtual ~PriorityQueue() = default; 43 | 44 | bool Push(std::shared_ptr task) override { 45 | if (capacity_ > 0 && queue_.size() >= capacity_) { 46 | return false; 47 | } 48 | queue_.push(std::move(task)); 49 | return true; 50 | } 51 | 52 | std::shared_ptr TryPop() override { 53 | if (queue_.empty()) { 54 | return nullptr; 55 | } 56 | std::shared_ptr result(std::move(queue_.top())); 57 | queue_.pop(); 58 | return result; 59 | } 60 | 61 | std::shared_ptr Peek() override { 62 | if (queue_.empty()) { 63 | return nullptr; 64 | } 65 | return queue_.top(); 66 | } 67 | 68 | bool Empty() const override { 69 | return queue_.empty(); 70 | } 71 | 72 | bool Full() const override { 73 | if (capacity_ > 0) { 74 | return queue_.size() == capacity_; 75 | } else { 76 | return false; 77 | } 78 | } 79 | 80 | size_t size() const override { 81 | return queue_.size(); 82 | } 83 | 84 | size_t capacity() const override { 85 | return capacity_; 86 | } 87 | 88 | private: 89 | std::priority_queue, 90 | std::deque>, 91 | Compare> queue_; 92 | size_t capacity_ { 0 }; 93 | }; 94 | 95 | template 96 | inline std::shared_ptr CreatePriorityQueue(size_t capacity = 0) { 97 | return std::static_pointer_cast( 98 | std::make_shared>(capacity)); 99 | } 100 | 101 | } // namespace concurrency 102 | } // namespace cnetpp 103 | 104 | #endif // CNETPP_CONCURRENCY_PRIORITY_QUEUE_H_ 105 | 106 | -------------------------------------------------------------------------------- /src/cnetpp/concurrency/queue_base.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, myjfm(mwxjmmyjfm@gmail.com). All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are met: 5 | // 6 | // * Redistributions of source code must retain the above copyright notice, 7 | // this list of conditions and the following disclaimer. 8 | // * Redistributions in binary form must reproduce the above copyright notice, 9 | // this list of conditions and the following disclaimer in the documentation 10 | // and/or other materials provided with the distribution. 11 | // * Neither the name of myjfm nor the names of other contributors may be 12 | // used to endorse or promote products derived from this software without 13 | // specific prior written permission. 14 | // 15 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | // CONTRACT, STRICT LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) 24 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | // POSSIBILITY OF SUCH DAMAGE. 26 | // 27 | #include 28 | 29 | #include 30 | 31 | namespace cnetpp { 32 | namespace concurrency { 33 | 34 | std::shared_ptr CreateDefaultQueue(size_t capacity) { 35 | return std::static_pointer_cast( 36 | std::make_shared(capacity)); 37 | } 38 | 39 | } // namespace concurrency 40 | } // namespace cnetpp 41 | -------------------------------------------------------------------------------- /src/cnetpp/concurrency/queue_base.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, myjfm(mwxjmmyjfm@gmail.com). All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are met: 5 | // 6 | // * Redistributions of source code must retain the above copyright notice, 7 | // this list of conditions and the following disclaimer. 8 | // * Redistributions in binary form must reproduce the above copyright notice, 9 | // this list of conditions and the following disclaimer in the documentation 10 | // and/or other materials provided with the distribution. 11 | // * Neither the name of myjfm nor the names of other contributors may be 12 | // used to endorse or promote products derived from this software without 13 | // specific prior written permission. 14 | // 15 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | // CONTRACT, STRICT LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) 24 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | // POSSIBILITY OF SUCH DAMAGE. 26 | // 27 | #ifndef CNETPP_CONCURRENCY_QUEUE_BASE_H_ 28 | #define CNETPP_CONCURRENCY_QUEUE_BASE_H_ 29 | 30 | #include 31 | 32 | #include 33 | #include 34 | 35 | namespace cnetpp { 36 | namespace concurrency { 37 | 38 | class QueueBase { 39 | public: 40 | QueueBase() = default; 41 | virtual ~QueueBase() = default; 42 | 43 | virtual bool Push(std::shared_ptr task) = 0; 44 | 45 | // get a task from queue, if empty, just return nullptr 46 | virtual std::shared_ptr TryPop() = 0; 47 | 48 | virtual std::shared_ptr Peek() = 0; 49 | 50 | virtual bool Empty() const = 0; 51 | 52 | virtual bool Full() const = 0; 53 | 54 | virtual size_t size() const = 0; 55 | 56 | virtual size_t capacity() const = 0; 57 | }; 58 | 59 | class DefaultQueue final : public QueueBase { 60 | public: 61 | explicit DefaultQueue(size_t capacity = 0) : capacity_(capacity) { 62 | } 63 | virtual ~DefaultQueue() = default; 64 | 65 | protected: 66 | bool Push(std::shared_ptr task) override { 67 | if (capacity_ > 0 && queue_.size() >= capacity_) { 68 | return false; 69 | } 70 | 71 | queue_.push(std::move(task)); 72 | return true; 73 | } 74 | 75 | std::shared_ptr TryPop() override { 76 | if (queue_.empty()) { 77 | return nullptr; 78 | } 79 | std::shared_ptr result(std::move(queue_.front())); 80 | queue_.pop(); 81 | return result; 82 | } 83 | 84 | std::shared_ptr Peek() override { 85 | if (queue_.empty()) { 86 | return nullptr; 87 | } 88 | return queue_.front(); 89 | } 90 | 91 | bool Empty() const override { 92 | return queue_.empty(); 93 | } 94 | 95 | bool Full() const override { 96 | if (capacity_ > 0) { 97 | return queue_.size() == capacity_; 98 | } else { 99 | return false; 100 | } 101 | } 102 | 103 | size_t size() const override { 104 | return queue_.size(); 105 | } 106 | 107 | size_t capacity() const override { 108 | return capacity_; 109 | } 110 | 111 | private: 112 | std::queue> queue_; 113 | size_t capacity_ { 0 }; 114 | }; 115 | 116 | std::shared_ptr CreateDefaultQueue(size_t capacity = 0); 117 | 118 | } // namespace concurrency 119 | } // namespace cnetpp 120 | 121 | #endif // CNETPP_CONCURRENCY_QUEUE_BASE_H_ 122 | -------------------------------------------------------------------------------- /src/cnetpp/concurrency/rwlock.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, myjfm(mwxjmmyjfm@gmail.com). All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are met: 5 | // 6 | // * Redistributions of source code must retain the above copyright notice, 7 | // this list of conditions and the following disclaimer. 8 | // * Redistributions in binary form must reproduce the above copyright notice, 9 | // this list of conditions and the following disclaimer in the documentation 10 | // and/or other materials provided with the distribution. 11 | // * Neither the name of myjfm nor the names of other contributors may be 12 | // used to endorse or promote products derived from this software without 13 | // specific prior written permission. 14 | // 15 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | // CONTRACT, STRICT LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) 24 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | // POSSIBILITY OF SUCH DAMAGE. 26 | // 27 | #include 28 | 29 | namespace cnetpp { 30 | namespace concurrency { 31 | 32 | #if _POSIX_VERSION >= 199506L && defined(_POSIX_THREADS) 33 | #define ASSERT_FUNC(func) do { assert(!func(&lock_)); } while (0) 34 | 35 | RWLock::RWLock() { 36 | pthread_rwlock_init(&lock_, nullptr); 37 | } 38 | 39 | RWLock::~RWLock() { 40 | ASSERT_FUNC(pthread_rwlock_destroy); 41 | } 42 | 43 | void RWLock::RDLock() { 44 | ASSERT_FUNC(pthread_rwlock_rdlock); 45 | } 46 | 47 | void RWLock::WRLock() { 48 | ASSERT_FUNC(pthread_rwlock_wrlock); 49 | } 50 | 51 | void RWLock::RDUnlock() { 52 | ASSERT_FUNC(pthread_rwlock_unlock); 53 | } 54 | void RWLock::WRUnlock() { 55 | ASSERT_FUNC(pthread_rwlock_unlock); 56 | } 57 | 58 | #undef ASSERT_FUNC 59 | #else 60 | RWLock::RWLock() : reader_count_(0) { 61 | } 62 | 63 | RWLock::~RWLock() { 64 | } 65 | 66 | void RWLock::RDLock() { 67 | std::unique_lock reader_count_guard(reader_count_mutex_); 68 | if (++reader_count_ == 1) { 69 | mutex_.lock(); 70 | } 71 | } 72 | 73 | void RWLock::RDUnlock() { 74 | std::unique_lock reader_count_guard(reader_count_mutex_); 75 | if (--reader_count_ == 0) { 76 | mutex_.unlock(); 77 | } 78 | } 79 | 80 | void RWLock::WRLock() { 81 | mutex_.lock(); 82 | } 83 | 84 | void RWLock::WRUnlock() { 85 | mutex_.unlock(); 86 | } 87 | #endif // _POSIX_VERSION >= 199506L && defined(_POSIX_THREADS) 88 | 89 | } // namespace concurrency 90 | } // namespace cnetpp 91 | 92 | -------------------------------------------------------------------------------- /src/cnetpp/concurrency/rwlock.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, myjfm(mwxjmmyjfm@gmail.com). All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are met: 5 | // 6 | // * Redistributions of source code must retain the above copyright notice, 7 | // this list of conditions and the following disclaimer. 8 | // * Redistributions in binary form must reproduce the above copyright notice, 9 | // this list of conditions and the following disclaimer in the documentation 10 | // and/or other materials provided with the distribution. 11 | // * Neither the name of myjfm nor the names of other contributors may be 12 | // used to endorse or promote products derived from this software without 13 | // specific prior written permission. 14 | // 15 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | // CONTRACT, STRICT LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) 24 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | // POSSIBILITY OF SUCH DAMAGE. 26 | // 27 | #ifndef CNETPP_CONCURRENCY_RWLOCK_H_ 28 | #define CNETPP_CONCURRENCY_RWLOCK_H_ 29 | 30 | #include 31 | 32 | #if _POSIX_VERSION >= 199506L && defined(_POSIX_THREADS) 33 | #include // wrap up the pthread_rwlock_t 34 | #else 35 | #include // use std::mutex to simulate the rwlock 36 | #endif 37 | 38 | namespace cnetpp { 39 | namespace concurrency { 40 | 41 | class RWLock final { 42 | public: 43 | class ReadScopeGuard final { 44 | public: 45 | explicit ReadScopeGuard(RWLock& lock) : lock_(lock) { 46 | lock_.RDLock(); 47 | } 48 | 49 | ~ReadScopeGuard() { 50 | lock_.RDUnlock(); 51 | } 52 | 53 | // disallow copy and move operations 54 | ReadScopeGuard(const ReadScopeGuard&) = delete; 55 | ReadScopeGuard& operator=(const ReadScopeGuard&) = delete; 56 | ReadScopeGuard(ReadScopeGuard&&) noexcept = delete; 57 | ReadScopeGuard& operator=(ReadScopeGuard&&) noexcept = delete; 58 | 59 | private: 60 | RWLock& lock_; 61 | }; 62 | 63 | class WriteScopeGuard final { 64 | public: 65 | explicit WriteScopeGuard(RWLock& lock) : lock_(lock) { 66 | lock_.WRLock(); 67 | } 68 | 69 | ~WriteScopeGuard() { 70 | lock_.WRUnlock(); 71 | } 72 | 73 | // disallow copy and move operations 74 | WriteScopeGuard(const WriteScopeGuard&) = delete; 75 | WriteScopeGuard& operator=(const WriteScopeGuard&) = delete; 76 | WriteScopeGuard(WriteScopeGuard&&) noexcept = delete; 77 | WriteScopeGuard& operator=(WriteScopeGuard&&) noexcept = delete; 78 | 79 | private: 80 | RWLock& lock_; 81 | }; 82 | 83 | RWLock(); 84 | ~RWLock(); 85 | 86 | // disallow copy and move operations 87 | RWLock(const RWLock&) = delete; 88 | RWLock& operator=(const RWLock&) = delete; 89 | RWLock(RWLock&&) noexcept = delete; 90 | RWLock& operator=(RWLock&&) noexcept = delete; 91 | 92 | void RDLock(); 93 | void RDUnlock(); 94 | 95 | void WRLock(); 96 | void WRUnlock(); 97 | 98 | private: 99 | #if _POSIX_VERSION >= 199506L && defined(_POSIX_THREADS) 100 | pthread_rwlock_t lock_; 101 | #else 102 | std::mutex mutex_; 103 | int reader_count_; 104 | std::mutex reader_count_mutex_; 105 | #endif 106 | }; 107 | 108 | } // namespace concurrency 109 | } // namespace cnetpp 110 | 111 | #endif // CNETPP_CONCURRENCY_RWLOCK_H_ 112 | -------------------------------------------------------------------------------- /src/cnetpp/concurrency/spin_lock.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, myjfm(mwxjmmyjfm@gmail.com). All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are met: 5 | // 6 | // * Redistributions of source code must retain the above copyright notice, 7 | // this list of conditions and the following disclaimer. 8 | // * Redistributions in binary form must reproduce the above copyright notice, 9 | // this list of conditions and the following disclaimer in the documentation 10 | // and/or other materials provided with the distribution. 11 | // * Neither the name of myjfm nor the names of other contributors may be 12 | // used to endorse or promote products derived from this software without 13 | // specific prior written permission. 14 | // 15 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | // CONTRACT, STRICT LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) 24 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | // POSSIBILITY OF SUCH DAMAGE. 26 | // 27 | #ifndef CNETPP_CONCURRENCY_SPIN_LOCK_H_ 28 | #define CNETPP_CONCURRENCY_SPIN_LOCK_H_ 29 | 30 | #include 31 | 32 | #include 33 | #include 34 | 35 | namespace cnetpp { 36 | namespace concurrency { 37 | 38 | class SpinLock final { 39 | public: 40 | class ScopeGuard final { 41 | public: 42 | explicit ScopeGuard(SpinLock& lock) : lock_(lock) { 43 | lock_.Lock(); 44 | } 45 | 46 | ~ScopeGuard() { 47 | lock_.Unlock(); 48 | } 49 | 50 | // disallow copy and move operations 51 | ScopeGuard(const ScopeGuard&) = delete; 52 | ScopeGuard& operator=(const ScopeGuard&) = delete; 53 | ScopeGuard(ScopeGuard&&) noexcept = delete; 54 | ScopeGuard& operator=(ScopeGuard&&) noexcept = delete; 55 | 56 | private: 57 | SpinLock& lock_; 58 | }; 59 | 60 | SpinLock() { 61 | flag_.clear(std::memory_order_release); 62 | } 63 | 64 | ~SpinLock() = default; 65 | 66 | void Lock() { 67 | auto i = 0; 68 | auto dummy = 0; 69 | while (!TryLock()) { 70 | i++; 71 | if (i < 16) { 72 | continue; 73 | } else if (i < 32) { 74 | dummy = i; 75 | dummy++; 76 | } else { 77 | std::this_thread::yield(); // schedule this thread again 78 | } 79 | } 80 | } 81 | 82 | bool TryLock() { 83 | return !flag_.test_and_set(std::memory_order_acquire); 84 | } 85 | 86 | void Unlock() { 87 | flag_.clear(std::memory_order_release); 88 | } 89 | 90 | // disallow copy and move operations 91 | SpinLock(const SpinLock&) = delete; 92 | SpinLock& operator=(const SpinLock&) = delete; 93 | SpinLock(SpinLock&&) noexcept = delete; 94 | SpinLock& operator=(SpinLock&&) noexcept = delete; 95 | 96 | private: 97 | std::atomic_flag flag_; 98 | }; 99 | 100 | } // namespace concurrency 101 | } // namespace cnetpp 102 | 103 | #endif // CNETPP_CONCURRENCY_SPIN_LOCK_H_ 104 | -------------------------------------------------------------------------------- /src/cnetpp/concurrency/task.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, myjfm(mwxjmmyjfm@gmail.com). All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are met: 5 | // 6 | // * Redistributions of source code must retain the above copyright notice, 7 | // this list of conditions and the following disclaimer. 8 | // * Redistributions in binary form must reproduce the above copyright notice, 9 | // this list of conditions and the following disclaimer in the documentation 10 | // and/or other materials provided with the distribution. 11 | // * Neither the name of myjfm nor the names of other contributors may be 12 | // used to endorse or promote products derived from this software without 13 | // specific prior written permission. 14 | // 15 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | // CONTRACT, STRICT LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) 24 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | // POSSIBILITY OF SUCH DAMAGE. 26 | // 27 | #ifndef CNETPP_CONCURRENCY_TASK_H_ 28 | #define CNETPP_CONCURRENCY_TASK_H_ 29 | 30 | #include 31 | #include 32 | 33 | namespace cnetpp { 34 | namespace concurrency { 35 | 36 | // we use this functor class as entity of thread 37 | class Task { 38 | public: 39 | virtual ~Task() = default; 40 | 41 | // the executer 42 | virtual bool operator()(void* arg = nullptr) = 0; 43 | 44 | virtual void Stop() { 45 | stop_.store(true, std::memory_order_release); 46 | } 47 | 48 | bool IsStopped() { 49 | return stop_.load(std::memory_order_acquire); 50 | } 51 | 52 | protected: 53 | std::atomic stop_ { false }; 54 | }; 55 | 56 | } // namespace concurrency 57 | } // namespace cnetpp 58 | 59 | #endif // CNETPP_CONCURRENCY_TASK_H_ 60 | 61 | -------------------------------------------------------------------------------- /src/cnetpp/concurrency/this_thread.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, myjfm(mwxjmmyjfm@gmail.com). All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are met: 5 | // 6 | // * Redistributions of source code must retain the above copyright notice, 7 | // this list of conditions and the following disclaimer. 8 | // * Redistributions in binary form must reproduce the above copyright notice, 9 | // this list of conditions and the following disclaimer in the documentation 10 | // and/or other materials provided with the distribution. 11 | // * Neither the name of myjfm nor the names of other contributors may be 12 | // used to endorse or promote products derived from this software without 13 | // specific prior written permission. 14 | // 15 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | // CONTRACT, STRICT LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) 24 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | // POSSIBILITY OF SUCH DAMAGE. 26 | // 27 | #include 28 | 29 | #include 30 | #include 31 | #include 32 | #if defined(linux) || defined(__linux) || defined(__linux__) 33 | #include 34 | #elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) 35 | #include 36 | #endif 37 | #include 38 | 39 | namespace cnetpp { 40 | namespace concurrency { 41 | 42 | int ThisThread::GetId() { 43 | static thread_local pid_t tid = 0; 44 | if (tid == 0) { 45 | #if defined(linux) || defined(__linux) || defined(__linux__) 46 | #ifndef __NR_gettid 47 | #define __NR_gettid 224 48 | #endif 49 | tid = syscall(__NR_gettid); 50 | #endif 51 | if (tid <= 0) { 52 | #if defined(linux) || defined(__linux) || defined(__linux__) 53 | tid = getpid(); 54 | #elif defined(WIN32) || defined(_WIN32) || defined(__WIN32__) 55 | tid = GetCurrentThreadId(); 56 | #else 57 | tid = (pid_t)(uintptr_t)pthread_self(); 58 | #endif 59 | } 60 | } 61 | return tid; 62 | } 63 | 64 | int ThisThread::GetLastError() { 65 | return errno; // thraed local variable 66 | } 67 | 68 | void ThisThread::SetLastError(int err) { 69 | errno = err; 70 | } 71 | 72 | std::string ThisThread::GetLastErrorString() { 73 | char buffer[256]; 74 | if (strerror_r(errno, buffer, 256) != 0) { 75 | return "Unknown errno: " + std::to_string(errno); 76 | } 77 | return buffer; 78 | } 79 | 80 | std::string ThisThread::GetErrorString(int err) { 81 | char buffer[256]; 82 | if (strerror_r(err, buffer, 256) != 0) { 83 | return "Unknown errno: " + std::to_string(err); 84 | } 85 | return buffer; 86 | } 87 | 88 | } // namespace concurrency 89 | } // namespace cnetpp 90 | -------------------------------------------------------------------------------- /src/cnetpp/concurrency/this_thread.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, myjfm(mwxjmmyjfm@gmail.com). All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are met: 5 | // 6 | // * Redistributions of source code must retain the above copyright notice, 7 | // this list of conditions and the following disclaimer. 8 | // * Redistributions in binary form must reproduce the above copyright notice, 9 | // this list of conditions and the following disclaimer in the documentation 10 | // and/or other materials provided with the distribution. 11 | // * Neither the name of myjfm nor the names of other contributors may be 12 | // used to endorse or promote products derived from this software without 13 | // specific prior written permission. 14 | // 15 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | // CONTRACT, STRICT LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) 24 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | // POSSIBILITY OF SUCH DAMAGE. 26 | // 27 | #ifndef CNETPP_CONCURRENCY_THIS_THREAD_H_ 28 | #define CNETPP_CONCURRENCY_THIS_THREAD_H_ 29 | 30 | #include 31 | #include 32 | #include 33 | 34 | #include 35 | #include 36 | 37 | namespace cnetpp { 38 | namespace concurrency { 39 | 40 | class ThisThread { 41 | public: 42 | // this method can get the thread id with int type 43 | static int GetId(); 44 | 45 | static int GetLastError(); 46 | 47 | static void SetLastError(int err); 48 | 49 | static std::string GetLastErrorString(); 50 | 51 | static std::string GetErrorString(int err); 52 | }; 53 | 54 | } // namespace concurrency 55 | } // namespace cnetpp 56 | 57 | #endif // CNETPP_CONCURRENCY_THIS_THREAD_H_ 58 | 59 | -------------------------------------------------------------------------------- /src/cnetpp/concurrency/thread.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, myjfm(mwxjmmyjfm@gmail.com). All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are met: 5 | // 6 | // * Redistributions of source code must retain the above copyright notice, 7 | // this list of conditions and the following disclaimer. 8 | // * Redistributions in binary form must reproduce the above copyright notice, 9 | // this list of conditions and the following disclaimer in the documentation 10 | // and/or other materials provided with the distribution. 11 | // * Neither the name of myjfm nor the names of other contributors may be 12 | // used to endorse or promote products derived from this software without 13 | // specific prior written permission. 14 | // 15 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | // CONTRACT, STRICT LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) 24 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | // POSSIBILITY OF SUCH DAMAGE. 26 | // 27 | #include 28 | #include 29 | 30 | #include 31 | 32 | #include 33 | 34 | namespace cnetpp { 35 | namespace concurrency { 36 | 37 | namespace { 38 | thread_local Thread* cnetpp_current_thread = nullptr; 39 | } 40 | 41 | std::atomic Thread::cnetpp_max_thread_index_{0}; 42 | 43 | Thread::Thread(std::shared_ptr task, const std::string& name) 44 | : name_(name), task_(std::move(task)) { 45 | if (name_.length() > kMaxNameLength) { 46 | CnetppFatal("Thread name is too long: %s", name_.c_str()); 47 | } 48 | thread_index_ = cnetpp_max_thread_index_.fetch_add(1); 49 | thread_pool_index_ = -1; 50 | } 51 | 52 | Thread::Thread(const std::function& closure, const std::string& name) 53 | : Thread(std::static_pointer_cast( 54 | std::make_shared(closure)), name) { 55 | } 56 | 57 | Thread::~Thread() { 58 | Stop(); 59 | } 60 | 61 | void Thread::Start() { 62 | if (!task_.get()) { 63 | CnetppFatal("task_ is null, please pass a valid task!"); 64 | } 65 | 66 | Status old = Status::kInit; 67 | if (!status_.compare_exchange_strong(old, Status::kRunning)) { 68 | CnetppFatal("Failed to start thread, invalid thread status: %d", 69 | static_cast(old)); 70 | } 71 | 72 | if (thread_.get()) { 73 | CnetppFatal("thread_ is not null, there must be something wrong."); 74 | } 75 | 76 | thread_ = std::make_unique([this] () { 77 | #if defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) 78 | pthread_setname_np(name_.c_str()); 79 | #else 80 | pthread_setname_np(pthread_self(), name_.c_str()); 81 | #endif 82 | cnetpp_current_thread = this; 83 | (*task_)(); 84 | }); 85 | } 86 | 87 | void Thread::Stop() { 88 | Status old = Status::kRunning; 89 | if (!status_.compare_exchange_strong(old, Status::kStop)) { 90 | return; 91 | } 92 | 93 | task_->Stop(); 94 | 95 | if (thread_->joinable()) { 96 | thread_->join(); 97 | } 98 | thread_.reset(); 99 | } 100 | 101 | void Thread::Join() { 102 | if (!thread_.get()) { 103 | return; 104 | } 105 | 106 | if (!IsJoinable()) { 107 | CnetppFatal("The thread is not joinable!"); 108 | } 109 | thread_->join(); 110 | thread_.reset(); 111 | status_.store(Status::kStop, std::memory_order_release); 112 | } 113 | 114 | void Thread::SetThreadPoolIndex(int index) { 115 | thread_pool_index_ = index; 116 | } 117 | 118 | int Thread::ThreadPoolIndex() const { 119 | return thread_pool_index_; 120 | } 121 | 122 | int Thread::ThreadIndex() const { 123 | return thread_index_; 124 | } 125 | 126 | const Thread* Thread::ThisThread() { 127 | return cnetpp_current_thread; 128 | } 129 | 130 | int Thread::MaxThreadIndex() { 131 | return cnetpp_max_thread_index_; 132 | } 133 | 134 | } // namespace concurrency 135 | } // namespace cnetpp 136 | 137 | -------------------------------------------------------------------------------- /src/cnetpp/concurrency/thread.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, myjfm(mwxjmmyjfm@gmail.com). All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are met: 5 | // 6 | // * Redistributions of source code must retain the above copyright notice, 7 | // this list of conditions and the following disclaimer. 8 | // * Redistributions in binary form must reproduce the above copyright notice, 9 | // this list of conditions and the following disclaimer in the documentation 10 | // and/or other materials provided with the distribution. 11 | // * Neither the name of myjfm nor the names of other contributors may be 12 | // used to endorse or promote products derived from this software without 13 | // specific prior written permission. 14 | // 15 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | // CONTRACT, STRICT LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) 24 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | // POSSIBILITY OF SUCH DAMAGE. 26 | // 27 | #ifndef CNETPP_CONCURRENCY_THREAD_H_ 28 | #define CNETPP_CONCURRENCY_THREAD_H_ 29 | 30 | #include 31 | #include 32 | 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | namespace cnetpp { 39 | namespace concurrency { 40 | 41 | // DO NOT inherit it, instead, inherit the Task interface 42 | class Thread final { 43 | public: 44 | using Id = std::thread::id; 45 | static const size_t kMaxNameLength = 16; 46 | 47 | enum class Status : int { 48 | kInit = 0x0, 49 | kRunning = 0x1, 50 | kStop = 0x3, 51 | }; 52 | 53 | explicit Thread(std::shared_ptr task, 54 | const std::string& name = ""); 55 | explicit Thread(const std::function& closure, 56 | const std::string& name = ""); 57 | 58 | ~Thread(); 59 | 60 | Thread(const Thread&) = delete; 61 | Thread& operator=(const Thread&) = delete; 62 | 63 | Status GetStatus() const noexcept { 64 | return status_.load(std::memory_order_acquire); 65 | } 66 | 67 | void Start(); 68 | 69 | void Stop(); 70 | 71 | const std::string& name() const { 72 | return name_; 73 | } 74 | 75 | Id GetId() const noexcept { 76 | return thread_->get_id(); 77 | } 78 | 79 | void Join(); 80 | 81 | // check whether this thread is joinable 82 | bool IsJoinable() const noexcept { 83 | return thread_->joinable(); 84 | } 85 | 86 | void SetThreadPoolIndex(int index); 87 | // index in thread pool, if not belong to any thread pool, 88 | // below will return -1 89 | int ThreadPoolIndex() const; 90 | int ThreadIndex() const; 91 | // current allocated max threads 92 | static int MaxThreadIndex(); 93 | // use below method in thread, otherwise will return nullptr 94 | static const Thread* ThisThread(); 95 | private: 96 | class InternalTask : public Task { 97 | public: 98 | InternalTask(const std::function& closure) : closure_(closure) { 99 | } 100 | 101 | ~InternalTask() = default; 102 | 103 | bool operator()(void* arg = nullptr) override { 104 | (void) arg; 105 | return closure_(); 106 | } 107 | 108 | private: 109 | std::function closure_; 110 | }; 111 | 112 | int thread_index_; 113 | int thread_pool_index_; 114 | 115 | std::string name_; 116 | 117 | std::shared_ptr task_; 118 | 119 | std::unique_ptr thread_; 120 | 121 | std::atomic status_ { Status::kInit }; 122 | private: 123 | static std::atomic cnetpp_max_thread_index_; 124 | }; 125 | 126 | } // namespace concurrency 127 | } // namespace cnetpp 128 | 129 | #endif // CNETPP_CONCURRENCY_THREAD_H_ 130 | 131 | -------------------------------------------------------------------------------- /src/cnetpp/concurrency/thread_pool.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, myjfm(mwxjmmyjfm@gmail.com). All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are met: 5 | // 6 | // * Redistributions of source code must retain the above copyright notice, 7 | // this list of conditions and the following disclaimer. 8 | // * Redistributions in binary form must reproduce the above copyright notice, 9 | // this list of conditions and the following disclaimer in the documentation 10 | // and/or other materials provided with the distribution. 11 | // * Neither the name of myjfm nor the names of other contributors may be 12 | // used to endorse or promote products derived from this software without 13 | // specific prior written permission. 14 | // 15 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | // CONTRACT, STRICT LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) 24 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | // POSSIBILITY OF SUCH DAMAGE. 26 | // 27 | #ifndef CNETPP_CONCURRENCY_THREAD_POOL_H_ 28 | #define CNETPP_CONCURRENCY_THREAD_POOL_H_ 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | #include 37 | #include 38 | #include 39 | #include 40 | 41 | namespace cnetpp { 42 | namespace concurrency { 43 | 44 | class ThreadPool final { 45 | public: 46 | explicit ThreadPool(const std::string& name); 47 | ThreadPool(const std::string& name, std::shared_ptr queue); 48 | ThreadPool(const std::string& name, bool enable_delay); 49 | ThreadPool(const std::string& name, std::shared_ptr queue, 50 | bool enable_delay); 51 | 52 | ~ThreadPool() { 53 | Stop(false); 54 | } 55 | 56 | // disallow copy and move operations 57 | ThreadPool(const ThreadPool&) = delete; 58 | ThreadPool& operator=(const ThreadPool&) = delete; 59 | 60 | void set_num_threads(size_t num) { 61 | assert(status_.load(std::memory_order_acquire) == Status::kInit); 62 | threads_.resize((num == 0) ? 1 : num); 63 | } 64 | 65 | void set_max_num_pending_tasks(size_t num) { 66 | max_num_pending_tasks_ = num; 67 | } 68 | 69 | // start all threads in this thread pool 70 | void Start(); 71 | 72 | // stop all threads in this thread pool 73 | void Stop(bool wait = false); 74 | 75 | size_t PendingCount() const; 76 | 77 | size_t NumRunningTasks() const { 78 | return num_running_tasks_.load(); 79 | } 80 | 81 | // add a task into the queue and one of the threads in the pool will run it 82 | bool AddTask(std::shared_ptr task); 83 | bool AddTask(const std::function& closure); 84 | 85 | bool AddDelayTask(std::shared_ptr task, 86 | std::chrono::microseconds delay); 87 | bool AddDelayTask(const std::function& closure, 88 | std::chrono::microseconds delay); 89 | 90 | size_t size() const { 91 | return threads_.size(); 92 | } 93 | 94 | private: 95 | enum class Status : int { 96 | kInit = 0x0, 97 | kRunning = 0x1, 98 | kStop = 0x2, 99 | }; 100 | 101 | std::string name_; 102 | 103 | std::atomic status_ { Status::kInit }; 104 | 105 | std::atomic stopping_ { false }; 106 | std::atomic force_stop_ { false }; 107 | 108 | size_t max_num_pending_tasks_ { 0 }; 109 | 110 | std::mutex mutex_; 111 | std::condition_variable queue_cv_; 112 | std::shared_ptr queue_; 113 | std::atomic num_running_tasks_ { 0 }; 114 | 115 | std::vector> threads_; 116 | 117 | class DelayTask : public Task { 118 | public: 119 | DelayTask(std::shared_ptr task, std::chrono::microseconds delay) 120 | : task_(std::move(task)), 121 | run_time_(std::chrono::system_clock::now() + delay) { 122 | } 123 | 124 | bool operator()(void* arg = nullptr) override { 125 | (void) arg; 126 | assert(task_); 127 | return (*task_)(); 128 | } 129 | 130 | void Stop() override { 131 | Task::Stop(); 132 | task_->Stop(); 133 | } 134 | 135 | struct Comparator { 136 | bool operator() (const std::shared_ptr& x, 137 | const std::shared_ptr& y) const { 138 | auto xx = std::static_pointer_cast(x); 139 | auto yy = std::static_pointer_cast(y); 140 | return xx->run_time_ > yy->run_time_; 141 | } 142 | }; 143 | std::shared_ptr task_; 144 | std::chrono::system_clock::time_point run_time_; 145 | }; 146 | 147 | using DelayQueue = PriorityQueue; 148 | 149 | bool enable_delay_ { false }; 150 | std::unique_ptr delay_thread_; 151 | std::condition_variable delay_queue_cv_; 152 | std::unique_ptr delay_queue_; 153 | 154 | void DoTask(); 155 | 156 | void PollDelayTask(); 157 | }; 158 | 159 | } // namespace concurrency 160 | } // namespace cnetpp 161 | 162 | #endif // CNETPP_CONCURRENCY_THREAD_POOL_H_ 163 | 164 | -------------------------------------------------------------------------------- /src/cnetpp/http/http_base.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, myjfm(mwxjmmyjfm@gmail.com). All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are met: 5 | // 6 | // * Redistributions of source code must retain the above copyright notice, 7 | // this list of conditions and the following disclaimer. 8 | // * Redistributions in binary form must reproduce the above copyright notice, 9 | // this list of conditions and the following disclaimer in the documentation 10 | // and/or other materials provided with the distribution. 11 | // * Neither the name of myjfm nor the names of other contributors may be 12 | // used to endorse or promote products derived from this software without 13 | // specific prior written permission. 14 | // 15 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | // CONTRACT, STRICT LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) 24 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | // POSSIBILITY OF SUCH DAMAGE. 26 | // 27 | #include 28 | #include 29 | #include 30 | 31 | namespace cnetpp { 32 | namespace http { 33 | 34 | void HttpBase::SetCallbacks(tcp::TcpOptions& tcp_options) { 35 | tcp_options.set_connected_callback( 36 | [this] (std::shared_ptr c) -> bool { 37 | return this->OnConnected(c); 38 | } 39 | ); 40 | tcp_options.set_closed_callback( 41 | [this] (std::shared_ptr c) -> bool { 42 | return this->OnClosed(c); 43 | } 44 | ); 45 | tcp_options.set_received_callback( 46 | [this] (std::shared_ptr c) -> bool { 47 | return this->OnReceived(c); 48 | } 49 | ); 50 | tcp_options.set_sent_callback( 51 | [this] (bool sent, std::shared_ptr c) -> bool { 52 | return this->OnSent(sent, c); 53 | } 54 | ); 55 | } 56 | 57 | bool HttpBase::OnConnected(std::shared_ptr tcp_connection) { 58 | assert(tcp_connection.get()); 59 | 60 | auto http_connection = std::make_shared(tcp_connection); 61 | http_connections_mutex_.lock(); 62 | http_connections_[tcp_connection->id()] = http_connection; 63 | http_connections_mutex_.unlock(); 64 | HandleConnected(http_connection); 65 | 66 | return http_connection->OnConnected(); 67 | } 68 | 69 | bool HttpBase::OnReceived(std::shared_ptr tcp_connection) { 70 | assert(tcp_connection.get()); 71 | http_connections_mutex_.lock(); 72 | auto itr = http_connections_.find(tcp_connection->id()); 73 | assert(itr != http_connections_.end()); 74 | auto http_connection = itr->second; 75 | http_connections_mutex_.unlock(); 76 | return http_connection->OnReceived(); 77 | } 78 | 79 | bool HttpBase::OnSent(bool success, 80 | std::shared_ptr tcp_connection) { 81 | assert(tcp_connection.get()); 82 | http_connections_mutex_.lock(); 83 | auto itr = http_connections_.find(tcp_connection->id()); 84 | assert(itr != http_connections_.end()); 85 | auto http_connection = itr->second; 86 | http_connections_mutex_.unlock(); 87 | return http_connection->OnSent(success); 88 | } 89 | 90 | bool HttpBase::OnClosed(std::shared_ptr tcp_connection) { 91 | assert(tcp_connection.get()); 92 | 93 | http_connections_mutex_.lock(); 94 | auto itr = http_connections_.find(tcp_connection->id()); 95 | // the connection might haven't established. 96 | if (itr == http_connections_.end()) { 97 | http_connections_mutex_.unlock(); 98 | auto http_options = 99 | std::static_pointer_cast(tcp_connection->cookie()); 100 | if (http_options->closed_callback()) { 101 | return http_options->closed_callback()(std::shared_ptr()); 102 | } 103 | return true; 104 | } 105 | auto http_connection = itr->second; 106 | http_connections_.erase(itr); 107 | http_connections_mutex_.unlock(); 108 | bool ret = http_connection->OnClosed(); 109 | return ret; 110 | } 111 | 112 | } // namespace http 113 | } // namespace cnetpp 114 | 115 | -------------------------------------------------------------------------------- /src/cnetpp/http/http_base.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, myjfm(mwxjmmyjfm@gmail.com). All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are met: 5 | // 6 | // * Redistributions of source code must retain the above copyright notice, 7 | // this list of conditions and the following disclaimer. 8 | // * Redistributions in binary form must reproduce the above copyright notice, 9 | // this list of conditions and the following disclaimer in the documentation 10 | // and/or other materials provided with the distribution. 11 | // * Neither the name of myjfm nor the names of other contributors may be 12 | // used to endorse or promote products derived from this software without 13 | // specific prior written permission. 14 | // 15 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | // CONTRACT, STRICT LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) 24 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | // POSSIBILITY OF SUCH DAMAGE. 26 | // 27 | #ifndef CNETPP_HTTP_HTTP_BASE_H_ 28 | #define CNETPP_HTTP_HTTP_BASE_H_ 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | #include 36 | #include 37 | #include 38 | 39 | namespace cnetpp { 40 | namespace http { 41 | 42 | class HttpBase { 43 | public: 44 | HttpBase() = default; 45 | virtual ~HttpBase() { 46 | } 47 | 48 | HttpBase(const HttpBase&) = delete; 49 | HttpBase& operator=(const HttpBase&) = delete; 50 | 51 | bool Shutdown() { 52 | if (!DoShutdown()) { 53 | return false; 54 | } 55 | http_connections_.clear(); 56 | return true; 57 | } 58 | 59 | protected: 60 | std::unordered_map > http_connections_; 62 | std::mutex http_connections_mutex_; 63 | 64 | void SetCallbacks(tcp::TcpOptions& tcp_options); 65 | 66 | virtual bool DoShutdown() = 0; 67 | 68 | virtual bool HandleConnected( 69 | std::shared_ptr http_connection) = 0; 70 | 71 | virtual bool OnConnected( 72 | std::shared_ptr tcp_connection); 73 | 74 | virtual bool OnReceived(std::shared_ptr tcp_connection); 75 | 76 | virtual bool OnSent(bool success, 77 | std::shared_ptr tcp_connection); 78 | 79 | virtual bool OnClosed(std::shared_ptr tcp_connection); 80 | }; 81 | 82 | } // namespace http 83 | } // namespace cnetpp 84 | 85 | #endif // CNETPP_HTTP_HTTP_BASE_H_ 86 | 87 | -------------------------------------------------------------------------------- /src/cnetpp/http/http_callbacks.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, myjfm(mwxjmmyjfm@gmail.com). All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are met: 5 | // 6 | // * Redistributions of source code must retain the above copyright notice, 7 | // this list of conditions and the following disclaimer. 8 | // * Redistributions in binary form must reproduce the above copyright notice, 9 | // this list of conditions and the following disclaimer in the documentation 10 | // and/or other materials provided with the distribution. 11 | // * Neither the name of myjfm nor the names of other contributors may be 12 | // used to endorse or promote products derived from this software without 13 | // specific prior written permission. 14 | // 15 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | // CONTRACT, STRICT LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) 24 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | // POSSIBILITY OF SUCH DAMAGE. 26 | // 27 | #ifndef CNETPP_HTTP_HTTP_CALLBACKS_H_ 28 | #define CNETPP_HTTP_HTTP_CALLBACKS_H_ 29 | 30 | #include 31 | #include 32 | 33 | namespace cnetpp { 34 | namespace http { 35 | 36 | class HttpConnection; 37 | 38 | using ConnectedCallbackType = 39 | std::function)>; 40 | using ClosedCallbackType = std::function)>; 41 | using ReceivedCallbackType = 42 | std::function)>; 43 | using SentCallbackType = 44 | std::function)>; 45 | 46 | } // namespace http 47 | } // namespace cnetpp 48 | 49 | #endif // CNETPP_HTTP_CALLBACKS_H_ 50 | 51 | -------------------------------------------------------------------------------- /src/cnetpp/http/http_client.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, myjfm(mwxjmmyjfm@gmail.com). All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are met: 5 | // 6 | // * Redistributions of source code must retain the above copyright notice, 7 | // this list of conditions and the following disclaimer. 8 | // * Redistributions in binary form must reproduce the above copyright notice, 9 | // this list of conditions and the following disclaimer in the documentation 10 | // and/or other materials provided with the distribution. 11 | // * Neither the name of myjfm nor the names of other contributors may be 12 | // used to endorse or promote products derived from this software without 13 | // specific prior written permission. 14 | // 15 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | // CONTRACT, STRICT LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) 24 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | // POSSIBILITY OF SUCH DAMAGE. 26 | // 27 | #include 28 | #include 29 | #include 30 | 31 | #include 32 | 33 | namespace cnetpp { 34 | namespace http { 35 | 36 | tcp::ConnectionId HttpClient::Connect(const base::EndPoint* remote, 37 | const HttpClientOptions& http_options) { 38 | auto new_http_options = 39 | std::shared_ptr(new HttpClientOptions(http_options)); 40 | return DoConnect(remote, new_http_options); 41 | } 42 | 43 | tcp::ConnectionId HttpClient::DoConnect( 44 | const base::EndPoint* remote, 45 | std::shared_ptr http_options) { 46 | tcp::TcpClientOptions options; 47 | options.set_send_buffer_size(http_options->send_buffer_size()); 48 | options.set_receive_buffer_size(http_options->receive_buffer_size()); 49 | SetCallbacks(options); 50 | auto new_http_options = std::static_pointer_cast(http_options); 51 | return tcp_client_.Connect(remote, options, new_http_options); 52 | } 53 | 54 | tcp::ConnectionId HttpClient::Connect(base::StringPiece url_str, 55 | const HttpClientOptions& http_options) { 56 | std::string url_with_scheme = ""; 57 | if (!url_str.starts_with("http")) { 58 | url_with_scheme.append("http://"); 59 | } 60 | url_with_scheme.append(url_str.data(), url_str.length()); 61 | // parse url 62 | base::Uri url; 63 | if (!url.Parse(url_with_scheme)) { 64 | return tcp::kInvalidConnectionId; 65 | } 66 | 67 | // resolve address of url 68 | struct addrinfo *presults = nullptr; 69 | struct addrinfo hint; 70 | bzero(&hint, sizeof(hint)); 71 | hint.ai_family = AF_UNSPEC; 72 | hint.ai_socktype = SOCK_STREAM; 73 | std::string port_str = std::to_string(url.Port()); 74 | if (getaddrinfo(url.Hostname().c_str(), 75 | port_str.c_str(), 76 | &hint, 77 | &presults) != 0 || 78 | !presults) { 79 | return tcp::kInvalidConnectionId; 80 | } 81 | base::EndPoint endpoint; 82 | // just pick the first item in presults as the ip address 83 | if (!endpoint.FromSockAddr(*presults->ai_addr, presults->ai_addrlen)) { 84 | freeaddrinfo(presults); 85 | return tcp::kInvalidConnectionId; 86 | } 87 | freeaddrinfo(presults); 88 | 89 | auto new_http_options = 90 | std::shared_ptr(new HttpClientOptions(http_options)); 91 | new_http_options->set_remote_hostname(url.Hostname()); 92 | 93 | // connect to server 94 | return DoConnect(&endpoint, new_http_options); 95 | } 96 | 97 | bool HttpClient::AsyncClose(tcp::ConnectionId connection_id) { 98 | return tcp_client_.AsyncClosed(connection_id); 99 | } 100 | 101 | bool HttpClient::HandleConnected( 102 | std::shared_ptr http_connection) { 103 | auto http_options = std::static_pointer_cast( 104 | http_connection->tcp_connection()->cookie()); 105 | http_connection->set_connected_callback(http_options->connected_callback()); 106 | http_connection->set_closed_callback(http_options->closed_callback()); 107 | http_connection->set_received_callback(http_options->received_callback()); 108 | http_connection->set_sent_callback(http_options->sent_callback()); 109 | if (!http_options->remote_hostname().empty()) { 110 | http_connection->set_remote_hostname(http_options->remote_hostname()); 111 | } 112 | http_connection->set_http_packet( 113 | std::shared_ptr(new HttpResponse)); 114 | return true; 115 | } 116 | 117 | } // namespace http 118 | } // namespace cnetpp 119 | 120 | -------------------------------------------------------------------------------- /src/cnetpp/http/http_client.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, myjfm(mwxjmmyjfm@gmail.com). All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are met: 5 | // 6 | // * Redistributions of source code must retain the above copyright notice, 7 | // this list of conditions and the following disclaimer. 8 | // * Redistributions in binary form must reproduce the above copyright notice, 9 | // this list of conditions and the following disclaimer in the documentation 10 | // and/or other materials provided with the distribution. 11 | // * Neither the name of myjfm nor the names of other contributors may be 12 | // used to endorse or promote products derived from this software without 13 | // specific prior written permission. 14 | // 15 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | // CONTRACT, STRICT LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) 24 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | // POSSIBILITY OF SUCH DAMAGE. 26 | // 27 | #ifndef CNETPP_HTTP_HTTP_CLIENT_H_ 28 | #define CNETPP_HTTP_HTTP_CLIENT_H_ 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | #include 37 | 38 | namespace cnetpp { 39 | namespace http { 40 | 41 | class HttpClient final : public HttpBase { 42 | public: 43 | HttpClient() = default; 44 | ~HttpClient() = default; 45 | 46 | bool Launch(const HttpClientOptions& http_options = HttpClientOptions()) { 47 | tcp::TcpClientOptions options; 48 | options.set_worker_count(http_options.worker_count()); 49 | return tcp_client_.Launch("hcli", options); 50 | } 51 | 52 | tcp::ConnectionId Connect(const base::EndPoint* remote, 53 | const HttpClientOptions& options); 54 | tcp::ConnectionId Connect(base::StringPiece url, 55 | const HttpClientOptions& options); 56 | 57 | bool AsyncClose(tcp::ConnectionId connection_id); 58 | 59 | private: 60 | tcp::TcpClient tcp_client_; 61 | 62 | tcp::ConnectionId DoConnect(const base::EndPoint* remote, 63 | std::shared_ptr http_options); 64 | 65 | bool DoShutdown() override { 66 | return tcp_client_.Shutdown(); 67 | } 68 | 69 | bool HandleConnected( 70 | std::shared_ptr http_connection) override; 71 | }; 72 | 73 | } // namespace http 74 | } // namespace cnetpp 75 | 76 | #endif // CNETPP_HTTP_HTTP_CLIENT_H_ 77 | 78 | -------------------------------------------------------------------------------- /src/cnetpp/http/http_options.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, myjfm(mwxjmmyjfm@gmail.com). All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are met: 5 | // 6 | // * Redistributions of source code must retain the above copyright notice, 7 | // this list of conditions and the following disclaimer. 8 | // * Redistributions in binary form must reproduce the above copyright notice, 9 | // this list of conditions and the following disclaimer in the documentation 10 | // and/or other materials provided with the distribution. 11 | // * Neither the name of myjfm nor the names of other contributors may be 12 | // used to endorse or promote products derived from this software without 13 | // specific prior written permission. 14 | // 15 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | // CONTRACT, STRICT LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) 24 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | // POSSIBILITY OF SUCH DAMAGE. 26 | // 27 | #ifndef CNETPP_HTTP_HTTP_OPTIONS_H_ 28 | #define CNETPP_HTTP_HTTP_OPTIONS_H_ 29 | 30 | #include 31 | 32 | namespace cnetpp { 33 | namespace http { 34 | 35 | class HttpOptions { 36 | public: 37 | HttpOptions() { 38 | } 39 | 40 | virtual ~HttpOptions() { 41 | } 42 | 43 | size_t worker_count() const { 44 | return worker_count_; 45 | } 46 | void set_worker_count(size_t worker_count) { 47 | worker_count_ = worker_count; 48 | } 49 | 50 | size_t tcp_send_buffer_size() const { 51 | return tcp_send_buffer_size_; 52 | } 53 | void set_tcp_send_buffer_size(size_t size) { 54 | tcp_send_buffer_size_ = size; 55 | } 56 | 57 | size_t tcp_receive_buffer_size() const { 58 | return tcp_receive_buffer_size_; 59 | } 60 | void set_tcp_receive_buffer_size(size_t size) { 61 | tcp_receive_buffer_size_ = size; 62 | } 63 | 64 | size_t send_buffer_size() const { 65 | return send_buffer_size_; 66 | } 67 | void set_send_buffer_size(size_t size) { 68 | send_buffer_size_ = size; 69 | } 70 | 71 | size_t receive_buffer_size() const { 72 | return receive_buffer_size_; 73 | } 74 | void set_receive_buffer_size(size_t size) { 75 | receive_buffer_size_ = size; 76 | } 77 | 78 | ConnectedCallbackType connected_callback() const { 79 | return connected_callback_; 80 | } 81 | void set_connected_callback(ConnectedCallbackType connected_callback) { 82 | connected_callback_ = connected_callback; 83 | } 84 | 85 | ClosedCallbackType closed_callback() const { 86 | return closed_callback_; 87 | } 88 | void set_closed_callback(ClosedCallbackType closed_callback) { 89 | closed_callback_ = closed_callback; 90 | } 91 | 92 | ReceivedCallbackType received_callback() const { 93 | return received_callback_; 94 | } 95 | void set_received_callback(ReceivedCallbackType received_callback) { 96 | received_callback_ = received_callback; 97 | } 98 | 99 | SentCallbackType sent_callback() const { 100 | return sent_callback_; 101 | } 102 | void set_sent_callback(SentCallbackType sent_callback) { 103 | sent_callback_ = sent_callback; 104 | } 105 | 106 | private: 107 | size_t worker_count_ { 0 }; 108 | size_t tcp_send_buffer_size_ {32 * 1024 }; 109 | size_t tcp_receive_buffer_size_ { 32 * 1024 }; 110 | size_t send_buffer_size_ { 0 }; 111 | size_t receive_buffer_size_ { 0 }; 112 | ConnectedCallbackType connected_callback_ { nullptr }; 113 | ClosedCallbackType closed_callback_ { nullptr }; 114 | ReceivedCallbackType received_callback_ { nullptr }; 115 | SentCallbackType sent_callback_ { nullptr }; 116 | }; 117 | 118 | class HttpClientOptions : public HttpOptions { 119 | public: 120 | HttpClientOptions() = default; 121 | ~HttpClientOptions() = default; 122 | 123 | const std::string& remote_hostname() const { 124 | return remote_hostname_; 125 | } 126 | void set_remote_hostname(const std::string& remote_hostname) { 127 | remote_hostname_ = remote_hostname; 128 | } 129 | void set_remote_hostname(std::string&& remote_hostname) { 130 | remote_hostname_ = std::move(remote_hostname); 131 | } 132 | 133 | private: 134 | std::string remote_hostname_; 135 | }; 136 | 137 | class HttpServerOptions : public HttpOptions { 138 | public: 139 | HttpServerOptions() = default; 140 | ~HttpServerOptions() = default; 141 | }; 142 | 143 | } // namespace http 144 | } // namespace cnetpp 145 | 146 | #endif // CNETPP_HTTP_HTTP_OPTIONS_H_ 147 | 148 | -------------------------------------------------------------------------------- /src/cnetpp/http/http_request.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, myjfm(mwxjmmyjfm@gmail.com). All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are met: 5 | // 6 | // * Redistributions of source code must retain the above copyright notice, 7 | // this list of conditions and the following disclaimer. 8 | // * Redistributions in binary form must reproduce the above copyright notice, 9 | // this list of conditions and the following disclaimer in the documentation 10 | // and/or other materials provided with the distribution. 11 | // * Neither the name of myjfm nor the names of other contributors may be 12 | // used to endorse or promote products derived from this software without 13 | // specific prior written permission. 14 | // 15 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | // CONTRACT, STRICT LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) 24 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | // POSSIBILITY OF SUCH DAMAGE. 26 | // 27 | #include 28 | #include 29 | 30 | namespace cnetpp { 31 | namespace http { 32 | 33 | // NOTE: The order must be consistent with enum values because GetMethodName 34 | // access this table by method_type enum as index 35 | static const std::map kValidMethodNames = 36 | { 37 | { HttpRequest::MethodType::kHead, "HEAD" }, 38 | { HttpRequest::MethodType::kGet, "GET" }, 39 | { HttpRequest::MethodType::kPost, "POST" }, 40 | { HttpRequest::MethodType::kPut, "PUT" }, 41 | { HttpRequest::MethodType::kDelete, "DELETE" }, 42 | { HttpRequest::MethodType::kOptions, "OPTIONS" }, 43 | { HttpRequest::MethodType::kTrace, "TRACE" }, 44 | { HttpRequest::MethodType::kConnect, "CONNECT" }, 45 | { HttpRequest::MethodType::kUnknown, NULL }, 46 | }; 47 | 48 | void HttpRequest::Reset() { 49 | HttpPacket::Reset(); 50 | method_ = MethodType::kUnknown; 51 | uri_ = "/"; 52 | } 53 | 54 | HttpRequest::MethodType HttpRequest::GetMethodByName(const char* method_name) { 55 | for (auto itr = kValidMethodNames.begin(); 56 | itr != kValidMethodNames.end(); 57 | ++itr) { 58 | // Method is case sensitive. 59 | if (itr->second && strcmp(method_name, itr->second) == 0) { 60 | return itr->first; 61 | } 62 | } 63 | return MethodType::kUnknown; 64 | } 65 | 66 | const char* HttpRequest::GetMethodName(HttpRequest::MethodType method) { 67 | auto itr = kValidMethodNames.find(method); 68 | if (itr != kValidMethodNames.end()) { 69 | return itr->second; 70 | } 71 | return nullptr; 72 | } 73 | 74 | bool HttpRequest::ParseStartLine(base::StringPiece data, ErrorType* error) { 75 | ErrorType error_placeholder; 76 | if (!error) { 77 | error = &error_placeholder; 78 | } 79 | 80 | std::vector fields; 81 | base::StringUtils::SplitByString(data, " ", &fields); 82 | if (fields.size() != 2 && fields.size() != 3) { 83 | *error = ErrorType::kStartLineNotComplete; 84 | return false; 85 | } 86 | 87 | method_ = GetMethodByName(fields[0].c_str()); 88 | if (method_ == MethodType::kUnknown) { 89 | *error = ErrorType::kMethodNotFound; 90 | return false; 91 | } 92 | uri_ = fields[1]; 93 | 94 | if (fields.size() == 3) { 95 | Version http_version = GetVersionNumber(fields[2]); 96 | if (http_version == Version::kVersionUnknown) { 97 | *error = ErrorType::kVersionUnsupported; 98 | return false; 99 | } 100 | set_http_version(http_version); 101 | } 102 | 103 | return true; 104 | } 105 | 106 | void HttpRequest::AppendStartLineToString(std::string* result) const { 107 | assert(method_ != MethodType::kUnknown); 108 | assert(result); 109 | result->append(GetMethodName(method_)); 110 | result->append(" "); 111 | result->append(uri_); 112 | result->append(" "); 113 | result->append(GetVersionString(http_version())); 114 | } 115 | 116 | } // namespace http 117 | } // namespace cnetpp 118 | 119 | -------------------------------------------------------------------------------- /src/cnetpp/http/http_request.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, myjfm(mwxjmmyjfm@gmail.com). All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are met: 5 | // 6 | // * Redistributions of source code must retain the above copyright notice, 7 | // this list of conditions and the following disclaimer. 8 | // * Redistributions in binary form must reproduce the above copyright notice, 9 | // this list of conditions and the following disclaimer in the documentation 10 | // and/or other materials provided with the distribution. 11 | // * Neither the name of myjfm nor the names of other contributors may be 12 | // used to endorse or promote products derived from this software without 13 | // specific prior written permission. 14 | // 15 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | // CONTRACT, STRICT LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) 24 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | // POSSIBILITY OF SUCH DAMAGE. 26 | // 27 | #ifndef CNETPP_HTTP_HTTP_REQUEST_H_ 28 | #define CNETPP_HTTP_HTTP_REQUEST_H_ 29 | 30 | #include 31 | 32 | #include 33 | #include 34 | 35 | namespace cnetpp { 36 | namespace http { 37 | 38 | // Describes a http request. 39 | class HttpRequest final : public HttpPacket { 40 | public: 41 | enum class MethodType { 42 | kUnknown = -1, 43 | kHead, 44 | kGet, 45 | kPost, 46 | kPut, 47 | kDelete, 48 | kOptions, 49 | kTrace, 50 | kConnect, 51 | kLastField, 52 | }; 53 | 54 | static MethodType GetMethodByName(const char* method_name); 55 | static const char* GetMethodName(MethodType method); 56 | 57 | HttpRequest() : method_(MethodType::kUnknown), uri_("/") { 58 | } 59 | ~HttpRequest() { 60 | } 61 | 62 | virtual void Reset(); 63 | 64 | MethodType method() const { 65 | return method_; 66 | } 67 | void set_method(MethodType method) { 68 | method_ = method; 69 | } 70 | 71 | const std::string& uri() const { 72 | return uri_; 73 | } 74 | void set_uri(base::StringPiece uri) { 75 | uri_ = uri.as_string(); 76 | } 77 | 78 | void Swap(HttpRequest* that) { 79 | HttpPacket::Swap(that); 80 | using std::swap; 81 | swap(method_, that->method_); 82 | swap(uri_, that->uri_); 83 | } 84 | 85 | private: 86 | virtual void AppendStartLineToString(std::string* result) const; 87 | virtual bool ParseStartLine(base::StringPiece data, ErrorType* error = NULL); 88 | 89 | MethodType method_; 90 | std::string uri_; 91 | }; 92 | 93 | } // namespace http 94 | } // namespace cnetpp 95 | 96 | // adapt to std::swap 97 | namespace std { 98 | 99 | template <> 100 | inline void swap(cnetpp::http::HttpRequest& left, 101 | cnetpp::http::HttpRequest& right) { 102 | left.Swap(&right); 103 | } 104 | 105 | } // namespace std 106 | 107 | #endif // CNETPP_HTTP_HTTP_REQUEST_H_ 108 | 109 | -------------------------------------------------------------------------------- /src/cnetpp/http/http_response.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, myjfm(mwxjmmyjfm@gmail.com). All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are met: 5 | // 6 | // * Redistributions of source code must retain the above copyright notice, 7 | // this list of conditions and the following disclaimer. 8 | // * Redistributions in binary form must reproduce the above copyright notice, 9 | // this list of conditions and the following disclaimer in the documentation 10 | // and/or other materials provided with the distribution. 11 | // * Neither the name of myjfm nor the names of other contributors may be 12 | // used to endorse or promote products derived from this software without 13 | // specific prior written permission. 14 | // 15 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | // CONTRACT, STRICT LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) 24 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | // POSSIBILITY OF SUCH DAMAGE. 26 | // 27 | #ifndef CNETPP_HTTP_HTTP_RESPONSE_H_ 28 | #define CNETPP_HTTP_HTTP_RESPONSE_H_ 29 | 30 | #include 31 | #include 32 | 33 | #include 34 | 35 | namespace cnetpp { 36 | namespace http { 37 | 38 | // Describes a http response. 39 | class HttpResponse final : public HttpPacket { 40 | public: 41 | // See RFC2616: 10 Status Code Definition 42 | enum class StatusCode { 43 | kUnknown = -1, 44 | kContinue = 100, 45 | kSwitchingProtocols = 101, 46 | 47 | kOk = 200, 48 | kCreated = 201, 49 | kAccepted = 202, 50 | kNonAuthoritativeInformation = 203, 51 | kNoContent = 204, 52 | kResetContent = 205, 53 | kPartialContent = 206, 54 | 55 | kMultipleChoices = 300, 56 | kMovedPermanently = 301, 57 | kFound = 302, 58 | kSeeOther = 303, 59 | kNotModified = 304, 60 | kUseProxy = 305, 61 | kTemporaryRedirect = 307, 62 | 63 | kBadRequest = 400, 64 | kUnauthorized = 401, 65 | kPaymentRequired = 402, 66 | kForbidden = 403, 67 | kNotFound = 404, 68 | kMethodNotAllowed = 405, 69 | kNotAcceptable = 406, 70 | kProxyAuthRequired = 407, 71 | kRequestTimeout = 408, 72 | kConflict = 409, 73 | kGone = 410, 74 | kLengthRequired = 411, 75 | kPreconditionFailed = 412, 76 | kRequestEntityTooLarge = 413, 77 | kRequestURITooLong = 414, 78 | kUnsupportedMediaType = 415, 79 | kRequestedRangeNotSatisfiable = 416, 80 | kExpectationFailed = 417, 81 | 82 | kInternalServerError = 500, 83 | kNotImplemented = 501, 84 | kBadGateway = 502, 85 | kServiceUnavailable = 503, 86 | kGatewayTimeout = 504, 87 | kHttpVersionNotSupported = 505, 88 | }; 89 | 90 | static const char* StatusCodeToReasonPhrase(StatusCode status_code); 91 | 92 | HttpResponse() : status_(StatusCode::kUnknown) { 93 | } 94 | ~HttpResponse() { 95 | } 96 | 97 | virtual void Reset(); 98 | 99 | StatusCode status() const { 100 | return status_; 101 | } 102 | void set_status(StatusCode status) { 103 | status_ = status; 104 | } 105 | 106 | void Swap(HttpResponse* that) { 107 | HttpPacket::Swap(that); 108 | using std::swap; 109 | swap(status_, that->status_); 110 | } 111 | 112 | private: 113 | virtual void AppendStartLineToString(std::string* result) const; 114 | virtual bool ParseStartLine(base::StringPiece data, ErrorType* error); 115 | 116 | StatusCode status_; 117 | }; 118 | 119 | } // namespace http 120 | } // namespace cnetpp 121 | 122 | // adapt to std::swap 123 | namespace std { 124 | 125 | template <> 126 | inline void swap(cnetpp::http::HttpResponse& left, 127 | cnetpp::http::HttpResponse& right) { 128 | left.Swap(&right); 129 | } 130 | 131 | } // namespace std 132 | 133 | #endif // CNETPP_HTTP_HTTP_RESPONSE_H_ 134 | 135 | -------------------------------------------------------------------------------- /src/cnetpp/http/http_server.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, myjfm(mwxjmmyjfm@gmail.com). All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are met: 5 | // 6 | // * Redistributions of source code must retain the above copyright notice, 7 | // this list of conditions and the following disclaimer. 8 | // * Redistributions in binary form must reproduce the above copyright notice, 9 | // this list of conditions and the following disclaimer in the documentation 10 | // and/or other materials provided with the distribution. 11 | // * Neither the name of myjfm nor the names of other contributors may be 12 | // used to endorse or promote products derived from this software without 13 | // specific prior written permission. 14 | // 15 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | // CONTRACT, STRICT LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) 24 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | // POSSIBILITY OF SUCH DAMAGE. 26 | // 27 | #include 28 | #include 29 | #include 30 | 31 | namespace cnetpp { 32 | namespace http { 33 | 34 | bool HttpServer::Launch(const base::EndPoint& local_address, 35 | const HttpServerOptions& http_options) { 36 | options_ = http_options; 37 | 38 | tcp::TcpServerOptions tcp_options; 39 | tcp_options.set_name("hsvr"); 40 | tcp_options.set_tcp_send_buffer_size(http_options.tcp_send_buffer_size()); 41 | tcp_options.set_tcp_receive_buffer_size( 42 | http_options.tcp_receive_buffer_size()); 43 | tcp_options.set_worker_count(http_options.worker_count()); 44 | tcp_options.set_send_buffer_size(http_options.send_buffer_size()); 45 | tcp_options.set_receive_buffer_size(http_options.receive_buffer_size()); 46 | SetCallbacks(tcp_options); 47 | return tcp_server_.Launch(local_address, tcp_options); 48 | } 49 | 50 | bool HttpServer::HandleConnected( 51 | std::shared_ptr http_connection) { 52 | http_connection->set_connected_callback(options_.connected_callback()); 53 | http_connection->set_closed_callback(options_.closed_callback()); 54 | http_connection->set_received_callback(options_.received_callback()); 55 | http_connection->set_sent_callback(options_.sent_callback()); 56 | http_connection->set_http_packet(std::shared_ptr(new HttpRequest)); 57 | return true; 58 | } 59 | 60 | } // namespace http 61 | } // namespace cnetpp 62 | 63 | -------------------------------------------------------------------------------- /src/cnetpp/http/http_server.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, myjfm(mwxjmmyjfm@gmail.com). All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are met: 5 | // 6 | // * Redistributions of source code must retain the above copyright notice, 7 | // this list of conditions and the following disclaimer. 8 | // * Redistributions in binary form must reproduce the above copyright notice, 9 | // this list of conditions and the following disclaimer in the documentation 10 | // and/or other materials provided with the distribution. 11 | // * Neither the name of myjfm nor the names of other contributors may be 12 | // used to endorse or promote products derived from this software without 13 | // specific prior written permission. 14 | // 15 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | // CONTRACT, STRICT LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) 24 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | // POSSIBILITY OF SUCH DAMAGE. 26 | // 27 | #ifndef CNETPP_HTTP_HTTP_SERVER_H_ 28 | #define CNETPP_HTTP_HTTP_SERVER_H_ 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | namespace cnetpp { 36 | namespace http { 37 | 38 | class HttpServer final : public HttpBase { 39 | public: 40 | HttpServer() = default; 41 | virtual ~HttpServer() = default; 42 | 43 | // you must first call this method before you do any requests 44 | bool Launch(const base::EndPoint& local_address, 45 | const HttpServerOptions& options = HttpServerOptions()); 46 | 47 | private: 48 | tcp::TcpServer tcp_server_; 49 | HttpServerOptions options_; 50 | 51 | bool DoShutdown() override { 52 | return tcp_server_.Shutdown(); 53 | } 54 | 55 | bool HandleConnected( 56 | std::shared_ptr http_connection) override; 57 | }; 58 | 59 | } // namespace http 60 | } // namespace cnetpp 61 | 62 | #endif // CNETPP_HTTP_HTTP_SERVER_H_ 63 | 64 | -------------------------------------------------------------------------------- /src/cnetpp/tcp/command.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, myjfm(mwxjmmyjfm@gmail.com). All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are met: 5 | // 6 | // * Redistributions of source code must retain the above copyright notice, 7 | // this list of conditions and the following disclaimer. 8 | // * Redistributions in binary form must reproduce the above copyright notice, 9 | // this list of conditions and the following disclaimer in the documentation 10 | // and/or other materials provided with the distribution. 11 | // * Neither the name of myjfm nor the names of other contributors may be 12 | // used to endorse or promote products derived from this software without 13 | // specific prior written permission. 14 | // 15 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | // CONTRACT, STRICT LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) 24 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | // POSSIBILITY OF SUCH DAMAGE. 26 | // 27 | #ifndef CNETPP_TCP_COMMAND_H_ 28 | #define CNETPP_TCP_COMMAND_H_ 29 | 30 | #include 31 | 32 | #include 33 | #include 34 | 35 | namespace cnetpp { 36 | namespace tcp { 37 | 38 | // Caller thread should use command to add or remove a connection, 39 | // It includes: 40 | // the command type, 41 | // the tcp connection, 42 | class Command final { 43 | public: 44 | enum class Type { 45 | kDummy = 0x0, 46 | kAddConnectedConn = 0x1, 47 | kRemoveConn = 0x2, 48 | kRemoveConnImmediately = 0x4, 49 | kReadable = 0x8, 50 | kWriteable = 0x10, 51 | kAddConnectingConn = 0x20, 52 | }; 53 | 54 | Command(int type, 55 | std::shared_ptr connection) 56 | : type_(type), 57 | connection_(connection) { 58 | } 59 | 60 | ~Command() { 61 | } 62 | Command(Command&& c) { 63 | if (this != &c) { 64 | type_ = c.type_; 65 | connection_ = std::move(c.connection_); 66 | } 67 | } 68 | Command& operator=(Command&& c) { 69 | if (this != &c) { 70 | type_ = c.type_; 71 | connection_ = std::move(c.connection_); 72 | } 73 | return *this; 74 | } 75 | 76 | // Two commands will handle a same tcp connection handler if one is copied 77 | // from another 78 | Command(const Command& c) { 79 | if (this != &c) { 80 | type_ = c.type_; 81 | connection_ = c.connection_; 82 | } 83 | } 84 | Command& operator=(const Command& c) { 85 | if (this != &c) { 86 | type_ = c.type_; 87 | connection_ = c.connection_; 88 | } 89 | return *this; 90 | } 91 | 92 | int type() const { 93 | return type_; 94 | } 95 | // only used for DLOG 96 | std::string TypeString() const { 97 | std::string res; 98 | if (type_ & static_cast(Type::kAddConnectingConn)) { 99 | res += "kAddConnectingConn|"; 100 | } 101 | if (type_ & static_cast(Type::kAddConnectedConn)) { 102 | res += "kAddConnectedConn|"; 103 | } 104 | if (type_ & static_cast(Type::kRemoveConn)) { 105 | res += "kRemoveConn|"; 106 | } 107 | if (type_ & static_cast(Type::kRemoveConnImmediately)) { 108 | res += "kRemoveConnImmediately|"; 109 | } 110 | if (type_ & static_cast(Type::kReadable)) { 111 | res += "kReadable|"; 112 | } 113 | if (type_ & static_cast(Type::kWriteable)) { 114 | res += "kWriteable|"; 115 | } 116 | if (res.size() > 0) { 117 | res.pop_back(); 118 | } 119 | return res; 120 | } 121 | 122 | std::shared_ptr connection() const { 123 | return connection_; 124 | } 125 | 126 | private: 127 | int type_; 128 | std::shared_ptr connection_; 129 | }; 130 | 131 | } // namespace tcp 132 | } // namespace cnetpp 133 | 134 | #endif // CNETPP_TCP_COMMAND_H_ 135 | 136 | -------------------------------------------------------------------------------- /src/cnetpp/tcp/connection_base.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, myjfm(mwxjmmyjfm@gmail.com). All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are met: 5 | // 6 | // * Redistributions of source code must retain the above copyright notice, 7 | // this list of conditions and the following disclaimer. 8 | // * Redistributions in binary form must reproduce the above copyright notice, 9 | // this list of conditions and the following disclaimer in the documentation 10 | // and/or other materials provided with the distribution. 11 | // * Neither the name of myjfm nor the names of other contributors may be 12 | // used to endorse or promote products derived from this software without 13 | // specific prior written permission. 14 | // 15 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | // CONTRACT, STRICT LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) 24 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | // POSSIBILITY OF SUCH DAMAGE. 26 | // 27 | #ifndef CNETPP_CONNECTION_BASE_H_ 28 | #define CNETPP_CONNECTION_BASE_H_ 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | #include 37 | #include 38 | #include 39 | 40 | namespace cnetpp { 41 | namespace tcp { 42 | 43 | // forward declaration 44 | class EventCenter; 45 | 46 | class ConnectionBase : public std::enable_shared_from_this { 47 | public: 48 | enum class State : int8_t { 49 | kConnecting, 50 | kConnected, 51 | kClosing, 52 | kClosed, 53 | }; 54 | 55 | virtual ~ConnectionBase() = default; 56 | 57 | virtual std::string ToName() const { 58 | return ""; 59 | } 60 | std::string ToString() const { 61 | return "[" + ToName() + " " + std::to_string(id_) + "]"; 62 | } 63 | 64 | const base::TcpSocket& socket() const { 65 | return socket_; 66 | } 67 | base::TcpSocket& mutable_socket() { 68 | return socket_; 69 | } 70 | 71 | ConnectionId id() const { 72 | return id_; 73 | } 74 | 75 | const std::thread::id& ep_thread_id() const { 76 | return ep_thread_id_; 77 | } 78 | void set_ep_thread_id() { 79 | ep_thread_id_ = std::this_thread::get_id(); 80 | } 81 | 82 | const ConnectedCallbackType& connected_callback() const { 83 | return connected_callback_; 84 | } 85 | ConnectedCallbackType& mutable_connected_callback() { 86 | return connected_callback_; 87 | } 88 | void set_connected_callback(const ConnectedCallbackType& connected_callback) { 89 | connected_callback_ = std::move(connected_callback); 90 | } 91 | 92 | int cached_event_type() const { 93 | return cached_event_type_; 94 | } 95 | void set_cached_event_type(int event_type) { 96 | cached_event_type_ = event_type; 97 | } 98 | 99 | State state() const { 100 | return state_; 101 | } 102 | void set_state(State state) { 103 | state_ = state; 104 | } 105 | 106 | // These three methods will be called by the event poller thread when a 107 | // socket fd becomes readable or writable 108 | // NOTE: user should not care about them 109 | virtual void HandleReadableEvent(EventCenter* event_center) = 0; 110 | virtual void HandleWriteableEvent(EventCenter* event_center) = 0; 111 | virtual void HandleCloseConnection() = 0; 112 | virtual void MarkAsClosed(bool immediately = true) = 0; 113 | 114 | protected: 115 | ConnectionBase(std::shared_ptr event_center, int fd) 116 | : event_center_(event_center), 117 | id_(ConnectionIdGenerator::Generate()) { 118 | socket_.Attach(fd); 119 | } 120 | 121 | std::weak_ptr event_center_; 122 | 123 | ConnectionId id_; 124 | base::TcpSocket socket_; 125 | 126 | // the event poller thread id 127 | std::thread::id ep_thread_id_; 128 | 129 | ConnectedCallbackType connected_callback_ { nullptr }; 130 | 131 | int cached_event_type_ { 0 }; 132 | 133 | State state_ { State::kConnecting }; 134 | }; 135 | 136 | } // namespace tcp 137 | } // namespace cnetpp 138 | 139 | #endif // CNETPP_TCP_CONNECTION_BASE_H_ 140 | 141 | -------------------------------------------------------------------------------- /src/cnetpp/tcp/connection_factory.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, myjfm(mwxjmmyjfm@gmail.com). All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are met: 5 | // 6 | // * Redistributions of source code must retain the above copyright notice, 7 | // this list of conditions and the following disclaimer. 8 | // * Redistributions in binary form must reproduce the above copyright notice, 9 | // this list of conditions and the following disclaimer in the documentation 10 | // and/or other materials provided with the distribution. 11 | // * Neither the name of myjfm nor the names of other contributors may be 12 | // used to endorse or promote products derived from this software without 13 | // specific prior written permission. 14 | // 15 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | // CONTRACT, STRICT LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) 24 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | // POSSIBILITY OF SUCH DAMAGE. 26 | // 27 | #ifndef CNETPP_TCP_CONNECTION_FACTORY_H_ 28 | #define CNETPP_TCP_CONNECTION_FACTORY_H_ 29 | 30 | #include 31 | #include 32 | #include 33 | 34 | namespace cnetpp { 35 | namespace tcp { 36 | 37 | class ConnectionFactory { 38 | public: 39 | ConnectionFactory() = default; 40 | virtual ~ConnectionFactory() = default; 41 | 42 | std::shared_ptr CreateConnection( 43 | std::shared_ptr event_center, 44 | int fd, 45 | bool is_listener) { 46 | if (is_listener) { 47 | return std::shared_ptr( 48 | new ListenConnection(event_center, fd)); 49 | } else { 50 | return std::shared_ptr( 51 | new TcpConnection(event_center, fd)); 52 | } 53 | } 54 | }; 55 | 56 | } // namespace tcp 57 | } // namespace cnetpp 58 | 59 | #endif // CNETPP_TCP_TCP_CONNECTION_FACTORY_H_ 60 | 61 | -------------------------------------------------------------------------------- /src/cnetpp/tcp/connection_id.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, myjfm(mwxjmmyjfm@gmail.com). All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are met: 5 | // 6 | // * Redistributions of source code must retain the above copyright notice, 7 | // this list of conditions and the following disclaimer. 8 | // * Redistributions in binary form must reproduce the above copyright notice, 9 | // this list of conditions and the following disclaimer in the documentation 10 | // and/or other materials provided with the distribution. 11 | // * Neither the name of myjfm nor the names of other contributors may be 12 | // used to endorse or promote products derived from this software without 13 | // specific prior written permission. 14 | // 15 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | // CONTRACT, STRICT LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) 24 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | // POSSIBILITY OF SUCH DAMAGE. 26 | // 27 | #include 28 | 29 | namespace cnetpp { 30 | namespace tcp { 31 | 32 | const ConnectionId kInvalidConnectionId = -1; 33 | std::atomic ConnectionIdGenerator::cur_id_(-1); 34 | 35 | ConnectionId ConnectionIdGenerator::Generate() { 36 | return ++cur_id_; 37 | } 38 | 39 | } // namespace tcp 40 | } // namespace cnetpp 41 | 42 | -------------------------------------------------------------------------------- /src/cnetpp/tcp/connection_id.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, myjfm(mwxjmmyjfm@gmail.com). All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are met: 5 | // 6 | // * Redistributions of source code must retain the above copyright notice, 7 | // this list of conditions and the following disclaimer. 8 | // * Redistributions in binary form must reproduce the above copyright notice, 9 | // this list of conditions and the following disclaimer in the documentation 10 | // and/or other materials provided with the distribution. 11 | // * Neither the name of myjfm nor the names of other contributors may be 12 | // used to endorse or promote products derived from this software without 13 | // specific prior written permission. 14 | // 15 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | // CONTRACT, STRICT LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) 24 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | // POSSIBILITY OF SUCH DAMAGE. 26 | // 27 | #ifndef CNETPP_TCP_CONNECTION_ID_H_ 28 | #define CNETPP_TCP_CONNECTION_ID_H_ 29 | 30 | #include 31 | #include 32 | 33 | namespace cnetpp { 34 | namespace tcp { 35 | 36 | using ConnectionId = int64_t; 37 | extern const ConnectionId kInvalidConnectionId; // -1 38 | 39 | class ConnectionIdGenerator { 40 | public: 41 | static ConnectionId Generate(); 42 | 43 | private: 44 | static std::atomic cur_id_; 45 | }; 46 | 47 | } // namespace tcp 48 | } // namespace cnetpp 49 | 50 | #endif // CNETPP_TCP_CONNECTION_ID_H_ 51 | 52 | -------------------------------------------------------------------------------- /src/cnetpp/tcp/epoll_event_poller_impl.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, myjfm(mwxjmmyjfm@gmail.com). All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are met: 5 | // 6 | // * Redistributions of source code must retain the above copyright notice, 7 | // this list of conditions and the following disclaimer. 8 | // * Redistributions in binary form must reproduce the above copyright notice, 9 | // this list of conditions and the following disclaimer in the documentation 10 | // and/or other materials provided with the distribution. 11 | // * Neither the name of myjfm nor the names of other contributors may be 12 | // used to endorse or promote products derived from this software without 13 | // specific prior written permission. 14 | // 15 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | // CONTRACT, STRICT LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) 24 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | // POSSIBILITY OF SUCH DAMAGE. 26 | // 27 | #if defined(linux) || defined(__linux) || defined(__linux__) 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | #include 35 | #include 36 | #include 37 | 38 | namespace cnetpp { 39 | namespace tcp { 40 | 41 | bool EpollEventPollerImpl::DoInit() { 42 | epoll_fd_ = ::epoll_create1(EPOLL_CLOEXEC); 43 | if (epoll_fd_ < 0) { 44 | CnetppError("epoll_create1() failed. erro message: %s", 45 | concurrency::ThisThread::GetErrorString( 46 | concurrency::ThisThread::GetLastError()).c_str()); 47 | return false; 48 | } 49 | return true; 50 | } 51 | 52 | bool EpollEventPollerImpl::Poll() { 53 | // before starting polling, we first process all the pending command events 54 | if (!ProcessInterrupt()) { 55 | return false; 56 | } 57 | 58 | int count { 0 }; 59 | do { 60 | count = ::epoll_wait(epoll_fd_, 61 | &epoll_events_[0], 62 | epoll_events_.size(), 63 | -1); 64 | } while (count == -1 && 65 | cnetpp::concurrency::ThisThread::GetLastError() == EINTR); 66 | 67 | if (count < 0) { 68 | return false; 69 | } 70 | 71 | for (auto i = 0; i < count; ++i) { 72 | auto fd = epoll_events_[i].data.fd; 73 | if (fd == interrupter_->get_read_fd()) { 74 | // we have some command events to be processed 75 | //if (!ProcessInterrupt()) { 76 | // return false; 77 | //} 78 | } else { 79 | Event event(fd); 80 | if (epoll_events_[i].events & (EPOLLHUP | EPOLLERR)) { 81 | event.mutable_mask() |= static_cast(Event::Type::kClose); 82 | CnetppDebug("epoll receive error events:%d", epoll_events_[i].events); 83 | } else { 84 | if (epoll_events_[i].events & (EPOLLIN | EPOLLRDBAND | EPOLLRDNORM)) { 85 | event.mutable_mask() |= static_cast(Event::Type::kRead); 86 | } 87 | if (epoll_events_[i].events & (EPOLLOUT | EPOLLWRNORM | EPOLLWRBAND)) { 88 | event.mutable_mask() |= static_cast(Event::Type::kWrite); 89 | } 90 | } 91 | 92 | std::shared_ptr event_center = event_center_.lock(); 93 | if (!event_center || !event_center->ProcessEvent(event, id_)) { 94 | return false; 95 | } 96 | } 97 | } 98 | return true; 99 | } 100 | 101 | bool EpollEventPollerImpl::AddPollerEvent(Event&& ev) { 102 | struct epoll_event epoll_ev {0u, 0}; 103 | epoll_ev.data.fd = ev.fd(); 104 | epoll_ev.events = EPOLLIN; 105 | if (ev.mask() & static_cast(Event::Type::kWrite)) { 106 | epoll_ev.events |= EPOLLOUT; 107 | } 108 | return ::epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, ev.fd(), &epoll_ev) == 0; 109 | } 110 | 111 | bool EpollEventPollerImpl::ModifyPollerEvent(Event&& ev) { 112 | struct epoll_event epoll_ev {0u, 0}; 113 | epoll_ev.data.fd = ev.fd(); 114 | epoll_ev.events = EPOLLIN; 115 | if (ev.mask() & static_cast(Event::Type::kWrite)) { 116 | epoll_ev.events |= EPOLLOUT; 117 | } 118 | return ::epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, ev.fd(), &epoll_ev) == 0; 119 | } 120 | 121 | bool EpollEventPollerImpl::RemovePollerEvent(Event&& ev) { 122 | if (ev.mask() & static_cast(Event::Type::kClose)) { 123 | return ::epoll_ctl(epoll_fd_, EPOLL_CTL_DEL, ev.fd(), NULL) == 0; 124 | } 125 | return false; 126 | } 127 | 128 | } // namespace tcp 129 | } // namespace cnetpp 130 | 131 | #endif // defined(linux) || defined(__linux) || defined(__linux__) 132 | 133 | -------------------------------------------------------------------------------- /src/cnetpp/tcp/epoll_event_poller_impl.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, myjfm(mwxjmmyjfm@gmail.com). All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are met: 5 | // 6 | // * Redistributions of source code must retain the above copyright notice, 7 | // this list of conditions and the following disclaimer. 8 | // * Redistributions in binary form must reproduce the above copyright notice, 9 | // this list of conditions and the following disclaimer in the documentation 10 | // and/or other materials provided with the distribution. 11 | // * Neither the name of myjfm nor the names of other contributors may be 12 | // used to endorse or promote products derived from this software without 13 | // specific prior written permission. 14 | // 15 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | // CONTRACT, STRICT LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) 24 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | // POSSIBILITY OF SUCH DAMAGE. 26 | // 27 | #if defined(linux) || defined(__linux) || defined(__linux__) 28 | #ifndef CNETPP_TCP_EPOLL_EVENT_POLLER_IMPL_H_ 29 | #define CNETPP_TCP_EPOLL_EVENT_POLLER_IMPL_H_ 30 | 31 | #include 32 | #include 33 | 34 | #include 35 | #include 36 | 37 | #include 38 | 39 | namespace cnetpp { 40 | namespace tcp { 41 | 42 | class EpollEventPollerImpl : public EventPoller { 43 | public: 44 | explicit EpollEventPollerImpl(int id, size_t max_connections) 45 | : EventPoller(id, max_connections), 46 | epoll_fd_(-1), 47 | epoll_events_(max_connections) { 48 | } 49 | 50 | ~EpollEventPollerImpl() = default; 51 | 52 | protected: 53 | bool DoInit() override; 54 | 55 | void DoShutdown() override { 56 | if (epoll_fd_ >= 0) { 57 | ::close(epoll_fd_); 58 | } 59 | } 60 | 61 | bool Poll() override; 62 | 63 | private: 64 | int epoll_fd_; 65 | 66 | std::vector epoll_events_; 67 | 68 | bool AddPollerEvent(Event&& ev) override; 69 | bool ModifyPollerEvent(Event&& ev) override; 70 | bool RemovePollerEvent(Event&& ev) override; 71 | }; 72 | 73 | } // namespace tcp 74 | } // namespace cnetpp 75 | 76 | #endif // CNETPP_TCP_EPOLL_EVENT_POLLER_IMPL_H_ 77 | #endif // define(linux) || defined(__linux) || defined(__linux__) 78 | 79 | -------------------------------------------------------------------------------- /src/cnetpp/tcp/event.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, myjfm(mwxjmmyjfm@gmail.com). All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are met: 5 | // 6 | // * Redistributions of source code must retain the above copyright notice, 7 | // this list of conditions and the following disclaimer. 8 | // * Redistributions in binary form must reproduce the above copyright notice, 9 | // this list of conditions and the following disclaimer in the documentation 10 | // and/or other materials provided with the distribution. 11 | // * Neither the name of myjfm nor the names of other contributors may be 12 | // used to endorse or promote products derived from this software without 13 | // specific prior written permission. 14 | // 15 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | // CONTRACT, STRICT LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) 24 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | // POSSIBILITY OF SUCH DAMAGE. 26 | // 27 | #ifndef CNETPP_TCP_EVENT_H_ 28 | #define CNETPP_TCP_EVENT_H_ 29 | 30 | namespace cnetpp { 31 | namespace tcp { 32 | 33 | // When the EventPoller finds some socket is readable or writable, it will 34 | // return an event 35 | class Event { 36 | public: 37 | enum class Type { 38 | kDummy = 0x0, 39 | kRead = 0x01, 40 | kWrite = 0x02, 41 | kClose = 0x04, 42 | }; 43 | 44 | explicit Event(int fd) : fd_(fd), mask_(static_cast(Type::kDummy)) { 45 | } 46 | Event(int fd, int mask) : fd_(fd), mask_(mask) { 47 | } 48 | 49 | Event(Event&& e) { 50 | fd_ = e.fd_; 51 | mask_ = e.mask_; 52 | } 53 | Event& operator=(Event&& e) { 54 | fd_ = e.fd_; 55 | mask_ = e.mask_; 56 | return *this; 57 | } 58 | 59 | Event(const Event&) = delete; 60 | Event& operator=(const Event&) = delete; 61 | 62 | int fd() const { 63 | return fd_; 64 | } 65 | 66 | int mask() const { 67 | return mask_; 68 | } 69 | int& mutable_mask() { 70 | return mask_; 71 | } 72 | 73 | private: 74 | int fd_; 75 | int mask_; 76 | }; 77 | 78 | } // namespace tcp 79 | } // namespace cnetpp 80 | 81 | #endif // CNETPP_TCP_EVENT_H_ 82 | 83 | -------------------------------------------------------------------------------- /src/cnetpp/tcp/event_center.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, myjfm(mwxjmmyjfm@gmail.com). All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are met: 5 | // 6 | // * Redistributions of source code must retain the above copyright notice, 7 | // this list of conditions and the following disclaimer. 8 | // * Redistributions in binary form must reproduce the above copyright notice, 9 | // this list of conditions and the following disclaimer in the documentation 10 | // and/or other materials provided with the distribution. 11 | // * Neither the name of myjfm nor the names of other contributors may be 12 | // used to endorse or promote products derived from this software without 13 | // specific prior written permission. 14 | // 15 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | // CONTRACT, STRICT LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) 24 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | // POSSIBILITY OF SUCH DAMAGE. 26 | // 27 | #ifndef CNETPP_TCP_EVENT_CENTER_H_ 28 | #define CNETPP_TCP_EVENT_CENTER_H_ 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | namespace cnetpp { 41 | namespace tcp { 42 | 43 | class EventPoller; 44 | 45 | class EventCenter final : public std::enable_shared_from_this { 46 | public: 47 | // Create an EventCenter instance 48 | // NOTE: This class is not singleton, so we can create more than one 49 | // EventCenter instances in one process. e.g. We can create two servers to 50 | // listen on two different ports. 'threads_num' indicates the number of 51 | // threads those process the network requests, if the value is set default, 52 | // it will use the number of logical processers. 53 | static std::shared_ptr New(const std::string& name, 54 | size_t thread_num = 0); 55 | 56 | ~EventCenter() = default; 57 | 58 | bool Launch(); 59 | 60 | void Shutdown(); 61 | 62 | void AddCommand(const Command& command, bool async = true); 63 | 64 | bool ProcessAllPendingCommands(size_t id); 65 | 66 | bool ProcessEvent(const Event& event, size_t id); 67 | 68 | const std::string& name() const { 69 | return name_; 70 | } 71 | 72 | private: 73 | EventCenter(const std::string& name, size_t thread_num = 0); 74 | 75 | class InternalEventTask final : public concurrency::Task { 76 | public: 77 | InternalEventTask(std::weak_ptr event_center, 78 | std::weak_ptr event_poller); 79 | ~InternalEventTask(); 80 | 81 | protected: 82 | bool operator()(void* arg = nullptr) override; 83 | void Stop() override; 84 | 85 | private: 86 | std::weak_ptr event_center_; 87 | std::weak_ptr event_poller_; 88 | }; 89 | 90 | // just for short typing 91 | using ConnectionPtr = std::shared_ptr; 92 | 93 | struct InternalEventPollerInfo { 94 | std::shared_ptr event_poller_thread_; 95 | 96 | std::shared_ptr event_poller_; 97 | 98 | std::vector pending_commands_; 99 | std::mutex pending_commands_mutex_; 100 | 101 | // all of closures 102 | // When some event arrives, the EventPoller will call the EventCallback. 103 | // No need to be protected by lock, because only the corresponding 104 | // EventPoller thread can access this structure 105 | std::unordered_map connections_; 106 | }; 107 | 108 | using InternalEventPollerInfoPtr = std::shared_ptr; 109 | 110 | std::vector internal_event_poller_infos_; 111 | 112 | std::string name_; 113 | 114 | void ProcessPendingCommand(InternalEventPollerInfoPtr info, 115 | const Command& command); 116 | 117 | }; 118 | 119 | } // namespace tcp 120 | } // namespace cnetpp 121 | 122 | #endif // CNETPP_TCP_EVENT_CENTER_H_ 123 | 124 | -------------------------------------------------------------------------------- /src/cnetpp/tcp/eventfd_interrupter_impl.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, myjfm(mwxjmmyjfm@gmail.com). All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are met: 5 | // 6 | // * Redistributions of source code must retain the above copyright notice, 7 | // this list of conditions and the following disclaimer. 8 | // * Redistributions in binary form must reproduce the above copyright notice, 9 | // this list of conditions and the following disclaimer in the documentation 10 | // and/or other materials provided with the distribution. 11 | // * Neither the name of myjfm nor the names of other contributors may be 12 | // used to endorse or promote products derived from this software without 13 | // specific prior written permission. 14 | // 15 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | // CONTRACT, STRICT LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) 24 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | // POSSIBILITY OF SUCH DAMAGE. 26 | // 27 | #if defined(linux) || defined(__linux) || defined(__linux__) 28 | #include 29 | 30 | #include 31 | #include 32 | 33 | namespace cnetpp { 34 | namespace tcp { 35 | 36 | EventfdInterrupterImpl::~EventfdInterrupterImpl() { 37 | if (fd_ != -1) { 38 | ::close(fd_); 39 | } 40 | } 41 | 42 | bool EventfdInterrupterImpl::Create() { 43 | fd_ = ::eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK); 44 | return fd_ >= 0; 45 | } 46 | 47 | // interrupt the epoll_wait call. 48 | bool EventfdInterrupterImpl::Interrupt() { 49 | return ::eventfd_write(fd_, 1) == 0; 50 | } 51 | 52 | // Reset the epoll interrupt. 53 | // Returns true if the epoll_wait call was interrupted. 54 | bool EventfdInterrupterImpl::Reset() { 55 | eventfd_t data; 56 | return ::eventfd_read(fd_, &data) == 0; 57 | } 58 | 59 | } // namespace tcp 60 | } // namespace cnetpp 61 | 62 | #endif // defined(linux) || defined(__linux) || defined(__linux__) 63 | 64 | -------------------------------------------------------------------------------- /src/cnetpp/tcp/eventfd_interrupter_impl.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, myjfm(mwxjmmyjfm@gmail.com). All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are met: 5 | // 6 | // * Redistributions of source code must retain the above copyright notice, 7 | // this list of conditions and the following disclaimer. 8 | // * Redistributions in binary form must reproduce the above copyright notice, 9 | // this list of conditions and the following disclaimer in the documentation 10 | // and/or other materials provided with the distribution. 11 | // * Neither the name of myjfm nor the names of other contributors may be 12 | // used to endorse or promote products derived from this software without 13 | // specific prior written permission. 14 | // 15 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | // CONTRACT, STRICT LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) 24 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | // POSSIBILITY OF SUCH DAMAGE. 26 | // 27 | #if defined(linux) || defined(__linux) || defined(__linux__) 28 | 29 | #ifndef CNETPP_TCP_EVENTFD_INTERRUPTER_IMPL_H_ 30 | #define CNETPP_TCP_EVENTFD_INTERRUPTER_IMPL_H_ 31 | 32 | #include 33 | 34 | namespace cnetpp { 35 | namespace tcp { 36 | 37 | class EventfdInterrupterImpl : public Interrupter { 38 | public: 39 | EventfdInterrupterImpl() : fd_(-1) { 40 | } 41 | 42 | ~EventfdInterrupterImpl(); 43 | 44 | bool Create(); 45 | 46 | bool Interrupt(); 47 | 48 | bool Reset(); 49 | 50 | int get_read_fd() const { 51 | return fd_; 52 | } 53 | 54 | private: 55 | int fd_; 56 | }; 57 | 58 | } // namespace tcp 59 | } // namespace cnetpp 60 | 61 | #endif // CNETPP_TCP_EVENTFD_INTERRUPTER_IMPL_H_ 62 | #endif // defined(linux) || defined(__linux) || defined(__linux__) 63 | 64 | -------------------------------------------------------------------------------- /src/cnetpp/tcp/interrupter.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, myjfm(mwxjmmyjfm@gmail.com). All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are met: 5 | // 6 | // * Redistributions of source code must retain the above copyright notice, 7 | // this list of conditions and the following disclaimer. 8 | // * Redistributions in binary form must reproduce the above copyright notice, 9 | // this list of conditions and the following disclaimer in the documentation 10 | // and/or other materials provided with the distribution. 11 | // * Neither the name of myjfm nor the names of other contributors may be 12 | // used to endorse or promote products derived from this software without 13 | // specific prior written permission. 14 | // 15 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | // CONTRACT, STRICT LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) 24 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | // POSSIBILITY OF SUCH DAMAGE. 26 | // 27 | #include 28 | #if defined(linux) || defined(__linux) || defined(__linux__) 29 | #include 30 | #else 31 | #include 32 | #endif 33 | 34 | namespace cnetpp { 35 | namespace tcp { 36 | 37 | std::unique_ptr Interrupter::New() { 38 | #if defined(linux) || defined(__linux) || defined(__linux__) 39 | return std::unique_ptr(new EventfdInterrupterImpl()); 40 | #else 41 | return std::unique_ptr(new PipeInterrupterImpl()); 42 | #endif 43 | } 44 | 45 | } // namespace tcp 46 | } // namespace cnetpp 47 | 48 | -------------------------------------------------------------------------------- /src/cnetpp/tcp/interrupter.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, myjfm(mwxjmmyjfm@gmail.com). All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are met: 5 | // 6 | // * Redistributions of source code must retain the above copyright notice, 7 | // this list of conditions and the following disclaimer. 8 | // * Redistributions in binary form must reproduce the above copyright notice, 9 | // this list of conditions and the following disclaimer in the documentation 10 | // and/or other materials provided with the distribution. 11 | // * Neither the name of myjfm nor the names of other contributors may be 12 | // used to endorse or promote products derived from this software without 13 | // specific prior written permission. 14 | // 15 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | // CONTRACT, STRICT LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) 24 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | // POSSIBILITY OF SUCH DAMAGE. 26 | // 27 | #ifndef CNETPP_TCP_INTERRUPTER_H_ 28 | #define CNETPP_TCP_INTERRUPTER_H_ 29 | 30 | #include 31 | 32 | namespace cnetpp { 33 | namespace tcp { 34 | 35 | // Currently, we only implements a interrupter based on pipe, 36 | // we will introduce eventfd interrupter in the future. 37 | class Interrupter { 38 | public: 39 | static std::unique_ptr New(); 40 | 41 | // Destructor. 42 | virtual ~Interrupter() { 43 | } 44 | 45 | // Do initialing work 46 | virtual bool Create() = 0; 47 | 48 | // Interrupt the poll thread from waiting. 49 | virtual bool Interrupt() = 0; 50 | 51 | // Poll thread calls this function to reset interrupt state 52 | virtual bool Reset() = 0; 53 | 54 | // Get the read descriptor to be passed to epoll. 55 | virtual int get_read_fd() const = 0; 56 | 57 | protected: 58 | Interrupter() = default; 59 | }; 60 | 61 | } // namespace tcp 62 | } // namespace cnetpp 63 | 64 | #endif // CNETPP_TCP_INTERRUPTER_H_ 65 | 66 | -------------------------------------------------------------------------------- /src/cnetpp/tcp/listen_connection.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, myjfm(mwxjmmyjfm@gmail.com). All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are met: 5 | // 6 | // * Redistributions of source code must retain the above copyright notice, 7 | // this list of conditions and the following disclaimer. 8 | // * Redistributions in binary form must reproduce the above copyright notice, 9 | // this list of conditions and the following disclaimer in the documentation 10 | // and/or other materials provided with the distribution. 11 | // * Neither the name of myjfm nor the names of other contributors may be 12 | // used to endorse or promote products derived from this software without 13 | // specific prior written permission. 14 | // 15 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | // CONTRACT, STRICT LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) 24 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | // POSSIBILITY OF SUCH DAMAGE. 26 | // 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | namespace cnetpp { 41 | namespace tcp { 42 | 43 | // This method will be called when a socket fd becomes readable 44 | void ListenConnection::HandleReadableEvent(EventCenter* event_center) { 45 | CnetppDebug("[ListenSocket 0X%08x] [ListenConnection 0X%08x] " 46 | "receive new connection...", socket_.fd(), this->id()); 47 | 48 | assert(event_center); 49 | 50 | base::ListenSocket listen_socket; 51 | listen_socket.Attach(socket_.fd()); 52 | 53 | base::TcpSocket new_socket; 54 | base::EndPoint remote_end_point; 55 | if (!listen_socket.Accept(&new_socket, &remote_end_point)) { 56 | listen_socket.Detach(); 57 | return; 58 | } 59 | listen_socket.Detach(); 60 | 61 | new_socket.SetCloexec(true); 62 | new_socket.SetBlocking(false); 63 | new_socket.SetTcpNoDelay(true); 64 | new_socket.SetTcpKeepAliveOption(60, 3, 20); 65 | new_socket.SetTcpUserTimeout(); 66 | new_socket.SetLinger(); 67 | #ifdef SO_NOSIGPIPE 68 | int one = 1; 69 | new_socket.SetOption(SOL_SOCKET, SO_NOSIGPIPE, &one, sizeof(one)); 70 | #endif 71 | 72 | ConnectionFactory cf; 73 | auto new_connection = 74 | cf.CreateConnection(event_center_.lock(), new_socket.fd(), false); 75 | CnetppDebug("[ListenSocket 0X%08x] [ListenConnection 0X%08x] " 76 | "receive client from %s", socket_.fd(), this->id(), 77 | remote_end_point.ToString().c_str()); 78 | base::EndPoint localEp; 79 | new_socket.GetLocalEndPoint(&localEp); 80 | CnetppDebug("[ListenSocket 0X%08x] [ListenConnection 0X%08x] " 81 | "create [Socket 0X%08x] <-> [TcpConnection 0X%08x] " 82 | "for remote client %s, [LocalEndPoint %s]", socket_.fd(), 83 | this->id(), new_socket.fd(), new_connection->id(), 84 | remote_end_point.ToString().c_str(), localEp.ToString().c_str()); 85 | auto new_tcp_connection = 86 | std::static_pointer_cast(new_connection); 87 | new_tcp_connection->set_closed_callback(options_.closed_callback()); 88 | new_tcp_connection->set_sent_callback(options_.sent_callback()); 89 | new_tcp_connection->set_received_callback(options_.received_callback()); 90 | new_tcp_connection->set_state(TcpConnection::State::kConnected); 91 | new_tcp_connection->SetSendBufferSize(options_.send_buffer_size()); 92 | new_tcp_connection->SetRecvBufferSize(options_.receive_buffer_size()); 93 | new_tcp_connection->set_remote_end_point(std::move(remote_end_point)); 94 | 95 | new_socket.Detach(); 96 | 97 | bool ok = false; 98 | 99 | if (connected_callback_) { 100 | // call callback user defined 101 | ok = connected_callback_(new_tcp_connection); 102 | } 103 | 104 | if (!ok) { 105 | return; 106 | } 107 | 108 | event_center->AddCommand( 109 | Command(static_cast(Command::Type::kAddConnectedConn), 110 | new_connection), 111 | true); 112 | } 113 | 114 | void ListenConnection::HandleWriteableEvent(EventCenter* event_center) { 115 | assert(event_center); 116 | event_center->AddCommand( 117 | Command(static_cast(Command::Type::kReadable), shared_from_this()), 118 | true); 119 | } 120 | 121 | } // namespace tcp 122 | } // namespace cnetpp 123 | 124 | -------------------------------------------------------------------------------- /src/cnetpp/tcp/listen_connection.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, myjfm(mwxjmmyjfm@gmail.com). All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are met: 5 | // 6 | // * Redistributions of source code must retain the above copyright notice, 7 | // this list of conditions and the following disclaimer. 8 | // * Redistributions in binary form must reproduce the above copyright notice, 9 | // this list of conditions and the following disclaimer in the documentation 10 | // and/or other materials provided with the distribution. 11 | // * Neither the name of myjfm nor the names of other contributors may be 12 | // used to endorse or promote products derived from this software without 13 | // specific prior written permission. 14 | // 15 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | // CONTRACT, STRICT LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) 24 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | // POSSIBILITY OF SUCH DAMAGE. 26 | // 27 | #ifndef CNETPP_LISTEN_CONNECTION_H_ 28 | #define CNETPP_LISTEN_CONNECTION_H_ 29 | 30 | #include 31 | #include 32 | 33 | #include 34 | 35 | namespace cnetpp { 36 | namespace tcp { 37 | 38 | // forward declaration 39 | class EventCenter; 40 | 41 | class ListenConnection : public ConnectionBase { 42 | public: 43 | friend class ConnectionFactory; 44 | virtual ~ListenConnection() = default; 45 | virtual std::string ToName() const override { 46 | return "ListenConnection"; 47 | } 48 | 49 | const TcpServerOptions& tcp_server_options() const { 50 | return options_; 51 | } 52 | TcpServerOptions& mutable_tcp_server_options() { 53 | return options_; 54 | } 55 | void set_tcp_server_options(const TcpServerOptions& options) { 56 | options_ = options; 57 | } 58 | 59 | virtual void HandleReadableEvent(EventCenter* event_center) override; 60 | virtual void HandleWriteableEvent(EventCenter* event_center) override; 61 | virtual void HandleCloseConnection() override { 62 | } 63 | virtual void MarkAsClosed(bool immediately = true) override { 64 | } 65 | 66 | private: 67 | ListenConnection(std::shared_ptr event_center, int fd) 68 | : ConnectionBase(event_center, fd) { 69 | } 70 | 71 | TcpServerOptions options_; 72 | }; 73 | 74 | } // namespace tcp 75 | } // namespace cnetpp 76 | 77 | #endif // CNETPP_TCP_LISTEN_CONNECTION_H_ 78 | 79 | -------------------------------------------------------------------------------- /src/cnetpp/tcp/pipe_interrupter_impl.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, myjfm(mwxjmmyjfm@gmail.com). All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are met: 5 | // 6 | // * Redistributions of source code must retain the above copyright notice, 7 | // this list of conditions and the following disclaimer. 8 | // * Redistributions in binary form must reproduce the above copyright notice, 9 | // this list of conditions and the following disclaimer in the documentation 10 | // and/or other materials provided with the distribution. 11 | // * Neither the name of myjfm nor the names of other contributors may be 12 | // used to endorse or promote products derived from this software without 13 | // specific prior written permission. 14 | // 15 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | // CONTRACT, STRICT LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) 24 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | // POSSIBILITY OF SUCH DAMAGE. 26 | // 27 | #include 28 | 29 | #include 30 | #include 31 | 32 | namespace cnetpp { 33 | namespace tcp { 34 | 35 | PipeInterrupterImpl::~PipeInterrupterImpl() { 36 | if (read_fd_ != -1) { 37 | ::close(read_fd_); 38 | } 39 | if (write_fd_ != -1) { 40 | ::close(write_fd_); 41 | } 42 | } 43 | 44 | bool PipeInterrupterImpl::Create() { 45 | int pipe_fds[2] { -1, -1 }; 46 | if (::pipe(pipe_fds) < 0) { 47 | return false; 48 | } 49 | 50 | read_fd_ = pipe_fds[0]; 51 | ::fcntl(read_fd_, F_SETFL, O_NONBLOCK); 52 | ::fcntl(read_fd_, F_SETFD, FD_CLOEXEC); 53 | 54 | write_fd_ = pipe_fds[1]; 55 | ::fcntl(write_fd_, F_SETFL, O_NONBLOCK); 56 | ::fcntl(write_fd_, F_SETFD, FD_CLOEXEC); 57 | return true; 58 | } 59 | 60 | // interrupt the epoll_wait call. 61 | bool PipeInterrupterImpl::Interrupt() { 62 | char byte = 0; 63 | if (write_fd_ < 0 || ::write(write_fd_, &byte, 1) < 0) { 64 | return false; 65 | } 66 | return true; 67 | } 68 | 69 | // Reset the epoll interrupt. 70 | // Returns true if the epoll_wait call was interrupted. 71 | bool PipeInterrupterImpl::Reset() { 72 | char data[64]; 73 | int bytes_read = ::read(read_fd_, data, sizeof(data)); 74 | bool was_interrupted = (bytes_read > 0); 75 | while (bytes_read == sizeof(data)) { 76 | bytes_read = ::read(read_fd_, data, sizeof(data)); 77 | } 78 | return was_interrupted; 79 | } 80 | 81 | } // namespace tcp 82 | } // namespace cnetpp 83 | 84 | -------------------------------------------------------------------------------- /src/cnetpp/tcp/pipe_interrupter_impl.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, myjfm(mwxjmmyjfm@gmail.com). All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are met: 5 | // 6 | // * Redistributions of source code must retain the above copyright notice, 7 | // this list of conditions and the following disclaimer. 8 | // * Redistributions in binary form must reproduce the above copyright notice, 9 | // this list of conditions and the following disclaimer in the documentation 10 | // and/or other materials provided with the distribution. 11 | // * Neither the name of myjfm nor the names of other contributors may be 12 | // used to endorse or promote products derived from this software without 13 | // specific prior written permission. 14 | // 15 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | // CONTRACT, STRICT LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) 24 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | // POSSIBILITY OF SUCH DAMAGE. 26 | // 27 | #ifndef CNETPP_TCP_PIPE_INTERRUPTER_IMPL_H_ 28 | #define CNETPP_TCP_PIPE_INTERRUPTER_IMPL_H_ 29 | 30 | #include 31 | 32 | namespace cnetpp { 33 | namespace tcp { 34 | 35 | class PipeInterrupterImpl : public Interrupter { 36 | public: 37 | PipeInterrupterImpl() : read_fd_(-1), write_fd_(-1) { 38 | } 39 | 40 | ~PipeInterrupterImpl(); 41 | 42 | bool Create(); 43 | 44 | bool Interrupt(); 45 | 46 | bool Reset(); 47 | 48 | int get_read_fd() const { 49 | return read_fd_; 50 | } 51 | 52 | private: 53 | // The read end of a connection used to interrupt the poll thread from waiting. 54 | // This file descriptor is passed to epoll such that when it is time to stop, 55 | // a single byte will be written on the other end of the connection and this 56 | // descriptor will become readable. 57 | int read_fd_; 58 | 59 | // The write end of a connection used to interrupt the poll thread from waiting. 60 | // A single byte may be written to this to wake up the thread from wait which is 61 | // waiting for the other end to become readable. 62 | int write_fd_; 63 | }; 64 | 65 | } // namespace tcp 66 | } // namespace cnetpp 67 | 68 | #endif // CNETPP_TCP_PIPE_INTERRUPTER_IMPL_H_ 69 | 70 | -------------------------------------------------------------------------------- /src/cnetpp/tcp/poll_event_poller_impl.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, myjfm(mwxjmmyjfm@gmail.com). All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are met: 5 | // 6 | // * Redistributions of source code must retain the above copyright notice, 7 | // this list of conditions and the following disclaimer. 8 | // * Redistributions in binary form must reproduce the above copyright notice, 9 | // this list of conditions and the following disclaimer in the documentation 10 | // and/or other materials provided with the distribution. 11 | // * Neither the name of myjfm nor the names of other contributors may be 12 | // used to endorse or promote products derived from this software without 13 | // specific prior written permission. 14 | // 15 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | // CONTRACT, STRICT LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) 24 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | // POSSIBILITY OF SUCH DAMAGE. 26 | // 27 | #if defined(linux) || defined(__linux) || defined(__linux__) || \ 28 | defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) 29 | #ifndef CNETPP_TCP_POLL_EVENT_POLLER_IMPL_H_ 30 | #define CNETPP_TCP_POLL_EVENT_POLLER_IMPL_H_ 31 | 32 | #include 33 | #include 34 | 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | namespace cnetpp { 41 | namespace tcp { 42 | 43 | class PollEventPollerImpl : public EventPoller { 44 | public: 45 | explicit PollEventPollerImpl(int id, size_t max_connections) 46 | : EventPoller(id, max_connections), 47 | poll_fds_(max_connections) { 48 | } 49 | 50 | ~PollEventPollerImpl() = default; 51 | 52 | protected: 53 | bool Poll() override; 54 | 55 | private: 56 | std::vector poll_fds_; 57 | int poll_fds_end_ { 0 }; 58 | 59 | // save the map from socket fd to its index in poll_fds_ 60 | // we use it to accelerate the deletion of a connection 61 | std::unordered_map fd_to_index_map_; 62 | 63 | std::deque events_to_be_removed_; 64 | 65 | bool AddPollerEvent(Event&& event) override; 66 | bool ModifyPollerEvent(Event&& event) override; 67 | bool RemovePollerEvent(Event&& event) override; 68 | 69 | void InternalRemovePollerEvent(); 70 | }; 71 | 72 | } // namespace tcp 73 | } // namespace cnetpp 74 | 75 | #endif // CNETPP_TCP_POLL_EVENT_POLLER_IMPL_H_ 76 | #endif // system related macros check 77 | -------------------------------------------------------------------------------- /src/cnetpp/tcp/select_event_poller_impl.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, myjfm(mwxjmmyjfm@gmail.com). All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are met: 5 | // 6 | // * Redistributions of source code must retain the above copyright notice, 7 | // this list of conditions and the following disclaimer. 8 | // * Redistributions in binary form must reproduce the above copyright notice, 9 | // this list of conditions and the following disclaimer in the documentation 10 | // and/or other materials provided with the distribution. 11 | // * Neither the name of myjfm nor the names of other contributors may be 12 | // used to endorse or promote products derived from this software without 13 | // specific prior written permission. 14 | // 15 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | // CONTRACT, STRICT LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) 24 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | // POSSIBILITY OF SUCH DAMAGE. 26 | // 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | #include 34 | #include 35 | 36 | namespace cnetpp { 37 | namespace tcp { 38 | 39 | bool SelectEventPollerImpl::Poll() { 40 | // before starting polling, we first process all the pending command events 41 | if (!ProcessInterrupt()) { 42 | return false; 43 | } 44 | 45 | int count{0}; 46 | fd_set rd_fds, wr_fds, ex_fds; 47 | int max_fd = BuildFdsets(&rd_fds, &wr_fds, &ex_fds); 48 | if(max_fd < 0) { 49 | return true; 50 | } 51 | 52 | do { 53 | count = ::select(max_fd + 1, &rd_fds, &wr_fds, &ex_fds, nullptr); 54 | } while (count == -1 && 55 | cnetpp::concurrency::ThisThread::GetLastError() == EINTR); 56 | 57 | if (count < 0) { 58 | return false; 59 | } 60 | 61 | // wake up by interrupter 62 | if (FD_ISSET(interrupter_->get_read_fd(), &rd_fds)) { 63 | if (!ProcessInterrupt()) { 64 | return false; 65 | } 66 | } 67 | 68 | for (auto fd_info_itr = select_fds_.begin(); 69 | fd_info_itr != select_fds_.end(); 70 | ++fd_info_itr) { 71 | bool has_event = false; 72 | int fd = fd_info_itr->first; 73 | Event event(fd); 74 | if (FD_ISSET(fd, &ex_fds)) { 75 | has_event = true; 76 | event.mutable_mask() |= static_cast(Event::Type::kClose); 77 | } else { 78 | if (FD_ISSET(fd, &rd_fds)) { 79 | has_event = true; 80 | event.mutable_mask() |= static_cast(Event::Type::kRead); 81 | } 82 | if (FD_ISSET(fd, &wr_fds)) { 83 | has_event = true; 84 | event.mutable_mask() |= static_cast(Event::Type::kWrite); 85 | } 86 | } 87 | 88 | if(has_event) { 89 | auto event_center = event_center_.lock(); 90 | if (!event_center || !event_center->ProcessEvent(event, id_)) { 91 | return false; 92 | } 93 | } 94 | } 95 | return true; 96 | } 97 | 98 | bool SelectEventPollerImpl::AddPollerEvent(Event&& event) { 99 | if (select_fds_.size() > max_connections_) { 100 | return false; 101 | } 102 | select_fds_.insert(std::make_pair(event.fd(), std::move(event))); 103 | return true; 104 | } 105 | 106 | bool SelectEventPollerImpl::ModifyPollerEvent(Event&& event) { 107 | auto itr = select_fds_.find(event.fd()); 108 | assert(itr != select_fds_.end()); 109 | itr->second = std::forward(event); 110 | return true; 111 | } 112 | 113 | bool SelectEventPollerImpl::RemovePollerEvent(Event&& event) { 114 | select_fds_.erase(event.fd()); 115 | return true; 116 | } 117 | 118 | int SelectEventPollerImpl::BuildFdsets(fd_set* rd_fdset, fd_set* wr_fdset, 119 | fd_set* ex_fdset) { 120 | int max_fd = -1; 121 | assert(rd_fdset && wr_fdset && ex_fdset); 122 | FD_ZERO(rd_fdset); 123 | FD_ZERO(wr_fdset); 124 | FD_ZERO(ex_fdset); 125 | int interrupter_rd_fd = interrupter_->get_read_fd(); 126 | assert(interrupter_rd_fd >= 0); 127 | FD_SET(interrupter_rd_fd, rd_fdset); 128 | FD_SET(interrupter_rd_fd, ex_fdset); 129 | max_fd = max_fd < interrupter_rd_fd ? interrupter_rd_fd : max_fd; 130 | for (auto fd_info_itr = select_fds_.begin(); fd_info_itr != select_fds_.end(); 131 | ++fd_info_itr) { 132 | int fd = fd_info_itr->first; 133 | if(fd_info_itr->second.mask() & static_cast(Event::Type::kRead)) { 134 | FD_SET(fd, rd_fdset); 135 | } 136 | if(fd_info_itr->second.mask() & static_cast(Event::Type::kWrite)) { 137 | FD_SET(fd, wr_fdset); 138 | } 139 | if(fd_info_itr->second.mask() & static_cast(Event::Type::kClose)) { 140 | FD_SET(fd, ex_fdset); 141 | } 142 | max_fd = max_fd < fd ? fd : max_fd; 143 | } 144 | return max_fd; 145 | } 146 | } // namespace tcp 147 | } // namespace cnetpp 148 | 149 | -------------------------------------------------------------------------------- /src/cnetpp/tcp/select_event_poller_impl.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, myjfm(mwxjmmyjfm@gmail.com). All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are met: 5 | // 6 | // * Redistributions of source code must retain the above copyright notice, 7 | // this list of conditions and the following disclaimer. 8 | // * Redistributions in binary form must reproduce the above copyright notice, 9 | // this list of conditions and the following disclaimer in the documentation 10 | // and/or other materials provided with the distribution. 11 | // * Neither the name of myjfm nor the names of other contributors may be 12 | // used to endorse or promote products derived from this software without 13 | // specific prior written permission. 14 | // 15 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | // CONTRACT, STRICT LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) 24 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | // POSSIBILITY OF SUCH DAMAGE. 26 | // 27 | #ifndef CNETPP_TCP_SELECT_EVENT_POLLER_IMPL_H_ 28 | #define CNETPP_TCP_SELECT_EVENT_POLLER_IMPL_H_ 29 | 30 | #include 31 | #include 32 | 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | #include 39 | #include 40 | 41 | namespace cnetpp { 42 | namespace tcp { 43 | 44 | class SelectEventPollerImpl : public EventPoller { 45 | public: 46 | explicit SelectEventPollerImpl(int id, size_t max_connections) 47 | : EventPoller(id, max_connections) { 48 | select_fds_.reserve(max_connections); 49 | } 50 | 51 | ~SelectEventPollerImpl() = default; 52 | 53 | protected: 54 | bool Poll() override; 55 | 56 | private: 57 | std::unordered_map select_fds_; 58 | 59 | bool AddPollerEvent(Event&& event) override; 60 | bool ModifyPollerEvent(Event&& event) override; 61 | bool RemovePollerEvent(Event&& event) override; 62 | 63 | int BuildFdsets(fd_set* rd_fdset, fd_set* wr_fdset, fd_set* ex_fdset); 64 | }; 65 | 66 | } // namespace tcp 67 | } // namespace cnetpp 68 | 69 | #endif // CNETPP_TCP_SELECT_EVENT_POLLER_IMPL_H_ 70 | 71 | -------------------------------------------------------------------------------- /src/cnetpp/tcp/tcp_callbacks.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, myjfm(mwxjmmyjfm@gmail.com). All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are met: 5 | // 6 | // * Redistributions of source code must retain the above copyright notice, 7 | // this list of conditions and the following disclaimer. 8 | // * Redistributions in binary form must reproduce the above copyright notice, 9 | // this list of conditions and the following disclaimer in the documentation 10 | // and/or other materials provided with the distribution. 11 | // * Neither the name of myjfm nor the names of other contributors may be 12 | // used to endorse or promote products derived from this software without 13 | // specific prior written permission. 14 | // 15 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | // CONTRACT, STRICT LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) 24 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | // POSSIBILITY OF SUCH DAMAGE. 26 | // 27 | #ifndef CNETPP_TCP_TCP_CALLBACKS_H_ 28 | #define CNETPP_TCP_TCP_CALLBACKS_H_ 29 | 30 | #include 31 | #include 32 | 33 | namespace cnetpp { 34 | namespace tcp { 35 | 36 | class TcpConnection; 37 | 38 | using ConnectedCallbackType = 39 | std::function)>; 40 | using ClosedCallbackType = 41 | std::function)>; 42 | using ReceivedCallbackType = 43 | std::function)>; 44 | using SentCallbackType = 45 | std::function)>; 46 | 47 | } // namespace tcp 48 | } // namespace cnetpp 49 | 50 | #endif // CNETPP_TCP_TCP_CALLBACKS_H_ 51 | 52 | -------------------------------------------------------------------------------- /src/cnetpp/tcp/tcp_client.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, myjfm(mwxjmmyjfm@gmail.com). All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are met: 5 | // 6 | // * Redistributions of source code must retain the above copyright notice, 7 | // this list of conditions and the following disclaimer. 8 | // * Redistributions in binary form must reproduce the above copyright notice, 9 | // this list of conditions and the following disclaimer in the documentation 10 | // and/or other materials provided with the distribution. 11 | // * Neither the name of myjfm nor the names of other contributors may be 12 | // used to endorse or promote products derived from this software without 13 | // specific prior written permission. 14 | // 15 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | // CONTRACT, STRICT LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) 24 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | // POSSIBILITY OF SUCH DAMAGE. 26 | // 27 | #ifndef ASYNC_CNETPP_TCP_TCP_CLIENT_H_ 28 | #define ASYNC_CNETPP_TCP_TCP_CLIENT_H_ 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | #include 38 | #include 39 | 40 | namespace cnetpp { 41 | namespace tcp { 42 | 43 | class TcpClient final { 44 | public: 45 | TcpClient() = default; 46 | ~TcpClient() = default; 47 | 48 | // disallow copy and move operations 49 | TcpClient(const TcpClient&) = delete; 50 | TcpClient& operator=(const TcpClient&) = delete; 51 | TcpClient(TcpClient&&) = delete; 52 | TcpClient& operator=(TcpClient&&) = delete; 53 | 54 | bool Launch(const std::string& name, 55 | const TcpClientOptions& options = TcpClientOptions()); 56 | bool Shutdown(); 57 | 58 | // connect with remote server 59 | // if keep local as nullptr, it will use one of local ip. 60 | ConnectionId Connect(const base::EndPoint* remote, 61 | const TcpClientOptions& options = TcpClientOptions(), 62 | std::shared_ptr cookie = nullptr); 63 | 64 | bool AsyncClosed(ConnectionId connection_id); 65 | 66 | private: 67 | std::shared_ptr event_center_; 68 | 69 | enum class Status { 70 | kInitialized, 71 | kConnecting, 72 | kConnected, 73 | kClosed 74 | }; 75 | 76 | struct InternalConnectionContext { 77 | Status status; 78 | TcpClientOptions options; 79 | std::shared_ptr tcp_connection; 80 | }; 81 | 82 | std::unordered_map contexts_; 83 | std::mutex contexts_mutex_; 84 | 85 | bool OnConnected(std::shared_ptr tcp_connection); 86 | 87 | bool OnClosed(std::shared_ptr tcp_connection); 88 | 89 | bool OnSent(bool success, std::shared_ptr tcp_connection); 90 | 91 | bool OnReceived(std::shared_ptr tcp_connection); 92 | }; 93 | 94 | } // namespace tcp 95 | } // namespace cnetpp 96 | 97 | #endif // ASYNC_CNETPP_TCP_TCP_CLIENT_H_ 98 | 99 | -------------------------------------------------------------------------------- /src/cnetpp/tcp/tcp_server.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, myjfm(mwxjmmyjfm@gmail.com). All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are met: 5 | // 6 | // * Redistributions of source code must retain the above copyright notice, 7 | // this list of conditions and the following disclaimer. 8 | // * Redistributions in binary form must reproduce the above copyright notice, 9 | // this list of conditions and the following disclaimer in the documentation 10 | // and/or other materials provided with the distribution. 11 | // * Neither the name of myjfm nor the names of other contributors may be 12 | // used to endorse or promote products derived from this software without 13 | // specific prior written permission. 14 | // 15 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | // CONTRACT, STRICT LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) 24 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | // POSSIBILITY OF SUCH DAMAGE. 26 | // 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | 39 | namespace cnetpp { 40 | namespace tcp { 41 | 42 | bool TcpServer::Launch(const base::EndPoint& local_address, 43 | const TcpServerOptions& options) { 44 | event_center_ = EventCenter::New(options.name(), options.worker_count()); 45 | assert(event_center_.get()); 46 | if (!event_center_->Launch()) { 47 | return false; 48 | } 49 | 50 | // create listen socket 51 | base::ListenSocket listen_socket(local_address); 52 | if (!listen_socket.IsValid()) { 53 | CnetppInfo("[TcpServer 0X%08x] create listen socket failed in addr %s", 54 | this, local_address.ToString().c_str()); 55 | return false; 56 | } 57 | 58 | CnetppDebug("[TcpServer 0X%08x] create listen socket [0X%08x] in addr %s", 59 | this, listen_socket.fd(), local_address.ToString().c_str()); 60 | 61 | int one = 0; (void) one; 62 | if (!listen_socket.SetCloexec(true) || 63 | !listen_socket.SetBlocking(false) || 64 | #if 0 65 | !listen_socket.SetReceiveBufferSize(options.tcp_receive_buffer_size()) || 66 | !listen_socket.SetSendBufferSize(options.tcp_send_buffer_size()) || 67 | #endif 68 | !listen_socket.SetReuseAddress(true) || 69 | #ifdef SO_NOSIGPIPE 70 | !listen_socket.SetOption(SOL_SOCKET, SO_NOSIGPIPE, &one, sizeof(one)) || 71 | #endif 72 | !listen_socket.Listen(options.backlog())) { 73 | return false; 74 | } 75 | 76 | ConnectionFactory cf; 77 | auto connection = 78 | cf.CreateConnection(event_center_, listen_socket.fd(), true); 79 | assert(connection.get()); 80 | connection->set_connected_callback(options.connected_callback()); 81 | auto listener = std::static_pointer_cast(connection); 82 | listener->set_tcp_server_options(options); 83 | 84 | CnetppDebug("[TcpServer 0X%08x] bind listen socket [0X%08x] " 85 | "with [ListenConnection 0X%08x]", 86 | this, listen_socket.fd(), connection->id()); 87 | // add the listen fd onto multiplexer 88 | Command cmd(static_cast(Command::Type::kAddConnectedConn), 89 | std::static_pointer_cast(listener)); 90 | event_center_->AddCommand(cmd, true); 91 | 92 | listen_socket.Detach(); 93 | return true; 94 | } 95 | 96 | bool TcpServer::Shutdown() { 97 | event_center_->Shutdown(); 98 | return true; 99 | } 100 | 101 | } // namespace tcp 102 | } // namespace cnetpp 103 | 104 | -------------------------------------------------------------------------------- /src/cnetpp/tcp/tcp_server.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, myjfm(mwxjmmyjfm@gmail.com). All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are met: 5 | // 6 | // * Redistributions of source code must retain the above copyright notice, 7 | // this list of conditions and the following disclaimer. 8 | // * Redistributions in binary form must reproduce the above copyright notice, 9 | // this list of conditions and the following disclaimer in the documentation 10 | // and/or other materials provided with the distribution. 11 | // * Neither the name of myjfm nor the names of other contributors may be 12 | // used to endorse or promote products derived from this software without 13 | // specific prior written permission. 14 | // 15 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | // CONTRACT, STRICT LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) 24 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | // POSSIBILITY OF SUCH DAMAGE. 26 | // 27 | #ifndef CNETPP_TCP_TCP_SERVER_H_ 28 | #define CNETPP_TCP_TCP_SERVER_H_ 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | #include 36 | #include 37 | 38 | namespace cnetpp { 39 | namespace tcp { 40 | 41 | namespace { 42 | const size_t kDefaultMaxCommandQueueLen = 1024; 43 | } 44 | 45 | class TcpServer final { 46 | public: 47 | // you must first call this method before you do any requests 48 | bool Launch(const base::EndPoint& local_address, 49 | const TcpServerOptions& options = TcpServerOptions()); 50 | bool Shutdown(); 51 | 52 | private: 53 | std::shared_ptr event_center_; 54 | 55 | // all callbacks 56 | ConnectedCallbackType connected_callback_; 57 | ClosedCallbackType closed_callback_; 58 | ReceivedCallbackType received_callback_; 59 | SentCallbackType sent_callback_; 60 | }; 61 | 62 | } // namespace tcp 63 | } // namespace cnetpp 64 | 65 | #endif // CNETPP_TCP_TCP_SERVER_H_ 66 | 67 | -------------------------------------------------------------------------------- /unittests/base/end_point_unittest.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include 6 | 7 | TEST(EndPoint, SockAddrTest) { 8 | sockaddr addr; 9 | socklen_t addr_len = sizeof(addr); 10 | cnetpp::base::EndPoint endpoint("127.0.0.1", 80); 11 | endpoint.ToSockAddr(&addr, &addr_len); 12 | cnetpp::base::EndPoint endpoint2; 13 | ASSERT_TRUE(endpoint2.FromSockAddr(addr, addr_len)); 14 | ASSERT_EQ(endpoint.ToString(), endpoint2.ToString()); 15 | } 16 | -------------------------------------------------------------------------------- /unittests/base/memory_cache_uinttest.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace cnetpp::base; 5 | 6 | void cleanup() { // cleanup 7 | MemoryCache::Instance()->max_cache_normal(0); 8 | MemoryCache::Instance()->max_cache_large(0); 9 | for (int i = 0; i < 8; i++) { 10 | uint32_t len = 0; 11 | void* ptr = MemoryCache::Instance()->Allocate(4096 * (1 << i)); 12 | void* ptr2 = MemoryCache::Instance()->Recycle(ptr, &len); 13 | MemoryCache::Instance()->Deallocate(ptr2); 14 | ASSERT_EQ(len, 2048u); 15 | } 16 | for (int i = 0; i < 16; i++) { 17 | uint32_t len = 0; 18 | void* ptr = MemoryCache::Instance()->Allocate((i + 1) * 1024 * 1024); 19 | void* ptr2 = MemoryCache::Instance()->Recycle(ptr, &len); 20 | MemoryCache::Instance()->Deallocate(ptr2); 21 | ASSERT_EQ(len, 2048u); 22 | } 23 | MemoryCache::Instance()->max_cache_normal(16); 24 | MemoryCache::Instance()->max_cache_large(8); 25 | } 26 | 27 | TEST(MemoryCache, Test) { 28 | { 29 | uint32_t len = 0; 30 | void* ptr = MemoryCache::Instance()->Allocate(4095); 31 | void* ptr2 = MemoryCache::Instance()->Recycle(ptr, &len); 32 | ASSERT_EQ(ptr, ptr2); 33 | MemoryCache::Instance()->Deallocate(ptr2); 34 | ASSERT_EQ(len, 4095u); 35 | } 36 | 37 | for (int i = 0; i < 8; i++) { 38 | uint32_t len = 0; 39 | void* ptr = MemoryCache::Instance()->Allocate(4096 * (1 << i)); 40 | void* ptr2 = MemoryCache::Instance()->Recycle(ptr, &len); 41 | ASSERT_FALSE(ptr == ptr2); 42 | MemoryCache::Instance()->Deallocate(ptr2); 43 | ASSERT_EQ(len, 2048u); 44 | } 45 | 46 | for (int i = 0; i < 16; i++) { 47 | uint32_t len = 0; 48 | void* ptr = MemoryCache::Instance()->Allocate((i + 1) * 1024 * 1024); 49 | void* ptr2 = MemoryCache::Instance()->Recycle(ptr, &len); 50 | ASSERT_FALSE(ptr == ptr2); 51 | MemoryCache::Instance()->Deallocate(ptr2); 52 | ASSERT_EQ(len, 2048u); 53 | } 54 | 55 | { // 17m 56 | uint32_t len = 0; 57 | void* ptr = MemoryCache::Instance()->Allocate(17 * 1024 * 1024); 58 | void* ptr2 = MemoryCache::Instance()->Recycle(ptr, &len); 59 | ASSERT_FALSE(ptr == ptr2); 60 | MemoryCache::Instance()->Deallocate(ptr2); 61 | ASSERT_EQ(len, 2048u); 62 | } 63 | 64 | cleanup(); 65 | 66 | { // max-8 67 | void* ptr[9]; 68 | for (int i = 0; i < 9; i++) { 69 | ptr[i] = MemoryCache::Instance()->Allocate(1024 * 1024); 70 | } 71 | for (int i = 0; i < 9; i++) { 72 | uint32_t len = 0; 73 | void* ptr2 = MemoryCache::Instance()->Recycle(ptr[i], &len); 74 | MemoryCache::Instance()->Deallocate(ptr2); 75 | ASSERT_EQ(len, 2048u); 76 | } 77 | for (int i = 0; i < 9; i++) { 78 | ptr[i] = MemoryCache::Instance()->Allocate(1024 * 1024); 79 | } 80 | for (int i = 0; i < 9; i++) { 81 | uint32_t len = 0; 82 | void* ptr2 = MemoryCache::Instance()->Recycle(ptr[i], &len); 83 | MemoryCache::Instance()->Deallocate(ptr2); 84 | ASSERT_EQ(len, 2048u); 85 | } 86 | } 87 | 88 | cleanup(); 89 | 90 | { 91 | void* ptr[9]; 92 | for (int i = 0; i < 9; i++) { 93 | ptr[i] = MemoryCache::Instance()->Allocate(1024 * 1024 + i); 94 | } 95 | for (int i = 0; i < 9; i++) { 96 | uint32_t len = 0; 97 | void* ptr2 = MemoryCache::Instance()->Recycle(ptr[i], &len); 98 | MemoryCache::Instance()->Deallocate(ptr2); 99 | ASSERT_EQ(len, 2048u); 100 | } 101 | for (int i = 0; i < 9; i++) { 102 | ptr[i] = MemoryCache::Instance()->Allocate(1024 * 1024 + 9 - i); 103 | } 104 | for (int i = 0; i < 9; i++) { 105 | uint32_t len = 0; 106 | void* ptr2 = MemoryCache::Instance()->Recycle(ptr[i], &len); 107 | MemoryCache::Instance()->Deallocate(ptr2); 108 | ASSERT_EQ(len, 2048u); 109 | } 110 | } 111 | 112 | cleanup(); 113 | 114 | { 115 | void* ptr[9]; 116 | for (int i = 0; i < 9; i++) { 117 | ptr[i] = MemoryCache::Instance()->Allocate(1024 * 1024 + 9 - i); 118 | } 119 | for (int i = 0; i < 9; i++) { 120 | uint32_t len = 0; 121 | void* ptr2 = MemoryCache::Instance()->Recycle(ptr[i], &len); 122 | MemoryCache::Instance()->Deallocate(ptr2); 123 | ASSERT_EQ(len, 2048u); 124 | } 125 | for (int i = 0; i < 9; i++) { 126 | ptr[i] = MemoryCache::Instance()->Allocate(1024 * 1024 + i); 127 | } 128 | for (int i = 0; i < 9; i++) { 129 | uint32_t len = 0; 130 | void* ptr2 = MemoryCache::Instance()->Recycle(ptr[i], &len); 131 | MemoryCache::Instance()->Deallocate(ptr2); 132 | ASSERT_EQ(len, 2048u); 133 | } 134 | } 135 | 136 | cleanup(); 137 | 138 | { 139 | void* ptr[9]; 140 | for (int i = 0; i < 9; i+=2) { 141 | ptr[i] = MemoryCache::Instance()->Allocate(1024 * 1024 + 9 - i); 142 | } 143 | for (int i = 1; i < 9; i+=2) { 144 | ptr[i] = MemoryCache::Instance()->Allocate(1024 * 1024 + 9 - i); 145 | } 146 | for (int i = 0; i < 9; i++) { 147 | uint32_t len = 0; 148 | void* ptr2 = MemoryCache::Instance()->Recycle(ptr[i], &len); 149 | MemoryCache::Instance()->Deallocate(ptr2); 150 | ASSERT_EQ(len, 2048u); 151 | } 152 | for (int i = 0; i < 9; i+=2) { 153 | ptr[i] = MemoryCache::Instance()->Allocate(1024 * 1024 + i); 154 | } 155 | for (int i = 1; i < 9; i+=2) { 156 | ptr[i] = MemoryCache::Instance()->Allocate(1024 * 1024 + i); 157 | } 158 | for (int i = 0; i < 9; i++) { 159 | uint32_t len = 0; 160 | void* ptr2 = MemoryCache::Instance()->Recycle(ptr[i], &len); 161 | MemoryCache::Instance()->Deallocate(ptr2); 162 | ASSERT_EQ(len, 2048u); 163 | } 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /unittests/base/string_piece_unittest.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include 6 | 7 | using namespace std; 8 | using namespace cnetpp::base; 9 | 10 | TEST(StringPiece, MiscTest) { 11 | StringPiece str((const char*)NULL, 0); 12 | ASSERT_TRUE(str.empty()); 13 | string s; 14 | str.copy_to_string(&s); 15 | ASSERT_EQ(s, ""); 16 | } 17 | 18 | TEST(StringPiece, CompareTest) { 19 | StringPiece str((const char*)NULL, 0); 20 | StringPiece str2("", 0); 21 | ASSERT_EQ(str, str2); 22 | ASSERT_EQ(str2, str2); 23 | ASSERT_EQ(str, str); 24 | ASSERT_TRUE(str == str2); 25 | } 26 | 27 | TEST(StringPiece, FindTest) { 28 | StringPiece str("This is a test string"); 29 | ASSERT_EQ(str.find("is", 0), (size_t)2); 30 | ASSERT_EQ(str.find("is", 4), (size_t)5); 31 | ASSERT_EQ(str.find('i', 0), (size_t)2); 32 | str.set((const char*)NULL, 0); 33 | ASSERT_EQ(str.find('c', 9), StringPiece::npos); 34 | } 35 | -------------------------------------------------------------------------------- /unittests/base/string_utils_test.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include "cnetpp/base/string_utils.h" 6 | 7 | using namespace std; 8 | using namespace cnetpp::base; 9 | 10 | TEST(StringUtilsTest, SplitByCharsTest01) { 11 | std::string str = "abc defhi gk"; 12 | auto res = StringUtils::SplitByChars(StringPiece(str.data(), 7), " "); 13 | ASSERT_EQ((size_t)2, res.size()); 14 | res = StringUtils::SplitByChars(str, " "); 15 | ASSERT_EQ((size_t)3, res.size()); 16 | } 17 | 18 | TEST(StringUtilsTest, Varint32Test) { 19 | for (int32_t i = 0; i < 0x7fffffff; ++i) { 20 | char buf[10]; 21 | auto length = StringUtils::ToVarint32(i, buf); 22 | uint32_t j; 23 | StringUtils::ParseVarint32( 24 | cnetpp::base::StringPiece(buf, length), &j); 25 | ASSERT_EQ((uint32_t)i, j); 26 | } 27 | } 28 | 29 | TEST(StringUtilsTest, Uint32Test) { 30 | for (uint32_t i = 0; i < 0xffffffff; ++i) { 31 | char buf[10]; 32 | StringUtils::PutUint32(i, buf); 33 | auto j = StringUtils::ToUint32( 34 | cnetpp::base::StringPiece(buf, sizeof(uint32_t))); 35 | ASSERT_EQ(i, j); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /unittests/base/uri_unittest.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | TEST(Uri, ParseTest) { 6 | cnetpp::base::Uri uri; 7 | uri.Parse("http://www.baidu.com"); 8 | ASSERT_EQ(uri.Port(), 80); 9 | ASSERT_EQ(uri.Scheme(), "http"); 10 | uri.Parse("https://www.baidu.com"); 11 | ASSERT_EQ(uri.Port(), 443); 12 | ASSERT_EQ(uri.Scheme(), "https"); 13 | uri.Parse("https://www.baidu.com:457"); 14 | ASSERT_EQ(uri.Port(), 457); 15 | ASSERT_EQ(uri.Host(), "www.baidu.com"); 16 | ASSERT_EQ(uri.Hostname(), "www.baidu.com"); 17 | ASSERT_EQ(uri.Authority(), "www.baidu.com:457"); 18 | ASSERT_EQ(uri.String(), "https://www.baidu.com:457"); 19 | uri.Parse("ftp://www.baidu.com"); 20 | ASSERT_EQ(uri.String(), "ftp://www.baidu.com"); 21 | ASSERT_EQ(uri.Port(), 0); 22 | 23 | cnetpp::base::Uri uri2; 24 | ASSERT_TRUE(uri2.ParseUriPath("/test/url?p=%2fa%2fb%2fc-d%2fe&q=%401")); 25 | auto params = uri2.QueryParams(); 26 | 27 | ASSERT_EQ(params.size(), (size_t)2); 28 | ASSERT_EQ(params[0].first, "p"); 29 | ASSERT_EQ(params[0].second, "/a/b/c-d/e"); 30 | ASSERT_EQ(params[1].first, "q"); 31 | ASSERT_EQ(params[1].second, "@1"); 32 | 33 | cnetpp::base::Uri uri3; 34 | ASSERT_TRUE(uri3.ParseUriPath("/test/url?path=%2Fdms%2Fwo%2Fdms%2Fwba_ant" 35 | "%2Fd%3D2%2Fh%3D02%3332Fnid%3D200")); 36 | auto params3 = uri3.QueryParams(); 37 | ASSERT_EQ(params3[0].first, "path"); 38 | ASSERT_EQ(params3[0].second, "/dms/wo/dms/wba_ant/d=2/h=02333/nid=200"); 39 | } 40 | -------------------------------------------------------------------------------- /unittests/concurrency/priority_queue_unittest.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | class MockTask : public cnetpp::concurrency::Task { 6 | public: 7 | MockTask(int value, int weight) : value_(value), weight_(weight) { 8 | } 9 | 10 | int value() const { 11 | return value_; 12 | } 13 | int weight() const { 14 | return weight_; 15 | } 16 | 17 | bool operator()(void* arg = nullptr) override { 18 | (void) arg; 19 | return true; 20 | } 21 | 22 | private: 23 | int value_; 24 | int weight_; 25 | }; 26 | 27 | struct MockTaskComparator { 28 | bool operator()(const std::shared_ptr& x, 29 | const std::shared_ptr& y) const { 30 | auto xx = std::static_pointer_cast(x); 31 | auto yy = std::static_pointer_cast(y); 32 | return xx->weight() > yy->weight(); 33 | } 34 | }; 35 | 36 | TEST(PriorityQueue, Test01) { 37 | auto pq = cnetpp::concurrency::CreatePriorityQueue(); 38 | ASSERT_TRUE(pq->Push(std::static_pointer_cast( 39 | std::make_shared(10, 2)))); 40 | ASSERT_TRUE(pq->Push(std::static_pointer_cast( 41 | std::make_shared(11, 1)))); 42 | auto peek = std::static_pointer_cast(pq->Peek()); 43 | ASSERT_EQ(peek->weight(), 1); 44 | ASSERT_EQ(peek->value(), 11); 45 | auto t1 = std::static_pointer_cast(pq->TryPop()); 46 | ASSERT_EQ(peek, t1); 47 | auto t2 = std::static_pointer_cast(pq->TryPop()); 48 | ASSERT_EQ(t2->weight(), 2); 49 | ASSERT_EQ(t2->value(), 10); 50 | } 51 | 52 | -------------------------------------------------------------------------------- /unittests/concurrency/thread_pool_unittest.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | 11 | TEST(ThreadPool, Test01) { 12 | auto tp = std::make_shared("Test01", true); 13 | tp->set_num_threads(200); 14 | tp->Start(); 15 | ASSERT_EQ(tp->size(), static_cast(200)); 16 | std::atomic i { 0 }; 17 | auto closure = [&i] () -> bool { i++; return true; }; 18 | for (int j = 0; j < 400; ++j) { 19 | tp->AddTask(closure); 20 | } 21 | for (int j = 0; j < 400; ++j) { 22 | tp->AddDelayTask(closure, std::chrono::seconds(1)); 23 | } 24 | std::this_thread::sleep_for(std::chrono::milliseconds(500)); 25 | EXPECT_EQ(i, 400); 26 | std::this_thread::sleep_for(std::chrono::seconds(1)); 27 | EXPECT_EQ(i, 800); 28 | tp->Stop(); 29 | } 30 | 31 | TEST(ThreadPool, TestMaxPendingTasks) { 32 | auto tp = std::make_shared("Test01", true); 33 | tp->set_num_threads(2); 34 | tp->set_max_num_pending_tasks(4); 35 | tp->Start(); 36 | ASSERT_EQ(tp->size(), static_cast(2)); 37 | std::atomic i { 0 }; 38 | auto closure = [&i] () -> bool { 39 | i++; 40 | std::this_thread::sleep_for(std::chrono::milliseconds(100)); 41 | return true; 42 | }; 43 | for (int j = 0; j < 2; ++j) { 44 | auto r = tp->AddDelayTask(closure, std::chrono::seconds(1)); 45 | EXPECT_TRUE(r); 46 | } 47 | for (int j = 0; j < 2; ++j) { 48 | auto r = tp->AddTask(closure); 49 | EXPECT_TRUE(r); 50 | } 51 | std::this_thread::sleep_for(std::chrono::milliseconds(10)); 52 | for (int j = 0; j < 2; ++j) { 53 | auto r = tp->AddTask(closure); 54 | EXPECT_TRUE(r); 55 | } 56 | for (int j = 0; j < 2; ++j) { 57 | auto r = tp->AddTask(closure); 58 | EXPECT_FALSE(r); 59 | } 60 | for (int j = 0; j < 2; ++j) { 61 | auto r = tp->AddDelayTask(closure, std::chrono::seconds(1)); 62 | EXPECT_FALSE(r); 63 | } 64 | std::this_thread::sleep_for(std::chrono::milliseconds(500)); 65 | EXPECT_EQ(i, 4); 66 | std::this_thread::sleep_for(std::chrono::seconds(1)); 67 | EXPECT_EQ(i, 6); 68 | tp->Stop(); 69 | } 70 | 71 | TEST(ThreadPool, TestStopImmediately) { 72 | auto tp = std::make_shared("Test01", true); 73 | tp->set_num_threads(2); 74 | tp->Start(); 75 | ASSERT_EQ(tp->size(), static_cast(2)); 76 | std::atomic i { 0 }; 77 | auto closure = [&i] () -> bool { 78 | i++; 79 | std::this_thread::sleep_for(std::chrono::milliseconds(100)); 80 | return true; 81 | }; 82 | for (int j = 0; j < 2; ++j) { 83 | auto r = tp->AddDelayTask(closure, std::chrono::seconds(1)); 84 | EXPECT_TRUE(r); 85 | } 86 | for (int j = 0; j < 2; ++j) { 87 | auto r = tp->AddTask(closure); 88 | EXPECT_TRUE(r); 89 | } 90 | std::this_thread::sleep_for(std::chrono::milliseconds(10)); 91 | tp->Stop(false); 92 | EXPECT_EQ(i, 2); 93 | } 94 | 95 | TEST(ThreadPool, TestDelayTask) { 96 | auto tp = std::make_shared("Test01", true); 97 | tp->set_num_threads(2); 98 | tp->Start(); 99 | ASSERT_EQ(tp->size(), static_cast(2)); 100 | std::atomic i { 0 }; 101 | std::atomic j { 0 }; 102 | auto closure1 = [&i] () -> bool { 103 | i++; 104 | return true; 105 | }; 106 | auto closure2 = [&j] () -> bool { 107 | j++; 108 | return true; 109 | }; 110 | ASSERT_TRUE(tp->AddDelayTask(closure1, std::chrono::milliseconds(10))); 111 | ASSERT_TRUE(tp->AddDelayTask(closure2, std::chrono::milliseconds(20))); 112 | std::this_thread::sleep_for(std::chrono::milliseconds(5)); 113 | EXPECT_EQ(i, 0); 114 | EXPECT_EQ(j, 0); 115 | std::this_thread::sleep_for(std::chrono::milliseconds(10)); 116 | EXPECT_EQ(i, 1); 117 | EXPECT_EQ(j, 0); 118 | std::this_thread::sleep_for(std::chrono::milliseconds(10)); 119 | EXPECT_EQ(i, 1); 120 | EXPECT_EQ(j, 1); 121 | //tp->Stop(); 122 | } 123 | 124 | TEST(ThreadPool, TestOnlyDelayTask) { 125 | auto tp = std::make_shared("Test01", true); 126 | tp->set_num_threads(0); 127 | tp->Start(); 128 | // at least one thread num 129 | ASSERT_EQ(tp->size(), static_cast(1)); 130 | std::atomic i { 0 }; 131 | std::atomic j { 0 }; 132 | auto closure1 = [&i] () -> bool { 133 | i++; 134 | return true; 135 | }; 136 | auto closure2 = [&j] () -> bool { 137 | j++; 138 | return true; 139 | }; 140 | ASSERT_TRUE(tp->AddDelayTask(closure1, std::chrono::milliseconds(10))); 141 | ASSERT_TRUE(tp->AddDelayTask(closure2, std::chrono::milliseconds(20))); 142 | std::this_thread::sleep_for(std::chrono::milliseconds(5)); 143 | EXPECT_EQ(i, 0); 144 | EXPECT_EQ(j, 0); 145 | std::this_thread::sleep_for(std::chrono::milliseconds(10)); 146 | EXPECT_EQ(i, 1); 147 | EXPECT_EQ(j, 0); 148 | std::this_thread::sleep_for(std::chrono::milliseconds(10)); 149 | EXPECT_EQ(i, 1); 150 | EXPECT_EQ(j, 1); 151 | //tp->Stop(); 152 | } 153 | -------------------------------------------------------------------------------- /unittests/concurrency/thread_unittest.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | TEST(Thread, Test01) { 13 | int base_thread_index = cnetpp::concurrency::Thread::MaxThreadIndex(); 14 | ASSERT_TRUE(cnetpp::concurrency::Thread::ThisThread() == nullptr); 15 | { 16 | std::atomic i { 0 }; 17 | char name[20]; 18 | char* p = name; 19 | auto t = std::make_shared([base_thread_index, 20 | &i, p] () -> bool { 21 | if (cnetpp::concurrency::Thread 22 | ::ThisThread()->ThreadIndex() != base_thread_index) { 23 | abort(); 24 | } 25 | i++; 26 | pthread_getname_np(pthread_self(), p, 20); 27 | return true; 28 | }, "Test01-1"); 29 | ASSERT_TRUE(cnetpp::concurrency::Thread::ThisThread() == nullptr); 30 | ASSERT_EQ(t->ThreadIndex(), base_thread_index); 31 | ASSERT_EQ(t->MaxThreadIndex(), base_thread_index + 1); 32 | ASSERT_EQ(t->ThreadPoolIndex(), -1); 33 | ASSERT_EQ(t->GetStatus(), cnetpp::concurrency::Thread::Status::kInit); 34 | t->Start(); 35 | ASSERT_EQ(t->GetStatus(), cnetpp::concurrency::Thread::Status::kRunning); 36 | ASSERT_TRUE(t->IsJoinable()); 37 | t->Stop(); 38 | ASSERT_EQ(t->GetStatus(), cnetpp::concurrency::Thread::Status::kStop); 39 | ASSERT_EQ(i, 1); 40 | ASSERT_EQ("Test01-1", t->name()); 41 | ASSERT_EQ(strcmp("Test01-1", name), 0); 42 | } 43 | { 44 | std::atomic i { 0 }; 45 | char name[20]; 46 | char* p = name; 47 | auto t = std::make_shared([base_thread_index, 48 | &i, p] () -> bool { 49 | if (cnetpp::concurrency::Thread 50 | ::ThisThread()->ThreadIndex() != base_thread_index + 1) { 51 | abort(); 52 | } 53 | i++; 54 | pthread_getname_np(pthread_self(), p, 20); 55 | return true; 56 | }, "Test01-2"); 57 | ASSERT_TRUE(cnetpp::concurrency::Thread::ThisThread() == nullptr); 58 | ASSERT_EQ(t->ThreadIndex(), base_thread_index + 1); 59 | ASSERT_EQ(t->MaxThreadIndex(), base_thread_index + 2); 60 | ASSERT_EQ(t->ThreadPoolIndex(), -1); 61 | ASSERT_EQ(t->GetStatus(), cnetpp::concurrency::Thread::Status::kInit); 62 | t->Start(); 63 | ASSERT_EQ(t->GetStatus(), cnetpp::concurrency::Thread::Status::kRunning); 64 | ASSERT_TRUE(t->IsJoinable()); 65 | t->Stop(); 66 | ASSERT_EQ(t->GetStatus(), cnetpp::concurrency::Thread::Status::kStop); 67 | ASSERT_EQ(i, 1); 68 | ASSERT_EQ("Test01-2", t->name()); 69 | ASSERT_EQ(strcmp("Test01-2", name), 0); 70 | } 71 | } 72 | 73 | --------------------------------------------------------------------------------