/* * RoboPeak Project * HAL Layer - Socket Interface * Copyright 2009 - 2013 RoboPeak Project * * Win32 Implementation */ #define _WINSOCKAPI_ #include "sdkcommon.h" #include "..\..\hal\socket.h" #include #include #include #include #include #pragma comment (lib, "Ws2_32.lib") namespace rp{ namespace net { static volatile bool _isWSAStartupCalled = false; static inline bool _checkWSAStartup() { int iResult; WSADATA wsaData; if (!_isWSAStartupCalled) { iResult = WSAStartup(MAKEWORD(2,2), &wsaData); if (iResult != 0) { return false; } _isWSAStartupCalled = true; } return true; } static const char* _inet_ntop(int af, const void* src, char* dst, int cnt){ struct sockaddr_storage srcaddr; memset(dst, 0, cnt); memset(&srcaddr, 0, sizeof(struct sockaddr_storage)); srcaddr.ss_family = af; switch (af) { case AF_INET: { struct sockaddr_in * ipv4 = reinterpret_cast< struct sockaddr_in *>(&srcaddr); memcpy(&(ipv4->sin_addr), src, sizeof(ipv4->sin_addr)); } break; case AF_INET6: { struct sockaddr_in6 * ipv6 = reinterpret_cast< struct sockaddr_in6 *>(&srcaddr); memcpy(&(ipv6->sin6_addr), src, sizeof(ipv6->sin6_addr)); } break; } if (WSAAddressToStringA((struct sockaddr*) &srcaddr, sizeof(struct sockaddr_storage), 0, dst, (LPDWORD) &cnt) != 0) { DWORD rv = WSAGetLastError(); return NULL; } return dst; } static int _inet_pton(int Family, const char * pszAddrString, void* pAddrBuf) { struct sockaddr_storage tmpholder; int actualSize = sizeof(sockaddr_storage); int result = WSAStringToAddressA((char *)pszAddrString, Family, NULL, (sockaddr*)&tmpholder, &actualSize); if (result) return -1; switch (Family) { case AF_INET: { struct sockaddr_in * ipv4 = reinterpret_cast< struct sockaddr_in *>(&tmpholder); memcpy(pAddrBuf, &(ipv4->sin_addr), sizeof(ipv4->sin_addr)); } break; case AF_INET6: { struct sockaddr_in6 * ipv6 = reinterpret_cast< struct sockaddr_in6 *>(&tmpholder); memcpy(pAddrBuf, &(ipv6->sin6_addr), sizeof(ipv6->sin6_addr)); } break; } return 1; } static inline int _halAddrTypeToOSType(SocketAddress::address_type_t type) { switch (type) { case SocketAddress::ADDRESS_TYPE_INET: return AF_INET; case SocketAddress::ADDRESS_TYPE_INET6: return AF_INET6; case SocketAddress::ADDRESS_TYPE_UNSPEC: return AF_UNSPEC; default: assert(!"should not reach here"); return AF_UNSPEC; } } SocketAddress::SocketAddress() { _checkWSAStartup(); _platform_data = reinterpret_cast(new sockaddr_storage); memset(_platform_data, 0, sizeof(sockaddr_storage)); reinterpret_cast(_platform_data)->ss_family = AF_INET; } SocketAddress::SocketAddress(const SocketAddress & src) { _platform_data = reinterpret_cast(new sockaddr_storage); memcpy(_platform_data, src._platform_data, sizeof(sockaddr_storage)); } SocketAddress::SocketAddress(const char * addrString, int port, SocketAddress::address_type_t type) { _checkWSAStartup(); _platform_data = reinterpret_cast(new sockaddr_storage); memset(_platform_data, 0, sizeof(sockaddr_storage)); // default to ipv4 in case the following operation fails reinterpret_cast(_platform_data)->ss_family = AF_INET; setAddressFromString(addrString, type); setPort(port); } SocketAddress::SocketAddress(void * platform_data) : _platform_data(platform_data) { _checkWSAStartup(); } SocketAddress & SocketAddress::operator = (const SocketAddress &src) { memcpy(_platform_data, src._platform_data, sizeof(sockaddr_storage)); return *this; } SocketAddress::~SocketAddress() { delete reinterpret_cast(_platform_data); } SocketAddress::address_type_t SocketAddress::getAddressType() const { switch(reinterpret_cast(_platform_data)->ss_family) { case AF_INET: return ADDRESS_TYPE_INET; case AF_INET6: return ADDRESS_TYPE_INET6; default: assert(!"should not reach here"); return ADDRESS_TYPE_INET; } } int SocketAddress::getPort() const { switch (getAddressType()) { case ADDRESS_TYPE_INET: return (int)ntohs(reinterpret_cast(_platform_data)->sin_port); case ADDRESS_TYPE_INET6: return (int)ntohs(reinterpret_cast(_platform_data)->sin6_port); default: return 0; } } u_result SocketAddress::setPort(int port) { switch (getAddressType()) { case ADDRESS_TYPE_INET: reinterpret_cast(_platform_data)->sin_port = htons((short)port); break; case ADDRESS_TYPE_INET6: reinterpret_cast(_platform_data)->sin6_port = htons((short)port); break; default: return RESULT_OPERATION_FAIL; } return RESULT_OK; } u_result SocketAddress::setAddressFromString(const char * address_string, SocketAddress::address_type_t type) { int ans = 0; int prevPort = getPort(); switch (type) { case ADDRESS_TYPE_INET: reinterpret_cast(_platform_data)->ss_family = AF_INET; ans = _inet_pton(AF_INET, address_string, &reinterpret_cast(_platform_data)->sin_addr); break; case ADDRESS_TYPE_INET6: reinterpret_cast(_platform_data)->ss_family = AF_INET6; ans = _inet_pton(AF_INET6, address_string, &reinterpret_cast(_platform_data)->sin6_addr); break; default: return RESULT_INVALID_DATA; } setPort(prevPort); return ans<=0?RESULT_INVALID_DATA:RESULT_OK; } u_result SocketAddress::getAddressAsString(char * buffer, size_t buffersize) const { int net_family = reinterpret_cast(_platform_data)->ss_family; const char *ans = NULL; switch (net_family) { case AF_INET: ans = _inet_ntop(net_family, &reinterpret_cast(_platform_data)->sin_addr, buffer, buffersize); break; case AF_INET6: ans = _inet_ntop(net_family, &reinterpret_cast(_platform_data)->sin6_addr, buffer, buffersize); break; } return ans<=0?RESULT_OPERATION_FAIL:RESULT_OK; } size_t SocketAddress::LoopUpHostName(const char * hostname, const char * sevicename, std::vector &addresspool , bool performDNS, SocketAddress::address_type_t type) { struct addrinfo hints; struct addrinfo *result; int ans; _checkWSAStartup(); memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = _halAddrTypeToOSType(type); hints.ai_flags = AI_PASSIVE; if (!performDNS) { hints.ai_family |= AI_NUMERICSERV | AI_NUMERICHOST; } ans = getaddrinfo(hostname, sevicename, &hints, &result); addresspool.clear(); if (ans != 0) { // hostname loopup failed return 0; } for (struct addrinfo * cursor = result; cursor != NULL; cursor = cursor->ai_next) { if (cursor->ai_family == ADDRESS_TYPE_INET || cursor->ai_family == ADDRESS_TYPE_INET6) { sockaddr_storage * storagebuffer = new sockaddr_storage; assert(sizeof(sockaddr_storage) >= cursor->ai_addrlen); memcpy(storagebuffer, cursor->ai_addr, cursor->ai_addrlen); addresspool.push_back(SocketAddress(storagebuffer)); } } freeaddrinfo(result); return addresspool.size(); } u_result SocketAddress::getRawAddress(_u8 * buffer, size_t bufferSize) const { switch (getAddressType()) { case ADDRESS_TYPE_INET: if (bufferSize < sizeof(reinterpret_cast(_platform_data)->sin_addr.s_addr)) return RESULT_INSUFFICIENT_MEMORY; memcpy(buffer, &reinterpret_cast(_platform_data)->sin_addr.s_addr, sizeof(reinterpret_cast(_platform_data)->sin_addr.s_addr)); break; case ADDRESS_TYPE_INET6: if (bufferSize < sizeof(reinterpret_cast(_platform_data)->sin6_addr.s6_addr)) return RESULT_INSUFFICIENT_MEMORY; memcpy(buffer, reinterpret_cast(_platform_data)->sin6_addr.s6_addr, sizeof(reinterpret_cast(_platform_data)->sin6_addr.s6_addr)); break; default: return RESULT_OPERATION_FAIL; } return RESULT_OK; } void SocketAddress::setLoopbackAddress(SocketAddress::address_type_t type) { int prevPort = getPort(); switch (type) { case ADDRESS_TYPE_INET: { sockaddr_in * addrv4 = reinterpret_cast(_platform_data); addrv4->sin_family = AF_INET; addrv4->sin_addr.s_addr = htonl(INADDR_LOOPBACK); } break; case ADDRESS_TYPE_INET6: { sockaddr_in6 * addrv6 = reinterpret_cast(_platform_data); addrv6->sin6_family = AF_INET6; addrv6->sin6_addr = in6addr_loopback; } break; default: return; } setPort(prevPort); } void SocketAddress::setBroadcastAddressIPv4() { int prevPort = getPort(); sockaddr_in * addrv4 = reinterpret_cast(_platform_data); addrv4->sin_family = AF_INET; addrv4->sin_addr.s_addr = htonl(INADDR_BROADCAST); setPort(prevPort); } void SocketAddress::setAnyAddress(SocketAddress::address_type_t type) { int prevPort = getPort(); switch (type) { case ADDRESS_TYPE_INET: { sockaddr_in * addrv4 = reinterpret_cast(_platform_data); addrv4->sin_family = AF_INET; addrv4->sin_addr.s_addr = htonl(INADDR_ANY); } break; case ADDRESS_TYPE_INET6: { sockaddr_in6 * addrv6 = reinterpret_cast(_platform_data); addrv6->sin6_family = AF_INET6; addrv6->sin6_addr = in6addr_any; } break; default: return; } setPort(prevPort); } }} ///-------------------------------- namespace rp { namespace arch { namespace net{ using namespace rp::net; class _single_thread StreamSocketImpl : public StreamSocket { public: StreamSocketImpl(SOCKET fd) : _socket_fd(fd) { assert(fd>=0); int bool_true = 1; ::setsockopt( _socket_fd, SOL_SOCKET, SO_REUSEADDR , (char *)&bool_true, (int)sizeof(bool_true) ); enableNoDelay(true); this->setTimeout(DEFAULT_SOCKET_TIMEOUT, SOCKET_DIR_BOTH); } virtual ~StreamSocketImpl() { closesocket(_socket_fd); } virtual void dispose() { delete this; } virtual u_result bind(const SocketAddress & localaddr) { const struct sockaddr * addr = reinterpret_cast(localaddr.getPlatformData()); assert(addr); int ans = ::bind(_socket_fd, addr, (int)sizeof(sockaddr_storage)); if (ans) { return RESULT_OPERATION_FAIL; } else { return RESULT_OK; } } virtual u_result getLocalAddress(SocketAddress & localaddr) { struct sockaddr * addr = reinterpret_cast( const_cast(localaddr.getPlatformData())); //donnot do this at home... assert(addr); int actualsize = sizeof(sockaddr_storage); int ans = ::getsockname(_socket_fd, addr, &actualsize); assert(actualsize <= sizeof(sockaddr_storage)); assert(addr->sa_family == AF_INET || addr->sa_family == AF_INET6); return ans?RESULT_OPERATION_FAIL:RESULT_OK; } virtual u_result setTimeout(_u32 timeout, socket_direction_mask msk) { int ans; timeval tv; tv.tv_sec = timeout / 1000; tv.tv_usec = (timeout % 1000) * 1000; if (msk & SOCKET_DIR_RD) { ans = ::setsockopt( _socket_fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, (int)sizeof(tv) ); if (ans) return RESULT_OPERATION_FAIL; } if (msk & SOCKET_DIR_WR) { ans = ::setsockopt( _socket_fd, SOL_SOCKET, SO_SNDTIMEO, (char *)&tv, (int)sizeof(tv) ); if (ans) return RESULT_OPERATION_FAIL; } return RESULT_OK; } virtual u_result connect(const SocketAddress & pairAddress) { const struct sockaddr * addr = reinterpret_cast(pairAddress.getPlatformData()); int ans = ::connect(_socket_fd, addr, (int)sizeof(sockaddr_storage)); if (!ans) return RESULT_OK; switch (WSAGetLastError()) { case WSAEAFNOSUPPORT: return RESULT_OPERATION_NOT_SUPPORT; #if 0 case EINPROGRESS: return RESULT_OK; //treat async connection as good status #endif case WSAETIMEDOUT: return RESULT_OPERATION_TIMEOUT; default: return RESULT_OPERATION_FAIL; } } virtual u_result listen(int backlog) { int ans = ::listen( _socket_fd, backlog); return ans?RESULT_OPERATION_FAIL:RESULT_OK; } virtual StreamSocket * accept(SocketAddress * pairAddress) { int addrsize; addrsize = sizeof(sockaddr_storage); SOCKET pair_socket = ::accept( _socket_fd, pairAddress?reinterpret_cast(const_cast(pairAddress->getPlatformData())):NULL , &addrsize); if (pair_socket>=0) { return new StreamSocketImpl(pair_socket); } else { return NULL; } } virtual u_result waitforIncomingConnection(_u32 timeout) { return waitforData(timeout); } virtual u_result send(const void * buffer, size_t len) { int ans = ::send( _socket_fd, (const char *)buffer, len, 0); if (ans != SOCKET_ERROR ) { assert(ans == (int)len); return RESULT_OK; } else { switch(WSAGetLastError()) { case WSAETIMEDOUT: return RESULT_OPERATION_TIMEOUT; default: return RESULT_OPERATION_FAIL; } } } virtual u_result recv(void *buf, size_t len, size_t & recv_len) { int ans = ::recv( _socket_fd, (char *)buf, len, 0); //::setsockopt(_socket_fd, IPPROTO_TCP, TCP_QUICKACK, (const char *)1, sizeof(int)); //::setsockopt(_socket_fd, IPPROTO_TCP, TCP_QUICKACK, (int[]){1}, sizeof(int)) if (ans == SOCKET_ERROR) { recv_len = 0; switch(WSAGetLastError()) { case WSAETIMEDOUT: return RESULT_OPERATION_TIMEOUT; default: return RESULT_OPERATION_FAIL; } } else { recv_len = ans; return RESULT_OK; } } virtual u_result getPeerAddress(SocketAddress & peerAddr) { struct sockaddr * addr = reinterpret_cast(const_cast(peerAddr.getPlatformData())); //donnot do this at home... assert(addr); int actualsize = (int)sizeof(sockaddr_storage); int ans = ::getpeername(_socket_fd, addr, &actualsize); assert(actualsize <= (int)sizeof(sockaddr_storage)); assert(addr->sa_family == AF_INET || addr->sa_family == AF_INET6); return ans?RESULT_OPERATION_FAIL:RESULT_OK; } virtual u_result shutdown(socket_direction_mask mask) { int shutdw_opt ; switch (mask) { case SOCKET_DIR_RD: shutdw_opt = SD_RECEIVE; break; case SOCKET_DIR_WR: shutdw_opt = SD_SEND; break; case SOCKET_DIR_BOTH: default: shutdw_opt = SD_BOTH; } int ans = ::shutdown(_socket_fd, shutdw_opt); return ans?RESULT_OPERATION_FAIL:RESULT_OK; } virtual u_result enableKeepAlive(bool enable) { int bool_true = enable?1:0; return ::setsockopt( _socket_fd, SOL_SOCKET, SO_KEEPALIVE , (const char *)&bool_true, (int)sizeof(bool_true) )?RESULT_OPERATION_FAIL:RESULT_OK; } virtual u_result enableNoDelay(bool enable ) { int bool_true = enable?1:0; return ::setsockopt( _socket_fd, IPPROTO_TCP, TCP_NODELAY, (const char *)&bool_true, (int)sizeof(bool_true) )?RESULT_OPERATION_FAIL:RESULT_OK; } virtual u_result waitforSent(_u32 timeout ) { fd_set wrset; FD_ZERO(&wrset); FD_SET(_socket_fd, &wrset); timeval tv; tv.tv_sec = timeout / 1000; tv.tv_usec = (timeout % 1000) * 1000; int ans = ::select(NULL, NULL, &wrset, NULL, &tv); switch (ans) { case 1: // fired return RESULT_OK; case 0: // timeout return RESULT_OPERATION_TIMEOUT; default: delay(0); //relax cpu return RESULT_OPERATION_FAIL; } } virtual u_result waitforData(_u32 timeout ) { fd_set rdset; FD_ZERO(&rdset); FD_SET(_socket_fd, &rdset); timeval tv; tv.tv_sec = timeout / 1000; tv.tv_usec = (timeout % 1000) * 1000; int ans = ::select(_socket_fd+1, &rdset, NULL, NULL, &tv); switch (ans) { case 1: // fired return RESULT_OK; case 0: // timeout return RESULT_OPERATION_TIMEOUT; default: delay(0); //relax cpu return RESULT_OPERATION_FAIL; } } protected: SOCKET _socket_fd; }; class _single_thread DGramSocketImpl : public DGramSocket { public: DGramSocketImpl(SOCKET fd) : _socket_fd(fd) { assert(fd>=0); int bool_true = 1; ::setsockopt( _socket_fd, SOL_SOCKET, SO_REUSEADDR | SO_BROADCAST , (char *)&bool_true, (int)sizeof(bool_true) ); setTimeout(DEFAULT_SOCKET_TIMEOUT, SOCKET_DIR_BOTH); } virtual ~DGramSocketImpl() { closesocket(_socket_fd); } virtual void dispose() { delete this; } virtual u_result bind(const SocketAddress & localaddr) { const struct sockaddr * addr = reinterpret_cast(localaddr.getPlatformData()); assert(addr); int ans = ::bind(_socket_fd, addr, (int)sizeof(sockaddr_storage)); if (ans) { return RESULT_OPERATION_FAIL; } else { return RESULT_OK; } } virtual u_result getLocalAddress(SocketAddress & localaddr) { struct sockaddr * addr = reinterpret_cast(const_cast((localaddr.getPlatformData()))); //donnot do this at home... assert(addr); int actualsize = (int)sizeof(sockaddr_storage); int ans = ::getsockname(_socket_fd, addr, &actualsize); assert(actualsize <= (int)sizeof(sockaddr_storage)); assert(addr->sa_family == AF_INET || addr->sa_family == AF_INET6); return ans?RESULT_OPERATION_FAIL:RESULT_OK; } virtual u_result setTimeout(_u32 timeout, socket_direction_mask msk) { int ans; timeval tv; tv.tv_sec = timeout / 1000; tv.tv_usec = (timeout % 1000) * 1000; if (msk & SOCKET_DIR_RD) { ans = ::setsockopt( _socket_fd, SOL_SOCKET, SO_RCVTIMEO, (const char *)&tv, (int)sizeof(tv) ); if (ans) return RESULT_OPERATION_FAIL; } if (msk & SOCKET_DIR_WR) { ans = ::setsockopt( _socket_fd, SOL_SOCKET, SO_SNDTIMEO, (const char *)&tv, (int)sizeof(tv) ); if (ans) return RESULT_OPERATION_FAIL; } return RESULT_OK; } virtual u_result waitforSent(_u32 timeout ) { fd_set wrset; FD_ZERO(&wrset); FD_SET(_socket_fd, &wrset); timeval tv; tv.tv_sec = timeout / 1000; tv.tv_usec = (timeout % 1000) * 1000; int ans = ::select(NULL, NULL, &wrset, NULL, &tv); switch (ans) { case 1: // fired return RESULT_OK; case 0: // timeout return RESULT_OPERATION_TIMEOUT; default: delay(0); //relax cpu return RESULT_OPERATION_FAIL; } } virtual u_result waitforData(_u32 timeout ) { fd_set rdset; FD_ZERO(&rdset); FD_SET(_socket_fd, &rdset); timeval tv; tv.tv_sec = timeout / 1000; tv.tv_usec = (timeout % 1000) * 1000; int ans = ::select(NULL, &rdset, NULL, NULL, &tv); switch (ans) { case 1: // fired return RESULT_OK; case 0: // timeout return RESULT_OPERATION_TIMEOUT; default: delay(0); //relax cpu return RESULT_OPERATION_FAIL; } } virtual u_result sendTo(const SocketAddress & target, const void * buffer, size_t len) { const struct sockaddr * addr = reinterpret_cast(target.getPlatformData()); assert(addr); int ans = ::sendto( _socket_fd, (const char *)buffer, (int)len, 0, addr, (int)sizeof(sockaddr_storage)); if (ans != SOCKET_ERROR) { assert(ans == (int)len); return RESULT_OK; } else { switch(WSAGetLastError()) { case WSAETIMEDOUT: return RESULT_OPERATION_TIMEOUT; case WSAEMSGSIZE: return RESULT_INVALID_DATA; default: return RESULT_OPERATION_FAIL; } } } virtual u_result recvFrom(void *buf, size_t len, size_t & recv_len, SocketAddress * sourceAddr) { struct sockaddr * addr = (sourceAddr?reinterpret_cast(const_cast(sourceAddr->getPlatformData())):NULL); int source_addr_size = (sourceAddr?sizeof(sockaddr_storage):0); int ans = ::recvfrom( _socket_fd, (char *)buf, (int)len, 0, addr, addr?&source_addr_size:NULL); if (ans == SOCKET_ERROR) { recv_len = 0; int errCode = WSAGetLastError(); switch(errCode) { case WSAETIMEDOUT: return RESULT_OPERATION_TIMEOUT; default: return RESULT_OPERATION_FAIL; } } else { recv_len = ans; return RESULT_OK; } } protected: SOCKET _socket_fd; }; }}} namespace rp { namespace net{ static inline int _socketHalFamilyToOSFamily(SocketBase::socket_family_t family) { switch (family) { case SocketBase::SOCKET_FAMILY_INET: return AF_INET; case SocketBase::SOCKET_FAMILY_INET6: return AF_INET6; case SocketBase::SOCKET_FAMILY_RAW: return AF_UNSPEC; //win32 doesn't support RAW Packet default: assert(!"should not reach here"); return AF_INET; // force treating as IPv4 in release mode } } StreamSocket * StreamSocket::CreateSocket(SocketBase::socket_family_t family) { _checkWSAStartup(); if (family == SOCKET_FAMILY_RAW) return NULL; int socket_family = _socketHalFamilyToOSFamily(family); int socket_fd = ::socket(socket_family, SOCK_STREAM, 0); if (socket_fd == -1) return NULL; StreamSocket * newborn = static_cast(new rp::arch::net::StreamSocketImpl(socket_fd)); return newborn; } DGramSocket * DGramSocket::CreateSocket(SocketBase::socket_family_t family) { _checkWSAStartup(); int socket_family = _socketHalFamilyToOSFamily(family); int socket_fd = ::socket(socket_family, (family==SOCKET_FAMILY_RAW)?SOCK_RAW:SOCK_DGRAM, 0); if (socket_fd == -1) return NULL; DGramSocket * newborn = static_cast(new rp::arch::net::DGramSocketImpl(socket_fd)); return newborn; } }}