X-Git-Url: https://git.piment-noir.org/?a=blobdiff_plain;f=src%2Flib%2Fplatform%2Fposix%2Fos-socket.h;h=7156c752c239c7f1c389572236c6cb539a865906;hb=103eb041ef46f322b3c374da47feabab6c378004;hp=9d557c1b4583a9bc631642f60e38036910f04cef;hpb=cb2397e953b3f892b4206d5bb87968ca4cccbac8;p=deb_libcec.git diff --git a/src/lib/platform/posix/os-socket.h b/src/lib/platform/posix/os-socket.h index 9d557c1..7156c75 100644 --- a/src/lib/platform/posix/os-socket.h +++ b/src/lib/platform/posix/os-socket.h @@ -2,7 +2,7 @@ /* * This file is part of the libCEC(R) library. * - * libCEC(R) is Copyright (C) 2011-2012 Pulse-Eight Limited. All rights reserved. + * libCEC(R) is Copyright (C) 2011-2013 Pulse-Eight Limited. All rights reserved. * libCEC(R) is an original work, containing original code. * * libCEC(R) is a trademark of Pulse-Eight Limited. @@ -32,61 +32,78 @@ */ -#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; + ssize_t iBytesWritten(0); struct timeval *tv(NULL); - while (iBytesWritten < len) + while (iBytesWritten < (ssize_t)len) { FD_ZERO(&port); FD_SET(socket, &port); - int returnv = select(socket + 1, NULL, &port, NULL, tv); + ssize_t returnv = (ssize_t)select(socket + 1, NULL, &port, NULL, tv); 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) { @@ -129,23 +146,23 @@ namespace PLATFORM FD_ZERO(&port); FD_SET(socket, &port); - int32_t returnv = select(socket + 1, &port, NULL, NULL, tv); + ssize_t returnv = (ssize_t)select(socket + 1, &port, NULL, NULL, tv); 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, (int)(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, (int)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; + } + //@} }