]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - tools/src/tools/Utils/common/eCosSocket.cpp
Initial revision
[karo-tx-redboot.git] / tools / src / tools / Utils / common / eCosSocket.cpp
1 //####COPYRIGHTBEGIN####
2 //                                                                          
3 // ----------------------------------------------------------------------------
4 // Copyright (C) 1998, 1999, 2000 Red Hat, Inc.
5 //
6 // This program is part of the eCos host tools.
7 //
8 // This program is free software; you can redistribute it and/or modify it 
9 // under the terms of the GNU General Public License as published by the Free 
10 // Software Foundation; either version 2 of the License, or (at your option) 
11 // any later version.
12 // 
13 // This program is distributed in the hope that it will be useful, but WITHOUT 
14 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
15 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for 
16 // more details.
17 // 
18 // You should have received a copy of the GNU General Public License along with
19 // this program; if not, write to the Free Software Foundation, Inc., 
20 // 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
21 //
22 // ----------------------------------------------------------------------------
23 //                                                                          
24 //####COPYRIGHTEND####
25 //=================================================================
26 //
27 //        eCosSocket.cpp
28 //
29 //        Socket test class
30 //
31 //=================================================================
32 //=================================================================
33 //#####DESCRIPTIONBEGIN####
34 //
35 // Author(s):     sdf
36 // Contributors:  sdf
37 // Date:          1999-04-01
38 // Description:   This class abstracts tcp/ip sockets for use in the testing infrastructure
39 // Usage:
40 //
41 //####DESCRIPTIONEND####
42
43 #include "eCosStd.h"
44 #include "eCosSocket.h"
45 #include "eCosSerial.h"
46 #include "eCosThreadUtils.h"
47 #include "eCosTrace.h"
48 #include <map>
49
50 enum {ERR_TIMEOUT=20000, ERR_READ_AFTER_CLOSE=20001};
51
52 // Blocking read on one or other of the data sources:
53 // Result:  -1 - socket error occurred
54 //           1 - data read from socket
55 //          -2 - serial error occurred
56 //           2 - data read from serial
57
58 CeCosSocket::SSReadResult CeCosSocket::SSRead (CeCosSerial &serial,CeCosSocket &socket,void *pBuf,unsigned int nSize,unsigned int &nRead,bool *pbStop)
59 {
60   SSReadResult rc=SS_STOPPED;
61   bool bBlocking=serial.GetBlockingReads();
62   bool bBlockingModified=false;
63   while(0==pbStop || !(*pbStop)){
64     if(!socket.Peek(nRead)){
65       rc=SS_SOCKET_ERROR;
66       break;
67     } else if(nRead){
68       nRead=MIN(nRead,nSize);
69       rc=socket.recv(pBuf,nRead)?SS_SOCKET_READ:SS_SOCKET_ERROR;
70       break;
71     } else {
72       if(bBlocking){
73         serial.SetBlockingReads(false);
74         bBlockingModified=true;
75         bBlocking=false;
76       }
77       if(serial.Read(pBuf,nSize,nRead)){
78         if(nRead>0){
79           rc=SS_SERIAL_READ;
80           break;
81         }
82       } else {
83         rc=SS_SERIAL_ERROR;
84         break;
85       }
86     }
87     CeCosThreadUtils::Sleep(10);
88   }
89   if(bBlockingModified){
90     serial.SetBlockingReads(true);
91   }
92   return rc;
93 }
94
95 // ctors and dtors
96
97 CeCosSocket::CeCosSocket ():
98 m_nDefaultTimeout(10*1000),
99 m_nSock(-1),
100 m_nClient(0)
101 {
102   VTRACE(_T("Create socket instance %08x\n"),(unsigned int)this);
103 }
104
105 CeCosSocket::CeCosSocket (int sock /*result of previous call of Listen*/, bool *pbStop):
106 m_nDefaultTimeout(10*1000),
107 m_nSock(-1),
108 m_nClient(0)
109 {
110   VTRACE(_T("Create socket instance %08x\n"),(unsigned int)this);
111   Accept(sock,pbStop);
112 }
113
114 CeCosSocket::CeCosSocket (LPCTSTR pszHostPort,Duration dTimeout):
115 m_nDefaultTimeout(10*1000),
116 m_nSock(-1),
117 m_nClient(0)
118 {
119   VTRACE(_T("Create socket instance %08x\n"),(unsigned int)this);
120   Connect(pszHostPort,dTimeout);
121 }
122
123 bool CeCosSocket::Accept(int sock /*result of previous call of Listen*/, bool *pbStop)
124 {
125   m_nSock=-1;
126   while(0==pbStop||!*pbStop){
127     struct sockaddr cli_addr;
128 #ifndef _WIN32
129     unsigned 
130 #endif
131       int clilen=sizeof(struct sockaddr);
132     m_nSock=::accept(sock, (struct sockaddr *) &cli_addr, &clilen);
133     SaveError();
134     if(-1==m_nSock){ 
135       if(WOULDBLOCK==SocketError()){
136         CeCosThreadUtils::Sleep(100);
137         continue;
138       }
139     } else {
140       memcpy(&m_nClient,cli_addr.sa_data+2,4);
141       TRACE(_T("Connection accepted from %s - socket %d\n"),(LPCTSTR )ClientName(m_nClient),m_nSock);
142       SetSocketOptions();
143       break;
144     }
145   } 
146   return -1!=m_nSock;
147 }
148
149 int CeCosSocket::Listen(int nTcpPort)
150 {
151   // Create socket
152   int sock=::socket(AF_INET, SOCK_STREAM, 0);
153   if (sock == -1) {
154     ERROR(_T("Couldn't create socket\n"));
155   } else {
156     VTRACE(_T("Created socket %d listening on port %d\n"),sock,nTcpPort);
157     // Bind socket to address
158     struct sockaddr_in serv_addr;
159     memset(&serv_addr, 0, sizeof serv_addr);
160     
161     serv_addr.sin_family = AF_INET;
162     serv_addr.sin_port=htons((short)nTcpPort);
163     serv_addr.sin_addr.s_addr = INADDR_ANY;
164     
165     if (::bind(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) == -1) {
166       TRACE(_T("Couldn't bind socket on port %d\n"),nTcpPort);
167       CloseSocket(sock);
168     } else if (-1==::listen(sock, SOMAXCONN)){
169       CloseSocket(sock);
170       TRACE(_T("socket error on listen - port %d\n"),nTcpPort);
171     } else {
172 #ifdef _WIN32
173       int nTrue=1;
174       bool rc=(0==::ioctlsocket(sock, FIONBIO, (unsigned long *)&nTrue));
175 #else //UNIX
176       int flags=::fcntl(sock,F_GETFL);
177       flags|=O_NONBLOCK;
178       bool rc=(0==::fcntl (sock, F_SETFL, flags));
179 #endif
180       if(!rc){
181         TRACE(_T("Failed to set socket options on socket %d\n"),sock);
182       }
183     }
184   }
185   return sock;
186 }
187
188 bool CeCosSocket::Connect(LPCTSTR pszHostPort,Duration dTimeout)
189 {
190   dTimeout=TimeoutDuration(dTimeout);
191   struct sockaddr_in serv_addr;
192   
193   VTRACE(_T("Connect: %s timeout=%d\n"),pszHostPort,dTimeout);
194   
195   // Get the target host address
196   String strHost;
197   int nPort;
198   CeCosSocket::ParseHostPort(pszHostPort,strHost,nPort);
199   String strErr;
200
201   char *ip=GetHostByName(strHost).GetCString();
202   memset(&serv_addr, 0, sizeof serv_addr);
203   // Create socket
204   m_nSock = ::socket(AF_INET, SOCK_STREAM, 0);
205   if (-1 == m_nSock) {
206     TRACE(_T("Could not create socket [%s]\n"),pszHostPort);
207   } else {
208 #ifdef _WIN32
209     SetSocketOptions();
210 #endif
211     VTRACE(_T("Created socket %d connected to %s\n"),m_nSock,pszHostPort);
212     // Bind socket to address
213     serv_addr.sin_family = AF_INET;
214     serv_addr.sin_port=htons((short)nPort);
215     SaveError();
216     serv_addr.sin_addr.s_addr = inet_addr(ip);
217     
218     // Connect to server
219     VTRACE(_T("Connect() : connecting to server\n"));
220     int cc=::connect(m_nSock, (struct sockaddr *) &serv_addr, sizeof(serv_addr));
221     SaveError();
222     String strMsg;
223     if(-1==cc){
224       if(
225 #ifdef _WIN32
226         WOULDBLOCK==SocketError()
227 #else // UNIX
228         EINPROGRESS==SocketError()
229 #endif
230         ){
231         // Allow dTimeout milliseconds for connect to complete
232         fd_set set;
233         FD_ZERO(&set);
234 #ifdef _WIN32
235 #pragma warning( push )
236 #pragma warning( disable : 4127 ) // conditional expression is constant
237 #endif
238         FD_SET((unsigned)m_nSock, &set);
239 #ifdef _WIN32
240 #pragma warning( pop )
241 #endif
242         struct timeval tv;
243         tv.tv_sec = dTimeout/1000;  
244         tv.tv_usec = 1000*(dTimeout % 1000);
245         switch(::select(m_nSock, NULL, &set , NULL, &tv)){
246         case 0:
247           m_nErr=ERR_TIMEOUT;
248           strMsg.Format(_T("attempt timed out after %d seconds"),dTimeout/1000);
249           break;
250         case -1:
251           SaveError();
252           strMsg=SocketErrString();
253           break;
254         default:
255           cc=0;
256         }
257       } else {
258         strMsg=SocketErrString();
259       }
260     }
261     
262     if(-1==cc){
263       TRACE(_T("Could not connect to %s - %s\n"),pszHostPort,(LPCTSTR)strMsg);
264       CloseSocket(m_nSock);
265     }  else {
266 #ifndef _WIN32
267       SetSocketOptions();
268 #endif
269     }
270   }
271   delete [] ip;
272   return -1!=m_nSock;
273 }
274
275 bool CeCosSocket::sendrecv(bool bSend,const void *pData,unsigned int nLength,
276                            LPCTSTR pszMsg,Duration dTimeout,CeCosSocket::StopFunc pFnStop,void *pParam)
277 {
278   
279   dTimeout=TimeoutDuration(dTimeout);
280   
281   LPCTSTR pszSR=(bSend?_T("sending"):_T("receiving"));
282   LPTSTR c=(LPTSTR )pData;
283   Time ft0=Now();
284   int nTodo=nLength;
285   while((nTodo>0) && ((0==pFnStop) || (!pFnStop(pParam)))){
286     int s=bSend?::send(m_nSock, (const char *)c, nTodo, 0): ::recv(m_nSock, (char *)c, nTodo, 0);
287     if(0==s && !bSend){
288       m_nErr=ERR_READ_AFTER_CLOSE;
289     } else {
290       SaveError();
291     }
292     if(-1==s && WOULDBLOCK==SocketError()){
293       Duration d=Duration(Now()-ft0);
294       if(d>dTimeout){
295         TRACE(_T("%d/%d mSec timeout on socket %d %s %s - processed %d/%d bytes\n") ,
296           d,dTimeout,m_nSock,pszSR,pszMsg, 
297           nLength-nTodo,nLength);
298         m_nErr=ERR_TIMEOUT;
299         break;
300       }
301       CeCosThreadUtils::Sleep(100);
302     } else if (s>0) {
303       c+=s;
304       nTodo-=s;
305       ft0=Now();
306     } else {
307       TRACE(_T("Error on socket %d %s %s - %s\n") ,m_nSock, pszSR, pszMsg, (LPCTSTR )SocketErrString());
308       break;
309     }
310   }
311   return 0==nTodo;
312 }
313
314 // Graceful socket closedown
315 CeCosSocket::~CeCosSocket()
316 {
317   Close();
318   VTRACE(_T("Delete socket instance %08x\n"),(unsigned int)this);
319 }
320
321 bool CeCosSocket::CloseSocket(int &sock)
322 {
323   bool rc=false;
324   if(-1!=sock){
325     VTRACE(_T("Closing socket %d\n"),sock);
326     try{
327       shutdown(sock,0);// SD_BOTH
328 #ifdef _WIN32
329       rc=(0==closesocket(sock));
330 #else // UNIX
331       rc=(0==close(sock));
332 #endif
333     }
334     catch(...) {
335       TRACE(_T("!!! Exception caught in CeCosSocket::CloseSocket!!!\n"));
336     }
337     sock=-1;
338   }
339   return rc;
340 }
341
342 bool CeCosSocket::SetSocketOptions()
343 {
344   bool rc;
345 #ifdef _WIN32
346   int nTrue=1;
347   rc=(0==::ioctlsocket(m_nSock, FIONBIO, (unsigned long *)&nTrue));
348   SaveError();
349 #else // UNIX
350   int flags=::fcntl(m_nSock,F_GETFL);
351   SaveError();
352   flags|=O_NONBLOCK;
353   rc=(0==::fcntl (m_nSock, F_SETFL, flags));
354   SaveError();
355 #endif
356   int bLinger=0;
357   setsockopt(m_nSock,SOL_SOCKET,SO_LINGER,(const char *)&bLinger, sizeof(bLinger));
358   if(!rc){
359     TRACE(_T("Failed to set socket options socket %d - %s\n"),m_nSock,(LPCTSTR )SocketErrString());
360   }
361   return rc;
362 }
363
364 String CeCosSocket::SocketErrString(int nErr)
365 {
366   String str;
367 #ifdef _WIN32
368   switch(nErr){
369   case ERR_TIMEOUT: str=_T("Read operation timed out");break;
370   case ERR_READ_AFTER_CLOSE: str=_T("Read operation after socket closed");break;
371     
372   case WSAEACCES: str=_T("Permission denied");break;
373   case WSAEADDRINUSE: str=_T("Address already in use");break;
374   case WSAEADDRNOTAVAIL: str=_T("Cannot assign requested address");break;
375   case WSAEAFNOSUPPORT: str=_T("Address family not supported by protocol family");break;
376   case WSAEALREADY: str=_T("Operation already in progress");break;
377   case WSAECONNABORTED: str=_T("Software caused connection abort");break;
378   case WSAECONNREFUSED: str=_T("Connection refused");break;
379   case WSAECONNRESET: str=_T("Connection reset by peer");break;
380   case WSAEDESTADDRREQ: str=_T("Destination address required");break;
381   case WSAEFAULT: str=_T("Bad address");break;
382   case WSAEHOSTDOWN: str=_T("Host is down");break;
383   case WSAEHOSTUNREACH: str=_T("No route to host");break;
384   case WSAEINPROGRESS: str=_T("Operation now in progress");break;
385   case WSAEINTR: str=_T("Interrupted function call");break;
386   case WSAEINVAL: str=_T("Invalid argument");break;
387   case WSAEISCONN: str=_T("Socket is already connected");break;
388   case WSAEMFILE: str=_T("Too many open files");break;
389   case WSAEMSGSIZE: str=_T("Message too long");break;
390   case WSAENETDOWN: str=_T("Network is down");break;
391   case WSAENETRESET: str=_T("Network dropped connection on reset");break;
392   case WSAENETUNREACH: str=_T("Network is unreachable");break;
393   case WSAENOBUFS: str=_T("No buffer space available");break;
394   case WSAENOPROTOOPT: str=_T("Bad protocol option");break;
395   case WSAENOTCONN: str=_T("Socket is not connected");break;
396   case WSAENOTSOCK: str=_T("Socket operation on non-socket");break;
397   case WSAEOPNOTSUPP: str=_T("Operation not supported");break;
398   case WSAEPFNOSUPPORT: str=_T("Protocol family not supported");break;
399   case WSAEPROCLIM: str=_T("Too many processes");break;
400   case WSAEPROTONOSUPPORT: str=_T("Protocol not supported");break;
401   case WSAEPROTOTYPE: str=_T("Protocol wrong type for socket");break;
402   case WSAESHUTDOWN: str=_T("Cannot send after socket shutdown");break;
403   case WSAESOCKTNOSUPPORT: str=_T("Socket type not supported");break;
404   case WSAETIMEDOUT: str=_T("Connection timed out");break;
405   case WSATYPE_NOT_FOUND: str=_T("Class type not found");break;
406   case WSAEWOULDBLOCK: str=_T("Resource temporarily unavailable");break;
407   case WSAHOST_NOT_FOUND: str=_T("Host not found");break;
408   case WSA_INVALID_HANDLE: str=_T("Specified event object handle is invalid");break;
409   case WSA_INVALID_PARAMETER: str=_T("One or more parameters are invalid");break;
410     //case WSAINVALIDPROCTABLE: str=_T("Invalid procedure table from service provider");break;
411     //case WSAINVALIDPROVIDER: str=_T("Invalid service provider version number");break;
412   case WSA_IO_INCOMPLETE: str=_T("Overlapped I/O event object not in signaled state");break;
413   case WSA_IO_PENDING: str=_T("Overlapped operations will complete later");break;
414   case WSA_NOT_ENOUGH_MEMORY: str=_T("Insufficient memory available");break;
415   case WSANOTINITIALISED: str=_T("Successful case WSAStartup not yet:performed");break;
416   case WSANO_DATA: str=_T("Valid name, no data record of requested type");break;
417   case WSANO_RECOVERY: str=_T("This is a non-recoverable error");break;
418     //case WSAPROVIDERFAILEDINIT: str=_T("Unable to initialize a service provider");break;
419   case WSASYSCALLFAILURE: str=_T("System call failure");break;
420   case WSASYSNOTREADY: str=_T("Network subsystem is unavailable");break;
421   case WSATRY_AGAIN: str=_T("Non-authoritative host not found");break;
422   case WSAVERNOTSUPPORTED: str=_T("WINSOCK.DLL version out of range");break;
423   case WSAEDISCON: str=_T("Graceful shutdown in progress");break;
424   case WSA_OPERATION_ABORTED: str=_T("Overlapped operation aborted");break;
425   default:
426     str.Format(_T("Unknown error %d (0x%08x)"),nErr,nErr);
427   }
428 #else // UNIX
429   switch(nErr){
430   case ERR_TIMEOUT: str=_T("Read operation timed out");break;
431   case ERR_READ_AFTER_CLOSE: str=_T("Read operation after socket closed");break;
432   default:
433     str=strerror(errno);
434   }
435 #endif
436   return str;
437 }
438
439 bool CeCosSocket::sendInteger(int n,LPCTSTR pszMsg,Duration dTimeout)
440 {
441   // This has to support cross-architectural endianness
442   unsigned char c[sizeof(int)];
443   for(unsigned int i=0;i<sizeof(int);i++){
444     c[i]=(unsigned char)(n&0xff);
445     n>>=8;
446   }
447   return send (c, sizeof(int),pszMsg,dTimeout);
448 }
449
450 bool CeCosSocket::recvInteger(int & n,LPCTSTR pszMsg,Duration dTimeout)
451 {
452   // This has to support cross-architectural endianness
453   unsigned char c[sizeof(int)];
454   bool rc=recv (c, sizeof(int),pszMsg,dTimeout);
455   n=0;
456   if(rc){
457     for(int i=sizeof(int)-1;i>=0;--i){
458       n<<=8;
459       n|=c[i];
460     }
461   }
462   return rc;
463 }
464
465 // Socket communications for strings are always non-UNICODE:
466 bool CeCosSocket::recvString  (String &str,LPCTSTR pszMsg,Duration dTimeout)
467 {
468   int nLength;
469   bool rc=false;
470   if(recvInteger(nLength,pszMsg,dTimeout)){
471     if(0==nLength){
472       rc=true;
473     } else {
474       Buffer b(1+nLength);
475       char *c=(char *)b.Data();
476       if(c){
477         rc=recv(c,nLength,pszMsg,dTimeout);
478         c[nLength]='\0';
479         str=String::CStrToUnicodeStr(c);
480       }
481     }
482   }
483   return rc;
484 }
485
486 // Socket communications for strings are always non-UNICODE:
487 bool CeCosSocket::sendString  (const String &str,LPCTSTR pszMsg,Duration dTimeout)
488 {
489   char *psz=str.GetCString();
490   int nLength=strlen(psz); 
491   bool rc=sendInteger(nLength,pszMsg,dTimeout) && (0==nLength || send(psz,nLength,pszMsg,dTimeout));
492   delete [] psz;
493   return rc;
494 }
495
496
497 // Give indication of bytes available to be read (but don't read them)
498 bool CeCosSocket::Peek (unsigned int &nAvail)
499 {
500   char buf[8192];
501   int n=::recv(m_nSock, buf, sizeof buf, MSG_PEEK);
502   nAvail=0;
503   bool rc=false;
504   switch(n) {
505   case -1:
506     SaveError();
507     if(WOULDBLOCK==SocketError()){
508       rc=true; // nAvail stays==0
509     } else {
510       ERROR(_T("Peek: err=%d %s\n"),SocketError(),(LPCTSTR)SocketErrString());
511     }
512     break;
513   case 0:
514     m_nErr=ERR_READ_AFTER_CLOSE;
515     break;
516   default:
517     rc=true;
518     nAvail=n;
519   }
520   return rc;
521 }
522
523 // Connect tcp/ip port and serial port together.
524 // Traffic is passed through pFunc, passed parameter pParam.
525 // The pFunc function:
526 //    may reallocate pBuf (using malloc/realloc etc...)
527 //    must leave pBuf allocated on exit
528 //    should not close either serial or socket
529 //    should leave writing to its caller
530 //    should return false if it wishes to terminate the connection (after caller has written output)
531 bool CeCosSocket::ConnectSocketToSerial (CeCosSocket &socket,CeCosSerial &serial,FilterFunc *pSerialToSocketFilterFunc/*=0*/,void *pSerialParam/*=0*/,FilterFunc *pSocketToSerialFilterFunc/*=0*/,void *pSocketParam/*=0*/,bool *pbStop/*=0*/)
532 {
533   serial.ClearError();
534   enum {BUFSIZE=8192};
535   void *pBuf=malloc(BUFSIZE);
536   TRACE(_T("ConnectSocketToSerial: connected\n"));
537   bool rc=true;
538   try {
539   /*
540   { //hack
541   unsigned int nWritten;//hack
542   serial.Write(_T("+"),1,nWritten);//hack
543   }//hack
544     */
545     while(rc && (0==pbStop || !(*pbStop))){
546       unsigned int nRead=0;
547       switch(SSRead (serial,socket,pBuf,BUFSIZE,nRead,pbStop)){
548       case SS_SERIAL_READ: 
549         VTRACE(_T("Serial:%d\n"),nRead);
550         if(pSerialToSocketFilterFunc){
551           rc=pSerialToSocketFilterFunc(pBuf,nRead,serial,socket,pSerialParam);
552         }
553         if(nRead && !socket.send(pBuf,nRead)){
554           TRACE(_T("Failed to write to socket\n"));
555           rc=false;
556         }
557         break;
558       case SS_SOCKET_READ:
559         unsigned int nWritten;
560         VTRACE(_T("Socket:%d\n"),nRead);
561         if(pSocketToSerialFilterFunc){
562           rc=pSocketToSerialFilterFunc(pBuf,nRead,serial,socket,pSocketParam);
563         }
564         {
565           LPTSTR c=(LPTSTR )pBuf;
566           int nToWrite=nRead;
567           while(nToWrite>0){
568             if(!serial.Write(pBuf,nRead,nWritten)){
569               TRACE(_T("Failed to write to serial\n"));
570               rc=false;
571               break;
572             }
573             nToWrite-=nWritten;
574             c+=nWritten;
575           }
576         }
577         break;
578       // Error conditions:
579       case SS_SERIAL_ERROR:
580         TRACE(_T("SSRead serial error - %s\n"),(LPCTSTR)serial.ErrString());
581         rc=false;
582         break;
583       case SS_SOCKET_ERROR:
584         TRACE(_T("SSRead socket error - %s\n"),(LPCTSTR)socket.SocketErrString());
585         rc=false;
586         break;
587       case SS_STOPPED:
588         TRACE(_T("SSRead stopped\n"));
589         rc=false;
590         break;
591       }
592     }
593   }
594   catch (...){
595     ERROR(_T("!!! ConnectSocketToSerial exception caught!!!\n"));
596     free(pBuf);
597     throw;
598   }
599   free(pBuf);
600   return rc;
601 }
602
603 // Connect two tcp/ip ports together.
604 // Traffic is passed through pFunc, passed parameter pParam.
605 // The pFunc function:
606 //    may reallocate pBuf (using malloc/realloc etc...)
607 //    must leave pBuf allocated on exit
608 //    should not close either serial or socket
609 //    should leave writing to its caller
610 //    should return false if it wishes to terminate the connection (after caller has written output)
611 bool CeCosSocket::ConnectSocketToSocket (CeCosSocket &o,FilterFunc *pSocketToSocketFilterFunc1,FilterFunc *pSocketToSocketFilterFunc2,void *pParam,bool *pbStop)
612 {
613   enum {BUFSIZE=8192};
614   void *pBuf=malloc(BUFSIZE);
615   TRACE(_T("ConnectSocketToSocket: connected\n"));
616   bool rc=true;
617   try {
618     while(rc && (0==pbStop || !(*pbStop))){
619       fd_set set;
620       FD_ZERO(&set);
621       FD_SET((unsigned)m_nSock, &set);
622       FD_SET((unsigned)o.m_nSock, &set);
623       struct timeval tv;
624       tv.tv_sec = 1;
625       tv.tv_usec = 0;
626       switch(::select(m_nSock,&set,0,0,&tv)){
627       case -1:
628         rc=false;
629         break;
630       case 1:
631       case 2:
632         {
633           unsigned int nAvail=0;
634           if(FD_ISSET((unsigned)m_nSock, &set) && Peek(nAvail) && recv(pBuf,nAvail)){
635             //rc=pSocketToSocketFilterFunc1(pBuf,nAvail,socket,this,o);
636             o.send(pBuf,nAvail);
637           }
638           if(FD_ISSET((unsigned)o.m_nSock, &set) && o.Peek(nAvail) && o.recv(pBuf,nAvail)){
639             //rc=pSocketToSocketFilterFunc2(pBuf,nAvail,socket,o,this);
640             send(pBuf,nAvail);
641           }
642         }
643       case 0:
644         break;
645       }
646     }
647   }
648   catch (...){
649     TRACE(_T("!!! ConnectSocketToSocket exception caught!!!\n"));
650     rc=false;
651   }
652   free(pBuf);
653   return rc;
654 }
655
656 bool CeCosSocket::ConnectSocketToSerial (
657                                          int nListenSock,LPCTSTR pszPort, int nBaud,
658                                          FilterFunc *pSerialToSocketFilterFunc/*=0*/,void *pSerialParam/*=0*/,FilterFunc *pSocketToSerialFilterFunc/*=0*/,void *pSocketParam/*=0*/,
659                                          bool *pbStop)
660 {
661   bool rc=false;
662   try{
663     TRACE(_T("ConnectSocketToSerial : socket %d <--> %s\n"),nListenSock,pszPort);
664     
665     CeCosSerial serial;
666     serial.SetBlockingReads(false);
667     // Open serial device.
668     if (!serial.Open(pszPort,nBaud)){
669       ERROR(_T("Couldn't open port %s\n"),pszPort);
670     } else {
671       // Flush the serial buffer.
672       serial.Flush();
673       
674       TRACE(_T("ConnectSocketToSerial: waiting for connection...\n"));
675       CeCosSocket socket;
676       if(!socket.Accept(nListenSock,pbStop)){
677         ERROR(_T("ConnectSocketToSerial - couldn't accept\n"));
678       } else {    
679         rc=ConnectSocketToSerial (socket,serial,pSerialToSocketFilterFunc,pSerialParam,pSocketToSerialFilterFunc,pSocketParam,pbStop);
680       }
681     }
682     TRACE(_T("ConnectSocketToSerial : done\n"));
683   }
684   catch(...){
685     TRACE(_T("ConnectSocketToSerial !!!exception handled!!!\n"));
686   }
687   return rc;
688 }
689
690 String CeCosSocket::ClientName(int nClient) 
691 {
692   char ip[4];
693   memcpy(ip,&nClient,4);
694   struct hostent *he=::gethostbyaddr((const char *)ip,4,AF_INET);
695   String str;
696   if(he){
697     str=String::CStrToUnicodeStr(he->h_name);
698   } else {
699     str.Format(_T("%u.%u.%u.%u"),ip[0],ip[1],ip[2],ip[3]);
700   }
701   return str;
702 }
703
704 String CeCosSocket::HostPort(LPCTSTR pszHost,int nPort) 
705 {
706   String str;
707   str.Format(_T("%s:%d"),pszHost,nPort);
708   return str;
709 }
710
711 // Split the string into host:port parts.  Result tells us whether it was successful.
712 bool CeCosSocket::ParseHostPort (LPCTSTR pszHostPort, String &strHost, int &nPort)
713 {
714   int n=_stscanf(pszHostPort,_T("%[^:]:%d"),strHost.GetBuffer(_tcslen(pszHostPort)),&nPort);
715   strHost.ReleaseBuffer();
716   return 2==n && nPort>0 && nPort<=0xffff;
717 }
718
719 // Is the string in the form host:port?
720 bool CeCosSocket::IsLegalHostPort (LPCTSTR pszHostPort)
721 {
722   int nPort=0;
723   String strHost;
724   return ParseHostPort(pszHostPort,strHost,nPort);
725 }
726
727 // Translate a timeout that may be one of the special values DEFAULTTIMEOUT or NOTIMEOUT to a value in milliseconds.
728 Duration CeCosSocket::TimeoutDuration(Duration dTimeout)
729 {
730   switch(dTimeout){
731   case DEFAULTTIMEOUT:
732     dTimeout=m_nDefaultTimeout;
733     break;
734   case NOTIMEOUT:
735     dTimeout=0x7fffffff;
736     break;
737   default:
738     break;
739   }
740   return dTimeout;
741 }
742
743 String CeCosSocket::SocketErrString() { 
744   return SocketErrString(m_nErr); 
745 }
746
747
748 bool CeCosSocket::SameHost(LPCTSTR host1, LPCTSTR host2)
749 {
750   return 0==_tcscmp(host1,host2) || (GetHostByName(host1)==GetHostByName(host2));
751 }
752
753 bool CeCosSocket::Init()
754 {
755 #ifdef _WIN32
756   WSADATA wsaData;
757   WORD wVersionRequested = MAKEWORD( 2, 0 ); 
758   WSAStartup( wVersionRequested, &wsaData );
759 #endif
760   return true;
761 }
762
763 void CeCosSocket::Term()
764 {
765 #ifdef _WIN32
766   WSACleanup();
767 #endif
768 }
769
770 LPCTSTR CeCosSocket::MyHostName()
771 {
772   static String str;
773   if(str.empty()){
774     char szMyname[256];
775     if(0==gethostname(szMyname,sizeof szMyname)){
776       str=String::CStrToUnicodeStr(szMyname);
777     }
778   }
779   return str;
780 }
781
782 LPCTSTR CeCosSocket::MySimpleHostName()
783 {
784   static String str;
785   if(str.empty()){
786     str=MyHostName();
787     // Remove all after a '.'
788     LPCTSTR c=_tcschr(str,_TCHAR('.'));
789     if(c){
790       str.resize(c-(LPCTSTR)str);
791     }
792   }
793   return str;
794 }
795
796 const String CeCosSocket::GetHostByName(LPCTSTR pszHost)
797 {
798   typedef std::map<String,String> MapStringToString;
799   static MapStringToString hostmap;
800   MapStringToString::iterator it=hostmap.find(pszHost);
801   if(hostmap.end()==it){
802     char *h=0; // avoid erroneous gcc warning message
803     h=String(pszHost).GetCString();
804     char ip[16];
805     struct hostent* host_dat;
806     if (0!=(host_dat=::gethostbyname(h))){
807       char *c=inet_ntoa( *( (struct in_addr *)host_dat->h_addr_list[0] )  );
808       if(c){
809         strcpy(ip,c);
810         hostmap[pszHost]=String::CStrToUnicodeStr(ip);
811       }
812     }
813     delete [] h;
814     return String::CStrToUnicodeStr(ip);
815   } else {
816     return it->second;
817   }
818 }