tcp/udp 추가, todo:iocp openssl 지원하도록 업데이트하기
This commit is contained in:
		| @@ -1,8 +1,7 @@ | |||||||
| cmake_minimum_required(VERSION 3.5) | cmake_minimum_required(VERSION 3.5) | ||||||
|  |  | ||||||
| set(PROJECT_NAME "Asteroid") | set(PROJECT_NAME "Asteroid") | ||||||
|  | set(CMAKE_EXPORT_COMPILE_COMMANDS ON) | ||||||
| set(CMAKE_BUILD_TYPE Debug) |  | ||||||
|  |  | ||||||
| if(NOT CMAKE_BUILD_TYPE) | if(NOT CMAKE_BUILD_TYPE) | ||||||
|     set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build." FORCE) |     set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build." FORCE) | ||||||
| @@ -23,5 +22,9 @@ if(WIN32) | |||||||
|     endif() |     endif() | ||||||
| endif() | endif() | ||||||
|  |  | ||||||
|  | file(GLOB_RECURSE RootProjectSources CONFIGURE_DEPENDS | ||||||
|  |     "impl/*.cpp" | ||||||
|  | ) | ||||||
|  |  | ||||||
| add_subdirectory(Client) | add_subdirectory(Client) | ||||||
| # add_subdirectory(Server) | # add_subdirectory(Server) | ||||||
							
								
								
									
										27
									
								
								CMakeSettings.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								CMakeSettings.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,27 @@ | |||||||
|  | { | ||||||
|  |   "configurations": [ | ||||||
|  |     { | ||||||
|  |       "name": "x64-Debug", | ||||||
|  |       "generator": "Ninja", | ||||||
|  |       "configurationType": "Debug", | ||||||
|  |       "inheritEnvironments": [ "msvc_x64_x64" ], | ||||||
|  |       "buildRoot": "${projectDir}\\out\\build\\${name}", | ||||||
|  |       "installRoot": "${projectDir}\\out\\install\\${name}", | ||||||
|  |       "cmakeCommandArgs": "", | ||||||
|  |       "buildCommandArgs": "", | ||||||
|  |       "ctestCommandArgs": "" | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "name": "x64-Release", | ||||||
|  |       "generator": "Ninja", | ||||||
|  |       "configurationType": "RelWithDebInfo", | ||||||
|  |       "buildRoot": "${projectDir}\\out\\build\\${name}", | ||||||
|  |       "installRoot": "${projectDir}\\out\\install\\${name}", | ||||||
|  |       "cmakeCommandArgs": "", | ||||||
|  |       "buildCommandArgs": "", | ||||||
|  |       "ctestCommandArgs": "", | ||||||
|  |       "inheritEnvironments": [ "msvc_x64_x64" ], | ||||||
|  |       "variables": [] | ||||||
|  |     } | ||||||
|  |   ] | ||||||
|  | } | ||||||
| @@ -52,7 +52,7 @@ file(GLOB_RECURSE Sources CONFIGURE_DEPENDS | |||||||
|     "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp" |     "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| add_executable(${PROJECT_NAME} ${Sources}) | add_executable(${PROJECT_NAME} ${RootProjectSources} ${Sources}) | ||||||
| target_link_libraries(${PROJECT_NAME} PRIVATE Vulkan::Vulkan) | target_link_libraries(${PROJECT_NAME} PRIVATE Vulkan::Vulkan) | ||||||
| target_link_libraries(${PROJECT_NAME} PRIVATE glm) | target_link_libraries(${PROJECT_NAME} PRIVATE glm) | ||||||
| target_link_libraries(${PROJECT_NAME} PRIVATE glfw) | target_link_libraries(${PROJECT_NAME} PRIVATE glfw) | ||||||
| @@ -62,10 +62,22 @@ target_link_libraries(${PROJECT_NAME} PRIVATE assimp::assimp) | |||||||
| target_link_libraries(${PROJECT_NAME} PRIVATE OpenSSL::Crypto) | target_link_libraries(${PROJECT_NAME} PRIVATE OpenSSL::Crypto) | ||||||
| target_link_libraries(${PROJECT_NAME} PRIVATE OpenSSL::SSL) | target_link_libraries(${PROJECT_NAME} PRIVATE OpenSSL::SSL) | ||||||
|  |  | ||||||
| target_include_directories(${PROJECT_NAME} PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/include") | if(WIN32) | ||||||
|  |     target_link_libraries(${PROJECT_NAME} PRIVATE ws2_32) | ||||||
|  | endif() | ||||||
|  | if(UNIX AND NOT APPLE AND CMAKE_BUILD_TYPE STREQUAL "Release") | ||||||
|  |     set_target_properties(${PROJECT_NAME} PROPERTIES | ||||||
|  |         BUILD_WITH_INSTALL_RPATH TRUE | ||||||
|  |         INSTALL_RPATH "$ORIGIN" | ||||||
|  |         SKIP_BUILD_RPATH FALSE | ||||||
|  |         BUILD_RPATH "$ORIGIN" | ||||||
|  |     ) | ||||||
|  | endif() | ||||||
|  |  | ||||||
|  | target_include_directories(${PROJECT_NAME} PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/../include" "${CMAKE_CURRENT_SOURCE_DIR}/include") | ||||||
| target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_20) | target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_20) | ||||||
|  |  | ||||||
| target_precompile_headers(${PROJECT_NAME} PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/include/precomp.h") | target_precompile_headers(${PROJECT_NAME} PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/../include/precomp.h") | ||||||
|  |  | ||||||
| file(GLOB_RECURSE ShaderSources CONFIGURE_DEPENDS | file(GLOB_RECURSE ShaderSources CONFIGURE_DEPENDS | ||||||
|     "${CMAKE_CURRENT_SOURCE_DIR}/shaders/*.vert" |     "${CMAKE_CURRENT_SOURCE_DIR}/shaders/*.vert" | ||||||
| @@ -81,3 +93,17 @@ add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD | |||||||
|     "${CMAKE_CURRENT_BINARY_DIR}/assets" |     "${CMAKE_CURRENT_BINARY_DIR}/assets" | ||||||
|     COMMENT "Copying assets to build directory" |     COMMENT "Copying assets to build directory" | ||||||
| ) | ) | ||||||
|  |  | ||||||
|  | add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD | ||||||
|  |     COMMAND ${CMAKE_COMMAND} -E copy_if_different | ||||||
|  |     "$<TARGET_FILE:spdlog>" | ||||||
|  |     "$<TARGET_FILE_DIR:${PROJECT_NAME}>" | ||||||
|  |     COMMENT "Copying spdlog DLL/so to output directory" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD | ||||||
|  |     COMMAND ${CMAKE_COMMAND} -E copy_directory | ||||||
|  |     "$<TARGET_FILE_DIR:spdlog>" | ||||||
|  |     "$<TARGET_FILE_DIR:${PROJECT_NAME}>" | ||||||
|  |     COMMENT "Copying spdlog library files and symlinks to output directory" | ||||||
|  | ) | ||||||
| @@ -70,7 +70,7 @@ void Graphics::CreateInstance() { | |||||||
|   VkApplicationInfo app_info = {}; |   VkApplicationInfo app_info = {}; | ||||||
|   app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; |   app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; | ||||||
|   app_info.pNext = nullptr; |   app_info.pNext = nullptr; | ||||||
|   app_info.pApplicationName = "Udemy Course"; |   app_info.pApplicationName = "Asteroid"; | ||||||
|   app_info.applicationVersion = VK_MAKE_API_VERSION(0, 0, 0, 0); |   app_info.applicationVersion = VK_MAKE_API_VERSION(0, 0, 0, 0); | ||||||
|   app_info.pEngineName = "VEng"; |   app_info.pEngineName = "VEng"; | ||||||
|   app_info.engineVersion = VK_MAKE_API_VERSION(0, 1, 0, 0); |   app_info.engineVersion = VK_MAKE_API_VERSION(0, 1, 0, 0); | ||||||
|   | |||||||
							
								
								
									
										10
									
								
								impl/session/session.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								impl/session/session.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | |||||||
|  | #include "session/session.h" | ||||||
|  |  | ||||||
|  | #include "utils/thread_pool.h" | ||||||
|  |  | ||||||
|  | namespace happytanuki { | ||||||
|  |  | ||||||
|  | Session::Session(utils::ThreadPool* tp, SessionProtocol proto) { | ||||||
|  | } | ||||||
|  |  | ||||||
|  | }  // namespace happytanuki | ||||||
							
								
								
									
										105
									
								
								impl/socket/address.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										105
									
								
								impl/socket/address.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,105 @@ | |||||||
|  | #include "socket/address.h" | ||||||
|  |  | ||||||
|  | #include <format> | ||||||
|  |  | ||||||
|  | #include "precomp.h" | ||||||
|  |  | ||||||
|  | namespace Socket { | ||||||
|  |  | ||||||
|  | Address::Address() { zeroFill(); } | ||||||
|  |  | ||||||
|  | Address::Address(int type, gsl::czstring presentationAddr, std::uint16_t port) { | ||||||
|  |   set(type, presentationAddr, port); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void Address::zeroFill() { memset(&addr_in6, 0, sizeof(addr_in6)); } | ||||||
|  |  | ||||||
|  | void Address::set(int type, gsl::czstring presentationAddr, | ||||||
|  |                   std::uint16_t port) { | ||||||
|  |   zeroFill(); | ||||||
|  |  | ||||||
|  |   if (type == AF_INET) { | ||||||
|  |     addr_in.sin_family = AF_INET; | ||||||
|  |     ::inet_pton(AF_INET, presentationAddr, &addr_in.sin_addr); | ||||||
|  |     addr_in.sin_port = htons(port); | ||||||
|  |     length = sizeof(sockaddr_in); | ||||||
|  |   } else if (type == AF_INET6) { | ||||||
|  |     addr_in6.sin6_family = AF_INET6; | ||||||
|  |     ::inet_pton(AF_INET6, presentationAddr, &addr_in6.sin6_addr); | ||||||
|  |     addr_in6.sin6_port = htons(port); | ||||||
|  |     length = sizeof(sockaddr_in6); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void Address::set(int type, in_addr_t addr, std::uint16_t port) { | ||||||
|  |   zeroFill(); | ||||||
|  |  | ||||||
|  |   if (type == AF_INET) { | ||||||
|  |     addr_in.sin_family = AF_INET; | ||||||
|  |     addr_in.sin_addr.s_addr = htonl(addr); | ||||||
|  |     addr_in.sin_port = htons(port); | ||||||
|  |     length = sizeof(sockaddr_in); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void Address::set(int type, in_addr addr, std::uint16_t port) { | ||||||
|  |   zeroFill(); | ||||||
|  |  | ||||||
|  |   if (type == AF_INET) { | ||||||
|  |     addr_in.sin_family = AF_INET; | ||||||
|  |     addr_in.sin_addr = addr; | ||||||
|  |     addr_in.sin_port = htons(port); | ||||||
|  |     length = sizeof(sockaddr_in); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void Address::set(int type, in6_addr addr, std::uint16_t port) { | ||||||
|  |   zeroFill(); | ||||||
|  |  | ||||||
|  |   if (type == AF_INET6) { | ||||||
|  |     addr_in6.sin6_family = AF_INET6; | ||||||
|  |     addr_in6.sin6_addr = addr; | ||||||
|  |     addr_in6.sin6_port = htons(port); | ||||||
|  |     length = sizeof(sockaddr_in6); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void Address::setType(int type) { | ||||||
|  |   zeroFill(); | ||||||
|  |  | ||||||
|  |   if (type == AF_INET) | ||||||
|  |     length = sizeof(sockaddr_in); | ||||||
|  |   else if (type == AF_INET6) | ||||||
|  |     length = sizeof(sockaddr_in6); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | Address::operator std::string() { | ||||||
|  |   std::optional<std::uint16_t> port = getPort(); | ||||||
|  |  | ||||||
|  |   if (!port) return std::string(); | ||||||
|  |  | ||||||
|  |   if (length == sizeof(addr_in)) { | ||||||
|  |     char addrStr[INET_ADDRSTRLEN]; | ||||||
|  |     ::inet_ntop(AF_INET, &addr_in.sin_addr, addrStr, sizeof(addrStr)); | ||||||
|  |  | ||||||
|  |     return std::format("{}:{}", addrStr, port.value()); | ||||||
|  |   } else if (length == sizeof(addr_in6)) { | ||||||
|  |     char addrStr[INET6_ADDRSTRLEN]; | ||||||
|  |     ::inet_ntop(AF_INET6, &addr_in6.sin6_addr, addrStr, sizeof(addrStr)); | ||||||
|  |  | ||||||
|  |     return std::format("{}:{}", addrStr, port.value()); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   return std::string(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | std::uint16_t Address::getPort() { | ||||||
|  |   if (length == sizeof(addr_in)) | ||||||
|  |     return ntohs(addr_in.sin_port); | ||||||
|  |   else if (length == sizeof(addr_in6)) | ||||||
|  |     return ntohs(addr_in6.sin6_port); | ||||||
|  |   else | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | }  // namespace Chattr | ||||||
							
								
								
									
										69
									
								
								impl/socket/iocp.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								impl/socket/iocp.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,69 @@ | |||||||
|  | #include "socket/iocp.h" | ||||||
|  |  | ||||||
|  | #include "utils/thread_pool.h" | ||||||
|  |  | ||||||
|  | namespace Socket { | ||||||
|  |  | ||||||
|  | IOCP::IOCP() {} | ||||||
|  |  | ||||||
|  | IOCP::~IOCP() { destruct(); } | ||||||
|  |  | ||||||
|  | void IOCP::destruct() { | ||||||
|  | #ifdef __linux__ | ||||||
|  |   uint64_t u = 1; | ||||||
|  |   ::write(epollDetroyerFd, &u, sizeof(uint64_t)); | ||||||
|  |   close(epollfd_); | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void IOCP::registerSocket(IOCPPASSINDATA* data) { | ||||||
|  |   data->event = IOCPEVENT::READ; | ||||||
|  | #ifdef _WIN32 | ||||||
|  |   HANDLE returnData = ::CreateIoCompletionPort( | ||||||
|  |       (HANDLE)data->socket->sock, completionPort_, data->socket->sock, 0); | ||||||
|  |   if (returnData == 0) completionPort_ = returnData; | ||||||
|  | #elif __linux__ | ||||||
|  |   int flags = ::fcntl(data->socket->sock, F_GETFL); | ||||||
|  |   flags |= O_NONBLOCK; | ||||||
|  |   fcntl(data->socket->sock, F_SETFL, flags); | ||||||
|  |  | ||||||
|  |   struct epoll_event ev; | ||||||
|  |   ev.events = EPOLLIN | EPOLLONESHOT; | ||||||
|  |   data->sendQueue = std::make_shared<std::queue<IOCPPASSINDATA*>>(); | ||||||
|  |   ev.data.ptr = data; | ||||||
|  |   int rc = epoll_ctl(epollfd_, EPOLL_CTL_ADD, data->socket->sock, &ev); | ||||||
|  |   if (rc < 0) log::critical("epoll_ctl()"); | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int IOCP::recv(IOCPPASSINDATA* data, int bufferCount) { | ||||||
|  |   data->event = IOCPEVENT::READ; | ||||||
|  | #ifdef _WIN32 | ||||||
|  |   DWORD recvbytes = 0, flags = 0; | ||||||
|  |   return ::WSARecv(data->socket->sock, &data->wsabuf, bufferCount, &recvbytes, | ||||||
|  |                    &flags, &data->overlapped, NULL); | ||||||
|  | #elif __linux__ | ||||||
|  |   struct epoll_event ev; | ||||||
|  |   ev.events = EPOLLIN | EPOLLONESHOT; | ||||||
|  |   ev.data.ptr = data; | ||||||
|  |   return ::epoll_ctl(epollfd_, EPOLL_CTL_MOD, data->socket->sock, &ev); | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int IOCP::send(IOCPPASSINDATA* data, int bufferCount, | ||||||
|  |                int __flags) { | ||||||
|  |   data->event = IOCPEVENT::WRITE; | ||||||
|  | #ifdef _WIN32 | ||||||
|  |   DWORD sendbytes = 0; | ||||||
|  |   return ::WSASend(data->socket->sock, &data->wsabuf, bufferCount, &sendbytes, | ||||||
|  |                    __flags, &data->overlapped, NULL); | ||||||
|  | #elif __linux__ | ||||||
|  |   struct epoll_event ev; | ||||||
|  |   ev.events = EPOLLIN | EPOLLOUT | EPOLLONESHOT; | ||||||
|  |   ev.data.ptr = data; | ||||||
|  |   data->sendQueue->push(data); | ||||||
|  |   return ::epoll_ctl(epollfd_, EPOLL_CTL_MOD, data->socket->sock, &ev); | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  |  | ||||||
|  | }  // namespace Chattr | ||||||
							
								
								
									
										42
									
								
								impl/socket/tcp_socket.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								impl/socket/tcp_socket.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,42 @@ | |||||||
|  | #include "socket/tcp_socket.h" | ||||||
|  |  | ||||||
|  | namespace Socket { | ||||||
|  |  | ||||||
|  | int TCPSocket::init(int domain) { return init(domain, SOCK_STREAM, 0); } | ||||||
|  |  | ||||||
|  | int TCPSocket::listen(int __n) { | ||||||
|  |   int retVal = ::listen(sock, __n); | ||||||
|  |   if (retVal == INVALID_SOCKET) spdlog::error("listen()"); | ||||||
|  |   return retVal; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void TCPSocket::accept(TCPSocket &newSock, Address &__addr) { | ||||||
|  |   newSock.set(::accept(sock, &__addr.addr, &__addr.length), domain); | ||||||
|  |   memcpy(&newSock.remoteAddr, &__addr, sizeof(Address)); | ||||||
|  |   if (newSock.sock == INVALID_SOCKET) spdlog::error("accept()"); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int TCPSocket::connect(Address &serveraddr) { | ||||||
|  |   int retVal = | ||||||
|  |       ::connect(sock, (struct sockaddr *)&serveraddr.addr, serveraddr.length); | ||||||
|  |   memcpy(&remoteAddr, &serveraddr, sizeof(Address)); | ||||||
|  |   if (retVal == INVALID_SOCKET) spdlog::error("connect()"); | ||||||
|  |   return retVal; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int TCPSocket::recv(void *__restrict __buf, size_t __n, int __flags) { | ||||||
|  |   int retVal = ::recv(sock, (char *)__buf, __n, __flags); | ||||||
|  |   if (retVal == SOCKET_ERROR) { | ||||||
|  |     if (errno == EAGAIN || errno == EWOULDBLOCK) return retVal; | ||||||
|  |     spdlog::error("recv()"); | ||||||
|  |   } | ||||||
|  |   return retVal; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int TCPSocket::send(const void *__buf, size_t __n, int __flags) { | ||||||
|  |   int retVal = ::send(sock, (char *)__buf, __n, __flags); | ||||||
|  |   if (retVal == SOCKET_ERROR) spdlog::error("send()"); | ||||||
|  |   return retVal; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | }  // namespace Socket | ||||||
							
								
								
									
										112
									
								
								impl/socket/udp_socket.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										112
									
								
								impl/socket/udp_socket.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,112 @@ | |||||||
|  | #include "socket/udp_socket.h" | ||||||
|  |  | ||||||
|  | namespace Socket { | ||||||
|  |  | ||||||
|  | UDPSocket::UDPSocket(int domain, int type, int protocol) { | ||||||
|  |   init(domain, type, protocol); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | UDPSocket::~UDPSocket() { destruct(); } | ||||||
|  |  | ||||||
|  | int UDPSocket::init(int domain, int type, int protocol) { | ||||||
|  |   this->domain = domain; | ||||||
|  |  | ||||||
|  |   sock = ::socket(domain, type, protocol); | ||||||
|  |   if (sock == INVALID_SOCKET) spdlog::critical("socket()"); | ||||||
|  |  | ||||||
|  |   valid_ = true; | ||||||
|  |  | ||||||
|  |   return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void UDPSocket::destruct() { | ||||||
|  |   if (!valid_) return; | ||||||
|  | #ifdef _WIN32 | ||||||
|  |   ::closesocket(sock); | ||||||
|  | #elif __linux__ | ||||||
|  |   ::close(sock); | ||||||
|  | #endif | ||||||
|  |   valid_ = false; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | UDPSocket::operator SOCKET() { | ||||||
|  |   if (valid_) { | ||||||
|  |     valid_ = false; | ||||||
|  |     return sock; | ||||||
|  |   } | ||||||
|  |   spdlog::critical("No valid socket created."); | ||||||
|  |   return INVALID_SOCKET; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void UDPSocket::set(const SOCKET __sock, int __domain) { | ||||||
|  |   if (__sock == INVALID_SOCKET) { | ||||||
|  |     spdlog::critical("socket()"); | ||||||
|  |     std::exit(EXIT_FAILURE); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   destruct(); | ||||||
|  |  | ||||||
|  |   sock = __sock; | ||||||
|  |   valid_ = true; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | int UDPSocket::setsockopt(int level, int optname, const char* optval, | ||||||
|  |                                int optlen) { | ||||||
|  |   return ::setsockopt(sock, level, optname, optval, optlen); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int UDPSocket::bind(Address __addr) { | ||||||
|  |   bindAddr = __addr; | ||||||
|  |   int retVal = ::bind(sock, &__addr.addr, __addr.length); | ||||||
|  |   if (retVal == INVALID_SOCKET) { | ||||||
|  |     spdlog::critical("bind()"); | ||||||
|  |     std::exit(EXIT_FAILURE); | ||||||
|  |   } | ||||||
|  |   return retVal; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int UDPSocket::recvfrom(void* __restrict __buf, size_t __n, int __flags, | ||||||
|  |                         struct Address& __addr) { | ||||||
|  |   std::lock_guard<std::mutex> lock(readMutex); | ||||||
|  |   int retVal = ::recvfrom(sock, (char*)__buf, __n, __flags, &__addr.addr, | ||||||
|  |                           &__addr.length); | ||||||
|  |   if (retVal == SOCKET_ERROR) spdlog::error("recvfrom()"); | ||||||
|  |   return retVal; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int UDPSocket::sendto(const void* __buf, size_t __n, int __flags, | ||||||
|  |                       struct Address __addr) { | ||||||
|  |   std::lock_guard<std::mutex> lock(writeMutex); | ||||||
|  |   int retVal = | ||||||
|  |       ::sendto(sock, (char*)__buf, __n, __flags, &__addr.addr, __addr.length); | ||||||
|  |   if (retVal == SOCKET_ERROR) spdlog::error("sendto()"); | ||||||
|  |   return retVal; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | UDPSocket::UDPSocket(const UDPSocket& other_) { | ||||||
|  |   memcpy(this, &other_, sizeof(UDPSocket)); | ||||||
|  |   valid_ = false; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | UDPSocket::UDPSocket(UDPSocket&& other_) noexcept { | ||||||
|  |   other_.valid_ = false; | ||||||
|  |   memcpy(this, &other_, sizeof(UDPSocket)); | ||||||
|  |   valid_ = true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | UDPSocket& UDPSocket::operator=(const UDPSocket& other_) { | ||||||
|  |   memcpy(this, &other_, sizeof(UDPSocket)); | ||||||
|  |   valid_ = false; | ||||||
|  |  | ||||||
|  |   return *this; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | UDPSocket& UDPSocket::operator=(UDPSocket&& other_) noexcept { | ||||||
|  |   other_.valid_ = false; | ||||||
|  |   memcpy(this, &other_, sizeof(UDPSocket)); | ||||||
|  |   valid_ = true; | ||||||
|  |  | ||||||
|  |   return *this; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | }  // namespace Socket | ||||||
							
								
								
									
										20
									
								
								impl/socket/wsa_manager.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								impl/socket/wsa_manager.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | |||||||
|  | #include "socket/wsa_manager.h" | ||||||
|  |  | ||||||
|  | namespace Socket { | ||||||
|  | WSAManager::WSAManager() { | ||||||
|  | #ifdef _WIN32 | ||||||
|  | 	WSADATA wsa; | ||||||
|  |   if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0) { | ||||||
|  |     spdlog::critical("WSAStartup()"); | ||||||
|  |     std::exit(EXIT_FAILURE); | ||||||
|  |   } | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  |  | ||||||
|  | WSAManager::~WSAManager() { | ||||||
|  | #ifdef _WIN32 | ||||||
|  | 	WSACleanup(); | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  |  | ||||||
|  | } | ||||||
							
								
								
									
										10
									
								
								impl/transport/transport.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								impl/transport/transport.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | |||||||
|  | #include "transport/transport.h" | ||||||
|  |  | ||||||
|  | namespace happytanuki { | ||||||
|  | Transport::Transport(utils::ThreadPool* tp) { tp_ = tp; } | ||||||
|  |  | ||||||
|  | void Transport::Send() {} | ||||||
|  |  | ||||||
|  | void Transport::Recv() {} | ||||||
|  |  | ||||||
|  | }  // namespace happytanuki | ||||||
							
								
								
									
										32
									
								
								impl/utils/generate_id.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								impl/utils/generate_id.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,32 @@ | |||||||
|  | #include "utils/snowflake.h" | ||||||
|  |  | ||||||
|  | #include <thread> | ||||||
|  |  | ||||||
|  | namespace utils { | ||||||
|  |  | ||||||
|  | static struct EpochInitializer { | ||||||
|  |   EpochInitializer() { EPOCH = std::chrono::system_clock::now(); } | ||||||
|  |   std::chrono::system_clock::time_point EPOCH; | ||||||
|  | } epochInitializer; | ||||||
|  |  | ||||||
|  | Snowflake GenerateID() { | ||||||
|  |   static std::mutex snowflakeGenerateMutex_; | ||||||
|  |  | ||||||
|  |   std::lock_guard<std::mutex> lock(snowflakeGenerateMutex_); | ||||||
|  |  | ||||||
|  |   std::size_t tid = | ||||||
|  |       std::hash<std::thread::id>{}(std::this_thread::get_id()); | ||||||
|  |  | ||||||
|  |   thread_local static int sequence = 0; | ||||||
|  |   Snowflake id = {}; | ||||||
|  |  | ||||||
|  |   auto timestamp = std::chrono::duration_cast<std::chrono::milliseconds>( | ||||||
|  |       std::chrono::system_clock::now() - epochInitializer.EPOCH); | ||||||
|  |   id.timestamp = timestamp.count(); | ||||||
|  |   id.instance = tid; | ||||||
|  |   id.sequence = sequence++; | ||||||
|  |  | ||||||
|  |   return id; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | };  // namespace Chattr | ||||||
							
								
								
									
										27
									
								
								impl/utils/log.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								impl/utils/log.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,27 @@ | |||||||
|  | #include "utils/log.h" | ||||||
|  |  | ||||||
|  | #include "spdlog/sinks/rotating_file_sink.h" | ||||||
|  | #include "spdlog/sinks/stdout_color_sinks.h" | ||||||
|  | #ifdef _WIN32 | ||||||
|  | #include "spdlog/sinks/msvc_sink.h" | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | namespace utils { | ||||||
|  |  | ||||||
|  | void setDefaultLogger(spdlog::level::level_enum logLevel, | ||||||
|  |                       gsl::czstring logFileName, std::uint32_t logFileSize, | ||||||
|  |                       std::uint32_t logFileCount) { | ||||||
|  |   std::vector<spdlog::sink_ptr> sinks; | ||||||
|  |   sinks.push_back(std::make_shared<spdlog::sinks::stdout_color_sink_mt>()); | ||||||
|  |   sinks.push_back(std::make_shared<spdlog::sinks::rotating_file_sink_mt>( | ||||||
|  |       logFileName, logFileSize, logFileCount, false)); | ||||||
|  | #ifdef _WIN32 | ||||||
|  |   sinks.push_back(std::make_shared<spdlog::sinks::msvc_sink_mt>()); | ||||||
|  | #endif | ||||||
|  |   auto chatteringLogger = std::make_shared<spdlog::logger>( | ||||||
|  |       "Chattering Logger", begin(sinks), end(sinks)); | ||||||
|  |   chatteringLogger->set_level(logLevel); | ||||||
|  |   spdlog::set_default_logger(chatteringLogger); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | }  // namespace Chattr::log | ||||||
							
								
								
									
										22
									
								
								include/session/session.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								include/session/session.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | |||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include <openssl/bio.h> | ||||||
|  | #include <openssl/err.h> | ||||||
|  | #include <openssl/ssl.h> | ||||||
|  |  | ||||||
|  | #include "socket/iocp.h" | ||||||
|  | #include "utils/thread_pool.h" | ||||||
|  |  | ||||||
|  | namespace happytanuki { | ||||||
|  |  | ||||||
|  | enum class SessionProtocol { UDP, TCP, TLS, QUIC }; | ||||||
|  |  | ||||||
|  | class Session { | ||||||
|  |  public: | ||||||
|  |   Session(utils::ThreadPool* tp, SessionProtocol proto); | ||||||
|  |  | ||||||
|  |  private: | ||||||
|  |   Socket::IOCP iocp_; | ||||||
|  |   utils::ThreadPool* tp_; | ||||||
|  | }; | ||||||
|  | }  // namespace happytanuki | ||||||
							
								
								
									
										27
									
								
								include/socket/address.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								include/socket/address.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,27 @@ | |||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | namespace Socket { | ||||||
|  |  | ||||||
|  | struct Address { | ||||||
|  |   Address(); | ||||||
|  |   Address(int type, gsl::czstring presentationAddr, std::uint16_t port); | ||||||
|  |  | ||||||
|  |   void zeroFill(); | ||||||
|  |   void set(int type, gsl::czstring presentationAddr, std::uint16_t port); | ||||||
|  |   void set(int type, in_addr_t addr, std::uint16_t port); | ||||||
|  |   void set(int type, in_addr addr, std::uint16_t port); | ||||||
|  |   void set(int type, in6_addr addr, std::uint16_t port); | ||||||
|  |   void setType(int type); | ||||||
|  |  | ||||||
|  |   operator std::string(); | ||||||
|  |   std::uint16_t getPort(); | ||||||
|  |  | ||||||
|  |   union { | ||||||
|  |     struct sockaddr addr; | ||||||
|  |     struct sockaddr_in addr_in; | ||||||
|  |     struct sockaddr_in6 addr_in6; | ||||||
|  |   }; | ||||||
|  |   socklen_t length; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | }  // namespace Chattr | ||||||
							
								
								
									
										376
									
								
								include/socket/iocp.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										376
									
								
								include/socket/iocp.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,376 @@ | |||||||
|  | #pragma once | ||||||
|  | #include <functional> | ||||||
|  | #include <queue> | ||||||
|  | #include <vector> | ||||||
|  |  | ||||||
|  | #include "socket/tcp_socket.h" | ||||||
|  | #include "socket/wsa_manager.h" | ||||||
|  | #include "utils/thread_pool.h" | ||||||
|  |  | ||||||
|  | #ifdef __linux__ | ||||||
|  |  | ||||||
|  | typedef struct _OVERLAPPED { | ||||||
|  |   char dummy; | ||||||
|  | } OVERLAPPED; | ||||||
|  |  | ||||||
|  | typedef struct __WSABUF { | ||||||
|  |   std::uint32_t len; | ||||||
|  |   char* buf; | ||||||
|  | } WSABUF; | ||||||
|  |  | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | namespace Socket { | ||||||
|  |  | ||||||
|  | class IOCP; | ||||||
|  |  | ||||||
|  | enum class IOCPEVENT { QUIT, READ, WRITE }; | ||||||
|  |  | ||||||
|  | struct IOCPPASSINDATA { | ||||||
|  |   OVERLAPPED overlapped; | ||||||
|  |   IOCPEVENT event; | ||||||
|  |   std::shared_ptr<UDPSocket> socket; | ||||||
|  |   std::uint32_t recvbytes; | ||||||
|  |   std::uint32_t sendbytes; | ||||||
|  |   std::uint32_t transferredbytes; | ||||||
|  |   WSABUF wsabuf; | ||||||
|  |   std::uint32_t bufsize; | ||||||
|  |   IOCP* IOCPInstance; | ||||||
|  | #ifdef __linux__ | ||||||
|  |   std::shared_ptr<std::queue<IOCPPASSINDATA*>> sendQueue; | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  |   IOCPPASSINDATA(std::uint32_t bufsize) { | ||||||
|  |     std::memset(&overlapped, 0, sizeof(overlapped)); | ||||||
|  |     event = IOCPEVENT::QUIT; | ||||||
|  |     socket = nullptr; | ||||||
|  |     recvbytes = 0; | ||||||
|  |     sendbytes = 0; | ||||||
|  |     transferredbytes = 0; | ||||||
|  |     this->bufsize = bufsize; | ||||||
|  |     IOCPInstance = nullptr; | ||||||
|  |  | ||||||
|  |     wsabuf.buf = new char[bufsize]; | ||||||
|  |   } | ||||||
|  |   IOCPPASSINDATA(const IOCPPASSINDATA& other) | ||||||
|  |       : event(other.event), | ||||||
|  |         socket(other.socket), | ||||||
|  |         transferredbytes(other.transferredbytes), | ||||||
|  |         bufsize(other.bufsize), | ||||||
|  |         IOCPInstance(other.IOCPInstance) | ||||||
|  | #ifdef __linux__ | ||||||
|  |         , | ||||||
|  |         sendQueue(other.sendQueue) | ||||||
|  | #endif | ||||||
|  |   { | ||||||
|  |     std::memset(&overlapped, 0, sizeof(overlapped)); | ||||||
|  |     recvbytes = 0; | ||||||
|  |     sendbytes = 0; | ||||||
|  |     wsabuf.buf = new char[bufsize]; | ||||||
|  |     std::memcpy(wsabuf.buf, other.wsabuf.buf, other.wsabuf.len); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   ~IOCPPASSINDATA() { | ||||||
|  |     if (wsabuf.buf != nullptr) delete wsabuf.buf; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   IOCPPASSINDATA& operator=(const IOCPPASSINDATA& other) { | ||||||
|  |     if (this != &other) { | ||||||
|  |       std::memset(&overlapped, 0, sizeof(overlapped)); | ||||||
|  |       event = other.event; | ||||||
|  |       socket = other.socket; | ||||||
|  |       recvbytes = 0; | ||||||
|  |       sendbytes = 0; | ||||||
|  |       transferredbytes = other.transferredbytes; | ||||||
|  |       bufsize = other.bufsize; | ||||||
|  |       IOCPInstance = other.IOCPInstance; | ||||||
|  | #ifdef __linux__ | ||||||
|  |       sendQueue = other.sendQueue; | ||||||
|  | #endif | ||||||
|  |       wsabuf.buf = new char[bufsize]; | ||||||
|  |       std::memcpy(wsabuf.buf, other.wsabuf.buf, other.wsabuf.len); | ||||||
|  |     } | ||||||
|  |     return *this; | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | class IOCP { | ||||||
|  |  public: | ||||||
|  | #ifdef _WIN32 | ||||||
|  |   static void iocpWather( | ||||||
|  |       utils::ThreadPool* threadPool, HANDLE completionPort_, | ||||||
|  |       std::function<void(utils::ThreadPool*, IOCPPASSINDATA*)> callback) { | ||||||
|  |     IOCPPASSINDATA* data; | ||||||
|  |     SOCKET sock; | ||||||
|  |     DWORD cbTransfrred; | ||||||
|  |     int retVal = GetQueuedCompletionStatus(completionPort_, &cbTransfrred, | ||||||
|  |                                            (PULONG_PTR)&sock, | ||||||
|  |                                            (LPOVERLAPPED*)&data, INFINITE); | ||||||
|  |     if (retVal == 0 || cbTransfrred == 0) { | ||||||
|  |       data->event = IOCPEVENT::QUIT; | ||||||
|  |       spdlog::debug("Disconnected. [{}]", | ||||||
|  |                     (std::string)(data->socket->remoteAddr)); | ||||||
|  |     } else { | ||||||
|  |       data->transferredbytes = cbTransfrred; | ||||||
|  |     } | ||||||
|  |     threadPool->enqueueJob(callback, data); | ||||||
|  |     threadPool->enqueueJob(iocpWather, completionPort_, callback); | ||||||
|  |   }; | ||||||
|  | #elif __linux__ | ||||||
|  |   static void socketReader( | ||||||
|  |       ThreadPool* threadPool, epoll_event event, int epollfd, | ||||||
|  |       std::function<void(ThreadPool*, IOCPPASSINDATA*)> callback) { | ||||||
|  |     pthread_t tid = pthread_self(); | ||||||
|  |  | ||||||
|  |     if (event.data.ptr == nullptr) { | ||||||
|  |       spdlog::error("invalid call on {}", tid); | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     IOCPPASSINDATA* rootIocpData = (IOCPPASSINDATA*)event.data.ptr; | ||||||
|  |  | ||||||
|  |     std::lock_guard<std::mutex> lock(rootIocpData->socket->readMutex); | ||||||
|  |     while (true) { | ||||||
|  |       char peekBuffer[1]; | ||||||
|  |       int rc = rootIocpData->socket->recv(peekBuffer, 1, MSG_PEEK); | ||||||
|  |       if (rc > 0) | ||||||
|  |         ; | ||||||
|  |       else if (rc == 0) { | ||||||
|  |         rootIocpData->event = IOCPEVENT::QUIT; | ||||||
|  |         spdlog::debug("Disconnected. [{}]", | ||||||
|  |                       (std::string)(rootIocpData->socket->remoteAddr)); | ||||||
|  |         ::epoll_ctl(epollfd, EPOLL_CTL_DEL, rootIocpData->socket->sock, NULL); | ||||||
|  |         threadPool->enqueueJob(callback, rootIocpData); | ||||||
|  |         // delete rootIocpData; | ||||||
|  |         return; | ||||||
|  |       } else { | ||||||
|  |         if (errno == EAGAIN || errno == EWOULDBLOCK) { | ||||||
|  |           spdlog::trace("No data to read on {}", tid); | ||||||
|  |           return; | ||||||
|  |         } else { | ||||||
|  |           rootIocpData->event = IOCPEVENT::QUIT; | ||||||
|  |           spdlog::debug("Disconnected. [{}]", | ||||||
|  |                         (std::string)(rootIocpData->socket->remoteAddr)); | ||||||
|  |           ::epoll_ctl(epollfd, EPOLL_CTL_DEL, rootIocpData->socket->sock, NULL); | ||||||
|  |           threadPool->enqueueJob(callback, rootIocpData); | ||||||
|  |           // delete rootIocpData; | ||||||
|  |           return; | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |       Chattr::IOCPPASSINDATA* ptr = new Chattr::IOCPPASSINDATA(*rootIocpData); | ||||||
|  |       ptr->wsabuf.len = 1500; | ||||||
|  |  | ||||||
|  |       int redSize = 0; | ||||||
|  |       int headerSize = 8; | ||||||
|  |       int totalRedSize = 0; | ||||||
|  |  | ||||||
|  |       while (totalRedSize < headerSize) { | ||||||
|  |         redSize = ptr->socket->recv(ptr->buf + totalRedSize, | ||||||
|  |                                     headerSize - totalRedSize, 0); | ||||||
|  |  | ||||||
|  |         if (redSize == SOCKET_ERROR) { | ||||||
|  |           ptr->event = IOCPEVENT::QUIT; | ||||||
|  |           spdlog::debug("Disconnected. [{}]", | ||||||
|  |                         (std::string)(ptr->socket->remoteAddr)); | ||||||
|  |           ::epoll_ctl(epollfd, EPOLL_CTL_DEL, ptr->socket->sock, NULL); | ||||||
|  |           threadPool->enqueueJob(callback, ptr); | ||||||
|  |           // delete ptr; | ||||||
|  |           return; | ||||||
|  |         } else if (redSize == 0) { | ||||||
|  |           ptr->event = IOCPEVENT::QUIT; | ||||||
|  |           spdlog::debug("Disconnected. [{}]", | ||||||
|  |                         (std::string)(ptr->socket->remoteAddr)); | ||||||
|  |           ::epoll_ctl(epollfd, EPOLL_CTL_DEL, ptr->socket->sock, NULL); | ||||||
|  |           threadPool->enqueueJob(callback, ptr); | ||||||
|  |           // delete ptr; | ||||||
|  |           return; | ||||||
|  |         } | ||||||
|  |         totalRedSize += redSize; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       Packet packet; | ||||||
|  |       ::memcpy(packet.serialized, ptr->buf, headerSize); | ||||||
|  |  | ||||||
|  |       redSize = 0; | ||||||
|  |       int dataLength = ntohs(packet.__data.packetLength); | ||||||
|  |  | ||||||
|  |       while (totalRedSize < dataLength + headerSize) { | ||||||
|  |         redSize = ptr->socket->recv(ptr->buf + totalRedSize, | ||||||
|  |                                     dataLength + headerSize - totalRedSize, 0); | ||||||
|  |  | ||||||
|  |         if (redSize == SOCKET_ERROR) { | ||||||
|  |           if (errno == EAGAIN || errno == EWOULDBLOCK) { | ||||||
|  |             spdlog::trace("No data to read on {}", tid); | ||||||
|  |             return; | ||||||
|  |           } | ||||||
|  |           ptr->event = IOCPEVENT::QUIT; | ||||||
|  |           spdlog::debug("Disconnected. [{}]", | ||||||
|  |                         (std::string)(ptr->socket->remoteAddr)); | ||||||
|  |           ::epoll_ctl(epollfd, EPOLL_CTL_DEL, ptr->socket->sock, NULL); | ||||||
|  |           threadPool->enqueueJob(callback, ptr); | ||||||
|  |           // delete ptr; | ||||||
|  |           return; | ||||||
|  |         } else if (redSize == 0) { | ||||||
|  |           ptr->event = IOCPEVENT::QUIT; | ||||||
|  |           spdlog::debug("Disconnected. [{}]", | ||||||
|  |                         (std::string)(ptr->socket->remoteAddr)); | ||||||
|  |           ::epoll_ctl(epollfd, EPOLL_CTL_DEL, ptr->socket->sock, NULL); | ||||||
|  |           threadPool->enqueueJob(callback, ptr); | ||||||
|  |           // delete ptr; | ||||||
|  |           return; | ||||||
|  |         } | ||||||
|  |         totalRedSize += redSize; | ||||||
|  |       } | ||||||
|  |       ptr->transferredbytes = totalRedSize; | ||||||
|  |       threadPool->enqueueJob(callback, ptr); | ||||||
|  |     } | ||||||
|  |   }; | ||||||
|  |   static void socketWriter( | ||||||
|  |       ThreadPool* threadPool, epoll_event event, int epollfd, | ||||||
|  |       std::function<void(ThreadPool*, IOCPPASSINDATA*)> callback) { | ||||||
|  |     pthread_t tid = pthread_self(); | ||||||
|  |  | ||||||
|  |     if (event.data.ptr == nullptr) { | ||||||
|  |       spdlog::error("invalid call on {}", tid); | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     IOCPPASSINDATA* rootIocpData = (IOCPPASSINDATA*)event.data.ptr; | ||||||
|  |  | ||||||
|  |     std::lock_guard<std::mutex> lock(rootIocpData->socket->writeMutex); | ||||||
|  |     while (!rootIocpData->sendQueue->empty()) { | ||||||
|  |       IOCPPASSINDATA* data = rootIocpData->sendQueue->front(); | ||||||
|  |       rootIocpData->sendQueue->pop(); | ||||||
|  |  | ||||||
|  |       if (data == nullptr) { | ||||||
|  |         spdlog::error("invalid call on {}", tid); | ||||||
|  |         break; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       int packetSize = data->wsabuf.len; | ||||||
|  |       int totalSentSize = 0; | ||||||
|  |       int sentSize = 0; | ||||||
|  |  | ||||||
|  |       spdlog::trace("Sending to: [{}]", (std::string)data->socket->remoteAddr); | ||||||
|  |  | ||||||
|  |       while (totalSentSize < packetSize) { | ||||||
|  |         sentSize = data->socket->send(data->buf + totalSentSize, | ||||||
|  |                                       packetSize - totalSentSize, 0); | ||||||
|  |  | ||||||
|  |         if (sentSize == SOCKET_ERROR) { | ||||||
|  |           if (errno == EAGAIN || errno == EWOULDBLOCK) { | ||||||
|  |             spdlog::warn("buffer full"); | ||||||
|  |             continue; | ||||||
|  |           } | ||||||
|  |           data->event = IOCPEVENT::QUIT; | ||||||
|  |           spdlog::debug("Disconnected. [{}]", | ||||||
|  |                         (std::string)(data->socket->remoteAddr)); | ||||||
|  |           ::epoll_ctl(epollfd, EPOLL_CTL_DEL, data->socket->sock, NULL); | ||||||
|  |           threadPool->enqueueJob(callback, data); | ||||||
|  |           // delete data; | ||||||
|  |           return; | ||||||
|  |         } | ||||||
|  |         totalSentSize += sentSize; | ||||||
|  |       } | ||||||
|  |       data->transferredbytes = totalSentSize; | ||||||
|  |       threadPool->enqueueJob(callback, data); | ||||||
|  |     } | ||||||
|  |   }; | ||||||
|  |   static void iocpWatcher( | ||||||
|  |       ThreadPool* threadPool, int epollfd, int epollDetroyerFd, | ||||||
|  |       std::function<void(ThreadPool*, IOCPPASSINDATA*)> callback) { | ||||||
|  |     struct epoll_event events[FD_SETSIZE]; | ||||||
|  |     pthread_t tid = pthread_self(); | ||||||
|  |  | ||||||
|  |     int nready = ::epoll_wait(epollfd, events, FD_SETSIZE, -1); | ||||||
|  |  | ||||||
|  |     for (int i = 0; i < nready; i++) { | ||||||
|  |       struct epoll_event current_event = events[i]; | ||||||
|  |  | ||||||
|  |       if (current_event.events & EPOLLIN) { | ||||||
|  |         if (current_event.data.fd == epollDetroyerFd) { | ||||||
|  |           return; | ||||||
|  |         } | ||||||
|  |         std::function<void(ThreadPool*, IOCPPASSINDATA*)> task(callback); | ||||||
|  |         threadPool->enqueueJob(socketReader, current_event, epollfd, task); | ||||||
|  |       } else if (current_event.events & EPOLLOUT) { | ||||||
|  |         std::function<void(ThreadPool*, IOCPPASSINDATA*)> task(callback); | ||||||
|  |         threadPool->enqueueJob(socketWriter, current_event, epollfd, task); | ||||||
|  |       } | ||||||
|  |       if (--nready <= 0) break; | ||||||
|  |     } | ||||||
|  |     threadPool->enqueueJob(iocpWatcher, epollfd, epollDetroyerFd, callback); | ||||||
|  |   }; | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  |   IOCP(); | ||||||
|  |   ~IOCP(); | ||||||
|  |  | ||||||
|  |   template <typename _Callable> | ||||||
|  |   void init(utils::ThreadPool* __IOCPThread, _Callable&& callback) { | ||||||
|  |     IOCPThread_ = __IOCPThread; | ||||||
|  | #ifdef _WIN32 | ||||||
|  |     completionPort_ = | ||||||
|  |         ::CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0); | ||||||
|  |     if (completionPort_ == NULL) { | ||||||
|  |       spdlog::critical("CreateIoCompletionPort()"); | ||||||
|  |       std::exit(EXIT_FAILURE); | ||||||
|  |     } | ||||||
|  | #elif __linux__ | ||||||
|  |     epollfd_ = ::epoll_create(1); | ||||||
|  |     epollDetroyerFd = ::eventfd(0, EFD_NONBLOCK); | ||||||
|  |     struct epoll_event ev; | ||||||
|  |     ev.events = EPOLLIN; | ||||||
|  |     ev.data.fd = epollDetroyerFd; | ||||||
|  |     ::epoll_ctl(epollfd_, EPOLL_CTL_ADD, epollDetroyerFd, &ev); | ||||||
|  | #endif | ||||||
|  |     auto boundFunc = [callback = std::move(callback)]( | ||||||
|  |                          utils::ThreadPool* __IOCPThread, | ||||||
|  |                          IOCPPASSINDATA* data) mutable { | ||||||
|  |       callback(__IOCPThread, data); | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  | #ifdef _WIN32 | ||||||
|  |     int tCount = __IOCPThread->threadCount; | ||||||
|  |  | ||||||
|  |     spdlog::info("Resizing threadpool size to: {}", tCount * 2); | ||||||
|  |  | ||||||
|  |     __IOCPThread->respawnWorker(tCount * 2); | ||||||
|  |  | ||||||
|  |     for (int i = 0; i < tCount; i++) { | ||||||
|  |       std::function<void(utils::ThreadPool*, IOCPPASSINDATA*)> task(boundFunc); | ||||||
|  |       __IOCPThread->enqueueJob(iocpWather, completionPort_, task); | ||||||
|  |     } | ||||||
|  | #elif __linux__ | ||||||
|  |     __IOCPThread->respawnWorker(__IOCPThread->threadCount + 1); | ||||||
|  |     spdlog::info("Spawning 1 Epoll Waiter..."); | ||||||
|  |     __IOCPThread->enqueueJob(iocpWatcher, epollfd_, epollDetroyerFd, boundFunc); | ||||||
|  | #endif | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   void destruct(); | ||||||
|  |  | ||||||
|  |   void registerSocket(IOCPPASSINDATA* data); | ||||||
|  |  | ||||||
|  |   int recv(IOCPPASSINDATA* data, int bufferCount); | ||||||
|  |   int send(IOCPPASSINDATA* data, int bufferCount, int __flags); | ||||||
|  |  | ||||||
|  | #ifdef __linux__ | ||||||
|  |   int epollDetroyerFd = -1; | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  |  private: | ||||||
|  |   struct WSAManager* wsaManager = WSAManager::GetInstance(); | ||||||
|  |   utils::ThreadPool* IOCPThread_; | ||||||
|  |  | ||||||
|  | #ifdef _WIN32 | ||||||
|  |   HANDLE completionPort_ = INVALID_HANDLE_VALUE; | ||||||
|  | #elif __linux__ | ||||||
|  |   int epollfd_ = -1; | ||||||
|  |   std::unordered_map<std::shared_ptr<TCPSocket>, std::mutex> writeMutex; | ||||||
|  |   std::unordered_map<std::shared_ptr<TCPSocket>, std::queue<IOCPPASSINDATA*>> | ||||||
|  |       writeBuffer; | ||||||
|  | #endif | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | }  // namespace Socket | ||||||
							
								
								
									
										18
									
								
								include/socket/tcp_socket.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								include/socket/tcp_socket.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | |||||||
|  | #pragma once | ||||||
|  | #include "udp_socket.h" | ||||||
|  |  | ||||||
|  | namespace Socket { | ||||||
|  |  | ||||||
|  | class TCPSocket : public UDPSocket { | ||||||
|  | public: | ||||||
|  |     using UDPSocket::UDPSocket; | ||||||
|  |     using UDPSocket::init; | ||||||
|  |     int init(int domain); | ||||||
|  |     int listen(int __n); | ||||||
|  |     void accept(TCPSocket& newSock, Address& addr); | ||||||
|  |     int connect(Socket::Address& serveraddr); | ||||||
|  |     int recv(void *__restrict __buf, size_t __n, int __flags); | ||||||
|  |     int send(const void *__buf, size_t __n, int __flags); | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | } | ||||||
							
								
								
									
										45
									
								
								include/socket/udp_socket.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								include/socket/udp_socket.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,45 @@ | |||||||
|  | #pragma once | ||||||
|  | #include "address.h" | ||||||
|  |  | ||||||
|  | namespace Socket { | ||||||
|  |  | ||||||
|  | struct Address; | ||||||
|  |  | ||||||
|  | class UDPSocket { | ||||||
|  |  public: | ||||||
|  |   UDPSocket() = default; | ||||||
|  |   UDPSocket(int domain, int type, int protocol); | ||||||
|  |   ~UDPSocket(); | ||||||
|  |  | ||||||
|  |   int init(int domain, int type, int protocol); | ||||||
|  |   void destruct(); | ||||||
|  |  | ||||||
|  |   operator SOCKET(); | ||||||
|  |   void set(const SOCKET __sock, int __domain); | ||||||
|  |   int setsockopt(int level, int optname, const char* optval, int optlen); | ||||||
|  |  | ||||||
|  |   int bind(Address __addr); | ||||||
|  |  | ||||||
|  |   int recvfrom(void* __restrict __buf, size_t __n, int __flags, | ||||||
|  |                struct Address& __addr); | ||||||
|  |   int sendto(const void* __buf, size_t __n, int __flags, struct Address __addr); | ||||||
|  |  | ||||||
|  |   UDPSocket(const UDPSocket&); | ||||||
|  |   UDPSocket(UDPSocket&&) noexcept; | ||||||
|  |   UDPSocket& operator=(const UDPSocket&); | ||||||
|  |   UDPSocket& operator=(UDPSocket&&) noexcept; | ||||||
|  |  | ||||||
|  |   struct Address bindAddr = {}; | ||||||
|  |   struct Address remoteAddr = {}; | ||||||
|  |  | ||||||
|  |   int domain = 0; | ||||||
|  |   SOCKET sock = INVALID_SOCKET; | ||||||
|  |  | ||||||
|  |   std::mutex readMutex; | ||||||
|  |   std::mutex writeMutex; | ||||||
|  |  | ||||||
|  |  protected: | ||||||
|  |   bool valid_ = false; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | }  // namespace Socket | ||||||
							
								
								
									
										20
									
								
								include/socket/wsa_manager.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								include/socket/wsa_manager.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | |||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | namespace Socket { | ||||||
|  |  | ||||||
|  | struct WSAManager { | ||||||
|  |  public: | ||||||
|  |   static WSAManager* GetInstance() { | ||||||
|  |     static WSAManager instance; | ||||||
|  |     return &instance; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   WSAManager(const WSAManager&) = delete; | ||||||
|  |   WSAManager& operator=(const WSAManager&) = delete; | ||||||
|  |  | ||||||
|  |  private: | ||||||
|  | 	WSAManager(); | ||||||
|  | 	~WSAManager(); | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | } | ||||||
							
								
								
									
										18
									
								
								include/transport/transport.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								include/transport/transport.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | |||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include "utils/thread_pool.h" | ||||||
|  |  | ||||||
|  | namespace happytanuki { | ||||||
|  |  | ||||||
|  | class Transport { | ||||||
|  |  public: | ||||||
|  |   Transport(utils::ThreadPool* tp); | ||||||
|  |  | ||||||
|  |   void Send(); | ||||||
|  |   void Recv(); | ||||||
|  |  | ||||||
|  |  private: | ||||||
|  |   utils::ThreadPool* tp_; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | }  // namespace happytanuki | ||||||
							
								
								
									
										9
									
								
								include/utils/log.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								include/utils/log.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | |||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | namespace utils { | ||||||
|  |  | ||||||
|  | void setDefaultLogger(spdlog::level::level_enum logLevel, | ||||||
|  |                       gsl::czstring logFileName, std::uint32_t logFileSize, | ||||||
|  |                       std::uint32_t logFileCount); | ||||||
|  |  | ||||||
|  | }  // namespace utils | ||||||
							
								
								
									
										32
									
								
								include/utils/snowflake.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								include/utils/snowflake.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,32 @@ | |||||||
|  | #pragma once | ||||||
|  | #include <cstdint> | ||||||
|  |  | ||||||
|  | namespace utils { | ||||||
|  |  | ||||||
|  | struct Snowflake { | ||||||
|  |   union { | ||||||
|  |     struct { | ||||||
|  |       std::uint64_t timestamp : 42; | ||||||
|  |       std::uint64_t instance : 10; | ||||||
|  |       std::uint64_t sequence : 12; | ||||||
|  |     }; | ||||||
|  |     std::uint64_t snowflake; | ||||||
|  |   }; | ||||||
|  |  | ||||||
|  |   bool operator==(const Snowflake& other) const { | ||||||
|  |     return snowflake == other.snowflake; | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | Snowflake GenerateID(); | ||||||
|  |  | ||||||
|  | }  // namespace Chattr | ||||||
|  |  | ||||||
|  | namespace std { | ||||||
|  | template <> | ||||||
|  | struct hash<utils::Snowflake> { | ||||||
|  |   std::size_t operator()(const utils::Snowflake& k) const { | ||||||
|  |     return std::hash<std::uint64_t>{}(k.snowflake); | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  | }  // namespace std | ||||||
		Reference in New Issue
	
	Block a user