X-Git-Url: https://git.piment-noir.org/?a=blobdiff_plain;f=src%2Flib%2Fplatform%2Fposix%2Fos-socket.h;h=9d98d9ad9285f3646046597b9ef1a71bc35f08d9;hb=4d3a75622545306c7a5d24789d2239ed2560703f;hp=a57f69d21d449103b49b40b8c25ed81c74fc8bb5;hpb=9b53a148ade63466655e6e5d8cb0ca2b64a76ae3;p=deb_libcec.git diff --git a/src/lib/platform/posix/os-socket.h b/src/lib/platform/posix/os-socket.h index a57f69d..9d98d9a 100644 --- a/src/lib/platform/posix/os-socket.h +++ b/src/lib/platform/posix/os-socket.h @@ -32,41 +32,58 @@ */ -#include "../os.h" -#include "../util/timeutils.h" +#include "lib/platform/os.h" +#include "lib/platform/util/timeutils.h" #include #include +#include +#include +#include +#include +#include +#include +#include + +/* Needed on Mac OS/X */ +#ifndef SOL_TCP +#define SOL_TCP IPPROTO_TCP +#endif namespace PLATFORM { + // Standard sockets + //@{ inline void SocketClose(socket_t socket) { - if (socket != INVALID_SOCKET) + if (socket != INVALID_SOCKET_VALUE) close(socket); } inline void SocketSetBlocking(socket_t socket, bool bSetTo) { -// return bSetTo ? -// fcntl(socket, F_SETFL, fcntl(socket, F_GETFL) & ~O_NONBLOCK) == 0 : -// fcntl(socket, F_SETFL, fcntl(socket, F_GETFL) | O_NONBLOCK) == 0; - fcntl(socket, F_SETFL, bSetTo ? FNDELAY : 0); + if (socket != INVALID_SOCKET_VALUE) + { + if (bSetTo) + fcntl(socket, F_SETFL, fcntl(socket, F_GETFL) & ~O_NONBLOCK); + else + fcntl(socket, F_SETFL, fcntl(socket, F_GETFL) | O_NONBLOCK); + } } - inline int64_t SocketWrite(socket_t socket, int *iError, uint8_t* data, uint32_t len) + inline ssize_t SocketWrite(socket_t socket, int *iError, void* data, size_t len) { fd_set port; - if (socket == -1) + if (socket == INVALID_SOCKET_VALUE) { *iError = EINVAL; - return -1; + return -EINVAL; } - int64_t iBytesWritten = 0; - struct timeval *tv; + ssize_t iBytesWritten(0); + struct timeval *tv(NULL); - while (iBytesWritten < len) + while (iBytesWritten < (ssize_t)len) { FD_ZERO(&port); FD_SET(socket, &port); @@ -74,19 +91,19 @@ namespace PLATFORM if (returnv < 0) { *iError = errno; - return -1; + return -errno; } else if (returnv == 0) { *iError = ETIMEDOUT; - return -1; + return -ETIMEDOUT; } - returnv = write(socket, data + iBytesWritten, len - iBytesWritten); + returnv = write(socket, (char*)data + iBytesWritten, len - iBytesWritten); if (returnv == -1) { *iError = errno; - return -1; + return -errno; } iBytesWritten += returnv; } @@ -94,18 +111,18 @@ namespace PLATFORM return iBytesWritten; } - inline int32_t SocketRead(socket_t socket, int *iError, uint8_t* data, uint32_t len, uint64_t iTimeoutMs /*= 0*/) + inline ssize_t SocketRead(socket_t socket, int *iError, void* data, size_t len, uint64_t iTimeoutMs /*= 0*/) { fd_set port; struct timeval timeout, *tv; int64_t iNow(0), iTarget(0); - int32_t iBytesRead = 0; + ssize_t iBytesRead(0); *iError = 0; - if (socket == -1) + if (socket == INVALID_SOCKET_VALUE) { *iError = EINVAL; - return -1; + return -EINVAL; } if (iTimeoutMs > 0) @@ -114,7 +131,7 @@ namespace PLATFORM iTarget = iNow + (int64_t) iTimeoutMs; } - while (iBytesRead < (int32_t) len && (iTimeoutMs == 0 || iTarget > iNow)) + while (iBytesRead >= 0 && iBytesRead < (ssize_t)len && (iTimeoutMs == 0 || iTarget > iNow)) { if (iTimeoutMs == 0) { @@ -134,18 +151,18 @@ namespace PLATFORM if (returnv == -1) { *iError = errno; - return -1; + return -errno; } else if (returnv == 0) { break; //nothing to read } - returnv = read(socket, data + iBytesRead, len - iBytesRead); + returnv = read(socket, (char*)data + iBytesRead, len - iBytesRead); if (returnv == -1) { *iError = errno; - return -1; + return -errno; } iBytesRead += returnv; @@ -156,4 +173,169 @@ namespace PLATFORM return iBytesRead; } + + inline int SocketIoctl(socket_t socket, int *iError, int request, void* data) + { + if (socket == INVALID_SOCKET_VALUE) + { + *iError = EINVAL; + return -1; + } + + int iReturn = ioctl(socket, request, data); + if (iReturn < 0) + *iError = errno; + return iReturn; + } + //@} + + // 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 -EINVAL; + } + + 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; + } + //@} }