From 7d409f071e4348978dbeb01bc9aa7c85d38d194d Mon Sep 17 00:00:00 2001 From: Peter Johnson Date: Tue, 4 Aug 2015 00:01:13 -0700 Subject: [PATCH] Add win32 tcpsockets implementation. --- CMakeLists.txt | 3 ++ src/tcpsockets/TCPAcceptor.cpp | 39 +++++++++++++++++++++-- src/tcpsockets/TCPConnector.cpp | 38 +++++++++++++++++++++-- src/tcpsockets/TCPStream.cpp | 55 +++++++++++++++++++++++++++++++-- 4 files changed, 127 insertions(+), 8 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ac08140764..19ea2d5910 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,6 +12,9 @@ include_directories(include src) add_library(ntcore SHARED ${SRC_FILES}) set_target_properties(ntcore PROPERTIES VERSION 1.0.0 SOVERSION 1) #target_link_libraries(ntcore) +if (WIN32) + target_link_libraries(ntcore ws2_32) +endif() INSTALL(TARGETS ntcore RUNTIME DESTINATION bin LIBRARY DESTINATION lib diff --git a/src/tcpsockets/TCPAcceptor.cpp b/src/tcpsockets/TCPAcceptor.cpp index c2268c31c2..2dc443a67e 100644 --- a/src/tcpsockets/TCPAcceptor.cpp +++ b/src/tcpsockets/TCPAcceptor.cpp @@ -25,10 +25,15 @@ #include #include +#ifdef _WIN32 +#include +#else #include #include #include +#endif +#include "llvm/SmallString.h" #include "Log.h" TCPAcceptor::TCPAcceptor(int port, const char* address) @@ -36,13 +41,26 @@ TCPAcceptor::TCPAcceptor(int port, const char* address) m_port(port), m_address(address), m_listening(false), - m_shutdown(false) {} + m_shutdown(false) { +#ifdef _WIN32 + WSAData wsaData; + WORD wVersionRequested = MAKEWORD(2, 2); + WSAStartup(wVersionRequested, &wsaData); +#endif +} TCPAcceptor::~TCPAcceptor() { if (m_lsd > 0) { shutdown(); +#ifdef _WIN32 + closesocket(m_lsd); +#else close(m_lsd); +#endif } +#ifdef _WIN32 + WSACleanup(); +#endif } int TCPAcceptor::start() { @@ -53,15 +71,22 @@ int TCPAcceptor::start() { std::memset(&address, 0, sizeof(address)); address.sin_family = PF_INET; - address.sin_port = htons(m_port); if (m_address.size() > 0) { +#ifdef _WIN32 + llvm::SmallString<128> addr_copy(m_address); + addr_copy.append('\0'); + int size = sizeof(address); + WSAStringToAddress(addr_copy.data(), PF_INET, nullptr, (struct sockaddr*)&address, &size); +#else inet_pton(PF_INET, m_address.c_str(), &(address.sin_addr)); +#endif } else { address.sin_addr.s_addr = INADDR_ANY; } + address.sin_port = htons(m_port); int optval = 1; - setsockopt(m_lsd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof optval); + setsockopt(m_lsd, SOL_SOCKET, SO_REUSEADDR, (char*)&optval, sizeof optval); int result = bind(m_lsd, (struct sockaddr*)&address, sizeof(address)); if (result != 0) { @@ -80,14 +105,22 @@ int TCPAcceptor::start() { void TCPAcceptor::shutdown() { m_shutdown = true; +#ifdef _WIN32 + ::shutdown(m_lsd, SD_BOTH); +#else ::shutdown(m_lsd, SHUT_RDWR); +#endif } std::unique_ptr TCPAcceptor::accept() { if (!m_listening) return nullptr; struct sockaddr_in address; +#ifdef _WIN32 + int len = sizeof(address); +#else socklen_t len = sizeof(address); +#endif std::memset(&address, 0, sizeof(address)); int sd = ::accept(m_lsd, (struct sockaddr*)&address, &len); if (sd < 0) { diff --git a/src/tcpsockets/TCPConnector.cpp b/src/tcpsockets/TCPConnector.cpp index 3f58a2e558..0bf930dc75 100644 --- a/src/tcpsockets/TCPConnector.cpp +++ b/src/tcpsockets/TCPConnector.cpp @@ -27,12 +27,18 @@ #include #include #include +#ifdef _WIN32 +#include +#include +#else #include #include #include +#endif #include "TCPStream.h" +#include "llvm/SmallString.h" #include "Log.h" static int ResolveHostName(const char* hostname, struct in_addr* addr) { @@ -49,14 +55,32 @@ static int ResolveHostName(const char* hostname, struct in_addr* addr) { std::unique_ptr TCPConnector::connect(const char* server, int port, int timeout) { +#ifdef _WIN32 + struct WSAHelper { + WSAHelper() { + WSAData wsaData; + WORD wVersionRequested = MAKEWORD(2, 2); + WSAStartup(wVersionRequested, &wsaData); + } + ~WSAHelper() { WSACleanup(); } + }; + static WSAHelper helper; +#endif struct sockaddr_in address; std::memset(&address, 0, sizeof(address)); address.sin_family = AF_INET; - address.sin_port = htons(port); if (ResolveHostName(server, &(address.sin_addr)) != 0) { +#ifdef _WIN32 + llvm::SmallString<128> addr_copy(server); + addr_copy.append('\0'); + int size = sizeof(address); + WSAStringToAddress(addr_copy.data(), PF_INET, nullptr, (struct sockaddr*)&address, &size); +#else inet_pton(PF_INET, server, &(address.sin_addr)); +#endif } + address.sin_port = htons(port); if (timeout == 0) { int sd = socket(AF_INET, SOCK_STREAM, 0); @@ -74,9 +98,14 @@ std::unique_ptr TCPConnector::connect(const char* server, int result = -1, valopt, sd = socket(AF_INET, SOCK_STREAM, 0); // Set socket to non-blocking +#ifdef _WIN32 + u_long mode = 1; + ioctlsocket(sd, FIONBIO, &mode); +#else arg = fcntl(sd, F_GETFL, nullptr); arg |= O_NONBLOCK; fcntl(sd, F_SETFL, arg); +#endif // Connect with time limit std::string message; @@ -89,7 +118,7 @@ std::unique_ptr TCPConnector::connect(const char* server, FD_SET(sd, &sdset); if (select(sd + 1, nullptr, &sdset, nullptr, &tv) > 0) { len = sizeof(int); - getsockopt(sd, SOL_SOCKET, SO_ERROR, (void*)(&valopt), &len); + getsockopt(sd, SOL_SOCKET, SO_ERROR, (char*)(&valopt), &len); if (valopt) { DEBUG("connect() error " << valopt << " - " << strerror(valopt)); } @@ -103,9 +132,14 @@ std::unique_ptr TCPConnector::connect(const char* server, } // Return socket to blocking mode +#ifdef _WIN32 + mode = 0; + ioctlsocket(sd, FIONBIO, &mode); +#else arg = fcntl(sd, F_GETFL, nullptr); arg &= (~O_NONBLOCK); fcntl(sd, F_SETFL, arg); +#endif // Create stream object if connected if (result == -1) return nullptr; diff --git a/src/tcpsockets/TCPStream.cpp b/src/tcpsockets/TCPStream.cpp index 0681ef7968..b5ca15feb5 100644 --- a/src/tcpsockets/TCPStream.cpp +++ b/src/tcpsockets/TCPStream.cpp @@ -23,13 +23,22 @@ #include "TCPStream.h" +#ifdef _WIN32 +#include +#else #include #include +#endif TCPStream::TCPStream(int sd, struct sockaddr_in* address) : m_sd(sd) { char ip[50]; +#ifdef _WIN32 + unsigned long size = sizeof(ip) - 1; + WSAAddressToString((struct sockaddr*)address, sizeof sockaddr_in, nullptr, ip, &size); +#else inet_ntop(PF_INET, (struct in_addr*)&(address->sin_addr.s_addr), ip, sizeof(ip) - 1); +#endif m_peerIP = ip; m_peerPort = ntohs(address->sin_port); } @@ -41,11 +50,33 @@ std::size_t TCPStream::send(const char* buffer, std::size_t len, Error* err) { *err = kConnectionClosed; return 0; } +#ifdef _WIN32 + WSABUF wsaBuf; + wsaBuf.buf = const_cast(buffer); + wsaBuf.len = (ULONG)len; + DWORD rv; + bool result = true; + while (WSASend(m_sd, &wsaBuf, 1, &rv, 0, nullptr, nullptr) == SOCKET_ERROR) { + if (WSAGetLastError() != WSAEWOULDBLOCK) { + result = false; + break; + } + Sleep(1); + } + if (!result) { + char Buffer[128]; + sprintf(Buffer, "Send() failed: WSA error=%d\n", WSAGetLastError()); + OutputDebugStringA(Buffer); + *err = kConnectionReset; + return 0; + } +#else ssize_t rv = write(m_sd, buffer, len); if (rv < 0) { *err = kConnectionReset; return 0; } +#endif return static_cast(rv); } @@ -55,12 +86,25 @@ std::size_t TCPStream::receive(char* buffer, std::size_t len, Error* err, *err = kConnectionClosed; return 0; } +#ifdef _WIN32 + int rv; +#else ssize_t rv; - if (timeout <= 0) +#endif + if (timeout <= 0) { +#ifdef _WIN32 + rv = recv(m_sd, buffer, len, 0); +#else rv = read(m_sd, buffer, len); - else if (WaitForReadEvent(timeout)) +#endif + } + else if (WaitForReadEvent(timeout)) { +#ifdef _WIN32 + rv = recv(m_sd, buffer, len, 0); +#else rv = read(m_sd, buffer, len); - else { +#endif + } else { *err = kConnectionTimedOut; return 0; } @@ -73,8 +117,13 @@ std::size_t TCPStream::receive(char* buffer, std::size_t len, Error* err, void TCPStream::close() { if (m_sd >= 0) { +#ifdef _WIN32 + ::shutdown(m_sd, SD_BOTH); + closesocket(m_sd); +#else ::shutdown(m_sd, SHUT_RDWR); ::close(m_sd); +#endif } m_sd = -1; }