Add win32 tcpsockets implementation.

This commit is contained in:
Peter Johnson
2015-08-04 00:01:13 -07:00
parent 4146db6fc8
commit 7d409f071e
4 changed files with 127 additions and 8 deletions

View File

@@ -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

View File

@@ -25,10 +25,15 @@
#include <cstdio>
#include <cstring>
#ifdef _WIN32
#include <WinSock2.h>
#else
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>
#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<NetworkStream> 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) {

View File

@@ -27,12 +27,18 @@
#include <fcntl.h>
#include <cstdio>
#include <cstring>
#ifdef _WIN32
#include <WinSock2.h>
#include <WS2tcpip.h>
#else
#include <netdb.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#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<NetworkStream> 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<NetworkStream> 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<NetworkStream> 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<NetworkStream> 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;

View File

@@ -23,13 +23,22 @@
#include "TCPStream.h"
#ifdef _WIN32
#include <WinSock2.h>
#else
#include <arpa/inet.h>
#include <unistd.h>
#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<char*>(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<std::size_t>(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;
}