updated copyright messages for 2013
[deb_libcec.git] / src / lib / platform / posix / os-socket.h
index 3cea52b667dcff50e98d4f15f6e515542c2ceb0a..7156c752c239c7f1c389572236c6cb539a865906 100644 (file)
@@ -2,7 +2,7 @@
 /*
  * This file is part of the libCEC(R) library.
  *
- * libCEC(R) is Copyright (C) 2011 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.
  */
 
 
-#include "../os.h"
-#include "../util/timeutils.h"
+#include "lib/platform/os.h"
+#include "lib/platform/util/timeutils.h"
 #include <stdio.h>
 #include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <poll.h>
+
+/* 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);
-      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;
+  }
+  //@}
 }