+ //@}
+
+ // TCP
+ //@{
+ inline void TcpSocketClose(tcp_socket_t socket)
+ {
+ SocketClose(socket);
+ }
+
+ inline void TcpSocketShutdown(tcp_socket_t socket)
+ {
+ if (socket != INVALID_SOCKET_VALUE)
+ shutdown(socket, SHUT_RDWR);
+ }
+
+ inline ssize_t TcpSocketWrite(tcp_socket_t socket, int *iError, void* data, size_t len)
+ {
+ if (socket == INVALID_SOCKET_VALUE)
+ {
+ *iError = EINVAL;
+ return -1;
+ }
+
+ ssize_t iReturn = send(socket, data, len, 0);
+ if (iReturn < (ssize_t)len)
+ *iError = errno;
+ return iReturn;
+ }
+
+ inline ssize_t TcpSocketRead(tcp_socket_t socket, int *iError, void* data, size_t len, uint64_t iTimeoutMs /*= 0*/)
+ {
+ int64_t iNow(0), iTarget(0);
+ ssize_t iBytesRead(0);
+ *iError = 0;
+
+ if (socket == INVALID_SOCKET_VALUE)
+ {
+ *iError = EINVAL;
+ return -1;
+ }
+
+ if (iTimeoutMs > 0)
+ {
+ iNow = GetTimeMs();
+ iTarget = iNow + (int64_t) iTimeoutMs;
+ }
+
+ struct pollfd fds;
+ fds.fd = socket;
+ fds.events = POLLIN;
+ fds.revents = 0;
+
+ while (iBytesRead >= 0 && iBytesRead < (ssize_t)len && (iTimeoutMs == 0 || iTarget > iNow))
+ {
+ if (iTimeoutMs > 0)
+ {
+ int iPollResult = poll(&fds, 1, iTarget - iNow);
+ if (iPollResult == 0)
+ {
+ *iError = ETIMEDOUT;
+ return -ETIMEDOUT;
+ }
+ }
+
+ ssize_t iReadResult = (iTimeoutMs > 0) ?
+ recv(socket, (char*)data + iBytesRead, len - iBytesRead, MSG_DONTWAIT) :
+ recv(socket, data, len, MSG_WAITALL);
+ if (iReadResult < 0)
+ {
+ if (errno == EAGAIN && iTimeoutMs > 0)
+ continue;
+ *iError = errno;
+ return -errno;
+ }
+ else if (iReadResult == 0 || (iReadResult != (ssize_t)len && iTimeoutMs == 0))
+ {
+ *iError = ECONNRESET;
+ return -ECONNRESET;
+ }
+
+ iBytesRead += iReadResult;
+
+ if (iTimeoutMs > 0)
+ iNow = GetTimeMs();
+ }
+
+ if (iBytesRead < (ssize_t)len)
+ *iError = ETIMEDOUT;
+ return iBytesRead;
+ }
+
+ inline bool TcpResolveAddress(const char *strHost, uint16_t iPort, int *iError, struct addrinfo **info)
+ {
+ struct addrinfo hints;
+ char service[33];
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_protocol = IPPROTO_TCP;
+ sprintf(service, "%d", iPort);
+
+ *iError = getaddrinfo(strHost, service, &hints, info);
+ return !(*iError);
+ }
+
+ inline int TcpGetSocketError(tcp_socket_t socket)
+ {
+ int iReturn(0);
+ socklen_t optLen = sizeof(socket_t);
+ getsockopt(socket, SOL_SOCKET, SO_ERROR, (void *)&iReturn, &optLen);
+ return iReturn;
+ }
+
+ inline bool TcpSetNoDelay(tcp_socket_t socket)
+ {
+ int iSetTo(1);
+ setsockopt(socket, SOL_TCP, TCP_NODELAY, &iSetTo, sizeof(iSetTo));
+ return true;
+ }
+
+ inline bool TcpConnectSocket(tcp_socket_t socket, struct addrinfo* addr, int *iError, uint64_t iTimeout = 0)
+ {
+ *iError = 0;
+ int iConnectResult = connect(socket, addr->ai_addr, addr->ai_addrlen);
+ if (iConnectResult == -1)
+ {
+ if (errno == EINPROGRESS)
+ {
+ struct pollfd pfd;
+ pfd.fd = socket;
+ pfd.events = POLLOUT;
+ pfd.revents = 0;
+
+ int iPollResult = poll(&pfd, 1, iTimeout);
+ if (iPollResult == 0)
+ *iError = ETIMEDOUT;
+ else if (iPollResult == -1)
+ *iError = errno;
+
+ socklen_t errlen = sizeof(int);
+ getsockopt(socket, SOL_SOCKET, SO_ERROR, (void *)iError, &errlen);
+ }
+ else
+ {
+ *iError = errno;
+ }
+ }
+
+ return *iError == 0;
+ }
+ //@}