diff --git a/server/CMakeLists.txt b/server/CMakeLists.txt index 8d1bf83..482de2f 100644 --- a/server/CMakeLists.txt +++ b/server/CMakeLists.txt @@ -6,7 +6,18 @@ file(GLOB_RECURSE server_src "src/*.cpp" ) -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -static") +if(CMAKE_COMPILER_IS_GNUCXX) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -static") +endif() + add_executable(server ${server_src}) -install(TARGETS server RUNTIME DESTINATION bin) +if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") + target_link_libraries(server pthread nsl resolv) +elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Windows") + target_link_libraries(server wsock32 ws2_32) +else() + target_link_libraries(server pthread socket nsl resolv) +endif() + +install(TARGETS server RUNTIME DESTINATION bin) diff --git a/server/src/main.cpp b/server/src/main.cpp index a239d56..56c150f 100644 --- a/server/src/main.cpp +++ b/server/src/main.cpp @@ -4,6 +4,7 @@ #include "utils/string.hpp" #include "utils/net.hpp" #include "utils/time.hpp" +#include "sock/tcpsock.hpp" int main(int argc, char **argv) { //auto sock = sosc::TcpClient(); @@ -14,14 +15,21 @@ int main(int argc, char **argv) { std::cout << i << std::endl; });*/ - uint32_t test = 0xDEADBEEF; - std::string net = HTONUL(test); - test = NTOHUL(net); + sosc::TcpClient client; + sosc::TcpServer server; - sosc::net::IpAddress ip1, ip2; - ip1.Parse("::*:FE:EF:F**F"); - ip2.Parse("::ABCD:F*:*:F00F"); - bool same = ip1 == ip2; + server.Listen(1111); + server.Accept(&client); + + client.Send("test"); + std::string got; + + while(client.IsOpen()) { + int length = client.Recv(&got); + + if(length > 0) + std::cout << got << std::endl; + } return 0; } diff --git a/server/src/sock/tcpsock.hpp b/server/src/sock/tcpsock.hpp index 5f412ba..4cd5714 100644 --- a/server/src/sock/tcpsock.hpp +++ b/server/src/sock/tcpsock.hpp @@ -2,6 +2,11 @@ #define SOSC_TCPSOCK_H #ifdef _WIN32 + #define WIN32_LEAN_AND_MEAN + #ifdef __MINGW32__ + #undef _WIN32_WINNT + #define _WIN32_WINNT _WIN32_WINNT_WIN8 + #endif #include #include @@ -21,11 +26,13 @@ #define SOSC_ADDR_T struct sockaddr_in #endif +#include #include #include #include -#include +#include #include "../utils/net.hpp" +#include "../utils/string.hpp" #define SOSC_TCP_BUFLEN 2048 @@ -33,11 +40,26 @@ namespace sosc { class TcpClient { public: TcpClient(); - bool Init(std::string host, std::uint16_t port); + bool Open(std::string host, std::uint16_t port); + int Recv(std::string* str, bool append = false); + int Send(const std::string& str); + + bool IsDataReady(); + inline bool IsOpen() const { + // TODO consider changing this + return this->sock_open; + } + + inline net::IpAddress GetIpAddress() const { + return this->ip; + } + + void Close(); ~TcpClient(); private: - bool Init(SOSC_SOCK_T sock, SOSC_ADDR_T addr, int addr_len); + void Open(SOSC_SOCK_T sock, SOSC_ADDR_T addr, int addr_len); + void SetBlocking(bool will_block); SOSC_SOCK_T sock; bool sock_open; @@ -54,10 +76,15 @@ private: class TcpServer { public: TcpServer(); + bool Listen(uint16_t port); + int Accept(TcpClient* client); + + void Close(); ~TcpServer(); private: SOSC_SOCK_T sock; + bool sock_open; }; } diff --git a/server/src/sock/tcpsock_win.cpp b/server/src/sock/tcpsock_win.cpp index 94d5bfa..9b54442 100644 --- a/server/src/sock/tcpsock_win.cpp +++ b/server/src/sock/tcpsock_win.cpp @@ -1,23 +1,172 @@ #include "tcpsock.hpp" #ifdef _WIN32 +void init_wsa() { + static bool is_inited = false; + if(is_inited) return; + + WSADATA wdata; + if(WSAStartup(MAKEWORD(2, 2), &wdata) != 0) + exit(-1); + + is_inited = true; +} + /****************************/ /* BEGIN TCPCLIENT CODE */ /****************************/ sosc::TcpClient::TcpClient() { + init_wsa(); this->sock_open = false; this->addr_len = -1; } -bool sosc::TcpClient::Init(std::string host, std::uint16_t port) { +bool sosc::TcpClient::Open(std::string host, std::uint16_t port) { if(this->sock_open) return false; - struct addrinfo hints, *result, *ptr; + struct addrinfo hints, *results, *ptr; + ZeroMemory(&hints, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + + if(getaddrinfo(host.c_str(), TOSTR(port).c_str(), &hints, &results) != 0) + return false; + + for(ptr = results; ptr != NULL; ptr = ptr->ai_next) { + this->sock = socket(ptr->ai_family, + ptr->ai_socktype, ptr->ai_protocol); + + if(this->sock == INVALID_SOCKET) { + freeaddrinfo(results); + return false; + } + + if(connect(this->sock, ptr->ai_addr, + (int)ptr->ai_addrlen) != SOCKET_ERROR) + { + break; + } + + closesocket(this->sock); + this->sock = INVALID_SOCKET; + } + + freeaddrinfo(results); + if(this->sock == INVALID_SOCKET) + return false; + + this->ip = net::IpAddress(); + this->sock_open = true; return true; } +void sosc::TcpClient::Open + (SOSC_SOCK_T sock, SOSC_ADDR_T addr, int addr_len) +{ + if(this->sock_open) + return; + + this->sock = sock; + this->sock_open = true; + + this->addr = addr; + this->addr_len = addr_len; + + char buffer[128]; + inet_ntop(addr.sin_family, (PVOID)&addr.sin_addr, buffer, 128); + this->ip.Parse(buffer); +} + +int sosc::TcpClient::Recv(std::string* str, bool append) { + if(!this->sock_open) + return -1; + + int total_length = 0; + bool first_recv = true; + while(this->IsDataReady()) { + int length = recv(this->sock, this->buffer, SOSC_TCP_BUFLEN, 0); + if(length <= 0) { + this->Close(); + return -1; + } + + if(first_recv && !append) + *str = std::string(this->buffer, length); + else + *str += std::string(this->buffer, length); + + total_length += length; + first_recv = false; + } + + return total_length; +} + +int sosc::TcpClient::Send(const std::string& str) { + if(!this->sock_open) + return -1; + + std::string::size_type total_sent = 0; + while(total_sent < str.length()) { + int sent = total_sent == 0 + ? send(this->sock, str.c_str(), str.length(), 0) + : send(this->sock, str.substr(total_sent).c_str(), + str.length() - total_sent, 0); + + if(sent == SOCKET_ERROR) { + this->Close(); + return -1; + } else + total_sent += sent; + } + + return 0; +} + +bool sosc::TcpClient::IsDataReady() { + if(!this->sock_open) + return false; + + this->SetBlocking(false); + int check = recv(this->sock, this->buffer, 1, MSG_PEEK), + error = WSAGetLastError(); + this->SetBlocking(true); + + if(check <= 0) { + if(check != 0 && (error == WSAEWOULDBLOCK || error == WSAETIMEDOUT)) + return false; + else { + this->Close(); + return false; + } + } else + return true; +} + +void sosc::TcpClient::SetBlocking(bool will_block) { + if(!this->sock_open) + return; + + u_long nblock = !will_block; + ioctlsocket(this->sock, FIONBIO, &nblock); +} + +void sosc::TcpClient::Close() { + if(!this->sock_open) + return; + + shutdown(this->sock, SD_BOTH); + closesocket(this->sock); + this->sock_open = false; +} + +sosc::TcpClient::~TcpClient() { + this->Close(); +} + /****************************/ /* END TCPCLIENT CODE */ /****************************/ @@ -25,9 +174,82 @@ bool sosc::TcpClient::Init(std::string host, std::uint16_t port) { /****************************/ sosc::TcpServer::TcpServer() { - + init_wsa(); + this->sock_open = false; } +bool sosc::TcpServer::Listen(uint16_t port) { + if(this->sock_open) + return false; + + struct addrinfo hints, *result; + ZeroMemory(&hints, sizeof(hints)); + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + hints.ai_flags = AI_PASSIVE; + + if(getaddrinfo(NULL, TOSTR(port).c_str(), &hints, &result) != 0) + return false; + + this->sock = socket(result->ai_family, + result->ai_socktype, result->ai_protocol); + + if(this->sock == INVALID_SOCKET) { + freeaddrinfo(result); + return false; + } + + if(bind(this->sock, result->ai_addr, + (int)result->ai_addrlen) == SOCKET_ERROR) + { + freeaddrinfo(result); + closesocket(this->sock); + return false; + } + + freeaddrinfo(result); + if(listen(this->sock, SOMAXCONN) == SOCKET_ERROR) { + closesocket(this->sock); + return false; + } + + this->sock_open = true; + return true; +} + +int sosc::TcpServer::Accept(TcpClient* client) { + if(!this->sock_open) + return -1; + + SOSC_SOCK_T sock; + SOSC_ADDR_T addr; + int addr_len = sizeof(addr); + + sock = accept(this->sock, (struct sockaddr*)&addr, &addr_len); + if(sock == INVALID_SOCKET) { + this->Close(); + return -1; + } + + client->Close(); + client->Open(sock, addr, addr_len); + return 0; +} + +void sosc::TcpServer::Close() { + if(!this->sock_open) + return; + + shutdown(this->sock, SD_BOTH); + closesocket(this->sock); + this->sock_open = false; +} + +sosc::TcpServer::~TcpServer() { + this->Close(); +} + /****************************/ /* END TCPSERVER CODE */ /****************************/