Compare commits
	
		
			24 Commits
		
	
	
		
			016d923d64
			...
			main
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 8b486008fa | |||
| be6417cd40 | |||
| 7c382bead0 | |||
| 91a3cfd9f4 | |||
| 89306442ae | |||
| d5342b5f61 | |||
| 25527405d5 | |||
| 65b7aa8f6e | |||
| 6c1b0c6852 | |||
| 7157e67040 | |||
| be6ea6e92f | |||
| 20f8c7b29d | |||
| 74e73ccc23 | |||
| 0aa312f67e | |||
| 78f2bfe2f6 | |||
| 1ae7486cd5 | |||
| df35dd43c1 | |||
| 914cfcba32 | |||
| 87cc1c7119 | |||
| 46abb2b2b9 | |||
| 993d41736d | |||
| 8ffe3a7519 | |||
| e0a371d536 | |||
| 63428ebf4d | 
							
								
								
									
										7
									
								
								.vscode/settings.json
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										7
									
								
								.vscode/settings.json
									
									
									
									
										vendored
									
									
								
							| @@ -81,6 +81,11 @@ | |||||||
|         "expected": "cpp", |         "expected": "cpp", | ||||||
|         "complex": "cpp", |         "complex": "cpp", | ||||||
|         "__config": "cpp", |         "__config": "cpp", | ||||||
|         "ranges": "cpp" |         "ranges": "cpp", | ||||||
|  |         "valarray": "cpp", | ||||||
|  |         "__tree": "cpp", | ||||||
|  |         "map": "cpp", | ||||||
|  |         "iostream": "cpp", | ||||||
|  |         "any": "cpp" | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @@ -33,6 +33,7 @@ FetchContent_MakeAvailable(JSONCPP) | |||||||
|  |  | ||||||
| file(GLOB_RECURSE additional_sources CONFIGURE_DEPENDS | file(GLOB_RECURSE additional_sources CONFIGURE_DEPENDS | ||||||
|     "${CMAKE_CURRENT_SOURCE_DIR}/../impl/*.cpp" |     "${CMAKE_CURRENT_SOURCE_DIR}/../impl/*.cpp" | ||||||
|  |     "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| add_executable(${PROJECT_NAME} | add_executable(${PROJECT_NAME} | ||||||
|   | |||||||
							
								
								
									
										106
									
								
								Client/include/ClientManager/ClientManager.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										106
									
								
								Client/include/ClientManager/ClientManager.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,106 @@ | |||||||
|  | #pragma once | ||||||
|  | #include "Utils/ThreadPool.hpp" | ||||||
|  | #include "Utils/ConfigManager.hpp" | ||||||
|  | #include "Socket/IOCP.hpp" | ||||||
|  | #include "Packet/Packet.hpp" | ||||||
|  |  | ||||||
|  | namespace Chattr { | ||||||
|  |  | ||||||
|  | class ClientManager { | ||||||
|  | public: | ||||||
|  |     void _IOCPClient(ThreadPool* thread, IOCPPASSINDATA* data); | ||||||
|  |  | ||||||
|  |     PacketSet packetParser(Packet Packet); | ||||||
|  |  | ||||||
|  | 	template<typename _Callable> | ||||||
|  | 	void init(_Callable _IOCPClient) { | ||||||
|  | 		auto config = ConfigManager::load(); | ||||||
|  | 		log::setDefaultLogger(config.logLevel, config.logFileName, config.logfileSize, config.logfileCount); | ||||||
|  | 		threadPool_.init(0); | ||||||
|  | 		iocp_.init(&threadPool_, _IOCPClient); | ||||||
|  |  | ||||||
|  |         struct Address serveraddr; | ||||||
|  |         if (config.ipVersion == 4) { | ||||||
|  |             sock_.init(AF_INET); | ||||||
|  |             serveraddr.set(AF_INET, config.IP, config.Port); | ||||||
|  |         } | ||||||
|  |         else if (config.ipVersion == 6) { | ||||||
|  |             sock_.init(AF_INET6); | ||||||
|  |             serveraddr.set(AF_INET6, config.IP, config.Port); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (sock_.connect(serveraddr) == INVALID_SOCKET) { | ||||||
|  |             spdlog::error("{}", strerror(errno)); | ||||||
|  |             std::exit(EXIT_FAILURE); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         data_ = new IOCPPASSINDATA; | ||||||
|  |         ::memset(&data_->overlapped, 0, sizeof(OVERLAPPED)); | ||||||
|  |         data_->socket = std::make_shared<TCPSocket>(std::move(sock_)); | ||||||
|  |         data_->recvbytes = data_->sendbytes = 0; | ||||||
|  |         data_->wsabuf.buf = data_->buf; | ||||||
|  |         data_->wsabuf.len = 1500; | ||||||
|  |         data_->IOCPInstance = &iocp_; | ||||||
|  |         iocp_.registerSocket(data_); | ||||||
|  |  | ||||||
|  |         spdlog::info("Connection established from [{}]", (std::string)serveraddr); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  |     void init() { | ||||||
|  |         init([this](ThreadPool* thread, IOCPPASSINDATA* data) { | ||||||
|  |             this->_IOCPClient(thread, data); | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void processResponsePacket(ResponsePacket responsePacket, IOCPPASSINDATA* data); | ||||||
|  |     void processLoginResponsePacket(LoginResponsePacket loginResponsePacket, IOCPPASSINDATA* data); | ||||||
|  |     void processRoomCreateResponsePacket(RoomCreateResponsePacket roomCreateResponsePacket, IOCPPASSINDATA* data); | ||||||
|  |     void processRoomListResponse(RoomListResponsePacket roomListResponsePacket, IOCPPASSINDATA* data); | ||||||
|  |     void processRoomJoinResponsePacket(RoomJoinResponsePacket roomJoinResponsePacket, IOCPPASSINDATA* data); | ||||||
|  |     void processRoomExitResponsePacket(RoomExitResponsePacket roomExitResponsePacket, IOCPPASSINDATA* data); | ||||||
|  |     void processUsersListResponsePacket(UsersListResponsePacket usersListResponsePacket, IOCPPASSINDATA* data); | ||||||
|  |     void processDataPostPacket(DataPostPacket dataPostPacket, IOCPPASSINDATA* data); | ||||||
|  |     void processContinuePacket(ContinuePacket continuePacket, IOCPPASSINDATA* data); | ||||||
|  |  | ||||||
|  |     void sendMessage(Snowflake ID, std::string message); | ||||||
|  |  | ||||||
|  |     void registerUser(std::string userName); | ||||||
|  |     void deleteUser(Snowflake UID); | ||||||
|  |     void getUserList(); | ||||||
|  |  | ||||||
|  |     void createRoom(std::string roomName); | ||||||
|  |     void getRoomList(); | ||||||
|  |  | ||||||
|  |     void joinRoom(Snowflake UID, Snowflake RID); | ||||||
|  |     void exitRoom(Snowflake UID, Snowflake RID); | ||||||
|  |  | ||||||
|  | 	void run(); | ||||||
|  | private: | ||||||
|  | 	ThreadPool threadPool_; | ||||||
|  | 	IOCP iocp_; | ||||||
|  |  | ||||||
|  |     Snowflake myID_; | ||||||
|  |     Snowflake myRoomID_; | ||||||
|  |  | ||||||
|  |     IOCPPASSINDATA* data_; | ||||||
|  |  | ||||||
|  |     bool inRoom_ = false; | ||||||
|  |  | ||||||
|  |     std::future<ResponsePacket> lastResponsePacket_; | ||||||
|  |  | ||||||
|  |     TCPSocket sock_; | ||||||
|  |  | ||||||
|  |     std::mutex resourceMutex_; | ||||||
|  |     std::mutex screenMutex_; | ||||||
|  |  | ||||||
|  |     std::queue<std::string> messageQueue_; | ||||||
|  |     std::vector<std::string> messageHistory_; | ||||||
|  |  | ||||||
|  |     std::unordered_map<Snowflake, std::string> roomNames_; | ||||||
|  |     std::unordered_map<std::string, Snowflake> findRoomId_; | ||||||
|  |  | ||||||
|  |     std::unordered_map<Snowflake, std::string> userNames_; | ||||||
|  |     std::unordered_map<std::string, Snowflake> findUserId_; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | } | ||||||
							
								
								
									
										490
									
								
								Client/src/ClientManager/ClientManager.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										490
									
								
								Client/src/ClientManager/ClientManager.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,490 @@ | |||||||
|  | #include "ClientManager/ClientManager.hpp" | ||||||
|  | #include "Utils/ConfigManager.hpp" | ||||||
|  | #include "Utils/StringTokenizer.hpp" | ||||||
|  | #include "Socket/Log.hpp" | ||||||
|  | #include <iostream> | ||||||
|  |  | ||||||
|  | namespace Chattr { | ||||||
|  |  | ||||||
|  | void ClientManager::_IOCPClient(Chattr::ThreadPool* thread, Chattr::IOCPPASSINDATA* data) { | ||||||
|  |     if (data->event == IOCPEVENT::QUIT) { | ||||||
|  |         delete data; | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     Chattr::Packet pack; | ||||||
|  |     int packetSize = data->transferredbytes; | ||||||
|  |  | ||||||
|  |     if (data->event == IOCPEVENT::WRITE && data->transferredbytes >= data->wsabuf.len) { | ||||||
|  |         data->event = IOCPEVENT::READ; | ||||||
|  |         data->wsabuf.len = 1500; | ||||||
|  |         data->IOCPInstance->recv(data, 1); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     memcpy(pack.serialized, data->wsabuf.buf, data->wsabuf.len); | ||||||
|  |  | ||||||
|  |     std::uint16_t packetLength = ::ntohs(pack.__data.packetLength); | ||||||
|  |  | ||||||
|  |     // if (data->event == IOCPEVENT::READ && data->transferredbytes < packetLength + 8) { | ||||||
|  |     //     data->IOCPInstance->recv(data, 1); | ||||||
|  |     //     data->wsabuf.len = 1500; | ||||||
|  |     //     return; | ||||||
|  |     // } | ||||||
|  |  | ||||||
|  |     pack.convToH(); | ||||||
|  |     PacketSet packetSet = packetParser(pack); | ||||||
|  |     pack.convToN(); | ||||||
|  |     switch (packetSet) { | ||||||
|  |     case PacketSet::LOGINRESPONSE: { | ||||||
|  |             LoginResponsePacket loginResponsePacket; | ||||||
|  |             std::memcpy(&loginResponsePacket.serialized, &pack.serialized, 8 + packetLength); | ||||||
|  |             loginResponsePacket.convToH(); | ||||||
|  |  | ||||||
|  |             lastResponsePacket_ = std::future<ResponsePacket>(); | ||||||
|  |             auto promise = std::promise<ResponsePacket>(); | ||||||
|  |             lastResponsePacket_ = promise.get_future(); | ||||||
|  |             promise.set_value(loginResponsePacket); | ||||||
|  |  | ||||||
|  |             processLoginResponsePacket(loginResponsePacket, data); | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     case PacketSet::ROOMCREATERESPONSE: | ||||||
|  |     case PacketSet::ROOMLISTRESPONSE: { | ||||||
|  |             RoomListResponsePacket roomListResponsePacket; | ||||||
|  |             std::memcpy(&roomListResponsePacket.serialized, &pack.serialized, 8 + packetLength); | ||||||
|  |             roomListResponsePacket.convToH(); | ||||||
|  |  | ||||||
|  |             lastResponsePacket_ = std::future<ResponsePacket>(); | ||||||
|  |             auto promise = std::promise<ResponsePacket>(); | ||||||
|  |             lastResponsePacket_ = promise.get_future(); | ||||||
|  |             promise.set_value(roomListResponsePacket); | ||||||
|  |             processRoomListResponse(roomListResponsePacket, data); | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     case PacketSet::ROOMJOINRESPONSE: | ||||||
|  |     case PacketSet::ROOMEXITRESPONSE: | ||||||
|  |     case PacketSet::USERSLISTRESPONSE: { | ||||||
|  |             UsersListResponsePacket usersListResponsePacket; | ||||||
|  |             std::memcpy(&usersListResponsePacket.serialized, &pack.serialized, 8 + packetLength); | ||||||
|  |             usersListResponsePacket.convToH(); | ||||||
|  |  | ||||||
|  |             lastResponsePacket_ = std::future<ResponsePacket>(); | ||||||
|  |             auto promise = std::promise<ResponsePacket>(); | ||||||
|  |             lastResponsePacket_ = promise.get_future(); | ||||||
|  |             promise.set_value(usersListResponsePacket); | ||||||
|  |             processUsersListResponsePacket(usersListResponsePacket, data); | ||||||
|  |     } | ||||||
|  |     case PacketSet::RESPONSE: { | ||||||
|  |             ResponsePacket responsePacket; | ||||||
|  |             std::memcpy(&responsePacket.serialized, &pack.serialized, 8 + packetLength); | ||||||
|  |             responsePacket.convToH(); | ||||||
|  |              | ||||||
|  |             lastResponsePacket_ = std::future<ResponsePacket>(); | ||||||
|  |             auto promise = std::promise<ResponsePacket>(); | ||||||
|  |             lastResponsePacket_ = promise.get_future(); | ||||||
|  |             promise.set_value(responsePacket); | ||||||
|  |  | ||||||
|  |             processResponsePacket(responsePacket, data); | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     case PacketSet::DATAPOST: { | ||||||
|  |             DataPostPacket dataPostPacket; | ||||||
|  |             std::memcpy(&dataPostPacket.serialized, &pack.serialized, 8 + packetLength); | ||||||
|  |             dataPostPacket.convToH(); | ||||||
|  |             processDataPostPacket(dataPostPacket, data); | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     case PacketSet::CONTINUE: { | ||||||
|  |             ContinuePacket continuePacket; | ||||||
|  |             std::memcpy(&continuePacket.serialized, &pack.serialized, 8 + packetLength); | ||||||
|  |             continuePacket.convToH(); | ||||||
|  |             processContinuePacket(continuePacket, data); | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     case PacketSet::INVALID: | ||||||
|  |     default: { | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     iocp_.recv(data_, 1); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | PacketSet ClientManager::packetParser(Packet Packet) { | ||||||
|  |     if (Packet.__data.packetLength < 0 || Packet.__data.packetLength > 1492) | ||||||
|  |         return PacketSet::INVALID; | ||||||
|  |  | ||||||
|  |     switch (Packet.__data.packetType) { | ||||||
|  |     case PacketCategory::PACKET_POST: | ||||||
|  |         if (Packet.__data.requestType != RequestType::DATA) { | ||||||
|  |             return PacketSet::INVALID; | ||||||
|  |         } | ||||||
|  |         switch (Packet.__data.dataType) { | ||||||
|  |         case DataType::TEXT: | ||||||
|  |         case DataType::BINARY: | ||||||
|  |             return PacketSet::DATAPOST; | ||||||
|  |         default: | ||||||
|  |             return PacketSet::INVALID; | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     case PacketCategory::PACKET_REQUEST: | ||||||
|  |         switch (Packet.__data.requestType) { | ||||||
|  |         case RequestType::LOGIN: | ||||||
|  |             return PacketSet::LOGINREQUEST; | ||||||
|  |         case RequestType::ROOM_CREATE: | ||||||
|  |             return PacketSet::ROOMCREATEREQUEST; | ||||||
|  |         case RequestType::ROOM_LIST: | ||||||
|  |             return PacketSet::ROOMLISTREQUEST; | ||||||
|  |         case RequestType::ROOM_JOIN: | ||||||
|  |             return PacketSet::ROOMJOINREQUEST; | ||||||
|  |         case RequestType::ROOM_EXIT: | ||||||
|  |             return PacketSet::ROOMEXITREQUEST; | ||||||
|  |         case RequestType::USERS_LIST: | ||||||
|  |             return PacketSet::USERSLISTREQUEST; | ||||||
|  |         case RequestType::ROOM_USERS_LIST: | ||||||
|  |             return PacketSet::ROOMUSERSLISTREQUEST; | ||||||
|  |         case RequestType::DATA: | ||||||
|  |             return PacketSet::INVALID; | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     case PacketCategory::PACKET_RESPONSE: | ||||||
|  |         switch (Packet.__data.requestType) { | ||||||
|  |         case RequestType::LOGIN: | ||||||
|  |             return PacketSet::LOGINRESPONSE; | ||||||
|  |         case RequestType::ROOM_CREATE: | ||||||
|  |             return PacketSet::ROOMCREATERESPONSE; | ||||||
|  |         case RequestType::ROOM_LIST: | ||||||
|  |             return PacketSet::ROOMLISTRESPONSE; | ||||||
|  |         case RequestType::ROOM_JOIN: | ||||||
|  |             return PacketSet::ROOMJOINRESPONSE; | ||||||
|  |         case RequestType::ROOM_EXIT: | ||||||
|  |             return PacketSet::ROOMEXITRESPONSE; | ||||||
|  |         case RequestType::USERS_LIST: | ||||||
|  |             return PacketSet::USERSLISTRESPONSE; | ||||||
|  |         case RequestType::ROOM_USERS_LIST: | ||||||
|  |             return PacketSet::ROOMUSERSLISTRESPONSE; | ||||||
|  |         case RequestType::DATA: | ||||||
|  |             return PacketSet::RESPONSE; | ||||||
|  |         default: | ||||||
|  |             return PacketSet::INVALID; | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     case PacketCategory::PACKET_CONTINUE: | ||||||
|  |         return PacketSet::CONTINUE; | ||||||
|  |     default: | ||||||
|  |         return PacketSet::INVALID; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return PacketSet::INVALID; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ClientManager::processResponsePacket(ResponsePacket responsePacket, IOCPPASSINDATA* data) { | ||||||
|  |     responsePacket; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void ClientManager::processLoginResponsePacket(LoginResponsePacket loginResponsePacket, IOCPPASSINDATA* data) { | ||||||
|  |     ::memcpy(&myID_.snowflake, loginResponsePacket.__data.yourId, sizeof(Snowflake)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ClientManager::processRoomCreateResponsePacket(RoomCreateResponsePacket roomCreateResponsePacket, Chattr::IOCPPASSINDATA* data) { | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ClientManager::processRoomListResponse(RoomListResponsePacket roomListResponsePacket, Chattr::IOCPPASSINDATA* data) { | ||||||
|  |     Snowflake roomId; | ||||||
|  |     ::memcpy(&roomId.snowflake, roomListResponsePacket.__data.roomId, sizeof(Snowflake)); | ||||||
|  |     std::string roomName((char*)roomListResponsePacket.__data.name, roomListResponsePacket.__data.packetLength - (sizeof(std::uint16_t) * 7)); | ||||||
|  |     roomNames_[roomId] = roomName; | ||||||
|  |     findRoomId_[roomName] = roomId; | ||||||
|  |  | ||||||
|  |     spdlog::info("{}", roomName); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ClientManager::processRoomJoinResponsePacket(RoomJoinResponsePacket roomJoinResponsePacket, Chattr::IOCPPASSINDATA* data) { | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ClientManager::processRoomExitResponsePacket(RoomExitResponsePacket roomExitResponsePacket, Chattr::IOCPPASSINDATA* data) { | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ClientManager::processUsersListResponsePacket(UsersListResponsePacket usersListResponsePacket, Chattr::IOCPPASSINDATA* data) { | ||||||
|  |     Snowflake userId; | ||||||
|  |     ::memcpy(&userId.snowflake, usersListResponsePacket.__data.userId, sizeof(Snowflake)); | ||||||
|  |     std::string userName((char*)usersListResponsePacket.__data.name, usersListResponsePacket.__data.packetLength - (sizeof(std::uint16_t) * 7)); | ||||||
|  |     userNames_[userId] = userName; | ||||||
|  |     findUserId_[userName] = userId; | ||||||
|  |  | ||||||
|  |     spdlog::info("{}", userName); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ClientManager::processDataPostPacket(DataPostPacket dataPostPacket, IOCPPASSINDATA* data) { | ||||||
|  |     Snowflake sentUserId; | ||||||
|  |     ::memcpy(&sentUserId.snowflake, dataPostPacket.__data.sourceId, sizeof(Snowflake)); | ||||||
|  |     std::string sentUserName = userNames_[sentUserId]; | ||||||
|  |     std::string message((char*)dataPostPacket.__data.data, dataPostPacket.__data.packetLength - (sizeof(std::uint16_t) * 5)); | ||||||
|  |  | ||||||
|  |     spdlog::info("[{}] {}", sentUserName, message); // todo: pass data to main thread | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ClientManager::processContinuePacket(ContinuePacket continuePacket, IOCPPASSINDATA* data) { | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ClientManager::sendMessage(Snowflake ID, std::string message) { | ||||||
|  |     DataPostPacket dataPostPacket; | ||||||
|  |     dataPostPacket.__data.packetType = PacketCategory::PACKET_POST; | ||||||
|  |     dataPostPacket.__data.requestType = RequestType::DATA; | ||||||
|  |     dataPostPacket.__data.dataType = DataType::TEXT; | ||||||
|  |     dataPostPacket.__data.packetLength = message.size() + sizeof(Snowflake) * 2; | ||||||
|  |     memcpy(dataPostPacket.__data.sourceId, &myID_.snowflake, sizeof(Snowflake)); | ||||||
|  |     memcpy(dataPostPacket.__data.destId, &ID.snowflake, sizeof(Snowflake)); | ||||||
|  |     memcpy(dataPostPacket.__data.data, message.c_str(), message.size()); | ||||||
|  |  | ||||||
|  |     int packetLength = dataPostPacket.__data.packetLength; | ||||||
|  |  | ||||||
|  |     data_->recvbytes = data_->sendbytes = 0; | ||||||
|  |     data_->transferredbytes = 0; | ||||||
|  |     data_->wsabuf.len = data_->sendbytes = packetLength + 8; | ||||||
|  |  | ||||||
|  |     dataPostPacket.convToN(); | ||||||
|  |     memcpy(data_->wsabuf.buf, dataPostPacket.serialized, packetLength + 8); | ||||||
|  |     iocp_.send(data_, 1, 0); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ClientManager::registerUser(std::string userName) { | ||||||
|  |     LoginRequestPacket loginRequestPacket; | ||||||
|  |     loginRequestPacket.__data.packetType = PacketCategory::PACKET_REQUEST; | ||||||
|  |     loginRequestPacket.__data.requestType = RequestType::LOGIN; | ||||||
|  |     loginRequestPacket.__data.dataType = DataType::BINARY; | ||||||
|  |     loginRequestPacket.__data.packetLength = userName.size(); | ||||||
|  |     memcpy(loginRequestPacket.__data.data, userName.c_str(), userName.size()); | ||||||
|  |  | ||||||
|  |     int packetLength = loginRequestPacket.__data.packetLength; | ||||||
|  |  | ||||||
|  |     data_->recvbytes = data_->sendbytes = 0; | ||||||
|  |     data_->transferredbytes = 0; | ||||||
|  |     data_->wsabuf.len = packetLength + 8; | ||||||
|  |  | ||||||
|  |     loginRequestPacket.convToN(); | ||||||
|  |     memcpy(data_->wsabuf.buf, loginRequestPacket.serialized, packetLength + 8); | ||||||
|  |     data_->sendbytes = packetLength + 8; | ||||||
|  |     iocp_.send(data_, 1, 0); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ClientManager::getUserList() { | ||||||
|  |     if (inRoom_) { | ||||||
|  |         RoomUsersListRequestPacket roomUsersListRequestPacket; | ||||||
|  |         roomUsersListRequestPacket.__data.packetType = PacketCategory::PACKET_REQUEST; | ||||||
|  |         roomUsersListRequestPacket.__data.requestType = RequestType::ROOM_USERS_LIST; | ||||||
|  |         roomUsersListRequestPacket.__data.dataType = DataType::BINARY; | ||||||
|  |         roomUsersListRequestPacket.__data.packetLength = sizeof(Snowflake); | ||||||
|  |         memcpy(roomUsersListRequestPacket.__data.roomId, &myRoomID_.snowflake, sizeof(Snowflake)); | ||||||
|  |  | ||||||
|  |         int packetLength = roomUsersListRequestPacket.__data.packetLength; | ||||||
|  |  | ||||||
|  |         data_->recvbytes = data_->sendbytes = 0; | ||||||
|  |         data_->transferredbytes = 0; | ||||||
|  |         data_->wsabuf.len = packetLength + 8; | ||||||
|  |  | ||||||
|  |         roomUsersListRequestPacket.convToN(); | ||||||
|  |         memcpy(data_->wsabuf.buf, roomUsersListRequestPacket.serialized, packetLength + 8); | ||||||
|  |         iocp_.send(data_, 1, 0); | ||||||
|  |     } | ||||||
|  |     else { | ||||||
|  |         UsersListRequestPacket usersListRequestPacket; | ||||||
|  |         usersListRequestPacket.__data.packetType = PacketCategory::PACKET_REQUEST; | ||||||
|  |         usersListRequestPacket.__data.requestType = RequestType::USERS_LIST; | ||||||
|  |         usersListRequestPacket.__data.dataType = DataType::BINARY; | ||||||
|  |         usersListRequestPacket.__data.packetLength = 0; | ||||||
|  |  | ||||||
|  |         int packetLength = usersListRequestPacket.__data.packetLength; | ||||||
|  |  | ||||||
|  |         data_->recvbytes = data_->sendbytes = 0; | ||||||
|  |         data_->transferredbytes = 0; | ||||||
|  |         data_->wsabuf.len = packetLength + 8; | ||||||
|  |  | ||||||
|  |         usersListRequestPacket.convToN(); | ||||||
|  |         memcpy(data_->wsabuf.buf, usersListRequestPacket.serialized, packetLength + 8); | ||||||
|  |         iocp_.send(data_, 1, 0); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ClientManager::createRoom(std::string roomName) { | ||||||
|  |     RoomCreateRequestPacket roomCreateRequestPacket; | ||||||
|  |     roomCreateRequestPacket.__data.packetType = PacketCategory::PACKET_REQUEST; | ||||||
|  |     roomCreateRequestPacket.__data.requestType = RequestType::ROOM_CREATE; | ||||||
|  |     roomCreateRequestPacket.__data.dataType = DataType::BINARY; | ||||||
|  |     roomCreateRequestPacket.__data.packetLength = roomName.size(); | ||||||
|  |     memcpy(roomCreateRequestPacket.__data.data, roomName.c_str(), roomName.size()); | ||||||
|  |  | ||||||
|  |     int packetLength = roomCreateRequestPacket.__data.packetLength; | ||||||
|  |  | ||||||
|  |     data_->recvbytes = data_->sendbytes = 0; | ||||||
|  |     data_->transferredbytes = 0; | ||||||
|  |     data_->wsabuf.len = packetLength + 8; | ||||||
|  |  | ||||||
|  |     roomCreateRequestPacket.convToN(); | ||||||
|  |     memcpy(data_->wsabuf.buf, roomCreateRequestPacket.serialized, packetLength + 8); | ||||||
|  |     iocp_.send(data_, 1, 0); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ClientManager::getRoomList() { | ||||||
|  |     RoomListRequestPacket roomListRequestPacket; | ||||||
|  |     roomListRequestPacket.__data.packetType = PacketCategory::PACKET_REQUEST; | ||||||
|  |     roomListRequestPacket.__data.requestType = RequestType::ROOM_LIST; | ||||||
|  |     roomListRequestPacket.__data.dataType = DataType::BINARY; | ||||||
|  |     roomListRequestPacket.__data.packetLength = 0; | ||||||
|  |  | ||||||
|  |     int packetLength = roomListRequestPacket.__data.packetLength; | ||||||
|  |  | ||||||
|  |     data_->recvbytes = data_->sendbytes = 0; | ||||||
|  |     data_->transferredbytes = 0; | ||||||
|  |     data_->wsabuf.len = packetLength + 8; | ||||||
|  |  | ||||||
|  |     roomListRequestPacket.convToN(); | ||||||
|  |     memcpy(data_->wsabuf.buf, roomListRequestPacket.serialized, packetLength + 8); | ||||||
|  |     iocp_.send(data_, 1, 0); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ClientManager::joinRoom(Snowflake UID, Snowflake RID) { | ||||||
|  |     RoomJoinRequestPacket roomJoinRequestPacket; | ||||||
|  |     roomJoinRequestPacket.__data.packetType = PacketCategory::PACKET_REQUEST; | ||||||
|  |     roomJoinRequestPacket.__data.requestType = RequestType::ROOM_JOIN; | ||||||
|  |     roomJoinRequestPacket.__data.dataType = DataType::BINARY; | ||||||
|  |     roomJoinRequestPacket.__data.packetLength = sizeof(Snowflake) * 2; | ||||||
|  |     memcpy(roomJoinRequestPacket.__data.myId, &UID.snowflake, sizeof(Snowflake)); | ||||||
|  |     memcpy(roomJoinRequestPacket.__data.roomId, &RID.snowflake, sizeof(Snowflake)); | ||||||
|  |  | ||||||
|  |     int packetLength = roomJoinRequestPacket.__data.packetLength; | ||||||
|  |  | ||||||
|  |     data_->recvbytes = data_->sendbytes = 0; | ||||||
|  |     data_->transferredbytes = 0; | ||||||
|  |     data_->wsabuf.len = packetLength + 8; | ||||||
|  |     roomJoinRequestPacket.convToN(); | ||||||
|  |     memcpy(data_->wsabuf.buf, roomJoinRequestPacket.serialized, packetLength + 8); | ||||||
|  |     iocp_.send(data_, 1, 0); | ||||||
|  |     inRoom_ = true; | ||||||
|  |     myRoomID_ = RID; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ClientManager::exitRoom(Snowflake UID, Snowflake RID) { | ||||||
|  |     RoomExitRequestPacket roomExitRequestPacket; | ||||||
|  |     roomExitRequestPacket.__data.packetType = PacketCategory::PACKET_REQUEST; | ||||||
|  |     roomExitRequestPacket.__data.requestType = RequestType::ROOM_EXIT; | ||||||
|  |     roomExitRequestPacket.__data.dataType = DataType::BINARY; | ||||||
|  |     roomExitRequestPacket.__data.packetLength = sizeof(Snowflake) * 2; | ||||||
|  |     memcpy(roomExitRequestPacket.__data.myId, &UID.snowflake, sizeof(Snowflake)); | ||||||
|  |     memcpy(roomExitRequestPacket.__data.roomId, &RID.snowflake, sizeof(Snowflake)); | ||||||
|  |  | ||||||
|  |     int packetLength = roomExitRequestPacket.__data.packetLength; | ||||||
|  |  | ||||||
|  |     data_->recvbytes = data_->sendbytes = 0; | ||||||
|  |     data_->transferredbytes = 0; | ||||||
|  |     data_->wsabuf.len = packetLength + 8; | ||||||
|  |  | ||||||
|  |     roomExitRequestPacket.convToN(); | ||||||
|  |     memcpy(data_->wsabuf.buf, roomExitRequestPacket.serialized, packetLength + 8); | ||||||
|  |     iocp_.send(data_, 1, 0); | ||||||
|  |     inRoom_ = false; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ClientManager::run() { | ||||||
|  |     StringTokenizer tokenizer; | ||||||
|  |     std::string nickname; | ||||||
|  |  | ||||||
|  |     std::cout << "Please enter your nickname: "; | ||||||
|  |     std::getline(std::cin, nickname); | ||||||
|  |     tokenizer.set(nickname.c_str(), nickname.size()); | ||||||
|  |  | ||||||
|  |     registerUser(tokenizer.get()[0]); | ||||||
|  |  | ||||||
|  |     std::cout << "Commads:" << std::endl; | ||||||
|  |     std::cout << "/w <username> : Send direct message to specified user" << std::endl; | ||||||
|  |     std::cout << "/join <roomname> : Enter specified room" << std::endl; | ||||||
|  |     std::cout << "/exit : Exit current room" << std::endl; | ||||||
|  |     std::cout << "/create <roomname> : Create room" << std::endl; | ||||||
|  |     std::cout << "/userlist : Print all registred users" << std::endl; | ||||||
|  |     std::cout << "/roomlist : Print all registred rooms" << std::endl; | ||||||
|  |     std::cout << "/quit : Terminate this program" << std::endl; | ||||||
|  |  | ||||||
|  |     while (true) { | ||||||
|  |         std::string input; | ||||||
|  |  | ||||||
|  |         std::unique_lock<std::mutex> lock2(screenMutex_); | ||||||
|  |         if (inRoom_) { | ||||||
|  |             std::cout << "[" + nickname + "@" + roomNames_[myRoomID_] + "]" + " "; | ||||||
|  |         } | ||||||
|  |         else { | ||||||
|  |             std::cout << "[" + nickname + "]" + " "; | ||||||
|  |         } | ||||||
|  |         lock2.unlock(); | ||||||
|  |  | ||||||
|  |         std::getline(std::cin, input); | ||||||
|  |         tokenizer.set(input.c_str(), input.size()); | ||||||
|  |         auto tokens = tokenizer.get(); | ||||||
|  |         if (tokens.size() == 0) | ||||||
|  |             continue; | ||||||
|  |  | ||||||
|  |         if (tokens[0] == "/w") { | ||||||
|  |             if (findUserId_.find(tokens[1]) == findUserId_.end()) { | ||||||
|  |                 resourceMutex_.lock(); | ||||||
|  |                 messageQueue_.push("User not found"); | ||||||
|  |                 resourceMutex_.unlock(); | ||||||
|  |                 continue; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             Snowflake destId = findUserId_[tokens[1]]; | ||||||
|  |  | ||||||
|  |             std::string message; | ||||||
|  |             for (int i = 2; i < tokens.size(); i++) | ||||||
|  |                 message += tokens[i] + " "; | ||||||
|  |                  | ||||||
|  |             sendMessage(destId, message); | ||||||
|  |         } | ||||||
|  |         else if (tokens[0] == "/join") { | ||||||
|  |             std::string roomName; | ||||||
|  |             for (int i = 1; i < tokens.size(); i++) | ||||||
|  |                 roomName += tokens[i]; | ||||||
|  |  | ||||||
|  |             if (findRoomId_.find(roomName) == findRoomId_.end()) { | ||||||
|  |                 resourceMutex_.lock(); | ||||||
|  |                 messageQueue_.push("Room not found"); | ||||||
|  |                 resourceMutex_.unlock(); | ||||||
|  |                 continue; | ||||||
|  |             } | ||||||
|  |             joinRoom(myID_, findRoomId_[roomName]); | ||||||
|  |         } | ||||||
|  |         else if (tokens[0] == "/exit") { | ||||||
|  |             if (!inRoom_) { | ||||||
|  |                 resourceMutex_.lock(); | ||||||
|  |                 messageQueue_.push("You are not in any room"); | ||||||
|  |                 resourceMutex_.unlock(); | ||||||
|  |                 continue; | ||||||
|  |             } | ||||||
|  |             exitRoom(myID_, myRoomID_); | ||||||
|  |         } | ||||||
|  |         else if (tokens[0] == "/create") { | ||||||
|  |             std::string roomName = tokens[1]; | ||||||
|  |             createRoom(roomName); | ||||||
|  |         } | ||||||
|  |         else if (tokens[0] == "/userlist") | ||||||
|  |             getUserList(); | ||||||
|  |         else if (tokens[0] == "/roomlist") | ||||||
|  |             getRoomList(); | ||||||
|  |         else if (tokens[0] == "/quit") { | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |         else if (inRoom_) { | ||||||
|  |             std::string message; | ||||||
|  |             for (int i = 0; i < tokens.size(); i++) | ||||||
|  |                 message += tokens[i]; | ||||||
|  |             sendMessage(myRoomID_, message); | ||||||
|  |         } | ||||||
|  |         else { | ||||||
|  |             resourceMutex_.lock(); | ||||||
|  |             messageQueue_.push("Command not found"); | ||||||
|  |             resourceMutex_.unlock(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | } | ||||||
							
								
								
									
										25
									
								
								Client/src/Socket/Log.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								Client/src/Socket/Log.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | |||||||
|  | #include "Socket/Log.hpp" | ||||||
|  |  | ||||||
|  | #include "spdlog/sinks/stdout_color_sinks.h" | ||||||
|  | #include "spdlog/sinks/rotating_file_sink.h" | ||||||
|  | #ifdef _WIN32 | ||||||
|  | #include "spdlog/sinks/msvc_sink.h" | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #include "precomp.hpp" | ||||||
|  |  | ||||||
|  | namespace Chattr::log { | ||||||
|  |  | ||||||
|  | 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); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | } | ||||||
							
								
								
									
										56
									
								
								Client/src/Utils/ConfigManager.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								Client/src/Utils/ConfigManager.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,56 @@ | |||||||
|  | #include "Utils/ConfigManager.hpp" | ||||||
|  | #include "precomp.hpp" | ||||||
|  | #include <fstream> | ||||||
|  | #include <json/json.h> | ||||||
|  | #include <iostream> | ||||||
|  | #include <string> | ||||||
|  |  | ||||||
|  | namespace Chattr { | ||||||
|  | ConfigManager::Config ConfigManager::load() { | ||||||
|  |   Config config; | ||||||
|  |  | ||||||
|  |   std::ifstream configfile("config.json", std::ifstream::binary); | ||||||
|  |   if (!configfile.is_open()) { | ||||||
|  |     std::ofstream defaultConfig("config.json", std::ios::out); | ||||||
|  |     config.configJsonRoot["IP Version"] = 6; | ||||||
|  |     config.configJsonRoot["IP"] = "::1"; | ||||||
|  |     config.configJsonRoot["Port"] = 9010; | ||||||
|  |     config.configJsonRoot["LogLevel"] = 1; | ||||||
|  |     config.configJsonRoot["LogfileName"] = "Chattering.log"; | ||||||
|  |     config.configJsonRoot["LogfileSize"] = UINT32_MAX; | ||||||
|  |     config.configJsonRoot["LogfileCount"] = 5; | ||||||
|  |     defaultConfig << config.configJsonRoot; | ||||||
|  |     defaultConfig.close(); | ||||||
|  |     spdlog::critical("\"config.json\" is missing. Default configuration has been written."); | ||||||
|  |   } | ||||||
|  |   try { | ||||||
|  |     if (configfile.is_open()) | ||||||
|  |       configfile >> config.configJsonRoot; | ||||||
|  |  | ||||||
|  |     config.ipVersion = config.configJsonRoot["IP Version"].asInt(); | ||||||
|  |     if (config.ipVersion != 4 && config.ipVersion != 6) | ||||||
|  |       throw std::runtime_error("Invalid IP Version."); | ||||||
|  |  | ||||||
|  |     config.IP = config.configJsonRoot["IP"].asCString(); | ||||||
|  |  | ||||||
|  |     config.Port = config.configJsonRoot["Port"].asInt(); | ||||||
|  |     if (config.Port < 0 || config.Port > 65535) | ||||||
|  |       throw std::runtime_error("Invalid listen port."); | ||||||
|  |  | ||||||
|  |     int ll_ = config.configJsonRoot["LogLevel"].asInt(); | ||||||
|  |     if (ll_ >= 0 && ll_ < spdlog::level::n_levels) | ||||||
|  |       config.logLevel = (spdlog::level::level_enum)ll_; | ||||||
|  |     else | ||||||
|  |       throw std::runtime_error("Invalid log level."); | ||||||
|  |  | ||||||
|  |     config.logFileName = config.configJsonRoot["LogfileName"].asCString(); | ||||||
|  |     config.logfileSize = config.configJsonRoot["LogfileSize"].asUInt(); | ||||||
|  |     config.logfileCount = config.configJsonRoot["LogfileCount"].asUInt(); | ||||||
|  |   } | ||||||
|  |   catch (Json::RuntimeError e) { | ||||||
|  |       spdlog::critical(std::string(std::string("[Json Error: ]") + e.what()).c_str()); | ||||||
|  |       std::exit(EXIT_FAILURE); | ||||||
|  |   } | ||||||
|  |   return config; | ||||||
|  | } | ||||||
|  | } | ||||||
| @@ -1,91 +1,14 @@ | |||||||
|  | #define _CLIENT | ||||||
| #include "Socket/TCPSocket.hpp" | #include "Socket/TCPSocket.hpp" | ||||||
| #include "Socket/Address.hpp" | #include "Socket/Address.hpp" | ||||||
| #include "Socket/Log.hpp" | #include "Socket/Log.hpp" | ||||||
| #include "Packet/Packet.hpp" | #include "Packet/Packet.hpp" | ||||||
| #include "Utils/Snowflake.hpp" | #include "Utils/Snowflake.hpp" | ||||||
|  | #include "ClientManager/ClientManager.hpp" | ||||||
| #include "precomp.hpp" | #include "precomp.hpp" | ||||||
|  |  | ||||||
| int main() { | int main() { | ||||||
|     Chattr::TCPSocket sock; |     Chattr::ClientManager client; | ||||||
|     sock.init(AF_INET6); |     client.init(); | ||||||
|  |     client.run(); | ||||||
|     Chattr::Address serveraddr(AF_INET6, "fd8a:5f:3adb:774d:dfae:983f:2e7a:ffba", 9010); |  | ||||||
|  |  | ||||||
|     if (sock.connect(serveraddr) == INVALID_SOCKET) { |  | ||||||
|         spdlog::error("{}", strerror(errno)); |  | ||||||
|         return 0; |  | ||||||
|     } |  | ||||||
|     spdlog::info("Connection established from {}", (std::string)serveraddr); |  | ||||||
|  |  | ||||||
|     Chattr::Snowflake myId; |  | ||||||
|  |  | ||||||
|     Chattr::LoginRequestPacket loginRequestPacket; |  | ||||||
|     loginRequestPacket.__data.packetType = Chattr::PacketCategory::PACKET_REQUEST; |  | ||||||
|     loginRequestPacket.__data.requestType = Chattr::RequestType::LOGIN; |  | ||||||
|     loginRequestPacket.__data.dataType = Chattr::DataType::BINARY; |  | ||||||
|     loginRequestPacket.__data.packetLength = 14; |  | ||||||
|     memcpy(loginRequestPacket.__data.data, "Hello, World!", 14); |  | ||||||
|     loginRequestPacket.convToN(); |  | ||||||
|     sock.send(loginRequestPacket.serialized, 8 + 14, 0); |  | ||||||
|  |  | ||||||
|     Chattr::LoginResponsePacket loginResponsePacket; |  | ||||||
|     sock.recv(loginResponsePacket.serialized, 18, 0); |  | ||||||
|     loginResponsePacket.convToH(); |  | ||||||
|     ::memcpy(&myId, loginResponsePacket.__data.yourId, sizeof(Chattr::Snowflake)); |  | ||||||
|  |  | ||||||
|     Chattr::UsersListRequestPacket usersListRequestPacket; |  | ||||||
|     usersListRequestPacket.__data.packetType = Chattr::PacketCategory::PACKET_REQUEST; |  | ||||||
|     usersListRequestPacket.__data.requestType = Chattr::RequestType::USERS_LIST; |  | ||||||
|     usersListRequestPacket.__data.dataType = Chattr::DataType::TEXT; |  | ||||||
|     usersListRequestPacket.__data.packetLength = 0; |  | ||||||
|     usersListRequestPacket.convToN(); |  | ||||||
|     sock.send(usersListRequestPacket.serialized, 8, 0); |  | ||||||
|  |  | ||||||
|     std::vector<std::pair<Chattr::Snowflake, std::string>> users; |  | ||||||
|  |  | ||||||
|     Chattr::UsersListResponsePacket usersListResponsePacket; |  | ||||||
|     sock.recv(usersListResponsePacket.serialized, 8, 0); |  | ||||||
|     std::uint16_t dataLength = ::ntohs(usersListResponsePacket.__data.packetLength); |  | ||||||
|     sock.recv(usersListResponsePacket.serialized + 8, dataLength, 0); |  | ||||||
|     usersListResponsePacket.convToH(); |  | ||||||
|  |  | ||||||
|     int usersCount = usersListResponsePacket.__data.usersCount; |  | ||||||
|     users.reserve(usersCount); |  | ||||||
|     Chattr::Snowflake userId; |  | ||||||
|     ::memcpy(&userId.snowflake, usersListResponsePacket.__data.userId, sizeof(Chattr::Snowflake)); |  | ||||||
|     users.emplace_back( |  | ||||||
|         userId, |  | ||||||
|         std::string((char*)usersListResponsePacket.__data.name, usersListResponsePacket.__data.packetLength - 14) |  | ||||||
|     ); |  | ||||||
|  |  | ||||||
|     for (int i = 0; i < usersCount - 1; i++) { |  | ||||||
|         sock.recv(usersListResponsePacket.serialized, 8, 0); |  | ||||||
|         std::uint16_t dataLength = ::ntohs(usersListResponsePacket.__data.packetLength); |  | ||||||
|         sock.recv(usersListResponsePacket.serialized + 8, dataLength, 0); |  | ||||||
|         usersListResponsePacket.convToH(); |  | ||||||
|  |  | ||||||
|         ::memcpy(&userId.snowflake, usersListResponsePacket.__data.userId, sizeof(Chattr::Snowflake)); |  | ||||||
|         users.emplace_back( |  | ||||||
|             userId, |  | ||||||
|             std::string((char*)usersListResponsePacket.__data.name, usersListResponsePacket.__data.packetLength - 14) |  | ||||||
|         ); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     Chattr::DataPostPacket dataPostPacket; |  | ||||||
|     dataPostPacket.__data.packetType = Chattr::PacketCategory::PACKET_POST; |  | ||||||
|     dataPostPacket.__data.requestType = Chattr::RequestType::DATA; |  | ||||||
|     dataPostPacket.__data.dataType = Chattr::DataType::TEXT; |  | ||||||
|     dataPostPacket.__data.packetLength = 14 + 8 + 8; |  | ||||||
|     for (auto user : users) |  | ||||||
|         if (user.first != myId) { |  | ||||||
|             ::memcpy(dataPostPacket.__data.destId, &user.first.snowflake, sizeof(Chattr::Snowflake)); |  | ||||||
|             break; |  | ||||||
|         } |  | ||||||
|     memcpy(dataPostPacket.__data.data, "Hello, World!", 14); |  | ||||||
|     dataPostPacket.convToN(); |  | ||||||
|     sock.send(&dataPostPacket.serialized, 8 + 14 + 8 + 8, 0); |  | ||||||
|  |  | ||||||
|     Chattr::ResponsePacket packet; |  | ||||||
|     sock.recv(&packet.serialized, 10, 0); |  | ||||||
|     packet.convToH(); |  | ||||||
| } | } | ||||||
| @@ -22,21 +22,23 @@ public: | |||||||
|         struct Address serveraddr; |         struct Address serveraddr; | ||||||
|         if (config.ipVersion == 4) { |         if (config.ipVersion == 4) { | ||||||
|             listenSock_.init(AF_INET); |             listenSock_.init(AF_INET); | ||||||
|             serveraddr.set(AF_INET, INADDR_ANY, config.listenPort); |             serveraddr.set(AF_INET, config.IP, config.Port); | ||||||
|             clientAddr_.setType(AF_INET); |             clientAddr_.setType(AF_INET); | ||||||
|         } |         } | ||||||
|         else if (config.ipVersion == 6) { |         else if (config.ipVersion == 6) { | ||||||
|             listenSock_.init(AF_INET6); |             listenSock_.init(AF_INET6); | ||||||
|             serveraddr.set(AF_INET6, in6addr_any, config.listenPort); |             serveraddr.set(AF_INET6, config.IP, config.Port); | ||||||
|             clientAddr_.setType(AF_INET6); |             clientAddr_.setType(AF_INET6); | ||||||
|         } |         } | ||||||
|         listenSock_.bind(serveraddr); |         listenSock_.bind(serveraddr); | ||||||
|         listenSock_.listen(SOMAXCONN); |         listenSock_.listen(SOMAXCONN); | ||||||
|  |          | ||||||
|  |         spdlog::info("Server listening on [{}]", (std::string)serveraddr); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|     void init() { |     void init() { | ||||||
|         init([this](ThreadPool* thread, IOCPPASSINDATA* data) { |         init([this](ThreadPool* thread, IOCPPASSINDATA* data) { | ||||||
|             _IOCPClient(thread, data); |             this->_IOCPClient(thread, data); | ||||||
|         }); |         }); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -46,14 +48,16 @@ public: | |||||||
|     void processRoomJoinRequestPacket(RoomJoinRequestPacket roomJoinRequestPacket, IOCPPASSINDATA* data); |     void processRoomJoinRequestPacket(RoomJoinRequestPacket roomJoinRequestPacket, IOCPPASSINDATA* data); | ||||||
|     void processRoomExitRequestPacket(RoomExitRequestPacket roomExitRequestPacket, IOCPPASSINDATA* data); |     void processRoomExitRequestPacket(RoomExitRequestPacket roomExitRequestPacket, IOCPPASSINDATA* data); | ||||||
|     void processUsersListRequestPacket(UsersListRequestPacket usersListRequestPacket, IOCPPASSINDATA* data); |     void processUsersListRequestPacket(UsersListRequestPacket usersListRequestPacket, IOCPPASSINDATA* data); | ||||||
|  |     void processUsersListInRoomRequestPacket(RoomUsersListRequestPacket roomUsersListRequestPacket, IOCPPASSINDATA* data); | ||||||
|     void processDataPostPacket(DataPostPacket dataPostPacket, IOCPPASSINDATA* data); |     void processDataPostPacket(DataPostPacket dataPostPacket, IOCPPASSINDATA* data); | ||||||
|     void processContinuePacket(ContinuePacket continuePacket, IOCPPASSINDATA* data); |     void processContinuePacket(ContinuePacket continuePacket, IOCPPASSINDATA* data); | ||||||
|  |  | ||||||
|     void registerUser(std::string userName, std::shared_ptr<TCPSocket> sock); |     bool registerUser(std::string userName, std::shared_ptr<TCPSocket> sock); | ||||||
|     void deleteUser(Snowflake UID); |     void deleteUser(Snowflake UID); | ||||||
|     std::vector<std::pair<Snowflake, std::string>> getUserList(); |     std::vector<std::pair<Snowflake, std::string>> getUserList(); | ||||||
|  |     std::vector<std::pair<Snowflake, std::string>> getUserListInRoom(Snowflake RID); | ||||||
|  |  | ||||||
|     void createRoom(std::string roomName); |     Snowflake createRoom(std::string roomName); | ||||||
|     void deleteRoom(Snowflake RID); |     void deleteRoom(Snowflake RID); | ||||||
|     std::vector<std::pair<Snowflake, std::string>> getRoomList(); |     std::vector<std::pair<Snowflake, std::string>> getRoomList(); | ||||||
|  |  | ||||||
| @@ -80,7 +84,7 @@ private: | |||||||
|     std::unordered_map<std::shared_ptr<TCPSocket>, Snowflake> userSocket2UID_; |     std::unordered_map<std::shared_ptr<TCPSocket>, Snowflake> userSocket2UID_; | ||||||
|  |  | ||||||
|     std::unordered_map<Snowflake, std::string> userNames_; |     std::unordered_map<Snowflake, std::string> userNames_; | ||||||
|  |     std::unordered_map<std::string, Snowflake> userName2ID_; | ||||||
|  |  | ||||||
| }; | }; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -5,9 +5,24 @@ | |||||||
| namespace Chattr { | namespace Chattr { | ||||||
|  |  | ||||||
| void ServerManager::_IOCPClient(Chattr::ThreadPool* thread, Chattr::IOCPPASSINDATA* data) { | void ServerManager::_IOCPClient(Chattr::ThreadPool* thread, Chattr::IOCPPASSINDATA* data) { | ||||||
|  |     if (data->event == IOCPEVENT::QUIT) { | ||||||
|  |         if (userSocket2UID_.find(data->socket) != userSocket2UID_.end()) { | ||||||
|  |             for (auto room : rooms_) { | ||||||
|  |                 if (room.second.find(userSocket2UID_[data->socket]) != room.second.end()) { | ||||||
|  |                     exitRoom(userSocket2UID_[data->socket], room.first); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             deleteUser(userSocket2UID_[data->socket]); | ||||||
|  |         } | ||||||
|  |         delete data; | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     Chattr::Packet pack; |     Chattr::Packet pack; | ||||||
|     int packetSize = data->transferredbytes; |     int packetSize = data->transferredbytes; | ||||||
|  |  | ||||||
|  |     memcpy(pack.serialized, data->wsabuf.buf, data->wsabuf.len); | ||||||
|  |  | ||||||
|     if (data->event == IOCPEVENT::WRITE && data->transferredbytes >= data->wsabuf.len) { |     if (data->event == IOCPEVENT::WRITE && data->transferredbytes >= data->wsabuf.len) { | ||||||
|         data->event = IOCPEVENT::READ; |         data->event = IOCPEVENT::READ; | ||||||
|         data->wsabuf.len = 1500; |         data->wsabuf.len = 1500; | ||||||
| @@ -15,8 +30,6 @@ void ServerManager::_IOCPClient(Chattr::ThreadPool* thread, Chattr::IOCPPASSINDA | |||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     memcpy(pack.serialized, data->wsabuf.buf, data->wsabuf.len); |  | ||||||
|  |  | ||||||
|     std::uint16_t packetLength = ::ntohs(pack.__data.packetLength); |     std::uint16_t packetLength = ::ntohs(pack.__data.packetLength); | ||||||
|  |  | ||||||
|     if (data->event == IOCPEVENT::READ && data->transferredbytes < packetLength + 8) { |     if (data->event == IOCPEVENT::READ && data->transferredbytes < packetLength + 8) { | ||||||
| @@ -71,6 +84,13 @@ void ServerManager::_IOCPClient(Chattr::ThreadPool* thread, Chattr::IOCPPASSINDA | |||||||
|             processUsersListRequestPacket(usersListRequestPacket, data); |             processUsersListRequestPacket(usersListRequestPacket, data); | ||||||
|         } |         } | ||||||
|         break; |         break; | ||||||
|  |     case PacketSet::ROOMUSERSLISTREQUEST: { | ||||||
|  |             RoomUsersListRequestPacket roomUsersListRequestPacket; | ||||||
|  |             std::memcpy(&roomUsersListRequestPacket.serialized, pack.serialized, 8 + packetLength); | ||||||
|  |             roomUsersListRequestPacket.convToH(); | ||||||
|  |             processUsersListInRoomRequestPacket(roomUsersListRequestPacket, data); | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|     case PacketSet::DATAPOST: { |     case PacketSet::DATAPOST: { | ||||||
|             DataPostPacket dataPostPacket; |             DataPostPacket dataPostPacket; | ||||||
|             std::memcpy(&dataPostPacket.serialized, &pack.serialized, 8 + packetLength); |             std::memcpy(&dataPostPacket.serialized, &pack.serialized, 8 + packetLength); | ||||||
| @@ -135,6 +155,8 @@ PacketSet ServerManager::packetParser(Packet Packet) { | |||||||
|             return PacketSet::ROOMEXITREQUEST; |             return PacketSet::ROOMEXITREQUEST; | ||||||
|         case RequestType::USERS_LIST: |         case RequestType::USERS_LIST: | ||||||
|             return PacketSet::USERSLISTREQUEST; |             return PacketSet::USERSLISTREQUEST; | ||||||
|  |         case RequestType::ROOM_USERS_LIST: | ||||||
|  |             return PacketSet::ROOMUSERSLISTREQUEST; | ||||||
|         case RequestType::DATA: |         case RequestType::DATA: | ||||||
|             return PacketSet::INVALID; |             return PacketSet::INVALID; | ||||||
|         } |         } | ||||||
| @@ -153,6 +175,8 @@ PacketSet ServerManager::packetParser(Packet Packet) { | |||||||
|             return PacketSet::ROOMEXITRESPONSE; |             return PacketSet::ROOMEXITRESPONSE; | ||||||
|         case RequestType::USERS_LIST: |         case RequestType::USERS_LIST: | ||||||
|             return PacketSet::USERSLISTRESPONSE; |             return PacketSet::USERSLISTRESPONSE; | ||||||
|  |         case RequestType::ROOM_USERS_LIST: | ||||||
|  |             return PacketSet::ROOMUSERSLISTRESPONSE; | ||||||
|         case RequestType::DATA: |         case RequestType::DATA: | ||||||
|             return PacketSet::INVALID; |             return PacketSet::INVALID; | ||||||
|         } |         } | ||||||
| @@ -167,40 +191,141 @@ PacketSet ServerManager::packetParser(Packet Packet) { | |||||||
| } | } | ||||||
|  |  | ||||||
| void ServerManager::processLoginRequestPacket(LoginRequestPacket loginRequestPacket, Chattr::IOCPPASSINDATA* data) { | void ServerManager::processLoginRequestPacket(LoginRequestPacket loginRequestPacket, Chattr::IOCPPASSINDATA* data) { | ||||||
|  |     std::unique_lock<std::mutex> lock(resourceMutex_); | ||||||
|     std::string userName( |     std::string userName( | ||||||
|         (char*)loginRequestPacket.__data.data, |         (char*)loginRequestPacket.__data.data, | ||||||
|         loginRequestPacket.__data.packetLength); |         loginRequestPacket.__data.packetLength); | ||||||
|     registerUser(userName, data->socket); |     if (registerUser(userName, data->socket)) { | ||||||
|  |         LoginResponsePacket loginResponsePacket; | ||||||
|  |         loginResponsePacket.__data.packetType = Chattr::PacketCategory::PACKET_RESPONSE; | ||||||
|  |         loginResponsePacket.__data.requestType = Chattr::RequestType::LOGIN; | ||||||
|  |         loginResponsePacket.__data.dataType = Chattr::DataType::BINARY; | ||||||
|  |         loginResponsePacket.__data.packetLength = sizeof(Chattr::ResponseStatusCode) + sizeof(Snowflake); | ||||||
|  |         loginResponsePacket.__data.responseStatusCode = Chattr::ResponseStatusCode::RES_OK; | ||||||
|  |         Snowflake yourId = userSocket2UID_[data->socket]; | ||||||
|  |         ::memcpy(loginResponsePacket.__data.yourId, &yourId, sizeof(Snowflake)); | ||||||
|  |  | ||||||
|     LoginResponsePacket loginResponsePacket; |         loginResponsePacket.convToN(); | ||||||
|     loginResponsePacket.__data.packetType = Chattr::PacketCategory::PACKET_RESPONSE; |         memcpy(data->wsabuf.buf, loginResponsePacket.serialized, 18); | ||||||
|     loginResponsePacket.__data.requestType = Chattr::RequestType::LOGIN; |         data->sendbytes = 18; | ||||||
|     loginResponsePacket.__data.dataType = Chattr::DataType::TEXT; |         data->wsabuf.len = 18; | ||||||
|     loginResponsePacket.__data.packetLength = sizeof(Chattr::ResponseStatusCode) + sizeof(Snowflake); |         data->IOCPInstance->send(data, 1, 0); | ||||||
|     loginResponsePacket.__data.responseStatusCode = Chattr::ResponseStatusCode::OK; |     } | ||||||
|     Snowflake yourId = userSocket2UID_[data->socket]; |     else { | ||||||
|     ::memcpy(loginResponsePacket.__data.yourId, &yourId, sizeof(Snowflake)); |         LoginResponsePacket loginResponsePacket; | ||||||
|  |         loginResponsePacket.__data.packetType = Chattr::PacketCategory::PACKET_RESPONSE; | ||||||
|  |         loginResponsePacket.__data.requestType = Chattr::RequestType::LOGIN; | ||||||
|  |         loginResponsePacket.__data.dataType = Chattr::DataType::BINARY; | ||||||
|  |         loginResponsePacket.__data.packetLength = sizeof(Chattr::ResponseStatusCode); | ||||||
|  |         loginResponsePacket.__data.responseStatusCode = Chattr::ResponseStatusCode::BAD_REQUEST; | ||||||
|  |  | ||||||
|     loginResponsePacket.convToN(); |         loginResponsePacket.convToN(); | ||||||
|     memcpy(data->wsabuf.buf, loginResponsePacket.serialized, 16); |         memcpy(data->wsabuf.buf, loginResponsePacket.serialized, 10); | ||||||
|     data->sendbytes = 16; |         data->sendbytes = 10; | ||||||
|     data->wsabuf.len = 16; |         data->wsabuf.len = 10; | ||||||
|     data->IOCPInstance->send(data, 1, 0); |         data->IOCPInstance->send(data, 1, 0); | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| void ServerManager::processRoomCreateRequestPacket(RoomCreateRequestPacket roomCreateRequestPacket, Chattr::IOCPPASSINDATA* data) { | void ServerManager::processRoomCreateRequestPacket(RoomCreateRequestPacket roomCreateRequestPacket, Chattr::IOCPPASSINDATA* data) { | ||||||
|  |     std::unique_lock<std::mutex> lock(resourceMutex_); | ||||||
|  |     std::string roomName( | ||||||
|  |         (char*)roomCreateRequestPacket.__data.data, | ||||||
|  |         roomCreateRequestPacket.__data.packetLength); | ||||||
|  |     Snowflake RID = createRoom(roomName); | ||||||
|  |  | ||||||
|  |     RoomCreateResponsePacket roomCreateResponsePacket; | ||||||
|  |     roomCreateResponsePacket.__data.packetType = Chattr::PacketCategory::PACKET_RESPONSE; | ||||||
|  |     roomCreateResponsePacket.__data.requestType = Chattr::RequestType::ROOM_CREATE; | ||||||
|  |     roomCreateResponsePacket.__data.dataType = Chattr::DataType::BINARY; | ||||||
|  |     roomCreateResponsePacket.__data.packetLength = sizeof(Chattr::ResponseStatusCode) + sizeof(Snowflake); | ||||||
|  |     roomCreateResponsePacket.__data.responseStatusCode = Chattr::ResponseStatusCode::RES_OK; | ||||||
|  |     ::memcpy(roomCreateResponsePacket.__data.createdRoomId, &RID, sizeof(Snowflake)); | ||||||
|  |  | ||||||
|  |     roomCreateResponsePacket.convToN(); | ||||||
|  |     memcpy(data->wsabuf.buf, roomCreateResponsePacket.serialized, 18); | ||||||
|  |     data->sendbytes = 18; | ||||||
|  |     data->wsabuf.len = 18; | ||||||
|  |     data->IOCPInstance->send(data, 1, 0); | ||||||
| } | } | ||||||
|  |  | ||||||
| void ServerManager::processRoomListRequest(RoomListRequestPacket roomListRequestPacket, Chattr::IOCPPASSINDATA* data) { | void ServerManager::processRoomListRequest(RoomListRequestPacket roomListRequestPacket, Chattr::IOCPPASSINDATA* data) { | ||||||
|  |     std::unique_lock<std::mutex> lock(resourceMutex_); | ||||||
|  |     auto roomsList = getRoomList(); | ||||||
|  |  | ||||||
|  |     for (auto room : roomsList) { | ||||||
|  |         RoomListResponsePacket roomListResponsePacket; | ||||||
|  |         roomListResponsePacket.__data.packetType = Chattr::PacketCategory::PACKET_RESPONSE; | ||||||
|  |         roomListResponsePacket.__data.requestType = Chattr::RequestType::ROOM_LIST; | ||||||
|  |         roomListResponsePacket.__data.dataType = Chattr::DataType::BINARY; | ||||||
|  |         roomListResponsePacket.__data.packetLength = sizeof(Chattr::ResponseStatusCode) + sizeof(std::uint32_t) + sizeof(Snowflake) + room.second.size(); | ||||||
|  |         roomListResponsePacket.__data.responseStatusCode = Chattr::ResponseStatusCode::RES_OK; | ||||||
|  |         roomListResponsePacket.__data.roomCount = roomsList.size(); | ||||||
|  |         ::memcpy(roomListResponsePacket.__data.roomId, &room.first, sizeof(Snowflake)); | ||||||
|  |         ::memcpy(roomListResponsePacket.__data.name, room.second.c_str(), room.second.size()); | ||||||
|  |  | ||||||
|  |         int packetLength = roomListResponsePacket.__data.packetLength; | ||||||
|  |  | ||||||
|  |         Chattr::IOCPPASSINDATA* ptr = new Chattr::IOCPPASSINDATA(*data); | ||||||
|  |         ptr->wsabuf.len = packetLength + 8; | ||||||
|  |  | ||||||
|  |         roomListResponsePacket.convToN(); | ||||||
|  |         memcpy(ptr->wsabuf.buf, roomListResponsePacket.serialized, packetLength + 8); | ||||||
|  |         data->sendbytes = packetLength + 8; | ||||||
|  |         data->IOCPInstance->send(ptr, 1, 0); | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| void ServerManager::processRoomJoinRequestPacket(RoomJoinRequestPacket roomJoinRequestPacket, Chattr::IOCPPASSINDATA* data) { | void ServerManager::processRoomJoinRequestPacket(RoomJoinRequestPacket roomJoinRequestPacket, Chattr::IOCPPASSINDATA* data) { | ||||||
|  |     std::unique_lock<std::mutex> lock(resourceMutex_); | ||||||
|  |     Snowflake myID, roomID; | ||||||
|  |     ::memcpy(&myID.snowflake, roomJoinRequestPacket.__data.myId, sizeof(Snowflake)); | ||||||
|  |     ::memcpy(&roomID.snowflake, roomJoinRequestPacket.__data.roomId, sizeof(Snowflake)); | ||||||
|  |  | ||||||
|  |     joinRoom(myID, roomID); | ||||||
|  |  | ||||||
|  |     RoomJoinResponsePacket roomJoinResponsePacket; | ||||||
|  |     roomJoinResponsePacket.__data.packetType = Chattr::PacketCategory::PACKET_RESPONSE; | ||||||
|  |     roomJoinResponsePacket.__data.requestType = Chattr::RequestType::ROOM_JOIN; | ||||||
|  |     roomJoinResponsePacket.__data.dataType = Chattr::DataType::BINARY; | ||||||
|  |     roomJoinResponsePacket.__data.packetLength = sizeof(Chattr::ResponseStatusCode); | ||||||
|  |     roomJoinResponsePacket.__data.responseStatusCode = Chattr::ResponseStatusCode::RES_OK; | ||||||
|  |  | ||||||
|  |     int packetLength = roomJoinResponsePacket.__data.packetLength; | ||||||
|  |  | ||||||
|  |     roomJoinResponsePacket.convToN(); | ||||||
|  |     ::memcpy(data->wsabuf.buf, roomJoinResponsePacket.serialized, 10); | ||||||
|  |     data->sendbytes = 10; | ||||||
|  |     data->wsabuf.len = 10; | ||||||
|  |     data->IOCPInstance->send(data, 1, 0); | ||||||
| } | } | ||||||
|  |  | ||||||
| void ServerManager::processRoomExitRequestPacket(RoomExitRequestPacket roomExitRequestPacket, Chattr::IOCPPASSINDATA* data) { | void ServerManager::processRoomExitRequestPacket(RoomExitRequestPacket roomExitRequestPacket, Chattr::IOCPPASSINDATA* data) { | ||||||
|  |     std::unique_lock<std::mutex> lock(resourceMutex_); | ||||||
|  |     Snowflake myID, roomID; | ||||||
|  |     ::memcpy(&myID.snowflake, roomExitRequestPacket.__data.myId, sizeof(Snowflake)); | ||||||
|  |     ::memcpy(&roomID.snowflake, roomExitRequestPacket.__data.roomId, sizeof(Snowflake)); | ||||||
|  |  | ||||||
|  |     exitRoom(myID, roomID); | ||||||
|  |  | ||||||
|  |     RoomExitResponsePacket roomExitResponsePacket; | ||||||
|  |     roomExitResponsePacket.__data.packetType = Chattr::PacketCategory::PACKET_RESPONSE; | ||||||
|  |     roomExitResponsePacket.__data.requestType = Chattr::RequestType::ROOM_EXIT; | ||||||
|  |     roomExitResponsePacket.__data.dataType = Chattr::DataType::BINARY; | ||||||
|  |     roomExitResponsePacket.__data.packetLength = sizeof(Chattr::ResponseStatusCode); | ||||||
|  |     roomExitResponsePacket.__data.responseStatusCode = Chattr::ResponseStatusCode::RES_OK; | ||||||
|  |  | ||||||
|  |     int packetLength = roomExitResponsePacket.__data.packetLength; | ||||||
|  |  | ||||||
|  |     roomExitResponsePacket.convToN(); | ||||||
|  |     ::memcpy(data->wsabuf.buf, roomExitResponsePacket.serialized, 10); | ||||||
|  |     data->sendbytes = 10; | ||||||
|  |     data->wsabuf.len = 10; | ||||||
|  |     data->IOCPInstance->send(data, 1, 0); | ||||||
| } | } | ||||||
|  |  | ||||||
| void ServerManager::processUsersListRequestPacket(UsersListRequestPacket usersListRequestPacket, Chattr::IOCPPASSINDATA* data) { | void ServerManager::processUsersListRequestPacket(UsersListRequestPacket usersListRequestPacket, Chattr::IOCPPASSINDATA* data) { | ||||||
|  |     std::unique_lock<std::mutex> lock(resourceMutex_); | ||||||
|     auto usersList = getUserList(); |     auto usersList = getUserList(); | ||||||
|  |  | ||||||
|     for (auto user : usersList) { |     for (auto user : usersList) { | ||||||
| @@ -209,20 +334,15 @@ void ServerManager::processUsersListRequestPacket(UsersListRequestPacket usersLi | |||||||
|         usersListResponsePacket.__data.requestType = Chattr::RequestType::USERS_LIST; |         usersListResponsePacket.__data.requestType = Chattr::RequestType::USERS_LIST; | ||||||
|         usersListResponsePacket.__data.dataType = Chattr::DataType::BINARY; |         usersListResponsePacket.__data.dataType = Chattr::DataType::BINARY; | ||||||
|         usersListResponsePacket.__data.packetLength = sizeof(Chattr::ResponseStatusCode) + sizeof(std::uint32_t) + sizeof(Snowflake) + user.second.size(); |         usersListResponsePacket.__data.packetLength = sizeof(Chattr::ResponseStatusCode) + sizeof(std::uint32_t) + sizeof(Snowflake) + user.second.size(); | ||||||
|         usersListResponsePacket.__data.responseStatusCode = Chattr::ResponseStatusCode::OK; |         usersListResponsePacket.__data.responseStatusCode = Chattr::ResponseStatusCode::RES_OK; | ||||||
|         usersListResponsePacket.__data.usersCount = usersList.size(); |         usersListResponsePacket.__data.usersCount = usersList.size(); | ||||||
|         ::memcpy(usersListResponsePacket.__data.userId, &user.first, sizeof(Snowflake)); |         ::memcpy(usersListResponsePacket.__data.userId, &user.first, sizeof(Snowflake)); | ||||||
|         ::memcpy(usersListResponsePacket.__data.name, user.second.c_str(), user.second.size()); |         ::memcpy(usersListResponsePacket.__data.name, user.second.c_str(), user.second.size()); | ||||||
|  |  | ||||||
|         int packetLength = usersListResponsePacket.__data.packetLength; |         int packetLength = usersListResponsePacket.__data.packetLength; | ||||||
|  |  | ||||||
|         Chattr::IOCPPASSINDATA* ptr = new Chattr::IOCPPASSINDATA; |         Chattr::IOCPPASSINDATA* ptr = new Chattr::IOCPPASSINDATA(*data); | ||||||
|         ::memset(&ptr->overlapped, 0, sizeof(OVERLAPPED)); |  | ||||||
|         ptr->socket = data->socket; |  | ||||||
|         ptr->recvbytes = ptr->sendbytes = 0; |  | ||||||
|         ptr->wsabuf.buf = ptr->buf; |  | ||||||
|         ptr->wsabuf.len = packetLength + 8; |         ptr->wsabuf.len = packetLength + 8; | ||||||
|         ptr->IOCPInstance = data->IOCPInstance; |  | ||||||
|  |  | ||||||
|         usersListResponsePacket.convToN(); |         usersListResponsePacket.convToN(); | ||||||
|         memcpy(ptr->wsabuf.buf, usersListResponsePacket.serialized, packetLength + 8); |         memcpy(ptr->wsabuf.buf, usersListResponsePacket.serialized, packetLength + 8); | ||||||
| @@ -231,7 +351,38 @@ void ServerManager::processUsersListRequestPacket(UsersListRequestPacket usersLi | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| void ServerManager::processDataPostPacket(DataPostPacket dataPostPacket, IOCPPASSINDATA* data) { | void ServerManager::processUsersListInRoomRequestPacket(RoomUsersListRequestPacket roomUsersListRequestPacket, IOCPPASSINDATA *data) { | ||||||
|  |     std::unique_lock<std::mutex> lock(resourceMutex_); | ||||||
|  |     Snowflake roomID; | ||||||
|  |     ::memcpy(&roomID.snowflake, roomUsersListRequestPacket.__data.roomId, sizeof(Snowflake)); | ||||||
|  |     auto usersList = getUserListInRoom(roomID); | ||||||
|  |  | ||||||
|  |     for (auto user : usersList) { | ||||||
|  |         UsersListResponsePacket usersListResponsePacket; | ||||||
|  |         usersListResponsePacket.__data.packetType = Chattr::PacketCategory::PACKET_RESPONSE; | ||||||
|  |         usersListResponsePacket.__data.requestType = Chattr::RequestType::USERS_LIST; | ||||||
|  |         usersListResponsePacket.__data.dataType = Chattr::DataType::BINARY; | ||||||
|  |         usersListResponsePacket.__data.packetLength = sizeof(Chattr::ResponseStatusCode) + sizeof(std::uint32_t) + sizeof(Snowflake) + user.second.size(); | ||||||
|  |         usersListResponsePacket.__data.responseStatusCode = Chattr::ResponseStatusCode::RES_OK; | ||||||
|  |         usersListResponsePacket.__data.usersCount = usersList.size(); | ||||||
|  |         ::memcpy(usersListResponsePacket.__data.userId, &user.first, sizeof(Snowflake)); | ||||||
|  |         ::memcpy(usersListResponsePacket.__data.name, user.second.c_str(), user.second.size()); | ||||||
|  |  | ||||||
|  |         int packetLength = usersListResponsePacket.__data.packetLength; | ||||||
|  |  | ||||||
|  |         Chattr::IOCPPASSINDATA* ptr = new Chattr::IOCPPASSINDATA(*data); | ||||||
|  |         ptr->wsabuf.len = packetLength + 8; | ||||||
|  |  | ||||||
|  |         usersListResponsePacket.convToN(); | ||||||
|  |         memcpy(ptr->wsabuf.buf, usersListResponsePacket.serialized, packetLength + 8); | ||||||
|  |         data->sendbytes = packetLength + 8; | ||||||
|  |         data->IOCPInstance->send(ptr, 1, 0); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ServerManager::processDataPostPacket(DataPostPacket dataPostPacket, IOCPPASSINDATA *data) | ||||||
|  | { | ||||||
|  |     std::unique_lock<std::mutex> lock(resourceMutex_); | ||||||
|     Snowflake destID; |     Snowflake destID; | ||||||
|     ::memcpy(&destID.snowflake, dataPostPacket.__data.destId, sizeof(Snowflake)); |     ::memcpy(&destID.snowflake, dataPostPacket.__data.destId, sizeof(Snowflake)); | ||||||
|  |  | ||||||
| @@ -253,7 +404,7 @@ void ServerManager::processDataPostPacket(DataPostPacket dataPostPacket, IOCPPAS | |||||||
|     responsePacket.__data.requestType = Chattr::RequestType::DATA; |     responsePacket.__data.requestType = Chattr::RequestType::DATA; | ||||||
|     responsePacket.__data.dataType = Chattr::DataType::TEXT; |     responsePacket.__data.dataType = Chattr::DataType::TEXT; | ||||||
|     responsePacket.__data.packetLength = sizeof(Chattr::ResponseStatusCode); |     responsePacket.__data.packetLength = sizeof(Chattr::ResponseStatusCode); | ||||||
|     responsePacket.__data.responseStatusCode = Chattr::ResponseStatusCode::OK; |     responsePacket.__data.responseStatusCode = Chattr::ResponseStatusCode::RES_OK; | ||||||
|  |  | ||||||
|     responsePacket.convToN(); |     responsePacket.convToN(); | ||||||
|     memcpy(data->wsabuf.buf, responsePacket.serialized, 10); |     memcpy(data->wsabuf.buf, responsePacket.serialized, 10); | ||||||
| @@ -263,36 +414,76 @@ void ServerManager::processDataPostPacket(DataPostPacket dataPostPacket, IOCPPAS | |||||||
|  |  | ||||||
|     int packetLength = dataPostPacket.__data.packetLength; |     int packetLength = dataPostPacket.__data.packetLength; | ||||||
|  |  | ||||||
|  |     dataPostPacket.convToN(); | ||||||
|     for (auto dest : destinationSockets) { |     for (auto dest : destinationSockets) { | ||||||
|  |         Chattr::IOCPPASSINDATA* ptr = new Chattr::IOCPPASSINDATA(*data); | ||||||
|         Chattr::IOCPPASSINDATA* ptr = new Chattr::IOCPPASSINDATA; |  | ||||||
|         ::memset(&ptr->overlapped, 0, sizeof(OVERLAPPED)); |  | ||||||
|         ptr->socket = dest; |         ptr->socket = dest; | ||||||
|         ptr->recvbytes = ptr->sendbytes = 0; |         ptr->wsabuf.len = packetLength + 8; | ||||||
|         ptr->wsabuf.buf = ptr->buf; |  | ||||||
|         ptr->wsabuf.len = packetLength + 6; |  | ||||||
|         ptr->IOCPInstance = data->IOCPInstance; |  | ||||||
|  |  | ||||||
|         dataPostPacket.convToN(); |         memcpy(ptr->wsabuf.buf, dataPostPacket.serialized, packetLength + 8); | ||||||
|         memcpy(ptr->wsabuf.buf, dataPostPacket.serialized, packetLength + 6); |         data->sendbytes = packetLength + 8; | ||||||
|         data->sendbytes = packetLength + 6; |  | ||||||
|         data->IOCPInstance->send(ptr, 1, 0); |         data->IOCPInstance->send(ptr, 1, 0); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| void ServerManager::processContinuePacket(ContinuePacket continuePacket, IOCPPASSINDATA* data) { | void ServerManager::processContinuePacket(ContinuePacket continuePacket, IOCPPASSINDATA* data) { | ||||||
|  |     std::unique_lock<std::mutex> lock(resourceMutex_); | ||||||
|  |     Snowflake destID; | ||||||
|  |     ::memcpy(&destID.snowflake, continuePacket.__data.destId, sizeof(Snowflake)); | ||||||
|  |  | ||||||
|  |     std::vector<std::shared_ptr<TCPSocket>> destinationSockets; | ||||||
|  |  | ||||||
|  |     if (userNames_.find(destID) != userNames_.end()) | ||||||
|  |         destinationSockets.push_back(UID2userSocket_[destID]); | ||||||
|  |     else | ||||||
|  |         for (auto user : rooms_[destID]) | ||||||
|  |             destinationSockets.push_back(user.second); | ||||||
|  |  | ||||||
|  |     spdlog::info("Received [{}] from : [{}] to : [{}]", | ||||||
|  |         std::string((char*)continuePacket.__data.data, continuePacket.__data.packetLength - (sizeof(std::uint16_t) * 5)), | ||||||
|  |         (std::string)data->socket->remoteAddr, | ||||||
|  |         destID.snowflake); | ||||||
|  |  | ||||||
|  |     ResponsePacket responsePacket; | ||||||
|  |     responsePacket.__data.packetType = Chattr::PacketCategory::PACKET_RESPONSE; | ||||||
|  |     responsePacket.__data.requestType = Chattr::RequestType::DATA; | ||||||
|  |     responsePacket.__data.dataType = Chattr::DataType::TEXT; | ||||||
|  |     responsePacket.__data.packetLength = sizeof(Chattr::ResponseStatusCode); | ||||||
|  |     responsePacket.__data.responseStatusCode = Chattr::ResponseStatusCode::RES_OK; | ||||||
|  |  | ||||||
|  |     responsePacket.convToN(); | ||||||
|  |     memcpy(data->wsabuf.buf, responsePacket.serialized, 10); | ||||||
|  |     data->sendbytes = 10; | ||||||
|  |     data->wsabuf.len = 10; | ||||||
|  |     data->IOCPInstance->send(data, 1, 0); | ||||||
|  |  | ||||||
|  |     int packetLength = continuePacket.__data.packetLength; | ||||||
|  |  | ||||||
|  |     for (auto dest : destinationSockets) { | ||||||
|  |         Chattr::IOCPPASSINDATA* ptr = new Chattr::IOCPPASSINDATA(*data); | ||||||
|  |         ptr->socket = dest; | ||||||
|  |         ptr->wsabuf.len = packetLength + 8; | ||||||
|  |  | ||||||
|  |         continuePacket.convToN(); | ||||||
|  |         memcpy(ptr->wsabuf.buf, continuePacket.serialized, packetLength + 8); | ||||||
|  |         data->sendbytes = packetLength + 8; | ||||||
|  |         data->IOCPInstance->send(ptr, 1, 0); | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| void ServerManager::registerUser(std::string userName, std::shared_ptr<TCPSocket> sock) { | bool ServerManager::registerUser(std::string userName, std::shared_ptr<TCPSocket> sock) { | ||||||
|     std::lock_guard<std::mutex> lock(resourceMutex_); |     if (userName2ID_.find(userName) != userName2ID_.end()) { | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|     Snowflake UID = GenerateID(); |     Snowflake UID = GenerateID(); | ||||||
|     userNames_[UID] = userName; |     userNames_[UID] = userName; | ||||||
|  |     userName2ID_[userName] = UID; | ||||||
|     UID2userSocket_[UID] = sock; |     UID2userSocket_[UID] = sock; | ||||||
|     userSocket2UID_[sock] = UID; |     userSocket2UID_[sock] = UID; | ||||||
|  |     return true; | ||||||
| } | } | ||||||
|  |  | ||||||
| void ServerManager::deleteUser(Snowflake UID) { | void ServerManager::deleteUser(Snowflake UID) { | ||||||
|     std::lock_guard<std::mutex> lock(resourceMutex_); |  | ||||||
|     userNames_.erase(UID); |     userNames_.erase(UID); | ||||||
|     std::shared_ptr<TCPSocket> sock = UID2userSocket_[UID]; |     std::shared_ptr<TCPSocket> sock = UID2userSocket_[UID]; | ||||||
|     UID2userSocket_.erase(UID); |     UID2userSocket_.erase(UID); | ||||||
| @@ -300,7 +491,6 @@ void ServerManager::deleteUser(Snowflake UID) { | |||||||
| } | } | ||||||
|  |  | ||||||
| std::vector<std::pair<Snowflake, std::string>> ServerManager::getUserList() { | std::vector<std::pair<Snowflake, std::string>> ServerManager::getUserList() { | ||||||
|     std::lock_guard<std::mutex> lock(resourceMutex_); |  | ||||||
|     std::vector<std::pair<Snowflake, std::string>> userList; |     std::vector<std::pair<Snowflake, std::string>> userList; | ||||||
|     userList.reserve(userNames_.size()); |     userList.reserve(userNames_.size()); | ||||||
|  |  | ||||||
| @@ -310,21 +500,30 @@ std::vector<std::pair<Snowflake, std::string>> ServerManager::getUserList() { | |||||||
|     return userList; |     return userList; | ||||||
| } | } | ||||||
|  |  | ||||||
| void ServerManager::createRoom(std::string roomName) { | std::vector<std::pair<Snowflake, std::string>> ServerManager::getUserListInRoom(Snowflake RID) { | ||||||
|     std::lock_guard<std::mutex> lock(resourceMutex_); |     std::vector<std::pair<Snowflake, std::string>> userList; | ||||||
|  |     userList.reserve(rooms_[RID].size()); | ||||||
|  |  | ||||||
|  |     for (auto user : rooms_[RID]) | ||||||
|  |         userList.push_back({ user.first, userNames_[user.first] }); | ||||||
|  |  | ||||||
|  |     return userList; | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  | Snowflake ServerManager::createRoom(std::string roomName) { | ||||||
|     Snowflake RID = GenerateID(); |     Snowflake RID = GenerateID(); | ||||||
|     roomNames_[RID] = roomName; |     roomNames_[RID] = roomName; | ||||||
|     rooms_[RID] = std::unordered_map<Snowflake, std::shared_ptr<TCPSocket>>(); |     rooms_[RID] = std::unordered_map<Snowflake, std::shared_ptr<TCPSocket>>(); | ||||||
|  |     return RID; | ||||||
| } | } | ||||||
|  |  | ||||||
| void ServerManager::deleteRoom(Snowflake RID) { | void ServerManager::deleteRoom(Snowflake RID) { | ||||||
|     std::lock_guard<std::mutex> lock(resourceMutex_); |  | ||||||
|     roomNames_.erase(RID); |     roomNames_.erase(RID); | ||||||
|     rooms_.erase(RID); |     rooms_.erase(RID); | ||||||
| } | } | ||||||
|  |  | ||||||
| std::vector<std::pair<Snowflake, std::string>> ServerManager::getRoomList() { | std::vector<std::pair<Snowflake, std::string>> ServerManager::getRoomList() { | ||||||
|     std::lock_guard<std::mutex> lock(resourceMutex_); |  | ||||||
|     std::vector<std::pair<Snowflake, std::string>> roomList; |     std::vector<std::pair<Snowflake, std::string>> roomList; | ||||||
|     roomList.reserve(roomNames_.size()); |     roomList.reserve(roomNames_.size()); | ||||||
|  |  | ||||||
| @@ -335,13 +534,11 @@ std::vector<std::pair<Snowflake, std::string>> ServerManager::getRoomList() { | |||||||
| } | } | ||||||
|  |  | ||||||
| void ServerManager::joinRoom(Snowflake UID, Snowflake RID) { | void ServerManager::joinRoom(Snowflake UID, Snowflake RID) { | ||||||
|     std::lock_guard<std::mutex> lock(resourceMutex_); |  | ||||||
|     std::shared_ptr<TCPSocket> sock = UID2userSocket_[UID]; |     std::shared_ptr<TCPSocket> sock = UID2userSocket_[UID]; | ||||||
|     rooms_[RID][UID] = sock; |     rooms_[RID][UID] = sock; | ||||||
| } | } | ||||||
|  |  | ||||||
| void ServerManager::exitRoom(Snowflake UID, Snowflake RID) { | void ServerManager::exitRoom(Snowflake UID, Snowflake RID) { | ||||||
|     std::lock_guard<std::mutex> lock(resourceMutex_); |  | ||||||
|     rooms_[RID].erase(UID); |     rooms_[RID].erase(UID); | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -349,13 +546,9 @@ void ServerManager::run() { | |||||||
|     while (true) { |     while (true) { | ||||||
|         spdlog::info("Waiting for connection..."); |         spdlog::info("Waiting for connection..."); | ||||||
|         listenSock_.accept(clientSock_, clientAddr_); |         listenSock_.accept(clientSock_, clientAddr_); | ||||||
|         bool enable = true; |         spdlog::trace("Accepted connection from {}, [{}]", clientSock_.sock, (std::string)clientAddr_); | ||||||
|         clientSock_.setsockopt(SOL_SOCKET, SO_KEEPALIVE, (const char*)&enable, sizeof(enable)); |  | ||||||
|         Chattr::IOCPPASSINDATA* ptr = new Chattr::IOCPPASSINDATA; |         Chattr::IOCPPASSINDATA* ptr = new Chattr::IOCPPASSINDATA; | ||||||
|         ::memset(&ptr->overlapped, 0, sizeof(OVERLAPPED)); |  | ||||||
|         ptr->socket = std::make_shared<TCPSocket>(std::move(clientSock_)); |         ptr->socket = std::make_shared<TCPSocket>(std::move(clientSock_)); | ||||||
|         ptr->recvbytes = ptr->sendbytes = 0; |  | ||||||
|         ptr->wsabuf.buf = ptr->buf; |  | ||||||
|         ptr->wsabuf.len = 1500; |         ptr->wsabuf.len = 1500; | ||||||
|         ptr->IOCPInstance = &iocp_; |         ptr->IOCPInstance = &iocp_; | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										25
									
								
								Server/src/Socket/Log.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								Server/src/Socket/Log.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | |||||||
|  | #include "Socket/Log.hpp" | ||||||
|  |  | ||||||
|  | #include "spdlog/sinks/stdout_color_sinks.h" | ||||||
|  | #include "spdlog/sinks/rotating_file_sink.h" | ||||||
|  | #ifdef _WIN32 | ||||||
|  | #include "spdlog/sinks/msvc_sink.h" | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #include "precomp.hpp" | ||||||
|  |  | ||||||
|  | namespace Chattr::log { | ||||||
|  |  | ||||||
|  | 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); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | } | ||||||
| @@ -13,7 +13,8 @@ ConfigManager::Config ConfigManager::load() { | |||||||
|   if (!configfile.is_open()) { |   if (!configfile.is_open()) { | ||||||
|     std::ofstream defaultConfig("config.json", std::ios::out); |     std::ofstream defaultConfig("config.json", std::ios::out); | ||||||
|     config.configJsonRoot["IP Version"] = 6; |     config.configJsonRoot["IP Version"] = 6; | ||||||
|     config.configJsonRoot["Listen Port"] = 9010; |     config.configJsonRoot["IP"] = "::"; | ||||||
|  |     config.configJsonRoot["Port"] = 9010; | ||||||
|     config.configJsonRoot["LogLevel"] = 1; |     config.configJsonRoot["LogLevel"] = 1; | ||||||
|     config.configJsonRoot["LogfileName"] = "Chattering.log"; |     config.configJsonRoot["LogfileName"] = "Chattering.log"; | ||||||
|     config.configJsonRoot["LogfileSize"] = UINT32_MAX; |     config.configJsonRoot["LogfileSize"] = UINT32_MAX; | ||||||
| @@ -30,8 +31,10 @@ ConfigManager::Config ConfigManager::load() { | |||||||
|     if (config.ipVersion != 4 && config.ipVersion != 6) |     if (config.ipVersion != 4 && config.ipVersion != 6) | ||||||
|       throw std::runtime_error("Invalid IP Version."); |       throw std::runtime_error("Invalid IP Version."); | ||||||
|  |  | ||||||
|     config.listenPort = config.configJsonRoot["Listen Port"].asInt(); |     config.IP = config.configJsonRoot["IP"].asCString(); | ||||||
|     if (config.listenPort < 0 || config.listenPort > 65535) |  | ||||||
|  |     config.Port = config.configJsonRoot["Port"].asInt(); | ||||||
|  |     if (config.Port < 0 || config.Port > 65535) | ||||||
|       throw std::runtime_error("Invalid listen port."); |       throw std::runtime_error("Invalid listen port."); | ||||||
|  |  | ||||||
|     int ll_ = config.configJsonRoot["LogLevel"].asInt(); |     int ll_ = config.configJsonRoot["LogLevel"].asInt(); | ||||||
|   | |||||||
| @@ -5,7 +5,24 @@ | |||||||
|  |  | ||||||
| namespace Chattr { | namespace Chattr { | ||||||
|  |  | ||||||
| void IOCP::registerSocket(Chattr::IOCPPASSINDATA* data) { | 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 | #ifdef _WIN32 | ||||||
| 	HANDLE returnData = ::CreateIoCompletionPort((HANDLE)data->socket->sock, completionPort_, data->socket->sock, 0); | 	HANDLE returnData = ::CreateIoCompletionPort((HANDLE)data->socket->sock, completionPort_, data->socket->sock, 0); | ||||||
| 	if (returnData == 0) | 	if (returnData == 0) | ||||||
| @@ -17,6 +34,7 @@ void IOCP::registerSocket(Chattr::IOCPPASSINDATA* data) { | |||||||
|  |  | ||||||
| 	struct epoll_event ev; | 	struct epoll_event ev; | ||||||
| 	ev.events = EPOLLIN | EPOLLONESHOT; | 	ev.events = EPOLLIN | EPOLLONESHOT; | ||||||
|  | 	data->sendQueue = std::make_shared<std::queue<IOCPPASSINDATA*>>(); | ||||||
| 	ev.data.ptr = data; | 	ev.data.ptr = data; | ||||||
| 	int rc = epoll_ctl(epollfd_, EPOLL_CTL_ADD, data->socket->sock, &ev); | 	int rc = epoll_ctl(epollfd_, EPOLL_CTL_ADD, data->socket->sock, &ev); | ||||||
| 	if (rc < 0) | 	if (rc < 0) | ||||||
| @@ -37,15 +55,16 @@ int IOCP::recv(Chattr::IOCPPASSINDATA* data, int bufferCount) { | |||||||
| #endif | #endif | ||||||
| } | } | ||||||
|  |  | ||||||
| int IOCP::send(Chattr::IOCPPASSINDATA* data, int bufferCount, int __flags) { | int IOCP::send(Chattr::IOCPPASSINDATA* data, int bufferCount, int __flags) { //TCPSocket의 소유권 확인하기. 어디선가 예상치 못하게 socket이 close되었음 | ||||||
| 	data->event = IOCPEVENT::WRITE; | 	data->event = IOCPEVENT::WRITE; | ||||||
| #ifdef _WIN32 | #ifdef _WIN32 | ||||||
| 	DWORD sendbytes = 0; | 	DWORD sendbytes = 0; | ||||||
| 	return ::WSASend(data->socket->sock, &data->wsabuf, bufferCount, &sendbytes, __flags, &data->overlapped, NULL); | 	return ::WSASend(data->socket->sock, &data->wsabuf, bufferCount, &sendbytes, __flags, &data->overlapped, NULL); | ||||||
| #elif __linux__ | #elif __linux__ | ||||||
| 	struct epoll_event ev; | 	struct epoll_event ev; | ||||||
| 	ev.events = EPOLLOUT | EPOLLONESHOT; | 	ev.events = EPOLLIN | EPOLLOUT | EPOLLONESHOT; | ||||||
| 	ev.data.ptr = data; | 	ev.data.ptr = data; | ||||||
|  | 	data->sendQueue->push(data); | ||||||
| 	return ::epoll_ctl(epollfd_, EPOLL_CTL_MOD, data->socket->sock, &ev); | 	return ::epoll_ctl(epollfd_, EPOLL_CTL_MOD, data->socket->sock, &ev); | ||||||
| #endif | #endif | ||||||
| } | } | ||||||
|   | |||||||
| @@ -10,18 +10,6 @@ | |||||||
|  |  | ||||||
| namespace Chattr::log { | namespace Chattr::log { | ||||||
|  |  | ||||||
| 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); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void critical(gsl::czstring msg) { | void critical(gsl::czstring msg) { | ||||||
| #ifdef _WIN32 | #ifdef _WIN32 | ||||||
|     LPSTR msgbuf = nullptr; |     LPSTR msgbuf = nullptr; | ||||||
|   | |||||||
| @@ -32,8 +32,11 @@ int TCPSocket::connect(Address& serveraddr) { | |||||||
|  |  | ||||||
| int TCPSocket::recv(void *__restrict __buf, size_t __n, int __flags) { | int TCPSocket::recv(void *__restrict __buf, size_t __n, int __flags) { | ||||||
|     int retVal = ::recv(sock, (char *)__buf, __n, __flags); |     int retVal = ::recv(sock, (char *)__buf, __n, __flags); | ||||||
|     if (retVal == SOCKET_ERROR) |     if (retVal == SOCKET_ERROR) { | ||||||
|  |         if (errno == EAGAIN || errno == EWOULDBLOCK) | ||||||
|  |             return retVal; | ||||||
|         log::error("recv()"); |         log::error("recv()"); | ||||||
|  |     } | ||||||
|     return retVal; |     return retVal; | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -3,25 +3,28 @@ | |||||||
| namespace Chattr { | namespace Chattr { | ||||||
|  |  | ||||||
| Snowflake GenerateID() { | Snowflake GenerateID() { | ||||||
|     static struct _EPOCH { |     static struct EpochInitializer { | ||||||
|         _EPOCH() { |         EpochInitializer() { | ||||||
|             EPOCH = std::chrono::system_clock::now(); |             EPOCH = std::chrono::system_clock::now(); | ||||||
|         } |         } | ||||||
|         std::chrono::system_clock::time_point EPOCH; |         std::chrono::system_clock::time_point EPOCH; | ||||||
|     } __EPOCH__; |     } epochInitializer; | ||||||
|      |      | ||||||
|     static std::mutex snowflakeGenerateMutex_; |     static std::mutex snowflakeGenerateMutex_; | ||||||
|  |  | ||||||
|     std::lock_guard<std::mutex> lock(snowflakeGenerateMutex_); |     std::lock_guard<std::mutex> lock(snowflakeGenerateMutex_); | ||||||
| #ifdef _WIN32 |  | ||||||
|     DWORD tid = GetCurrentThreadId(); |     std::size_t tid; | ||||||
| #elif __linux__ |     #ifdef _WIN32 | ||||||
|     pthread_t tid = pthread_self(); |         tid = static_cast<std::size_t>(GetCurrentThreadId()); | ||||||
| #endif |     #elif __linux__ | ||||||
|     static int sequence = 0; |         tid = static_cast<std::size_t>(pthread_self()); | ||||||
|  |     #endif | ||||||
|  |  | ||||||
|  |     thread_local static int sequence = 0; | ||||||
|     Snowflake id = {}; |     Snowflake id = {}; | ||||||
|  |  | ||||||
|     auto timestamp = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - __EPOCH__.EPOCH); |     auto timestamp = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - epochInitializer.EPOCH); | ||||||
|     id.timestamp = timestamp.count(); |     id.timestamp = timestamp.count(); | ||||||
|     id.instance = tid; |     id.instance = tid; | ||||||
|     id.sequence = sequence++; |     id.sequence = sequence++; | ||||||
|   | |||||||
| @@ -12,6 +12,7 @@ enum class PacketSet { | |||||||
|     ROOMJOINREQUEST, |     ROOMJOINREQUEST, | ||||||
|     ROOMEXITREQUEST, |     ROOMEXITREQUEST, | ||||||
|     USERSLISTREQUEST, |     USERSLISTREQUEST, | ||||||
|  |     ROOMUSERSLISTREQUEST, | ||||||
|     DATAPOST, |     DATAPOST, | ||||||
|     CONTINUE, |     CONTINUE, | ||||||
|     RESPONSE, |     RESPONSE, | ||||||
| @@ -21,6 +22,7 @@ enum class PacketSet { | |||||||
|     ROOMJOINRESPONSE, |     ROOMJOINRESPONSE, | ||||||
|     ROOMEXITRESPONSE, |     ROOMEXITRESPONSE, | ||||||
|     USERSLISTRESPONSE, |     USERSLISTRESPONSE, | ||||||
|  |     ROOMUSERSLISTRESPONSE, | ||||||
|     INVALID |     INVALID | ||||||
| }; | }; | ||||||
|  |  | ||||||
| @@ -38,6 +40,7 @@ enum class RequestType : std::uint8_t { | |||||||
|     ROOM_JOIN, |     ROOM_JOIN, | ||||||
|     ROOM_EXIT, |     ROOM_EXIT, | ||||||
|     USERS_LIST, |     USERS_LIST, | ||||||
|  |     ROOM_USERS_LIST, | ||||||
|     DATA |     DATA | ||||||
| }; | }; | ||||||
|  |  | ||||||
| @@ -84,29 +87,93 @@ public: | |||||||
|             RequestType         requestType; |             RequestType         requestType; | ||||||
|             DataType            dataType; |             DataType            dataType; | ||||||
|             std::uint16_t       packetLength; |             std::uint16_t       packetLength; | ||||||
|             std::uint16_t       destId[4]; |             std::uint16_t       myId[4]; | ||||||
|  |             std::uint16_t       roomId[4]; | ||||||
|             std::uint8_t        name[]; |             std::uint8_t        name[]; | ||||||
|         } __data; |         } __data; | ||||||
|         std::uint8_t serialized[1500] = ""; |         std::uint8_t serialized[1500] = ""; | ||||||
|     }; |     }; | ||||||
|     std::uint8_t* convToN() { |     std::uint8_t* convToN() { | ||||||
|         __data.packetLength = ::htons(__data.packetLength); |         __data.packetLength = ::htons(__data.packetLength); | ||||||
|         for (int i = 0; i < 4; i++) |         for (int i = 0; i < 4; i++) { | ||||||
|             __data.destId[i] = ::htons(__data.destId[i]); |             __data.myId[i] = ::htons(__data.myId[i]); | ||||||
|  |             __data.roomId[i] = ::htons(__data.roomId[i]); | ||||||
|  |         } | ||||||
|         return serialized; |         return serialized; | ||||||
|     } |     } | ||||||
|     std::uint8_t* convToH() { |     std::uint8_t* convToH() { | ||||||
|         __data.packetLength = ::ntohs(__data.packetLength); |         __data.packetLength = ::ntohs(__data.packetLength); | ||||||
|         for (int i = 0; i < 4; i++) |         for (int i = 0; i < 4; i++) { | ||||||
|             __data.destId[i] = ::ntohs(__data.destId[i]); |             __data.myId[i] = ::ntohs(__data.myId[i]); | ||||||
|  |             __data.roomId[i] = ::ntohs(__data.roomId[i]); | ||||||
|  |         } | ||||||
|         return serialized; |         return serialized; | ||||||
|     } |     } | ||||||
| }; | }; | ||||||
|  |  | ||||||
| class alignas(4) RoomExitRequestPacket : public Packet {}; | class alignas(4) RoomExitRequestPacket : public Packet { | ||||||
|  | public: | ||||||
|  |     union { | ||||||
|  |         struct { | ||||||
|  |             PacketCategory      packetType; | ||||||
|  |             RequestType         requestType; | ||||||
|  |             DataType            dataType; | ||||||
|  |             std::uint16_t       packetLength; | ||||||
|  |             std::uint16_t       myId[4]; | ||||||
|  |             std::uint16_t       roomId[4]; | ||||||
|  |             std::uint8_t        name[]; | ||||||
|  |         } __data; | ||||||
|  |         std::uint8_t serialized[1500] = ""; | ||||||
|  |     }; | ||||||
|  |     std::uint8_t* convToN() { | ||||||
|  |         __data.packetLength = ::htons(__data.packetLength); | ||||||
|  |         for (int i = 0; i < 4; i++) { | ||||||
|  |             __data.myId[i] = ::htons(__data.myId[i]); | ||||||
|  |             __data.roomId[i] = ::htons(__data.roomId[i]); | ||||||
|  |         } | ||||||
|  |         return serialized; | ||||||
|  |     } | ||||||
|  |     std::uint8_t* convToH() { | ||||||
|  |         __data.packetLength = ::ntohs(__data.packetLength); | ||||||
|  |         for (int i = 0; i < 4; i++) { | ||||||
|  |             __data.myId[i] = ::ntohs(__data.myId[i]); | ||||||
|  |             __data.roomId[i] = ::ntohs(__data.roomId[i]); | ||||||
|  |         } | ||||||
|  |         return serialized; | ||||||
|  |     } | ||||||
|  | }; | ||||||
|  |  | ||||||
| class alignas(4) UsersListRequestPacket : public Packet {}; | class alignas(4) UsersListRequestPacket : public Packet {}; | ||||||
|  |  | ||||||
|  | class alignas(4) RoomUsersListRequestPacket : public Packet { | ||||||
|  | public: | ||||||
|  |     union { | ||||||
|  |         struct { | ||||||
|  |             PacketCategory      packetType; | ||||||
|  |             RequestType         requestType; | ||||||
|  |             DataType            dataType; | ||||||
|  |             std::uint16_t       packetLength; | ||||||
|  |             std::uint16_t       roomId[4]; | ||||||
|  |             std::uint8_t        data[]; | ||||||
|  |         } __data; | ||||||
|  |         std::uint8_t serialized[1500] = ""; | ||||||
|  |     }; | ||||||
|  |     std::uint8_t* convToN() { | ||||||
|  |         __data.packetLength = ::htons(__data.packetLength); | ||||||
|  |         for (int i = 0; i < 4; i++) { | ||||||
|  |             __data.roomId[i] = ::htons(__data.roomId[i]); | ||||||
|  |         } | ||||||
|  |         return serialized; | ||||||
|  |     } | ||||||
|  |     std::uint8_t* convToH() { | ||||||
|  |         __data.packetLength = ::ntohs(__data.packetLength); | ||||||
|  |         for (int i = 0; i < 4; i++) { | ||||||
|  |             __data.roomId[i] = ::ntohs(__data.roomId[i]); | ||||||
|  |         } | ||||||
|  |         return serialized; | ||||||
|  |     } | ||||||
|  | }; | ||||||
|  |  | ||||||
| class alignas(4) DataPostPacket : public Packet { | class alignas(4) DataPostPacket : public Packet { | ||||||
| public: | public: | ||||||
|     union { |     union { | ||||||
| @@ -115,6 +182,7 @@ public: | |||||||
|             RequestType         requestType; |             RequestType         requestType; | ||||||
|             DataType            dataType; |             DataType            dataType; | ||||||
|             std::uint16_t       packetLength; |             std::uint16_t       packetLength; | ||||||
|  |             std::uint16_t       sourceId[4]; | ||||||
|             std::uint16_t       destId[4]; |             std::uint16_t       destId[4]; | ||||||
|             std::uint8_t        data[]; |             std::uint8_t        data[]; | ||||||
|         } __data; |         } __data; | ||||||
| @@ -122,14 +190,18 @@ public: | |||||||
|     }; |     }; | ||||||
|     std::uint8_t* convToN() { |     std::uint8_t* convToN() { | ||||||
|         __data.packetLength = ::htons(__data.packetLength); |         __data.packetLength = ::htons(__data.packetLength); | ||||||
|         for (int i = 0; i < 4; i++) |         for (int i = 0; i < 4; i++) { | ||||||
|  |             __data.sourceId[i] = ::htons(__data.sourceId[i]); | ||||||
|             __data.destId[i] = ::htons(__data.destId[i]); |             __data.destId[i] = ::htons(__data.destId[i]); | ||||||
|  |         } | ||||||
|         return serialized; |         return serialized; | ||||||
|     } |     } | ||||||
|     std::uint8_t* convToH() { |     std::uint8_t* convToH() { | ||||||
|         __data.packetLength = ::ntohs(__data.packetLength); |         __data.packetLength = ::ntohs(__data.packetLength); | ||||||
|         for (int i = 0; i < 4; i++) |         for (int i = 0; i < 4; i++) { | ||||||
|  |             __data.sourceId[i] = ::ntohs(__data.sourceId[i]); | ||||||
|             __data.destId[i] = ::ntohs(__data.destId[i]); |             __data.destId[i] = ::ntohs(__data.destId[i]); | ||||||
|  |         } | ||||||
|         return serialized; |         return serialized; | ||||||
|     } |     } | ||||||
| }; | }; | ||||||
| @@ -162,7 +234,7 @@ public: | |||||||
| }; | }; | ||||||
|  |  | ||||||
| enum class ResponseStatusCode : std::uint16_t { | enum class ResponseStatusCode : std::uint16_t { | ||||||
|     OK = 200, |     RES_OK = 200, | ||||||
|     CREATED = 201, |     CREATED = 201, | ||||||
|     ACCEPTED = 202, |     ACCEPTED = 202, | ||||||
|     BAD_REQUEST = 400, |     BAD_REQUEST = 400, | ||||||
|   | |||||||
| @@ -6,10 +6,11 @@ | |||||||
| #include "Packet/Packet.hpp" | #include "Packet/Packet.hpp" | ||||||
| #include <functional> | #include <functional> | ||||||
| #include <vector> | #include <vector> | ||||||
|  | #include <queue> | ||||||
|  |  | ||||||
| #include "precomp.hpp" | #include "precomp.hpp" | ||||||
|  |  | ||||||
| #ifndef _WIN32 | #ifdef __linux__ | ||||||
|  |  | ||||||
| typedef struct _OVERLAPPED { | typedef struct _OVERLAPPED { | ||||||
|     char dummy; |     char dummy; | ||||||
| @@ -27,7 +28,7 @@ namespace Chattr { | |||||||
| class IOCP; | class IOCP; | ||||||
|  |  | ||||||
| enum class IOCPEVENT { | enum class IOCPEVENT { | ||||||
|     ERR, |     QUIT, | ||||||
|     READ, |     READ, | ||||||
|     WRITE |     WRITE | ||||||
| }; | }; | ||||||
| @@ -42,6 +43,60 @@ struct IOCPPASSINDATA { | |||||||
|     std::uint32_t transferredbytes; |     std::uint32_t transferredbytes; | ||||||
|     WSABUF wsabuf; |     WSABUF wsabuf; | ||||||
|     IOCP* IOCPInstance; |     IOCP* IOCPInstance; | ||||||
|  | #ifdef __linux__ | ||||||
|  |     std::shared_ptr<std::queue<IOCPPASSINDATA*>> sendQueue; | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  |     IOCPPASSINDATA() { | ||||||
|  |         std::memset(&overlapped, 0, sizeof(overlapped)); | ||||||
|  |         event = IOCPEVENT::QUIT; | ||||||
|  |         socket = nullptr; | ||||||
|  |         recvbytes = 0; | ||||||
|  |         sendbytes = 0; | ||||||
|  |         transferredbytes = 0; | ||||||
|  |         wsabuf.len = 1500; | ||||||
|  |         wsabuf.buf = this->buf; | ||||||
|  |         IOCPInstance = nullptr; | ||||||
|  |     } | ||||||
|  |     IOCPPASSINDATA(const IOCPPASSINDATA& other) | ||||||
|  |         : event(other.event), | ||||||
|  |           socket(other.socket), | ||||||
|  |           transferredbytes(other.transferredbytes), | ||||||
|  |           wsabuf(other.wsabuf), | ||||||
|  |           IOCPInstance(other.IOCPInstance) | ||||||
|  | #ifdef __linux__ | ||||||
|  |         , sendQueue(other.sendQueue) | ||||||
|  | #endif | ||||||
|  |     { | ||||||
|  |         recvbytes = 0; | ||||||
|  |         sendbytes = 0; | ||||||
|  |         wsabuf.buf = this->buf; | ||||||
|  |         // buf는 memcpy로 복사 | ||||||
|  |         std::memcpy(buf, other.buf, sizeof(buf)); | ||||||
|  |         // overlapped는 0으로 초기화 (복사하면 안 됨) | ||||||
|  |         std::memset(&overlapped, 0, sizeof(overlapped)); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     ~IOCPPASSINDATA() = default; | ||||||
|  |  | ||||||
|  |     // 복사 대입 연산자 | ||||||
|  |     IOCPPASSINDATA& operator=(const IOCPPASSINDATA& other) { | ||||||
|  |         if (this != &other) { | ||||||
|  |             event = other.event; | ||||||
|  |             socket = other.socket; | ||||||
|  |             recvbytes = 0; | ||||||
|  |             sendbytes = 0; | ||||||
|  |             transferredbytes = other.transferredbytes; | ||||||
|  |             wsabuf.buf = this->buf; | ||||||
|  |             IOCPInstance = other.IOCPInstance; | ||||||
|  | #ifdef __linux__ | ||||||
|  |             sendQueue = other.sendQueue; | ||||||
|  | #endif | ||||||
|  |             std::memcpy(buf, other.buf, sizeof(buf)); | ||||||
|  |             std::memset(&overlapped, 0, sizeof(overlapped)); | ||||||
|  |         } | ||||||
|  |         return *this; | ||||||
|  |     } | ||||||
| }; | }; | ||||||
|  |  | ||||||
| class IOCP { | class IOCP { | ||||||
| @@ -55,9 +110,11 @@ public: | |||||||
|         DWORD cbTransfrred; |         DWORD cbTransfrred; | ||||||
|         int retVal = GetQueuedCompletionStatus(completionPort_, &cbTransfrred, (PULONG_PTR)&sock, (LPOVERLAPPED*)&data, INFINITE); |         int retVal = GetQueuedCompletionStatus(completionPort_, &cbTransfrred, (PULONG_PTR)&sock, (LPOVERLAPPED*)&data, INFINITE); | ||||||
|         if (retVal == 0 || cbTransfrred == 0) { |         if (retVal == 0 || cbTransfrred == 0) { | ||||||
|             spdlog::debug("Client disconnected. [{}]", (std::string)(data->socket->remoteAddr)); |             data->event = IOCPEVENT::QUIT; | ||||||
|             delete data; |             spdlog::debug("Disconnected. [{}]", (std::string)(data->socket->remoteAddr)); | ||||||
|  |             threadPool->enqueueJob(callback, data); | ||||||
|             threadPool->enqueueJob(iocpWather, completionPort_, callback); |             threadPool->enqueueJob(iocpWather, completionPort_, callback); | ||||||
|  |             // delete data; | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|         data->transferredbytes = cbTransfrred; |         data->transferredbytes = cbTransfrred; | ||||||
| @@ -66,117 +123,166 @@ public: | |||||||
|     }; |     }; | ||||||
| #elif __linux__ | #elif __linux__ | ||||||
|     static void socketReader(ThreadPool* threadPool, epoll_event event, int epollfd, std::function<void(ThreadPool*, IOCPPASSINDATA*)> callback) { |     static void socketReader(ThreadPool* threadPool, epoll_event event, int epollfd, std::function<void(ThreadPool*, IOCPPASSINDATA*)> callback) { | ||||||
|         IOCPPASSINDATA* iocpData = (IOCPPASSINDATA*)event.data.ptr; |  | ||||||
|          |  | ||||||
|         pthread_t tid = pthread_self(); |         pthread_t tid = pthread_self(); | ||||||
|  |  | ||||||
|         if (iocpData == nullptr) { |         if (event.data.ptr == nullptr) { | ||||||
|             spdlog::error("invalid call on {}", tid); |             spdlog::error("invalid call on {}", tid); | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|          |          | ||||||
|         std::lock_guard<std::mutex> lock(iocpData->socket->readMutex); |         IOCPPASSINDATA* rootIocpData = (IOCPPASSINDATA*)event.data.ptr; | ||||||
|  |  | ||||||
|         spdlog::trace("reading on tid: {} [{}]", tid, (std::string)iocpData->socket->remoteAddr); |         std::lock_guard<std::mutex> lock(rootIocpData->socket->readMutex); | ||||||
|  |         while (true) { | ||||||
|         int redSize = 0; |             char peekBuffer[1]; | ||||||
|         int headerSize = 8; |             int rc = rootIocpData->socket->recv(peekBuffer, 1, MSG_PEEK); | ||||||
|         int totalRedSize = 0; |             if (rc > 0); | ||||||
|  |             else if (rc == 0) { | ||||||
|         while (totalRedSize < headerSize) { |                 rootIocpData->event = IOCPEVENT::QUIT; | ||||||
|             redSize = iocpData->socket->recv(iocpData->buf, headerSize - totalRedSize, 0); |                 spdlog::debug("Disconnected. [{}]", (std::string)(rootIocpData->socket->remoteAddr)); | ||||||
|              |                 ::epoll_ctl(epollfd, EPOLL_CTL_DEL, rootIocpData->socket->sock, NULL); | ||||||
|             if (redSize <= 0) { |                 threadPool->enqueueJob(callback, rootIocpData); | ||||||
|  |                 // delete rootIocpData; | ||||||
|  |                 return; | ||||||
|  |             } | ||||||
|  |             else { | ||||||
|                 if (errno == EAGAIN || errno == EWOULDBLOCK) { |                 if (errno == EAGAIN || errno == EWOULDBLOCK) { | ||||||
|                     spdlog::trace("{}", strerror(errno)); |                     spdlog::trace("No data to read on {}", tid); | ||||||
|                     break; |  | ||||||
|                 } else { |  | ||||||
|                     spdlog::debug("Client disconnected. [{}]", (std::string)iocpData->socket->remoteAddr); |  | ||||||
|                     ::epoll_ctl(epollfd, EPOLL_CTL_DEL, iocpData->socket->sock, NULL); |  | ||||||
|                     delete iocpData; |  | ||||||
|                     return; |                     return; | ||||||
|                 } |                 } | ||||||
|                  |                 else { | ||||||
|             } |                     rootIocpData->event = IOCPEVENT::QUIT; | ||||||
|             totalRedSize += redSize; |                     spdlog::debug("Disconnected. [{}]", (std::string)(rootIocpData->socket->remoteAddr)); | ||||||
|         } |                     ::epoll_ctl(epollfd, EPOLL_CTL_DEL, rootIocpData->socket->sock, NULL); | ||||||
|  |                     threadPool->enqueueJob(callback, rootIocpData); | ||||||
|         Packet packet; |                     // delete rootIocpData; | ||||||
|         ::memcpy(&packet.serialized, iocpData->buf, headerSize); |  | ||||||
|  |  | ||||||
|         redSize = 0; |  | ||||||
|         int dataLength = ntohs(packet.__data.packetLength); |  | ||||||
|  |  | ||||||
|         while (totalRedSize < dataLength + headerSize) { |  | ||||||
|             redSize = iocpData->socket->recv(iocpData->buf + totalRedSize, dataLength + headerSize - totalRedSize, 0); |  | ||||||
|              |  | ||||||
|             if (redSize <= 0) { |  | ||||||
|                 if (errno == EAGAIN || errno == EWOULDBLOCK) { |  | ||||||
|                     spdlog::trace("{}", strerror(errno)); |  | ||||||
|                     break; |  | ||||||
|                 } else { |  | ||||||
|                     spdlog::debug("Client disconnected. [{}]", (std::string)iocpData->socket->remoteAddr); |  | ||||||
|                     ::epoll_ctl(epollfd, EPOLL_CTL_DEL, iocpData->socket->sock, NULL); |  | ||||||
|                     delete iocpData; |  | ||||||
|                     return; |                     return; | ||||||
|                 } |                 } | ||||||
|                  |  | ||||||
|             } |             } | ||||||
|             totalRedSize += redSize; |             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); | ||||||
|         } |         } | ||||||
|         iocpData->transferredbytes = totalRedSize; |  | ||||||
|         threadPool->enqueueJob(callback, iocpData); |  | ||||||
|     }; |     }; | ||||||
|     static void socketWriter(ThreadPool* threadPool, epoll_event event, int epollfd, std::function<void(ThreadPool*, IOCPPASSINDATA*)> callback) { |     static void socketWriter(ThreadPool* threadPool, epoll_event event, int epollfd, std::function<void(ThreadPool*, IOCPPASSINDATA*)> callback) { | ||||||
|         IOCPPASSINDATA* iocpData = (IOCPPASSINDATA*)event.data.ptr; |  | ||||||
|          |  | ||||||
|         pthread_t tid = pthread_self(); |         pthread_t tid = pthread_self(); | ||||||
|  |  | ||||||
|         if (iocpData == nullptr) { |         if (event.data.ptr == nullptr) { | ||||||
|             spdlog::error("invalid call on {}", tid); |             spdlog::error("invalid call on {}", tid); | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|          |          | ||||||
|         std::lock_guard<std::mutex> lock(iocpData->socket->writeMutex); |         IOCPPASSINDATA* rootIocpData = (IOCPPASSINDATA*)event.data.ptr; | ||||||
|  |  | ||||||
|         spdlog::trace("Writing on tid: {} [{}]", tid, (std::string)iocpData->socket->remoteAddr); |         std::lock_guard<std::mutex> lock(rootIocpData->socket->writeMutex); | ||||||
|  |         while (!rootIocpData->sendQueue->empty()) { | ||||||
|  |             IOCPPASSINDATA* data = rootIocpData->sendQueue->front(); | ||||||
|  |             rootIocpData->sendQueue->pop(); | ||||||
|  |  | ||||||
|         int packetSize = iocpData->transferredbytes; |             if (data == nullptr) { | ||||||
|         int totalSentSize = 0; |                 spdlog::error("invalid call on {}", tid); | ||||||
|         int sentSize = 0; |                 break; | ||||||
|  |             } | ||||||
|  |  | ||||||
|         spdlog::trace("Sending to: [{}]", (std::string)iocpData->socket->remoteAddr); |             int packetSize = data->wsabuf.len; | ||||||
|  |             int totalSentSize = 0; | ||||||
|  |             int sentSize = 0; | ||||||
|  |  | ||||||
|         while (totalSentSize < packetSize) { |             spdlog::trace("Sending to: [{}]", (std::string)data->socket->remoteAddr); | ||||||
|             sentSize = iocpData->socket->send(iocpData->buf, packetSize - totalSentSize, 0); |  | ||||||
|  |  | ||||||
|             if (sentSize <= 0) { |             while (totalSentSize < packetSize) { | ||||||
|                 if (errno == EAGAIN || errno == EWOULDBLOCK) { |                 sentSize = data->socket->send(data->buf + totalSentSize, packetSize - totalSentSize, 0); | ||||||
|                     spdlog::trace("{}", strerror(errno)); |  | ||||||
|                     break; |                 if (sentSize == SOCKET_ERROR) { | ||||||
|                 } else { |                     if (errno == EAGAIN || errno == EWOULDBLOCK) { | ||||||
|                     spdlog::debug("Client disconnected. [{}]", (std::string)iocpData->socket->remoteAddr); |                         spdlog::warn("buffer full"); | ||||||
|                     ::epoll_ctl(epollfd, EPOLL_CTL_DEL, iocpData->socket->sock, NULL); |                         continue; | ||||||
|                     delete iocpData; |                     } | ||||||
|  |                     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; |                     return; | ||||||
|                 } |                 } | ||||||
|  |                 totalSentSize += sentSize; | ||||||
|             } |             } | ||||||
|             totalSentSize += sentSize; |             data->transferredbytes = totalSentSize; | ||||||
|  |             threadPool->enqueueJob(callback, data); | ||||||
|         } |         } | ||||||
|         iocpData->transferredbytes = totalSentSize; |  | ||||||
|         threadPool->enqueueJob(callback, iocpData); |  | ||||||
|     }; |     }; | ||||||
|     static void iocpWatcher(ThreadPool* threadPool, int epollfd, std::function<void(ThreadPool*, IOCPPASSINDATA*)> callback) { |     static void iocpWatcher(ThreadPool* threadPool, int epollfd, int epollDetroyerFd, std::function<void(ThreadPool*, IOCPPASSINDATA*)> callback) { | ||||||
|         struct epoll_event events[FD_SETSIZE]; |         struct epoll_event events[FD_SETSIZE]; | ||||||
|         pthread_t tid = pthread_self(); |         pthread_t tid = pthread_self(); | ||||||
|  |  | ||||||
|         spdlog::trace("epoll waiting on {}", tid); |  | ||||||
|         int nready = ::epoll_wait(epollfd, events, FD_SETSIZE, -1); |         int nready = ::epoll_wait(epollfd, events, FD_SETSIZE, -1); | ||||||
|  |  | ||||||
|         for (int i=0; i<nready; i++) { |         for (int i=0; i<nready; i++) { | ||||||
|             struct epoll_event current_event = events[i]; |             struct epoll_event current_event = events[i]; | ||||||
|  |  | ||||||
|             if (current_event.events & EPOLLIN) { |             if (current_event.events & EPOLLIN) { | ||||||
|  |                 if (current_event.data.fd == epollDetroyerFd) { | ||||||
|  |                     return; | ||||||
|  |                 } | ||||||
|                 std::function<void(ThreadPool*, IOCPPASSINDATA*)> task(callback); |                 std::function<void(ThreadPool*, IOCPPASSINDATA*)> task(callback); | ||||||
|                 threadPool->enqueueJob(socketReader, current_event, epollfd, task); |                 threadPool->enqueueJob(socketReader, current_event, epollfd, task); | ||||||
|             } |             } | ||||||
| @@ -184,11 +290,16 @@ public: | |||||||
|                 std::function<void(ThreadPool*, IOCPPASSINDATA*)> task(callback); |                 std::function<void(ThreadPool*, IOCPPASSINDATA*)> task(callback); | ||||||
|                 threadPool->enqueueJob(socketWriter, current_event, epollfd, task); |                 threadPool->enqueueJob(socketWriter, current_event, epollfd, task); | ||||||
|             } |             } | ||||||
|  |             if (--nready <= 0) | ||||||
|  |                 break; | ||||||
|         } |         } | ||||||
|         threadPool->enqueueJob(iocpWatcher, epollfd, callback); |         threadPool->enqueueJob(iocpWatcher, epollfd, epollDetroyerFd, callback); | ||||||
|     }; |     }; | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  |     IOCP(); | ||||||
|  |     ~IOCP(); | ||||||
|  |  | ||||||
|     template<typename _Callable> |     template<typename _Callable> | ||||||
|     void init(ThreadPool* __IOCPThread, _Callable&& callback) { |     void init(ThreadPool* __IOCPThread, _Callable&& callback) { | ||||||
|         IOCPThread_ = __IOCPThread; |         IOCPThread_ = __IOCPThread; | ||||||
| @@ -198,6 +309,11 @@ public: | |||||||
|             log::critical("CreateIoCompletionPort()"); |             log::critical("CreateIoCompletionPort()"); | ||||||
| #elif __linux__ | #elif __linux__ | ||||||
|         epollfd_ = ::epoll_create(1); |         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 | #endif | ||||||
|         auto boundFunc = [callback = std::move(callback)](ThreadPool* __IOCPThread, IOCPPASSINDATA* data) mutable { |         auto boundFunc = [callback = std::move(callback)](ThreadPool* __IOCPThread, IOCPPASSINDATA* data) mutable { | ||||||
|             callback(__IOCPThread, data); |             callback(__IOCPThread, data); | ||||||
| @@ -215,24 +331,33 @@ public: | |||||||
|             __IOCPThread->enqueueJob(iocpWather, completionPort_, task); |             __IOCPThread->enqueueJob(iocpWather, completionPort_, task); | ||||||
|         } |         } | ||||||
| #elif __linux__ | #elif __linux__ | ||||||
|  |         __IOCPThread->respawnWorker(__IOCPThread->threadCount + 1); | ||||||
|         spdlog::info("Spawning 1 Epoll Waiter..."); |         spdlog::info("Spawning 1 Epoll Waiter..."); | ||||||
|         __IOCPThread->enqueueJob(iocpWatcher, epollfd_, boundFunc); |         __IOCPThread->enqueueJob(iocpWatcher, epollfd_, epollDetroyerFd, boundFunc); | ||||||
| #endif | #endif | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     void registerSocket(Chattr::IOCPPASSINDATA* data); |     void destruct(); | ||||||
|  |  | ||||||
|     int recv(Chattr::IOCPPASSINDATA* data, int bufferCount); |     void registerSocket(IOCPPASSINDATA* data); | ||||||
|     int send(Chattr::IOCPPASSINDATA* data, int bufferCount, int __flags); |  | ||||||
|  |     int recv(IOCPPASSINDATA* data, int bufferCount); | ||||||
|  |     int send(IOCPPASSINDATA* data, int bufferCount, int __flags); | ||||||
|  |  | ||||||
|  | #ifdef __linux__ | ||||||
|  |     int epollDetroyerFd = -1; | ||||||
|  | #endif | ||||||
|  |  | ||||||
| private: | private: | ||||||
|     struct Chattr::WSAManager wsaManager; |     struct WSAManager wsaManager; | ||||||
|     ThreadPool* IOCPThread_; |     ThreadPool* IOCPThread_; | ||||||
|  |  | ||||||
| #ifdef _WIN32 | #ifdef _WIN32 | ||||||
|     HANDLE completionPort_ = INVALID_HANDLE_VALUE; |     HANDLE completionPort_ = INVALID_HANDLE_VALUE; | ||||||
| #elif __linux__ | #elif __linux__ | ||||||
|     int epollfd_ = -1; |     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 | #endif | ||||||
| }; | }; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -7,7 +7,8 @@ public: | |||||||
|   struct Config { |   struct Config { | ||||||
|     Json::Value configJsonRoot; |     Json::Value configJsonRoot; | ||||||
|     std::uint32_t ipVersion = 0; |     std::uint32_t ipVersion = 0; | ||||||
|     std::uint32_t listenPort = 0; |     gsl::czstring IP = ""; | ||||||
|  |     std::uint32_t Port = 0; | ||||||
|     spdlog::level::level_enum logLevel = spdlog::level::off; |     spdlog::level::level_enum logLevel = spdlog::level::off; | ||||||
|     gsl::czstring logFileName = ""; |     gsl::czstring logFileName = ""; | ||||||
|     std::uint32_t logfileSize = 0; |     std::uint32_t logfileSize = 0; | ||||||
|   | |||||||
| @@ -15,6 +15,7 @@ | |||||||
| #include <fcntl.h> | #include <fcntl.h> | ||||||
| #include <errno.h> | #include <errno.h> | ||||||
| #include <netinet/in.h> | #include <netinet/in.h> | ||||||
|  | #include <sys/eventfd.h> | ||||||
| #define SOCKET int | #define SOCKET int | ||||||
| #define INVALID_SOCKET -1 | #define INVALID_SOCKET -1 | ||||||
| #define SOCKET_ERROR -1 | #define SOCKET_ERROR -1 | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user