cec: added tcp client sockets to lib/platform
authorLars Op den Kamp <lars@opdenkamp.eu>
Mon, 30 Jan 2012 01:28:03 +0000 (02:28 +0100)
committerLars Op den Kamp <lars@opdenkamp.eu>
Mon, 30 Jan 2012 09:37:37 +0000 (10:37 +0100)
project/libcec.vcxproj
project/libcec.vcxproj.filters
src/lib/platform/posix/os-tcp.h [new file with mode: 0644]
src/lib/platform/posix/serialport.cpp
src/lib/platform/sockets/serialport.h
src/lib/platform/sockets/tcp.h [new file with mode: 0644]
src/lib/platform/windows/os-tcp.h [new file with mode: 0644]

index 29d5a77257c21426003dc629f54d4a142f7c2229..9c4c8962a808aad2c28f93308d7f420d1d430f48 100644 (file)
@@ -41,6 +41,7 @@
     <ClInclude Include="..\src\lib\platform\os.h" />
     <ClInclude Include="..\src\lib\platform\sockets\serialport.h" />
     <ClInclude Include="..\src\lib\platform\sockets\socket.h" />
+    <ClInclude Include="..\src\lib\platform\sockets\tcp.h" />
     <ClInclude Include="..\src\lib\platform\threads\mutex.h" />
     <ClInclude Include="..\src\lib\platform\threads\threads.h" />
     <ClInclude Include="..\src\lib\platform\util\baudrate.h" />
@@ -48,6 +49,7 @@
     <ClInclude Include="..\src\lib\platform\util\StdString.h" />
     <ClInclude Include="..\src\lib\platform\util\timeutils.h" />
     <ClInclude Include="..\src\lib\platform\windows\os-socket.h" />
+    <ClInclude Include="..\src\lib\platform\windows\os-tcp.h" />
     <ClInclude Include="..\src\lib\platform\windows\os-threads.h" />
     <ClInclude Include="..\src\lib\platform\windows\os-types.h" />
   </ItemGroup>
index 636dafc000e1f4fd5f52bf334385392a8c8902f3..511d05250d2fa3011c5eb12159a2ca947a01ed5d 100644 (file)
     <ClInclude Include="..\src\lib\platform\util\baudrate.h">
       <Filter>platform\util</Filter>
     </ClInclude>
+    <ClInclude Include="..\src\lib\platform\sockets\tcp.h">
+      <Filter>platform\sockets</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\lib\platform\windows\os-tcp.h">
+      <Filter>platform\windows</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="..\src\lib\CECProcessor.cpp" />
diff --git a/src/lib/platform/posix/os-tcp.h b/src/lib/platform/posix/os-tcp.h
new file mode 100644 (file)
index 0000000..df4a2a9
--- /dev/null
@@ -0,0 +1,88 @@
+#pragma once
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011 Pulse-Eight Limited.  All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing       <license@pulse-eight.com>
+ *     http://www.pulse-eight.com/
+ *     http://www.pulse-eight.net/
+ */
+
+#include "../os.h"
+#include "../sockets/socket.h"
+
+namespace PLATFORM
+{
+  inline int TcpGetSocketError(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(socket_t socket)
+  {
+    int iSetTo(1);
+    setsockopt(socket, SOL_TCP, TCP_NODELAY, &iSetTo, sizeof(iSetTo));
+    return true;
+  }
+
+  inline bool TcpConnectSocket(socket_t socket, struct addrinfo* addr, int *iError, uint64_t iTimeout = 0)
+  {
+    bool bConnected = (connect(socket, addr->ai_addr, addr->ai_addrlen) == 0);
+    if (!bConnected && 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;
+      else
+        *iError = TcpGetSocketError(socket);
+    }
+
+    return bConnected;
+  }
+
+  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);
+
+    return ((*iError = getaddrinfo(strHost, service, &hints, &info)) == 0);
+  }
+}
index 71405d474c3a6734a80095705aad3d4f57982dc0..4b3af9aaf6450f674f7d9023743bc8a73b7267c8 100644 (file)
@@ -52,13 +52,13 @@ using namespace PLATFORM;
 
 CSerialPort::CSerialPort()
 {
-  m_tostdout = false;
+  m_bToStdOut = false;
 }
 
 //setting all this stuff up is a pain in the ass
 bool CSerialPort::Open(string name, uint32_t baudrate, uint8_t databits /* = 8 */, uint8_t stopbits /* = 1 */, uint8_t parity /* = PAR_NONE */)
 {
-  m_name = name;
+  m_strName = name;
   CLockObject lock(m_mutex);
 
   if (databits < 5 || databits > 8)
index bbe01363ce69266f484c4157df19cda7a0bb1734..c6cb5953a1a9d7a45d2d5b28d17a57250e2b42ee 100644 (file)
@@ -60,23 +60,23 @@ namespace PLATFORM
       CStdString GetName(void) const
       {
         CStdString strName;
-        strName = m_name;
+        strName = m_strName;
         return strName;
       }
 
-  #ifdef __WINDOWS__
+    #ifdef __WINDOWS__
       virtual bool IsOpen(void);
       virtual void Close(void);
       virtual int64_t Write(uint8_t* data, uint32_t len);
       virtual int32_t Read(uint8_t* data, uint32_t len, uint64_t iTimeoutMs = 0);
+    #endif
 
-  private:
-      void FormatWindowsError(int iErrorCode, CStdString &strMessage);
+    private:
       bool SetBaudRate(uint32_t baudrate);
 
-      std::string  m_name;
-      bool         m_tostdout;
-
+    private:
+    #ifdef __WINDOWS__
+      void FormatWindowsError(int iErrorCode, CStdString &strMessage);
       bool SetTimeouts(bool bBlocking);
 
       HANDLE                m_handle; 
@@ -91,5 +91,7 @@ namespace PLATFORM
   #else
       struct termios     m_options;
   #endif
+      std::string  m_strName;
+      bool         m_bToStdOut;
   };
 };
diff --git a/src/lib/platform/sockets/tcp.h b/src/lib/platform/sockets/tcp.h
new file mode 100644 (file)
index 0000000..c69159a
--- /dev/null
@@ -0,0 +1,96 @@
+#pragma once
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011 Pulse-Eight Limited.  All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing       <license@pulse-eight.com>
+ *     http://www.pulse-eight.com/
+ *     http://www.pulse-eight.net/
+ */
+
+#include "socket.h"
+
+#if defined(__WINDOWS__)
+#include "../windows/os-tcp.h"
+#else
+#include "../posix/os-tcp.h"
+#endif
+
+namespace PLATFORM
+{
+  class CTcpSocket : public CSocket
+  {
+    public:
+      CTcpSocket(void);
+      virtual ~CTcpSocket(void) {}
+
+      virtual bool Open(const CStdString &strHostname, uint16_t iPort, uint64_t nTimeout)
+      {
+        bool bReturn(false);
+        struct addrinfo *address, *addr;
+        int iResult = TcpResolveAddress(strHostname, iPort, address);
+        if (iResult)
+        {
+          m_strError = strerror(iResult);
+          return bReturn;
+        }
+
+        for(addr = address; !bReturn && addr; addr = addr->ai_next)
+        {
+          int iError(0);
+          m_socket = TcpCreateSocket(addr, &iError, nTimeout);
+          if (m_socket != INVALID_SOCKET && m_socket != SOCKET_ERROR)
+            bReturn = true;
+          else
+            m_strError = strerror(iError);
+        }
+
+        freeaddrinfo(address);
+        return bReturn;
+      }
+
+  protected:
+    virtual socket_t TcpCreateSocket(struct addrinfo* addr, int* iError, uint64_t iTimeout)
+    {
+      socket_t fdSock = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
+      if (fdSock == -1)
+      {
+        *iError = TcpGetSocketError();
+        return (socket_t)SOCKET_ERROR;
+      }
+
+      if (TcpConnectSocket(addr, fdSock, iError, iTimeout) != 0)
+      {
+        closesocket(fdSock);
+        return (socket_t)SOCKET_ERROR;
+      }
+
+      TcpSetNoDelay(fdSock);
+
+      return fdSock;
+    }
+  };
+};
diff --git a/src/lib/platform/windows/os-tcp.h b/src/lib/platform/windows/os-tcp.h
new file mode 100644 (file)
index 0000000..f16cb69
--- /dev/null
@@ -0,0 +1,123 @@
+#pragma once
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011 Pulse-Eight Limited.  All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing       <license@pulse-eight.com>
+ *     http://www.pulse-eight.com/
+ *     http://www.pulse-eight.net/
+ */
+
+#include "../os.h"
+#include "../sockets/socket.h"
+
+namespace PLATFORM
+{
+  inline int TcpResolveAddress(const CStdString &strHostname, uint16_t iPort, struct addrinfo *address)
+  {
+     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);
+
+     return getaddrinfo(strHostname.c_str(), service, &hints, &address);
+   }
+
+  inline int TcpGetSocketError()
+  {
+    int error = WSAGetLastError();
+    switch(error)
+    {
+      case WSAEINPROGRESS: return EINPROGRESS;
+      case WSAECONNRESET : return ECONNRESET;
+      case WSAETIMEDOUT  : return ETIMEDOUT;
+      case WSAEWOULDBLOCK: return EAGAIN;
+      default            : return error;
+    }
+  }
+
+  inline int TcpConnectSocket(struct addrinfo* addr, socket_t socket, int *iError, uint64_t iTimeout)
+  {
+    int nRes = 0;
+    socklen_t errlen = sizeof(int);
+
+    SocketSetBlocking(socket, false);
+
+    /* connect to the other side */
+    nRes = connect(socket, addr->ai_addr, addr->ai_addrlen);
+
+    /* poll until a connection is established */
+    if (nRes == -1)
+    {
+      if (TcpGetSocketError() == EINPROGRESS || TcpGetSocketError() == EAGAIN)
+      {
+        fd_set fd_write, fd_except;
+        struct timeval tv;
+        tv.tv_sec  = (long)(iTimeout / 1000);
+        tv.tv_usec = (long)(1000 * (iTimeout % 1000));
+
+        FD_ZERO(&fd_write);
+        FD_ZERO(&fd_except);
+        FD_SET(socket, &fd_write);
+        FD_SET(socket, &fd_except);
+
+        nRes = select(sizeof(socket)*8, NULL, &fd_write, &fd_except, &tv);
+        if (nRes == 0)
+        {
+          *iError = ETIMEDOUT;
+          return SOCKET_ERROR;
+        }
+        else if (nRes == -1)
+        {
+          *iError = TcpGetSocketError();
+          return SOCKET_ERROR;
+        }
+
+        /* check for errors */
+        getsockopt(socket, SOL_SOCKET, SO_ERROR, (char *)iError, &errlen);
+      }
+      else
+      {
+        *iError = TcpGetSocketError();
+      }
+    }
+
+    SocketSetBlocking(socket, true);
+
+    return 0;
+  }
+
+  inline bool TcpSetNoDelay(socket_t socket)
+  {
+    int nVal = 1;
+    setsockopt(socket, IPPROTO_TCP, TCP_NODELAY, (const char*)&nVal, sizeof(nVal));
+    return true;
+  }
+}