]> git.kernelconcepts.de Git - karo-tx-redboot.git/blobdiff - tools/src/tools/Utils/common/eCosSocket.cpp
Initial revision
[karo-tx-redboot.git] / tools / src / tools / Utils / common / eCosSocket.cpp
diff --git a/tools/src/tools/Utils/common/eCosSocket.cpp b/tools/src/tools/Utils/common/eCosSocket.cpp
new file mode 100644 (file)
index 0000000..b19f260
--- /dev/null
@@ -0,0 +1,818 @@
+//####COPYRIGHTBEGIN####
+//                                                                          
+// ----------------------------------------------------------------------------
+// Copyright (C) 1998, 1999, 2000 Red Hat, Inc.
+//
+// This program is part of the eCos host tools.
+//
+// This program is free software; 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.
+//
+// ----------------------------------------------------------------------------
+//                                                                          
+//####COPYRIGHTEND####
+//=================================================================
+//
+//        eCosSocket.cpp
+//
+//        Socket test class
+//
+//=================================================================
+//=================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):     sdf
+// Contributors:  sdf
+// Date:          1999-04-01
+// Description:   This class abstracts tcp/ip sockets for use in the testing infrastructure
+// Usage:
+//
+//####DESCRIPTIONEND####
+
+#include "eCosStd.h"
+#include "eCosSocket.h"
+#include "eCosSerial.h"
+#include "eCosThreadUtils.h"
+#include "eCosTrace.h"
+#include <map>
+
+enum {ERR_TIMEOUT=20000, ERR_READ_AFTER_CLOSE=20001};
+
+// Blocking read on one or other of the data sources:
+// Result:  -1 - socket error occurred
+//           1 - data read from socket
+//          -2 - serial error occurred
+//           2 - data read from serial
+
+CeCosSocket::SSReadResult CeCosSocket::SSRead (CeCosSerial &serial,CeCosSocket &socket,void *pBuf,unsigned int nSize,unsigned int &nRead,bool *pbStop)
+{
+  SSReadResult rc=SS_STOPPED;
+  bool bBlocking=serial.GetBlockingReads();
+  bool bBlockingModified=false;
+  while(0==pbStop || !(*pbStop)){
+    if(!socket.Peek(nRead)){
+      rc=SS_SOCKET_ERROR;
+      break;
+    } else if(nRead){
+      nRead=MIN(nRead,nSize);
+      rc=socket.recv(pBuf,nRead)?SS_SOCKET_READ:SS_SOCKET_ERROR;
+      break;
+    } else {
+      if(bBlocking){
+        serial.SetBlockingReads(false);
+        bBlockingModified=true;
+        bBlocking=false;
+      }
+      if(serial.Read(pBuf,nSize,nRead)){
+        if(nRead>0){
+          rc=SS_SERIAL_READ;
+          break;
+        }
+      } else {
+        rc=SS_SERIAL_ERROR;
+        break;
+      }
+    }
+    CeCosThreadUtils::Sleep(10);
+  }
+  if(bBlockingModified){
+    serial.SetBlockingReads(true);
+  }
+  return rc;
+}
+
+// ctors and dtors
+
+CeCosSocket::CeCosSocket ():
+m_nDefaultTimeout(10*1000),
+m_nSock(-1),
+m_nClient(0)
+{
+  VTRACE(_T("Create socket instance %08x\n"),(unsigned int)this);
+}
+
+CeCosSocket::CeCosSocket (int sock /*result of previous call of Listen*/, bool *pbStop):
+m_nDefaultTimeout(10*1000),
+m_nSock(-1),
+m_nClient(0)
+{
+  VTRACE(_T("Create socket instance %08x\n"),(unsigned int)this);
+  Accept(sock,pbStop);
+}
+
+CeCosSocket::CeCosSocket (LPCTSTR pszHostPort,Duration dTimeout):
+m_nDefaultTimeout(10*1000),
+m_nSock(-1),
+m_nClient(0)
+{
+  VTRACE(_T("Create socket instance %08x\n"),(unsigned int)this);
+  Connect(pszHostPort,dTimeout);
+}
+
+bool CeCosSocket::Accept(int sock /*result of previous call of Listen*/, bool *pbStop)
+{
+  m_nSock=-1;
+  while(0==pbStop||!*pbStop){
+    struct sockaddr cli_addr;
+#ifndef _WIN32
+    unsigned 
+#endif
+      int clilen=sizeof(struct sockaddr);
+    m_nSock=::accept(sock, (struct sockaddr *) &cli_addr, &clilen);
+    SaveError();
+    if(-1==m_nSock){ 
+      if(WOULDBLOCK==SocketError()){
+        CeCosThreadUtils::Sleep(100);
+        continue;
+      }
+    } else {
+      memcpy(&m_nClient,cli_addr.sa_data+2,4);
+      TRACE(_T("Connection accepted from %s - socket %d\n"),(LPCTSTR )ClientName(m_nClient),m_nSock);
+      SetSocketOptions();
+      break;
+    }
+  } 
+  return -1!=m_nSock;
+}
+
+int CeCosSocket::Listen(int nTcpPort)
+{
+  // Create socket
+  int sock=::socket(AF_INET, SOCK_STREAM, 0);
+  if (sock == -1) {
+    ERROR(_T("Couldn't create socket\n"));
+  } else {
+    VTRACE(_T("Created socket %d listening on port %d\n"),sock,nTcpPort);
+    // Bind socket to address
+    struct sockaddr_in serv_addr;
+    memset(&serv_addr, 0, sizeof serv_addr);
+    
+    serv_addr.sin_family = AF_INET;
+    serv_addr.sin_port=htons((short)nTcpPort);
+    serv_addr.sin_addr.s_addr = INADDR_ANY;
+    
+    if (::bind(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) == -1) {
+      TRACE(_T("Couldn't bind socket on port %d\n"),nTcpPort);
+      CloseSocket(sock);
+    } else if (-1==::listen(sock, SOMAXCONN)){
+      CloseSocket(sock);
+      TRACE(_T("socket error on listen - port %d\n"),nTcpPort);
+    } else {
+#ifdef _WIN32
+      int nTrue=1;
+      bool rc=(0==::ioctlsocket(sock, FIONBIO, (unsigned long *)&nTrue));
+#else //UNIX
+      int flags=::fcntl(sock,F_GETFL);
+      flags|=O_NONBLOCK;
+      bool rc=(0==::fcntl (sock, F_SETFL, flags));
+#endif
+      if(!rc){
+        TRACE(_T("Failed to set socket options on socket %d\n"),sock);
+      }
+    }
+  }
+  return sock;
+}
+
+bool CeCosSocket::Connect(LPCTSTR pszHostPort,Duration dTimeout)
+{
+  dTimeout=TimeoutDuration(dTimeout);
+  struct sockaddr_in serv_addr;
+  
+  VTRACE(_T("Connect: %s timeout=%d\n"),pszHostPort,dTimeout);
+  
+  // Get the target host address
+  String strHost;
+  int nPort;
+  CeCosSocket::ParseHostPort(pszHostPort,strHost,nPort);
+  String strErr;
+
+  char *ip=GetHostByName(strHost).GetCString();
+  memset(&serv_addr, 0, sizeof serv_addr);
+  // Create socket
+  m_nSock = ::socket(AF_INET, SOCK_STREAM, 0);
+  if (-1 == m_nSock) {
+    TRACE(_T("Could not create socket [%s]\n"),pszHostPort);
+  } else {
+#ifdef _WIN32
+    SetSocketOptions();
+#endif
+    VTRACE(_T("Created socket %d connected to %s\n"),m_nSock,pszHostPort);
+    // Bind socket to address
+    serv_addr.sin_family = AF_INET;
+    serv_addr.sin_port=htons((short)nPort);
+    SaveError();
+    serv_addr.sin_addr.s_addr = inet_addr(ip);
+    
+    // Connect to server
+    VTRACE(_T("Connect() : connecting to server\n"));
+    int cc=::connect(m_nSock, (struct sockaddr *) &serv_addr, sizeof(serv_addr));
+    SaveError();
+    String strMsg;
+    if(-1==cc){
+      if(
+#ifdef _WIN32
+        WOULDBLOCK==SocketError()
+#else // UNIX
+        EINPROGRESS==SocketError()
+#endif
+        ){
+        // Allow dTimeout milliseconds for connect to complete
+        fd_set set;
+        FD_ZERO(&set);
+#ifdef _WIN32
+#pragma warning( push )
+#pragma warning( disable : 4127 ) // conditional expression is constant
+#endif
+        FD_SET((unsigned)m_nSock, &set);
+#ifdef _WIN32
+#pragma warning( pop )
+#endif
+        struct timeval tv;
+        tv.tv_sec = dTimeout/1000;  
+        tv.tv_usec = 1000*(dTimeout % 1000);
+        switch(::select(m_nSock, NULL, &set , NULL, &tv)){
+        case 0:
+          m_nErr=ERR_TIMEOUT;
+          strMsg.Format(_T("attempt timed out after %d seconds"),dTimeout/1000);
+          break;
+        case -1:
+          SaveError();
+          strMsg=SocketErrString();
+          break;
+        default:
+          cc=0;
+        }
+      } else {
+        strMsg=SocketErrString();
+      }
+    }
+    
+    if(-1==cc){
+      TRACE(_T("Could not connect to %s - %s\n"),pszHostPort,(LPCTSTR)strMsg);
+      CloseSocket(m_nSock);
+    }  else {
+#ifndef _WIN32
+      SetSocketOptions();
+#endif
+    }
+  }
+  delete [] ip;
+  return -1!=m_nSock;
+}
+
+bool CeCosSocket::sendrecv(bool bSend,const void *pData,unsigned int nLength,
+                           LPCTSTR pszMsg,Duration dTimeout,CeCosSocket::StopFunc pFnStop,void *pParam)
+{
+  
+  dTimeout=TimeoutDuration(dTimeout);
+  
+  LPCTSTR pszSR=(bSend?_T("sending"):_T("receiving"));
+  LPTSTR c=(LPTSTR )pData;
+  Time ft0=Now();
+  int nTodo=nLength;
+  while((nTodo>0) && ((0==pFnStop) || (!pFnStop(pParam)))){
+    int s=bSend?::send(m_nSock, (const char *)c, nTodo, 0): ::recv(m_nSock, (char *)c, nTodo, 0);
+    if(0==s && !bSend){
+      m_nErr=ERR_READ_AFTER_CLOSE;
+    } else {
+      SaveError();
+    }
+    if(-1==s && WOULDBLOCK==SocketError()){
+      Duration d=Duration(Now()-ft0);
+      if(d>dTimeout){
+        TRACE(_T("%d/%d mSec timeout on socket %d %s %s - processed %d/%d bytes\n") ,
+          d,dTimeout,m_nSock,pszSR,pszMsg, 
+          nLength-nTodo,nLength);
+        m_nErr=ERR_TIMEOUT;
+        break;
+      }
+      CeCosThreadUtils::Sleep(100);
+    } else if (s>0) {
+      c+=s;
+      nTodo-=s;
+      ft0=Now();
+    } else {
+      TRACE(_T("Error on socket %d %s %s - %s\n") ,m_nSock, pszSR, pszMsg, (LPCTSTR )SocketErrString());
+      break;
+    }
+  }
+  return 0==nTodo;
+}
+
+// Graceful socket closedown
+CeCosSocket::~CeCosSocket()
+{
+  Close();
+  VTRACE(_T("Delete socket instance %08x\n"),(unsigned int)this);
+}
+
+bool CeCosSocket::CloseSocket(int &sock)
+{
+  bool rc=false;
+  if(-1!=sock){
+    VTRACE(_T("Closing socket %d\n"),sock);
+    try{
+      shutdown(sock,0);// SD_BOTH
+#ifdef _WIN32
+      rc=(0==closesocket(sock));
+#else // UNIX
+      rc=(0==close(sock));
+#endif
+    }
+    catch(...) {
+      TRACE(_T("!!! Exception caught in CeCosSocket::CloseSocket!!!\n"));
+    }
+    sock=-1;
+  }
+  return rc;
+}
+
+bool CeCosSocket::SetSocketOptions()
+{
+  bool rc;
+#ifdef _WIN32
+  int nTrue=1;
+  rc=(0==::ioctlsocket(m_nSock, FIONBIO, (unsigned long *)&nTrue));
+  SaveError();
+#else // UNIX
+  int flags=::fcntl(m_nSock,F_GETFL);
+  SaveError();
+  flags|=O_NONBLOCK;
+  rc=(0==::fcntl (m_nSock, F_SETFL, flags));
+  SaveError();
+#endif
+  int bLinger=0;
+  setsockopt(m_nSock,SOL_SOCKET,SO_LINGER,(const char *)&bLinger, sizeof(bLinger));
+  if(!rc){
+    TRACE(_T("Failed to set socket options socket %d - %s\n"),m_nSock,(LPCTSTR )SocketErrString());
+  }
+  return rc;
+}
+
+String CeCosSocket::SocketErrString(int nErr)
+{
+  String str;
+#ifdef _WIN32
+  switch(nErr){
+  case ERR_TIMEOUT: str=_T("Read operation timed out");break;
+  case ERR_READ_AFTER_CLOSE: str=_T("Read operation after socket closed");break;
+    
+  case WSAEACCES: str=_T("Permission denied");break;
+  case WSAEADDRINUSE: str=_T("Address already in use");break;
+  case WSAEADDRNOTAVAIL: str=_T("Cannot assign requested address");break;
+  case WSAEAFNOSUPPORT: str=_T("Address family not supported by protocol family");break;
+  case WSAEALREADY: str=_T("Operation already in progress");break;
+  case WSAECONNABORTED: str=_T("Software caused connection abort");break;
+  case WSAECONNREFUSED: str=_T("Connection refused");break;
+  case WSAECONNRESET: str=_T("Connection reset by peer");break;
+  case WSAEDESTADDRREQ: str=_T("Destination address required");break;
+  case WSAEFAULT: str=_T("Bad address");break;
+  case WSAEHOSTDOWN: str=_T("Host is down");break;
+  case WSAEHOSTUNREACH: str=_T("No route to host");break;
+  case WSAEINPROGRESS: str=_T("Operation now in progress");break;
+  case WSAEINTR: str=_T("Interrupted function call");break;
+  case WSAEINVAL: str=_T("Invalid argument");break;
+  case WSAEISCONN: str=_T("Socket is already connected");break;
+  case WSAEMFILE: str=_T("Too many open files");break;
+  case WSAEMSGSIZE: str=_T("Message too long");break;
+  case WSAENETDOWN: str=_T("Network is down");break;
+  case WSAENETRESET: str=_T("Network dropped connection on reset");break;
+  case WSAENETUNREACH: str=_T("Network is unreachable");break;
+  case WSAENOBUFS: str=_T("No buffer space available");break;
+  case WSAENOPROTOOPT: str=_T("Bad protocol option");break;
+  case WSAENOTCONN: str=_T("Socket is not connected");break;
+  case WSAENOTSOCK: str=_T("Socket operation on non-socket");break;
+  case WSAEOPNOTSUPP: str=_T("Operation not supported");break;
+  case WSAEPFNOSUPPORT: str=_T("Protocol family not supported");break;
+  case WSAEPROCLIM: str=_T("Too many processes");break;
+  case WSAEPROTONOSUPPORT: str=_T("Protocol not supported");break;
+  case WSAEPROTOTYPE: str=_T("Protocol wrong type for socket");break;
+  case WSAESHUTDOWN: str=_T("Cannot send after socket shutdown");break;
+  case WSAESOCKTNOSUPPORT: str=_T("Socket type not supported");break;
+  case WSAETIMEDOUT: str=_T("Connection timed out");break;
+  case WSATYPE_NOT_FOUND: str=_T("Class type not found");break;
+  case WSAEWOULDBLOCK: str=_T("Resource temporarily unavailable");break;
+  case WSAHOST_NOT_FOUND: str=_T("Host not found");break;
+  case WSA_INVALID_HANDLE: str=_T("Specified event object handle is invalid");break;
+  case WSA_INVALID_PARAMETER: str=_T("One or more parameters are invalid");break;
+    //case WSAINVALIDPROCTABLE: str=_T("Invalid procedure table from service provider");break;
+    //case WSAINVALIDPROVIDER: str=_T("Invalid service provider version number");break;
+  case WSA_IO_INCOMPLETE: str=_T("Overlapped I/O event object not in signaled state");break;
+  case WSA_IO_PENDING: str=_T("Overlapped operations will complete later");break;
+  case WSA_NOT_ENOUGH_MEMORY: str=_T("Insufficient memory available");break;
+  case WSANOTINITIALISED: str=_T("Successful case WSAStartup not yet:performed");break;
+  case WSANO_DATA: str=_T("Valid name, no data record of requested type");break;
+  case WSANO_RECOVERY: str=_T("This is a non-recoverable error");break;
+    //case WSAPROVIDERFAILEDINIT: str=_T("Unable to initialize a service provider");break;
+  case WSASYSCALLFAILURE: str=_T("System call failure");break;
+  case WSASYSNOTREADY: str=_T("Network subsystem is unavailable");break;
+  case WSATRY_AGAIN: str=_T("Non-authoritative host not found");break;
+  case WSAVERNOTSUPPORTED: str=_T("WINSOCK.DLL version out of range");break;
+  case WSAEDISCON: str=_T("Graceful shutdown in progress");break;
+  case WSA_OPERATION_ABORTED: str=_T("Overlapped operation aborted");break;
+  default:
+    str.Format(_T("Unknown error %d (0x%08x)"),nErr,nErr);
+  }
+#else // UNIX
+  switch(nErr){
+  case ERR_TIMEOUT: str=_T("Read operation timed out");break;
+  case ERR_READ_AFTER_CLOSE: str=_T("Read operation after socket closed");break;
+  default:
+    str=strerror(errno);
+  }
+#endif
+  return str;
+}
+
+bool CeCosSocket::sendInteger(int n,LPCTSTR pszMsg,Duration dTimeout)
+{
+  // This has to support cross-architectural endianness
+  unsigned char c[sizeof(int)];
+  for(unsigned int i=0;i<sizeof(int);i++){
+    c[i]=(unsigned char)(n&0xff);
+    n>>=8;
+  }
+  return send (c, sizeof(int),pszMsg,dTimeout);
+}
+
+bool CeCosSocket::recvInteger(int & n,LPCTSTR pszMsg,Duration dTimeout)
+{
+  // This has to support cross-architectural endianness
+  unsigned char c[sizeof(int)];
+  bool rc=recv (c, sizeof(int),pszMsg,dTimeout);
+  n=0;
+  if(rc){
+    for(int i=sizeof(int)-1;i>=0;--i){
+      n<<=8;
+      n|=c[i];
+    }
+  }
+  return rc;
+}
+
+// Socket communications for strings are always non-UNICODE:
+bool CeCosSocket::recvString  (String &str,LPCTSTR pszMsg,Duration dTimeout)
+{
+  int nLength;
+  bool rc=false;
+  if(recvInteger(nLength,pszMsg,dTimeout)){
+    if(0==nLength){
+      rc=true;
+    } else {
+      Buffer b(1+nLength);
+      char *c=(char *)b.Data();
+      if(c){
+        rc=recv(c,nLength,pszMsg,dTimeout);
+        c[nLength]='\0';
+        str=String::CStrToUnicodeStr(c);
+      }
+    }
+  }
+  return rc;
+}
+
+// Socket communications for strings are always non-UNICODE:
+bool CeCosSocket::sendString  (const String &str,LPCTSTR pszMsg,Duration dTimeout)
+{
+  char *psz=str.GetCString();
+  int nLength=strlen(psz); 
+  bool rc=sendInteger(nLength,pszMsg,dTimeout) && (0==nLength || send(psz,nLength,pszMsg,dTimeout));
+  delete [] psz;
+  return rc;
+}
+
+
+// Give indication of bytes available to be read (but don't read them)
+bool CeCosSocket::Peek (unsigned int &nAvail)
+{
+  char buf[8192];
+  int n=::recv(m_nSock, buf, sizeof buf, MSG_PEEK);
+  nAvail=0;
+  bool rc=false;
+  switch(n) {
+  case -1:
+    SaveError();
+    if(WOULDBLOCK==SocketError()){
+      rc=true; // nAvail stays==0
+    } else {
+      ERROR(_T("Peek: err=%d %s\n"),SocketError(),(LPCTSTR)SocketErrString());
+    }
+    break;
+  case 0:
+    m_nErr=ERR_READ_AFTER_CLOSE;
+    break;
+  default:
+    rc=true;
+    nAvail=n;
+  }
+  return rc;
+}
+
+// Connect tcp/ip port and serial port together.
+// Traffic is passed through pFunc, passed parameter pParam.
+// The pFunc function:
+//    may reallocate pBuf (using malloc/realloc etc...)
+//    must leave pBuf allocated on exit
+//    should not close either serial or socket
+//    should leave writing to its caller
+//    should return false if it wishes to terminate the connection (after caller has written output)
+bool CeCosSocket::ConnectSocketToSerial (CeCosSocket &socket,CeCosSerial &serial,FilterFunc *pSerialToSocketFilterFunc/*=0*/,void *pSerialParam/*=0*/,FilterFunc *pSocketToSerialFilterFunc/*=0*/,void *pSocketParam/*=0*/,bool *pbStop/*=0*/)
+{
+  serial.ClearError();
+  enum {BUFSIZE=8192};
+  void *pBuf=malloc(BUFSIZE);
+  TRACE(_T("ConnectSocketToSerial: connected\n"));
+  bool rc=true;
+  try {
+  /*
+  { //hack
+  unsigned int nWritten;//hack
+  serial.Write(_T("+"),1,nWritten);//hack
+  }//hack
+    */
+    while(rc && (0==pbStop || !(*pbStop))){
+      unsigned int nRead=0;
+      switch(SSRead (serial,socket,pBuf,BUFSIZE,nRead,pbStop)){
+      case SS_SERIAL_READ: 
+        VTRACE(_T("Serial:%d\n"),nRead);
+        if(pSerialToSocketFilterFunc){
+          rc=pSerialToSocketFilterFunc(pBuf,nRead,serial,socket,pSerialParam);
+        }
+        if(nRead && !socket.send(pBuf,nRead)){
+          TRACE(_T("Failed to write to socket\n"));
+          rc=false;
+        }
+        break;
+      case SS_SOCKET_READ:
+        unsigned int nWritten;
+        VTRACE(_T("Socket:%d\n"),nRead);
+        if(pSocketToSerialFilterFunc){
+          rc=pSocketToSerialFilterFunc(pBuf,nRead,serial,socket,pSocketParam);
+        }
+        {
+          LPTSTR c=(LPTSTR )pBuf;
+          int nToWrite=nRead;
+          while(nToWrite>0){
+            if(!serial.Write(pBuf,nRead,nWritten)){
+              TRACE(_T("Failed to write to serial\n"));
+              rc=false;
+              break;
+            }
+            nToWrite-=nWritten;
+            c+=nWritten;
+          }
+        }
+        break;
+      // Error conditions:
+      case SS_SERIAL_ERROR:
+        TRACE(_T("SSRead serial error - %s\n"),(LPCTSTR)serial.ErrString());
+        rc=false;
+        break;
+      case SS_SOCKET_ERROR:
+        TRACE(_T("SSRead socket error - %s\n"),(LPCTSTR)socket.SocketErrString());
+        rc=false;
+        break;
+      case SS_STOPPED:
+        TRACE(_T("SSRead stopped\n"));
+        rc=false;
+        break;
+      }
+    }
+  }
+  catch (...){
+    ERROR(_T("!!! ConnectSocketToSerial exception caught!!!\n"));
+    free(pBuf);
+    throw;
+  }
+  free(pBuf);
+  return rc;
+}
+
+// Connect two tcp/ip ports together.
+// Traffic is passed through pFunc, passed parameter pParam.
+// The pFunc function:
+//    may reallocate pBuf (using malloc/realloc etc...)
+//    must leave pBuf allocated on exit
+//    should not close either serial or socket
+//    should leave writing to its caller
+//    should return false if it wishes to terminate the connection (after caller has written output)
+bool CeCosSocket::ConnectSocketToSocket (CeCosSocket &o,FilterFunc *pSocketToSocketFilterFunc1,FilterFunc *pSocketToSocketFilterFunc2,void *pParam,bool *pbStop)
+{
+  enum {BUFSIZE=8192};
+  void *pBuf=malloc(BUFSIZE);
+  TRACE(_T("ConnectSocketToSocket: connected\n"));
+  bool rc=true;
+  try {
+    while(rc && (0==pbStop || !(*pbStop))){
+      fd_set set;
+      FD_ZERO(&set);
+      FD_SET((unsigned)m_nSock, &set);
+      FD_SET((unsigned)o.m_nSock, &set);
+      struct timeval tv;
+      tv.tv_sec = 1;
+      tv.tv_usec = 0;
+      switch(::select(m_nSock,&set,0,0,&tv)){
+      case -1:
+        rc=false;
+        break;
+      case 1:
+      case 2:
+        {
+          unsigned int nAvail=0;
+          if(FD_ISSET((unsigned)m_nSock, &set) && Peek(nAvail) && recv(pBuf,nAvail)){
+            //rc=pSocketToSocketFilterFunc1(pBuf,nAvail,socket,this,o);
+            o.send(pBuf,nAvail);
+          }
+          if(FD_ISSET((unsigned)o.m_nSock, &set) && o.Peek(nAvail) && o.recv(pBuf,nAvail)){
+            //rc=pSocketToSocketFilterFunc2(pBuf,nAvail,socket,o,this);
+            send(pBuf,nAvail);
+          }
+        }
+      case 0:
+        break;
+      }
+    }
+  }
+  catch (...){
+    TRACE(_T("!!! ConnectSocketToSocket exception caught!!!\n"));
+    rc=false;
+  }
+  free(pBuf);
+  return rc;
+}
+
+bool CeCosSocket::ConnectSocketToSerial (
+                                         int nListenSock,LPCTSTR pszPort, int nBaud,
+                                         FilterFunc *pSerialToSocketFilterFunc/*=0*/,void *pSerialParam/*=0*/,FilterFunc *pSocketToSerialFilterFunc/*=0*/,void *pSocketParam/*=0*/,
+                                         bool *pbStop)
+{
+  bool rc=false;
+  try{
+    TRACE(_T("ConnectSocketToSerial : socket %d <--> %s\n"),nListenSock,pszPort);
+    
+    CeCosSerial serial;
+    serial.SetBlockingReads(false);
+    // Open serial device.
+    if (!serial.Open(pszPort,nBaud)){
+      ERROR(_T("Couldn't open port %s\n"),pszPort);
+    } else {
+      // Flush the serial buffer.
+      serial.Flush();
+      
+      TRACE(_T("ConnectSocketToSerial: waiting for connection...\n"));
+      CeCosSocket socket;
+      if(!socket.Accept(nListenSock,pbStop)){
+        ERROR(_T("ConnectSocketToSerial - couldn't accept\n"));
+      } else {    
+        rc=ConnectSocketToSerial (socket,serial,pSerialToSocketFilterFunc,pSerialParam,pSocketToSerialFilterFunc,pSocketParam,pbStop);
+      }
+    }
+    TRACE(_T("ConnectSocketToSerial : done\n"));
+  }
+  catch(...){
+    TRACE(_T("ConnectSocketToSerial !!!exception handled!!!\n"));
+  }
+  return rc;
+}
+
+String CeCosSocket::ClientName(int nClient) 
+{
+  char ip[4];
+  memcpy(ip,&nClient,4);
+  struct hostent *he=::gethostbyaddr((const char *)ip,4,AF_INET);
+  String str;
+  if(he){
+    str=String::CStrToUnicodeStr(he->h_name);
+  } else {
+    str.Format(_T("%u.%u.%u.%u"),ip[0],ip[1],ip[2],ip[3]);
+  }
+  return str;
+}
+
+String CeCosSocket::HostPort(LPCTSTR pszHost,int nPort) 
+{
+  String str;
+  str.Format(_T("%s:%d"),pszHost,nPort);
+  return str;
+}
+
+// Split the string into host:port parts.  Result tells us whether it was successful.
+bool CeCosSocket::ParseHostPort (LPCTSTR pszHostPort, String &strHost, int &nPort)
+{
+  int n=_stscanf(pszHostPort,_T("%[^:]:%d"),strHost.GetBuffer(_tcslen(pszHostPort)),&nPort);
+  strHost.ReleaseBuffer();
+  return 2==n && nPort>0 && nPort<=0xffff;
+}
+
+// Is the string in the form host:port?
+bool CeCosSocket::IsLegalHostPort (LPCTSTR pszHostPort)
+{
+  int nPort=0;
+  String strHost;
+  return ParseHostPort(pszHostPort,strHost,nPort);
+}
+
+// Translate a timeout that may be one of the special values DEFAULTTIMEOUT or NOTIMEOUT to a value in milliseconds.
+Duration CeCosSocket::TimeoutDuration(Duration dTimeout)
+{
+  switch(dTimeout){
+  case DEFAULTTIMEOUT:
+    dTimeout=m_nDefaultTimeout;
+    break;
+  case NOTIMEOUT:
+    dTimeout=0x7fffffff;
+    break;
+  default:
+    break;
+  }
+  return dTimeout;
+}
+
+String CeCosSocket::SocketErrString() { 
+  return SocketErrString(m_nErr); 
+}
+
+
+bool CeCosSocket::SameHost(LPCTSTR host1, LPCTSTR host2)
+{
+  return 0==_tcscmp(host1,host2) || (GetHostByName(host1)==GetHostByName(host2));
+}
+
+bool CeCosSocket::Init()
+{
+#ifdef _WIN32
+  WSADATA wsaData;
+  WORD wVersionRequested = MAKEWORD( 2, 0 ); 
+  WSAStartup( wVersionRequested, &wsaData );
+#endif
+  return true;
+}
+
+void CeCosSocket::Term()
+{
+#ifdef _WIN32
+  WSACleanup();
+#endif
+}
+
+LPCTSTR CeCosSocket::MyHostName()
+{
+  static String str;
+  if(str.empty()){
+    char szMyname[256];
+    if(0==gethostname(szMyname,sizeof szMyname)){
+      str=String::CStrToUnicodeStr(szMyname);
+    }
+  }
+  return str;
+}
+
+LPCTSTR CeCosSocket::MySimpleHostName()
+{
+  static String str;
+  if(str.empty()){
+    str=MyHostName();
+    // Remove all after a '.'
+    LPCTSTR c=_tcschr(str,_TCHAR('.'));
+    if(c){
+      str.resize(c-(LPCTSTR)str);
+    }
+  }
+  return str;
+}
+
+const String CeCosSocket::GetHostByName(LPCTSTR pszHost)
+{
+  typedef std::map<String,String> MapStringToString;
+  static MapStringToString hostmap;
+  MapStringToString::iterator it=hostmap.find(pszHost);
+  if(hostmap.end()==it){
+    char *h=0; // avoid erroneous gcc warning message
+    h=String(pszHost).GetCString();
+    char ip[16];
+    struct hostent* host_dat;
+    if (0!=(host_dat=::gethostbyname(h))){
+      char *c=inet_ntoa( *( (struct in_addr *)host_dat->h_addr_list[0] )  );
+      if(c){
+        strcpy(ip,c);
+        hostmap[pszHost]=String::CStrToUnicodeStr(ip);
+      }
+    }
+    delete [] h;
+    return String::CStrToUnicodeStr(ip);
+  } else {
+    return it->second;
+  }
+}