1 // =============================================================================
2 // PROJECT CHRONO - http://projectchrono.org
3 //
4 // Copyright (c) 2014 projectchrono.org
5 // All rights reserved.
6 //
7 // Use of this source code is governed by a BSD-style license that can be found
8 // in the LICENSE file at the top level of the distribution and at
9 // http://projectchrono.org/license-chrono.txt.
10 //
11 // =============================================================================
12 // Authors: Alessandro Tasora
13 // =============================================================================
14 
15 #define _WINSOCK_DEPRECATED_NO_WARNINGS
16 
17 #include "chrono_cosimulation/ChSocket.h"
18 #include "chrono_cosimulation/ChExceptionSocket.h"
19 
20 namespace chrono {
21 namespace cosimul {
22 
23 const int MSG_HEADER_LEN = 6;
24 
ChSocket(int pNumber)25 ChSocket::ChSocket(int pNumber) {
26     portNumber = pNumber;
27     blocking = 1;
28 
29     try {
30         if ((socketId = (int)socket(AF_INET, SOCK_STREAM, 0)) == -1) {
31 #ifdef WINDOWS_XP
32             int errorCode;
33             std::string errorMsg = "";
34             detectErrorOpenWinSocket(&errorCode, errorMsg);
35             ChExceptionSocket* openWinSocketException = new ChExceptionSocket(errorCode, errorMsg);
36             throw openWinSocketException;
37 #endif
38 
39 #ifdef UNIX
40             ChExceptionSocket* openUnixSocketException = new ChExceptionSocket(0, "unix: error getting host by name");
41             throw openUnixSocketException;
42 #endif
43         }
44     } catch (ChExceptionSocket* excp) {
45         excp->response();
46         delete excp;
47         exit(1);
48     }
49 
50     /*
51        set the initial address of client that shall be communicated with to
52        any address as long as they are using the same port number.
53        The clientAddr structure is used in the future for storing the actual
54        address of client applications with which communication is going
55        to start
56     */
57     clientAddr.sin_family = AF_INET;
58     clientAddr.sin_addr.s_addr = htonl(INADDR_ANY);
59     clientAddr.sin_port = htons(portNumber);
60 }
61 
~ChSocket()62 ChSocket::~ChSocket() {
63 #ifdef WINDOWS_XP
64     closesocket(socketId);
65 #else
66     close(socketId);
67 #endif
68 }
69 
setDebug(int debugToggle)70 void ChSocket::setDebug(int debugToggle) {
71     try {
72         if (setsockopt(socketId, SOL_SOCKET, SO_DEBUG, (char*)&debugToggle, sizeof(debugToggle)) == -1) {
73 #ifdef WINDOWS_XP
74             int errorCode;
75             std::string errorMsg = "DEBUG option:";
76             detectErrorSetSocketOption(&errorCode, errorMsg);
77             ChExceptionSocket* socketOptionException = new ChExceptionSocket(errorCode, errorMsg);
78             throw socketOptionException;
79 #endif
80 
81 #ifdef UNIX
82             ChExceptionSocket* unixSocketOptionException = new ChExceptionSocket(0, "unix: error getting host by name");
83             throw unixSocketOptionException;
84 #endif
85         }
86     } catch (ChExceptionSocket* excp) {
87         excp->response();
88         delete excp;
89         exit(1);
90     }
91 }
92 
setReuseAddr(int reuseToggle)93 void ChSocket::setReuseAddr(int reuseToggle) {
94     try {
95         if (setsockopt(socketId, SOL_SOCKET, SO_REUSEADDR, (char*)&reuseToggle, sizeof(reuseToggle)) == -1) {
96 #ifdef WINDOWS_XP
97             int errorCode;
98             std::string errorMsg = "REUSEADDR option:";
99             detectErrorSetSocketOption(&errorCode, errorMsg);
100             ChExceptionSocket* socketOptionException = new ChExceptionSocket(errorCode, errorMsg);
101             throw socketOptionException;
102 #endif
103 
104 #ifdef UNIX
105             ChExceptionSocket* unixSocketOptionException = new ChExceptionSocket(0, "unix: error getting host by name");
106             throw unixSocketOptionException;
107 #endif
108         }
109     } catch (ChExceptionSocket* excp) {
110         excp->response();
111         delete excp;
112         exit(1);
113     }
114 }
115 
setKeepAlive(int aliveToggle)116 void ChSocket::setKeepAlive(int aliveToggle) {
117     try {
118         if (setsockopt(socketId, SOL_SOCKET, SO_KEEPALIVE, (char*)&aliveToggle, sizeof(aliveToggle)) == -1) {
119 #ifdef WINDOWS_XP
120             int errorCode;
121             std::string errorMsg = "ALIVE option:";
122             detectErrorSetSocketOption(&errorCode, errorMsg);
123             ChExceptionSocket* socketOptionException = new ChExceptionSocket(errorCode, errorMsg);
124             throw socketOptionException;
125 #endif
126 
127 #ifdef UNIX
128             ChExceptionSocket* unixSocketOptionException = new ChExceptionSocket(0, "unix: error getting host by name");
129             throw unixSocketOptionException;
130 #endif
131         }
132     } catch (ChExceptionSocket* excp) {
133         excp->response();
134         delete excp;
135         exit(1);
136     }
137 }
138 
setLingerSeconds(int seconds)139 void ChSocket::setLingerSeconds(int seconds) {
140     struct linger lingerOption;
141 
142     if (seconds > 0) {
143         lingerOption.l_linger = seconds;
144         lingerOption.l_onoff = 1;
145     } else
146         lingerOption.l_onoff = 0;
147 
148     try {
149         if (setsockopt(socketId, SOL_SOCKET, SO_LINGER, (char*)&lingerOption, sizeof(struct linger)) == -1) {
150 #ifdef WINDOWS_XP
151             int errorCode;
152             std::string errorMsg = "LINGER option:";
153             detectErrorSetSocketOption(&errorCode, errorMsg);
154             ChExceptionSocket* socketOptionException = new ChExceptionSocket(errorCode, errorMsg);
155             throw socketOptionException;
156 #endif
157 
158 #ifdef UNIX
159             ChExceptionSocket* unixSocketOptionException = new ChExceptionSocket(0, "unix: error getting host by name");
160             throw unixSocketOptionException;
161 #endif
162         }
163     } catch (ChExceptionSocket* excp) {
164         excp->response();
165         delete excp;
166         exit(1);
167     }
168 }
169 
setLingerOnOff(bool lingerOn)170 void ChSocket::setLingerOnOff(bool lingerOn) {
171     struct linger lingerOption;
172 
173     if (lingerOn)
174         lingerOption.l_onoff = 1;
175     else
176         lingerOption.l_onoff = 0;
177 
178     try {
179         if (setsockopt(socketId, SOL_SOCKET, SO_LINGER, (char*)&lingerOption, sizeof(struct linger)) == -1) {
180 #ifdef WINDOWS_XP
181             int errorCode;
182             std::string errorMsg = "LINGER option:";
183             detectErrorSetSocketOption(&errorCode, errorMsg);
184             ChExceptionSocket* socketOptionException = new ChExceptionSocket(errorCode, errorMsg);
185             throw socketOptionException;
186 #endif
187 
188 #ifdef UNIX
189             ChExceptionSocket* unixSocketOptionException = new ChExceptionSocket(0, "unix: error getting host by name");
190             throw unixSocketOptionException;
191 #endif
192         }
193     } catch (ChExceptionSocket* excp) {
194         excp->response();
195         delete excp;
196         exit(1);
197     }
198 }
199 
setSendBufSize(int sendBufSize)200 void ChSocket::setSendBufSize(int sendBufSize) {
201     try {
202         if (setsockopt(socketId, SOL_SOCKET, SO_SNDBUF, (char*)&sendBufSize, sizeof(sendBufSize)) == -1) {
203 #ifdef WINDOWS_XP
204             int errorCode;
205             std::string errorMsg = "SENDBUFSIZE option:";
206             detectErrorSetSocketOption(&errorCode, errorMsg);
207             ChExceptionSocket* socketOptionException = new ChExceptionSocket(errorCode, errorMsg);
208             throw socketOptionException;
209 #endif
210 
211 #ifdef UNIX
212             ChExceptionSocket* unixSocketOptionException = new ChExceptionSocket(0, "unix: error getting host by name");
213             throw unixSocketOptionException;
214 #endif
215         }
216     } catch (ChExceptionSocket* excp) {
217         excp->response();
218         delete excp;
219         exit(1);
220     }
221 }
222 
setReceiveBufSize(int receiveBufSize)223 void ChSocket::setReceiveBufSize(int receiveBufSize) {
224     try {
225         if (setsockopt(socketId, SOL_SOCKET, SO_RCVBUF, (char*)&receiveBufSize, sizeof(receiveBufSize)) == -1) {
226 #ifdef WINDOWS_XP
227             int errorCode;
228             std::string errorMsg = "RCVBUF option:";
229             detectErrorSetSocketOption(&errorCode, errorMsg);
230             ChExceptionSocket* socketOptionException = new ChExceptionSocket(errorCode, errorMsg);
231             throw socketOptionException;
232 #endif
233 
234 #ifdef UNIX
235             ChExceptionSocket* unixSocketOptionException = new ChExceptionSocket(0, "unix: error getting host by name");
236             throw unixSocketOptionException;
237 #endif
238         }
239     } catch (ChExceptionSocket* excp) {
240         excp->response();
241         delete excp;
242         exit(1);
243     }
244 }
245 
setSocketBlocking(int blockingToggle)246 void ChSocket::setSocketBlocking(int blockingToggle) {
247     if (blockingToggle) {
248         if (getSocketBlocking())
249             return;
250         else
251             blocking = 1;
252     } else {
253         if (!getSocketBlocking())
254             return;
255         else
256             blocking = 0;
257     }
258 
259     try {
260 #ifdef WINDOWS_XP
261         if (ioctlsocket(socketId, FIONBIO, (unsigned long*)&blocking) == -1) {
262             int errorCode;
263             std::string errorMsg = "Blocking option: ";
264             detectErrorSetSocketOption(&errorCode, errorMsg);
265             ChExceptionSocket* socketOptionException = new ChExceptionSocket(errorCode, errorMsg);
266             throw socketOptionException;
267         }
268 #endif
269 
270 #ifdef UNIX
271         if (ioctl(socketId, FIONBIO, (char*)&blocking) == -1) {
272             ChExceptionSocket* unixSocketOptionException = new ChExceptionSocket(0, "unix: error getting host by name");
273             throw unixSocketOptionException;
274         }
275 #endif
276     } catch (ChExceptionSocket* excp) {
277         excp->response();
278         delete excp;
279         exit(1);
280     }
281 }
282 
getDebug()283 int ChSocket::getDebug() {
284     int myOption;
285 #if defined(TARGET_OS_MAC) || defined(UNIX)
286     socklen_t myOptionLen = sizeof(myOption);
287 #else
288     int myOptionLen = sizeof(myOption);
289 #endif
290 
291     try {
292         if (getsockopt(socketId, SOL_SOCKET, SO_DEBUG, (char*)&myOption, &myOptionLen) == -1) {
293 #ifdef WINDOWS_XP
294             int errorCode;
295             std::string errorMsg = "get DEBUG option: ";
296             detectErrorGetSocketOption(&errorCode, errorMsg);
297             ChExceptionSocket* socketOptionException = new ChExceptionSocket(errorCode, errorMsg);
298             throw socketOptionException;
299 #endif
300 
301 #ifdef UNIX
302             ChExceptionSocket* unixSocketOptionException = new ChExceptionSocket(0, "unix: error getting host by name");
303             throw unixSocketOptionException;
304 #endif
305         }
306     } catch (ChExceptionSocket* excp) {
307         excp->response();
308         delete excp;
309         exit(1);
310     }
311 
312     return myOption;
313 }
314 
getReuseAddr()315 int ChSocket::getReuseAddr() {
316     int myOption;
317 #if defined(TARGET_OS_MAC) || defined(UNIX)
318     socklen_t myOptionLen = sizeof(myOption);
319 #else
320     int myOptionLen = sizeof(myOption);
321 #endif
322 
323     try {
324         if (getsockopt(socketId, SOL_SOCKET, SO_REUSEADDR, (char*)&myOption, &myOptionLen) == -1) {
325 #ifdef WINDOWS_XP
326             int errorCode;
327             std::string errorMsg = "get REUSEADDR option: ";
328             detectErrorGetSocketOption(&errorCode, errorMsg);
329             ChExceptionSocket* socketOptionException = new ChExceptionSocket(errorCode, errorMsg);
330             throw socketOptionException;
331 #endif
332 
333 #ifdef UNIX
334             ChExceptionSocket* unixSocketOptionException = new ChExceptionSocket(0, "unix: error getting host by name");
335             throw unixSocketOptionException;
336 #endif
337         }
338     } catch (ChExceptionSocket* excp) {
339         excp->response();
340         delete excp;
341         exit(1);
342     }
343 
344     return myOption;
345 }
346 
getKeepAlive()347 int ChSocket::getKeepAlive() {
348     int myOption;
349 #if defined(TARGET_OS_MAC) || defined(UNIX)
350     socklen_t myOptionLen = sizeof(myOption);
351 #else
352     int myOptionLen = sizeof(myOption);
353 #endif
354 
355     try {
356         if (getsockopt(socketId, SOL_SOCKET, SO_KEEPALIVE, (char*)&myOption, &myOptionLen) == -1) {
357 #ifdef WINDOWS_XP
358             int errorCode;
359             std::string errorMsg = "get KEEPALIVE option: ";
360             detectErrorGetSocketOption(&errorCode, errorMsg);
361             ChExceptionSocket* socketOptionException = new ChExceptionSocket(errorCode, errorMsg);
362             throw socketOptionException;
363 #endif
364 
365 #ifdef UNIX
366             ChExceptionSocket* unixSocketOptionException = new ChExceptionSocket(0, "unix: error getting host by name");
367             throw unixSocketOptionException;
368 #endif
369         }
370     } catch (ChExceptionSocket* excp) {
371         excp->response();
372         delete excp;
373         exit(1);
374     }
375     return myOption;
376 }
377 
getLingerSeconds()378 int ChSocket::getLingerSeconds() {
379     struct linger lingerOption;
380 #if defined(TARGET_OS_MAC) || defined(UNIX)
381     socklen_t myOptionLen = sizeof(struct linger);
382 #else
383     int myOptionLen = sizeof(struct linger);
384 #endif
385 
386     try {
387         if (getsockopt(socketId, SOL_SOCKET, SO_LINGER, (char*)&lingerOption, &myOptionLen) == -1) {
388 #ifdef WINDOWS_XP
389             int errorCode;
390             std::string errorMsg = "get LINER option: ";
391             detectErrorGetSocketOption(&errorCode, errorMsg);
392             ChExceptionSocket* socketOptionException = new ChExceptionSocket(errorCode, errorMsg);
393             throw socketOptionException;
394 #endif
395 
396 #ifdef UNIX
397             ChExceptionSocket* unixSocketOptionException = new ChExceptionSocket(0, "unix: error getting host by name");
398             throw unixSocketOptionException;
399 #endif
400         }
401     } catch (ChExceptionSocket* excp) {
402         excp->response();
403         delete excp;
404         exit(1);
405     }
406 
407     return lingerOption.l_linger;
408 }
409 
getLingerOnOff()410 bool ChSocket::getLingerOnOff() {
411     struct linger lingerOption;
412 #if defined(TARGET_OS_MAC) || defined(UNIX)
413     socklen_t myOptionLen = sizeof(struct linger);
414 #else
415     int myOptionLen = sizeof(struct linger);
416 #endif
417 
418     try {
419         if (getsockopt(socketId, SOL_SOCKET, SO_LINGER, (char*)&lingerOption, &myOptionLen) == -1) {
420 #ifdef WINDOWS_XP
421             int errorCode;
422             std::string errorMsg = "get LINER option: ";
423             detectErrorGetSocketOption(&errorCode, errorMsg);
424             ChExceptionSocket* socketOptionException = new ChExceptionSocket(errorCode, errorMsg);
425             throw socketOptionException;
426 #endif
427 
428 #ifdef UNIX
429             ChExceptionSocket* unixSocketOptionException = new ChExceptionSocket(0, "unix: error getting host by name");
430             throw unixSocketOptionException;
431 #endif
432         }
433     } catch (ChExceptionSocket* excp) {
434         excp->response();
435         delete excp;
436         exit(1);
437     }
438 
439     if (lingerOption.l_onoff == 1)
440         return true;
441     else
442         return false;
443 }
444 
getSendBufSize()445 int ChSocket::getSendBufSize() {
446     int sendBuf;
447 #if defined(TARGET_OS_MAC) || defined(UNIX)
448     socklen_t myOptionLen = sizeof(sendBuf);
449 #else
450     int myOptionLen = sizeof(sendBuf);
451 #endif
452 
453     try {
454         if (getsockopt(socketId, SOL_SOCKET, SO_SNDBUF, (char*)&sendBuf, &myOptionLen) == -1) {
455 #ifdef WINDOWS_XP
456             int errorCode;
457             std::string errorMsg = "get SNDBUF option: ";
458             detectErrorGetSocketOption(&errorCode, errorMsg);
459             ChExceptionSocket* socketOptionException = new ChExceptionSocket(errorCode, errorMsg);
460             throw socketOptionException;
461 #endif
462 
463 #ifdef UNIX
464             ChExceptionSocket* unixSocketOptionException = new ChExceptionSocket(0, "unix: error getting host by name");
465             throw unixSocketOptionException;
466 #endif
467         }
468     } catch (ChExceptionSocket* excp) {
469         excp->response();
470         delete excp;
471         exit(1);
472     }
473     return sendBuf;
474 }
475 
getReceiveBufSize()476 int ChSocket::getReceiveBufSize() {
477     int rcvBuf;
478 #if defined(TARGET_OS_MAC) || defined(UNIX)
479     socklen_t myOptionLen = sizeof(rcvBuf);
480 #else
481     int myOptionLen = sizeof(rcvBuf);
482 #endif
483     try {
484         if (getsockopt(socketId, SOL_SOCKET, SO_RCVBUF, (char*)&rcvBuf, &myOptionLen) == -1) {
485 #ifdef WINDOWS_XP
486             int errorCode;
487             std::string errorMsg = "get RCVBUF option: ";
488             detectErrorGetSocketOption(&errorCode, errorMsg);
489             ChExceptionSocket* socketOptionException = new ChExceptionSocket(errorCode, errorMsg);
490             throw socketOptionException;
491 #endif
492 
493 #ifdef UNIX
494             ChExceptionSocket* unixSocketOptionException = new ChExceptionSocket(0, "unix: error getting host by name");
495             throw unixSocketOptionException;
496 #endif
497         }
498     } catch (ChExceptionSocket* excp) {
499         excp->response();
500         delete excp;
501         exit(1);
502     }
503     return rcvBuf;
504 }
505 
506 #ifdef WINDOWS_XP
detectErrorOpenWinSocket(int * errCode,std::string & errMsg)507 void ChSocket::detectErrorOpenWinSocket(int* errCode, std::string& errMsg) {
508     *errCode = WSAGetLastError();
509 
510     if (*errCode == WSANOTINITIALISED)
511         errMsg.append("Successful WSAStartup must occur before using this function.");
512     else if (*errCode == WSAENETDOWN)
513         errMsg.append("The network subsystem or the associated service provider has failed.");
514     else if (*errCode == WSAEAFNOSUPPORT)
515         errMsg.append("The specified address family is not supported.");
516     else if (*errCode == WSAEINPROGRESS)
517         errMsg.append(
518             "A blocking Windows Sockets 1.1 call is in progress, or the service provider is still processing a "
519             "callback function.");
520     else if (*errCode == WSAEMFILE)
521         errMsg.append("No more socket descriptors are available.");
522     else if (*errCode == WSAENOBUFS)
523         errMsg.append("No buffer space is available. The socket cannot be created.");
524     else if (*errCode == WSAEPROTONOSUPPORT)
525         errMsg.append("The specified protocol is not supported.");
526     else if (*errCode == WSAEPROTOTYPE)
527         errMsg.append("The specified protocol is the wrong type for this socket.");
528     else if (*errCode == WSAESOCKTNOSUPPORT)
529         errMsg.append("The specified socket type is not supported in this address family.");
530     else
531         errMsg.append("unknown problems!");
532 }
533 
detectErrorSetSocketOption(int * errCode,std::string & errMsg)534 void ChSocket::detectErrorSetSocketOption(int* errCode, std::string& errMsg) {
535     *errCode = WSAGetLastError();
536 
537     if (*errCode == WSANOTINITIALISED)
538         errMsg.append("A successful WSAStartup must occur before using this function.");
539     else if (*errCode == WSAENETDOWN)
540         errMsg.append("The network subsystem has failed.");
541     else if (*errCode == WSAEFAULT)
542         errMsg.append("optval is not in a valid part of the process address space or optlen parameter is too small.");
543     else if (*errCode == WSAEINPROGRESS)
544         errMsg.append(
545             "A blocking Windows Sockets 1.1 call is in progress, or the service provider is still processing a "
546             "callback function.");
547     else if (*errCode == WSAEINVAL)
548         errMsg.append("level is not valid, or the information in optval is not valid.");
549     else if (*errCode == WSAENETRESET)
550         errMsg.append("Connection has timed out when SO_KEEPALIVE is set.");
551     else if (*errCode == WSAENOPROTOOPT)
552         errMsg.append(
553             "The option is unknown or unsupported for the specified provider or socket (see SO_GROUP_PRIORITY "
554             "limitations).");
555     else if (*errCode == WSAENOTCONN)
556         errMsg.append("Connection has been reset when SO_KEEPALIVE is set.");
557     else if (*errCode == WSAENOTSOCK)
558         errMsg.append("The descriptor is not a socket.");
559     else
560         errMsg.append("unknown problem!");
561 }
562 
detectErrorGetSocketOption(int * errCode,std::string & errMsg)563 void ChSocket::detectErrorGetSocketOption(int* errCode, std::string& errMsg) {
564     *errCode = WSAGetLastError();
565 
566     if (*errCode == WSANOTINITIALISED)
567         errMsg.append("A successful WSAStartup must occur before using this function.");
568     else if (*errCode == WSAENETDOWN)
569         errMsg.append("The network subsystem has failed.");
570     else if (*errCode == WSAEFAULT)
571         errMsg.append(
572             "One of the optval or the optlen parameters is not a valid part of the user address space, or the optlen "
573             "parameter is too small.");
574     else if (*errCode == WSAEINPROGRESS)
575         errMsg.append(
576             "A blocking Windows Sockets 1.1 call is in progress, or the service provider is still processing a "
577             "callback function.");
578     else if (*errCode == WSAEINVAL)
579         errMsg.append("The level parameter is unknown or invalid.");
580     else if (*errCode == WSAENOPROTOOPT)
581         errMsg.append("The option is unknown or unsupported by the indicated protocol family.");
582     else if (*errCode == WSAENOTSOCK)
583         errMsg.append("The descriptor is not a socket.");
584 
585     else
586         errMsg.append("unknown problems!");
587 }
588 
589 #endif
590 
operator <<(std::ostream & io,ChSocket & s)591 std::ostream& operator<<(std::ostream& io, ChSocket& s) {
592     std::string flagStr = "";
593 
594     io << "--------------- Summary of socket settings -------------------" << std::endl;
595     io << "   Socket Id:     " << s.getSocketId() << std::endl;
596     io << "   port #:        " << s.getPortNumber() << std::endl;
597     io << "   debug:         " << (flagStr = s.getDebug() ? "true" : "false") << std::endl;
598     io << "   reuse addr:    " << (flagStr = s.getReuseAddr() ? "true" : "false") << std::endl;
599     io << "   keep alive:    " << (flagStr = s.getKeepAlive() ? "true" : "false") << std::endl;
600     io << "   send buf size: " << s.getSendBufSize() << std::endl;
601     io << "   recv bug size: " << s.getReceiveBufSize() << std::endl;
602     io << "   blocking:      " << (flagStr = s.getSocketBlocking() ? "true" : "false") << std::endl;
603     io << "   linger on:     " << (flagStr = s.getLingerOnOff() ? "true" : "false") << std::endl;
604     io << "   linger seconds: " << s.getLingerSeconds() << std::endl;
605     io << "----------- End of Summary of socket settings ----------------" << std::endl;
606     return io;
607 }
608 
bindSocket()609 void ChSocketTCP::bindSocket() {
610     try {
611         if (::bind(socketId, (struct sockaddr*)&clientAddr, sizeof(struct sockaddr_in)) == -1) {
612 #ifdef WINDOWS_XP
613             int errorCode = 0;
614             std::string errorMsg = "error calling bind(): \n";
615             detectErrorBind(&errorCode, errorMsg);
616             ChExceptionSocket* socketBindException = new ChExceptionSocket(errorCode, errorMsg);
617             throw socketBindException;
618 #endif
619 #ifdef UNIX
620             ChExceptionSocket* unixSocketBindException = new ChExceptionSocket(0, "unix: error calling bind()");
621             throw unixSocketBindException;
622 #endif
623         }
624     } catch (ChExceptionSocket* excp) {
625         excp->response();
626         delete excp;
627         exit(1);
628     }
629 }
630 
631 #ifdef WINDOWS_XP
632 
detectErrorBind(int * errCode,std::string & errMsg)633 void ChSocketTCP::detectErrorBind(int* errCode, std::string& errMsg) {
634     *errCode = WSAGetLastError();
635 
636     if (*errCode == WSANOTINITIALISED)
637         errMsg.append("A successful WSAStartup must occur before using this function.");
638     else if (*errCode == WSAENETDOWN)
639         errMsg.append("The network subsystem has failed.");
640     else if (*errCode == WSAEADDRINUSE) {
641         errMsg.append("A process on the machine is already bound to the same\n");
642         errMsg.append("fully-qualified address and the socket has not been marked\n");
643         errMsg.append("to allow address re-use with SO_REUSEADDR. For example,\n");
644         errMsg.append("IP address and port are bound in the af_inet case");
645     } else if (*errCode == WSAEADDRNOTAVAIL)
646         errMsg.append("The specified address is not a valid address for this machine.");
647     else if (*errCode == WSAEFAULT) {
648         errMsg.append("The name or the namelen parameter is not a valid part of\n");
649         errMsg.append("the user address space, the namelen parameter is too small,\n");
650         errMsg.append("the name parameter contains incorrect address format for the\n");
651         errMsg.append("associated address family, or the first two bytes of the memory\n");
652         errMsg.append("block specified by name does not match the address family\n");
653         errMsg.append("associated with the socket descriptor s.");
654     } else if (*errCode == WSAEINPROGRESS) {
655         errMsg.append("A blocking Windows Sockets 1.1 call is in progress, or the\n");
656         errMsg.append("service provider is still processing a callback function.");
657     } else if (*errCode == WSAEINVAL)
658         errMsg.append("The socket is already bound to an address. ");
659     else if (*errCode == WSAENOBUFS)
660         errMsg.append("Not enough buffers available, too many connections.");
661     else if (*errCode == WSAENOTSOCK)
662         errMsg.append("The descriptor is not a socket.");
663     else
664         errMsg.append("unknown problems!");
665 }
666 
detectErrorRecv(int * errCode,std::string & errMsg)667 void ChSocketTCP::detectErrorRecv(int* errCode, std::string& errMsg) {
668     *errCode = WSAGetLastError();
669 
670     if (*errCode == WSANOTINITIALISED)
671         errMsg.append("A successful WSAStartup must occur before using this function.");
672     else if (*errCode == WSAENETDOWN)
673         errMsg.append("The network subsystem has failed.");
674     else if (*errCode == WSAEFAULT)
675         errMsg.append("The buf parameter is not completely contained in a valid part of the user address space.");
676     else if (*errCode == WSAENOTCONN)
677         errMsg.append("The socket is not connected.");
678     else if (*errCode == WSAEINTR)
679         errMsg.append("The (blocking) call was canceled through WSACancelBlockingCall.");
680     else if (*errCode == WSAEINPROGRESS) {
681         errMsg.append("A blocking Windows Sockets 1.1 call is in progress, or the\n");
682         errMsg.append("service provider is still processing a callback function.");
683     } else if (*errCode == WSAENETRESET) {
684         errMsg.append("The connection has been broken due to the keep-alive activity\n");
685         errMsg.append("detecting a failure while the operation was in progress.");
686     } else if (*errCode == WSAENOTSOCK)
687         errMsg.append("The descriptor is not a socket.");
688     else if (*errCode == WSAEOPNOTSUPP) {
689         errMsg.append("MSG_OOB was specified, but the socket is not stream-style\n");
690         errMsg.append("such as type SOCK_STREAM, out-of-band data is not supported\n");
691         errMsg.append("in the communication domain associated with this socket, or\n");
692         errMsg.append("the socket is unidirectional and supports only send operations.");
693     } else if (*errCode == WSAESHUTDOWN) {
694         errMsg.append("The socket has been shut down; it is not possible to recv on a\n");
695         errMsg.append("socket after shutdown has been invoked with how set to SD_RECEIVE or SD_BOTH.");
696     } else if (*errCode == WSAEWOULDBLOCK)
697         errMsg.append("The socket is marked as nonblocking and the receive operation would block.");
698     else if (*errCode == WSAEMSGSIZE)
699         errMsg.append("The message was too large to fit into the specified buffer and was truncated.");
700     else if (*errCode == WSAEINVAL) {
701         errMsg.append("The socket has not been bound with bind, or an unknown flag\n");
702         errMsg.append("was specified, or MSG_OOB was specified for a socket with\n");
703         errMsg.append("SO_OOBINLINE enabled or (for byte stream sockets only) len was zero or negative.");
704     } else if (*errCode == WSAECONNABORTED) {
705         errMsg.append("The virtual circuit was terminated due to a time-out or\n");
706         errMsg.append("other failure. The application should close the socket as it is no longer usable.");
707     } else if (*errCode == WSAETIMEDOUT) {
708         errMsg.append("The connection has been dropped because of a network\n");
709         errMsg.append("failure or because the peer system failed to respond.");
710     } else if (*errCode == WSAECONNRESET) {
711         errMsg.append("The virtual circuit was reset by the remote side executing a\n");
712         errMsg.append("\"hard\" or \"abortive\" close. The application should close\n");
713         errMsg.append("the socket as it is no longer usable. On a UDP datagram socket\n");
714         errMsg.append("this error would indicate that a previous send operation\n");
715         errMsg.append("resulted in an ICMP \"Port Unreachable\" message.");
716     } else
717         errMsg.append("unknown problems!");
718 }
719 
detectErrorConnect(int * errCode,std::string & errMsg)720 void ChSocketTCP::detectErrorConnect(int* errCode, std::string& errMsg) {
721     *errCode = WSAGetLastError();
722 
723     if (*errCode == WSANOTINITIALISED)
724         errMsg.append("A successful WSAStartup must occur before using this function.");
725     else if (*errCode == WSAENETDOWN)
726         errMsg.append("The network subsystem has failed.");
727     else if (*errCode == WSAEADDRINUSE) {
728         errMsg.append("The socket's local address is already in use and the socket\n");
729         errMsg.append("was not marked to allow address reuse with SO_REUSEADDR. This\n");
730         errMsg.append("error usually occurs when executing bind, but could be delayed\n");
731         errMsg.append("until this function if the bind was to a partially wild-card\n");
732         errMsg.append("address (involving ADDR_ANY) and if a specific address needs\n");
733         errMsg.append("to be committed at the time of this function.");
734     } else if (*errCode == WSAEINTR)
735         errMsg.append("The (blocking) Windows Socket 1.1 call was canceled through WSACancelBlockingCall.");
736     else if (*errCode == WSAEINPROGRESS) {
737         errMsg.append("A blocking Windows Sockets 1.1 call is in progress, or\n");
738         errMsg.append("the service provider is still processing a callback function.");
739     } else if (*errCode == WSAEALREADY) {
740         errMsg.append("A nonblocking connect call is in progress on the specified socket.\n");
741         errMsg.append("Note In order to preserve backward compatibility, this error is\n");
742         errMsg.append("reported as WSAEINVAL to Windows Sockets 1.1 applications that\n");
743         errMsg.append("link to either WINSOCK.DLL or WSOCK32.DLL.");
744     } else if (*errCode == WSAEADDRNOTAVAIL)
745         errMsg.append("The remote address is not a valid address (such as ADDR_ANY).");
746     else if (*errCode == WSAEAFNOSUPPORT)
747         errMsg.append("Addresses in the specified family cannot be used with this socket.");
748     else if (*errCode == WSAECONNREFUSED)
749         errMsg.append("The attempt to connect was forcefully rejected.");
750     else if (*errCode == WSAEFAULT) {
751         errMsg.append("The name or the namelen parameter is not a valid part of\n");
752         errMsg.append("the user address space, the namelen parameter is too small,\n");
753         errMsg.append("or the name parameter contains incorrect address format for\n");
754         errMsg.append("the associated address family.");
755     } else if (*errCode == WSAEINVAL) {
756         errMsg.append("The parameter s is a listening socket, or the destination\n");
757         errMsg.append("address specified is not consistent with that of the constrained\n");
758         errMsg.append("group the socket belongs to.");
759     } else if (*errCode == WSAEISCONN)
760         errMsg.append("The socket is already connected (connection-oriented sockets only).");
761     else if (*errCode == WSAENETUNREACH)
762         errMsg.append("The network cannot be reached from this host at this time.");
763     else if (*errCode == WSAENOBUFS)
764         errMsg.append("No buffer space is available. The socket cannot be connected.");
765     else if (*errCode == WSAENOTSOCK)
766         errMsg.append("The descriptor is not a socket.");
767     else if (*errCode == WSAETIMEDOUT)
768         errMsg.append("Attempt to connect timed out without establishing a connection.");
769     else if (*errCode == WSAEWOULDBLOCK) {
770         errMsg.append("The socket is marked as nonblocking and the connection\n");
771         errMsg.append("cannot be completed immediately.");
772     } else if (*errCode == WSAEACCES) {
773         errMsg.append("Attempt to connect datagram socket to broadcast address failed\n");
774         errMsg.append("because setsockopt option SO_BROADCAST is not enabled.");
775     } else
776         errMsg.append("unknown problems!");
777 }
778 
detectErrorAccept(int * errCode,std::string & errMsg)779 void ChSocketTCP::detectErrorAccept(int* errCode, std::string& errMsg) {
780     *errCode = WSAGetLastError();
781 
782     if (*errCode == WSANOTINITIALISED)
783         errMsg.append("A successful WSAStartup must occur before using this FUNCTION.");
784     else if (*errCode == WSAENETDOWN)
785         errMsg.append("The network subsystem has failed.");
786     else if (*errCode == WSAEFAULT)
787         errMsg.append("The addrlen parameter is too small or addr is not a valid part of the user address space.");
788     else if (*errCode == WSAEINTR)
789         errMsg.append("A blocking Windows Sockets 1.1 call was canceled through WSACancelBlockingCall.");
790     else if (*errCode == WSAEINPROGRESS) {
791         errMsg.append("A blocking Windows Sockets 1.1 call is in progress, or the\n");
792         errMsg.append("service provider is still processing a callback function.");
793     } else if (*errCode == WSAEINVAL)
794         errMsg.append("The listen function was not invoked prior to accept.");
795     else if (*errCode == WSAEMFILE)
796         errMsg.append("The queue is nonempty upon entry to accept and there are no descriptors available.");
797     else if (*errCode == WSAENOBUFS)
798         errMsg.append("No buffer space is available.");
799     else if (*errCode == WSAENOTSOCK)
800         errMsg.append("The descriptor is not a socket.");
801     else if (*errCode == WSAEOPNOTSUPP)
802         errMsg.append("The referenced socket is not a type that supports connection-oriented service.");
803     else if (*errCode == WSAEWOULDBLOCK)
804         errMsg.append("The socket is marked as nonblocking and no connections are present to be accepted.");
805     else
806         errMsg.append("unknown problems!");
807 }
808 
detectErrorListen(int * errCode,std::string & errMsg)809 void ChSocketTCP::detectErrorListen(int* errCode, std::string& errMsg) {
810     *errCode = WSAGetLastError();
811 
812     if (*errCode == WSANOTINITIALISED)
813         errMsg.append("A successful WSAStartup must occur before using this function.");
814     else if (*errCode == WSAENETDOWN)
815         errMsg.append("The network subsystem has failed.");
816     else if (*errCode == WSAEADDRINUSE) {
817         errMsg.append("The socket's local address is already in use and the socket was\n");
818         errMsg.append("not marked to allow address reuse with SO_REUSEADDR. This error\n");
819         errMsg.append("usually occurs during execution of the bind function, but could\n");
820         errMsg.append("be delayed until this function if the bind was to a partially\n");
821         errMsg.append("wild-card address (involving ADDR_ANY) and if a specific address\n");
822         errMsg.append("needs to be \"committed\" at the time of this function.");
823     } else if (*errCode == WSAEINPROGRESS) {
824         errMsg.append("A blocking Windows Sockets 1.1 call is in progress, or the service\n");
825         errMsg.append("provider is still processing a callback function.");
826     } else if (*errCode == WSAEINVAL)
827         errMsg.append("The socket has not been bound with bind.");
828     else if (*errCode == WSAEISCONN)
829         errMsg.append("The socket is already connected.");
830     else if (*errCode == WSAEMFILE)
831         errMsg.append("No more socket descriptors are available.");
832     else if (*errCode == WSAENOBUFS)
833         errMsg.append("No buffer space is available.");
834     else if (*errCode == WSAENOTSOCK)
835         errMsg.append("The descriptor is not a socket.");
836     else if (*errCode == WSAEOPNOTSUPP)
837         errMsg.append("The referenced socket is not of a type that supports the listen operation.");
838     else
839         errMsg.append("unknown problems!");
840 }
841 
detectErrorSend(int * errCode,std::string & errMsg)842 void ChSocketTCP::detectErrorSend(int* errCode, std::string& errMsg) {
843     *errCode = WSAGetLastError();
844 
845     if (*errCode == WSANOTINITIALISED)
846         errMsg.append("A successful WSAStartup must occur before using this function.");
847     else if (*errCode == WSAENETDOWN)
848         errMsg.append("The network subsystem has failed.");
849     else if (*errCode == WSAEACCES) {
850         errMsg.append("The requested address is a broadcast address,\n");
851         errMsg.append("but the appropriate flag was not set. Call setsockopt\n");
852         errMsg.append("with the SO_BROADCAST parameter to allow the use of the broadcast address.");
853     } else if (*errCode == WSAEINTR) {
854         errMsg.append("A blocking Windows Sockets 1.1 call was canceled\n");
855         errMsg.append("through WSACancelBlockingCall.");
856     } else if (*errCode == WSAEINPROGRESS) {
857         errMsg.append("A blocking Windows Sockets 1.1 call is in progress,\n");
858         errMsg.append("or the service provider is still processing a callback function.");
859     } else if (*errCode == WSAEFAULT) {
860         errMsg.append("The buf parameter is not completely contained in a\n");
861         errMsg.append("valid part of the user address space.");
862     } else if (*errCode == WSAENETRESET) {
863         errMsg.append("The connection has been broken due to the keep-alive\n");
864         errMsg.append("activity detecting a failure while the operation was in progress.");
865     } else if (*errCode == WSAENOBUFS)
866         errMsg.append("No buffer space is available.");
867     else if (*errCode == WSAENOTCONN)
868         errMsg.append("The socket is not connected.");
869     else if (*errCode == WSAENOTSOCK)
870         errMsg.append("The descriptor is not a socket.");
871     else if (*errCode == WSAEOPNOTSUPP) {
872         errMsg.append("MSG_OOB was specified, but the socket is not stream-style\n");
873         errMsg.append("such as type SOCK_STREAM, out-of-band data is not supported\n");
874         errMsg.append("in the communication domain associated with this socket,\n");
875         errMsg.append("or the socket is unidirectional and supports only receive operations.");
876     } else if (*errCode == WSAESHUTDOWN) {
877         errMsg.append("The socket has been shut down; it is not possible to send\n");
878         errMsg.append("on a socket after shutdown has been invoked with how set\n");
879         errMsg.append("to SD_SEND or SD_BOTH.");
880     } else if (*errCode == WSAEWOULDBLOCK)
881         errMsg.append("The socket is marked as nonblocking and the requested operation would block.\n");
882     else if (*errCode == WSAEMSGSIZE) {
883         errMsg.append("The socket is message oriented, and the message is larger\n");
884         errMsg.append("than the maximum supported by the underlying transport.");
885     } else if (*errCode == WSAEHOSTUNREACH)
886         errMsg.append("The remote host cannot be reached from this host at this time.");
887     else if (*errCode == WSAEINVAL) {
888         errMsg.append("The socket has not been bound with bind, or an unknown flag\n");
889         errMsg.append("was specified, or MSG_OOB was specified for a socket with SO_OOBINLINE enabled.");
890     } else if (*errCode == WSAECONNABORTED) {
891         errMsg.append("The virtual circuit was terminated due to a time-out or \n");
892         errMsg.append("other failure. The application should close the socket as it is no longer usable.");
893     } else if (*errCode == WSAECONNRESET) {
894         errMsg.append("The virtual circuit was reset by the remote side executing a \"hard\" \n");
895         errMsg.append("or \"abortive\" close. For UPD sockets, the remote host was unable to\n");
896         errMsg.append("deliver a previously sent UDP datagram and responded with a\n");
897         errMsg.append("\"Port Unreachable\" ICMP packet. The application should close\n");
898         errMsg.append("the socket as it is no longer usable.");
899     } else if (*errCode == WSAETIMEDOUT) {
900         errMsg.append("The connection has been dropped, because of a network failure\n");
901         errMsg.append("or because the system on the other end went down without notice.");
902     } else
903         errMsg.append("unknown problems!");
904 }
905 
906 #endif
907 
connectToServer(std::string & serverNameOrAddr,hostType hType)908 void ChSocketTCP::connectToServer(std::string& serverNameOrAddr, hostType hType) {
909     /*
910        when this method is called, a client socket has been built already,
911        so we have the socketId and portNumber ready.
912 
913        a ChHostInfo instance is created, no matter how the server's name is
914        given (such as www.yuchen.net) or the server's address is given (such
915        as 169.56.32.35), we can use this ChHostInfo instance to get the
916        IP address of the server
917     */
918 
919     ChHostInfo serverInfo(serverNameOrAddr, hType);
920 
921     // Store the IP address and socket port number
922     struct sockaddr_in serverAddress;
923     serverAddress.sin_family = AF_INET;
924     serverAddress.sin_addr.s_addr = inet_addr(serverInfo.getHostIPAddress());
925     serverAddress.sin_port = htons(portNumber);
926 
927     // Connect to the given address
928     try {
929         if (connect(socketId, (struct sockaddr*)&serverAddress, sizeof(serverAddress)) == -1) {
930 #ifdef WINDOWS_XP
931             int errorCode = 0;
932             std::string errorMsg = "error calling connect():\n";
933             detectErrorConnect(&errorCode, errorMsg);
934             ChExceptionSocket* socketConnectException = new ChExceptionSocket(errorCode, errorMsg);
935             throw socketConnectException;
936 #endif
937 
938 #ifdef UNIX
939             ChExceptionSocket* unixSocketConnectException = new ChExceptionSocket(0, "unix: error calling connect()");
940             throw unixSocketConnectException;
941 #endif
942         }
943     } catch (ChExceptionSocket* excp) {
944         excp->response();
945         delete excp;
946         exit(1);
947     }
948 }
949 
acceptClient(std::string & clientHost)950 ChSocketTCP* ChSocketTCP::acceptClient(std::string& clientHost) {
951     int newSocket;  // the new socket file descriptor returned by the accept systme call
952 
953     // the length of the client's address
954 #if defined(TARGET_OS_MAC) || defined(UNIX)
955     socklen_t clientAddressLen = sizeof(struct sockaddr_in);
956 #else
957     int clientAddressLen = sizeof(struct sockaddr_in);
958 #endif
959     struct sockaddr_in clientAddress;  // Address of the client that sent data
960 
961     // Accepts a new client connection and stores its socket file descriptor
962     try {
963         if ((newSocket = (int)accept(socketId, (struct sockaddr*)&clientAddress, &clientAddressLen)) == -1) {
964 #ifdef WINDOWS_XP
965             int errorCode = 0;
966             std::string errorMsg = "error calling accept(): \n";
967             detectErrorAccept(&errorCode, errorMsg);
968             ChExceptionSocket* socketAcceptException = new ChExceptionSocket(errorCode, errorMsg);
969             throw socketAcceptException;
970 #endif
971 
972 #ifdef UNIX
973             ChExceptionSocket* unixSocketAcceptException = new ChExceptionSocket(0, "unix: error calling accept()");
974             throw unixSocketAcceptException;
975 #endif
976         }
977     } catch (ChExceptionSocket* excp) {
978         excp->response();
979         delete excp;
980         return NULL;
981     }
982 
983     // Get the host name given the address
984     char* sAddress = inet_ntoa((struct in_addr)clientAddress.sin_addr);
985     ChHostInfo clientInfo(std::string(sAddress), ADDRESS);
986     char* hostName = clientInfo.getHostName();
987     clientHost += std::string(hostName);
988 
989     // Create and return the new ChSocketTCP object
990     ChSocketTCP* retSocket = new ChSocketTCP();
991     retSocket->setSocketId(newSocket);
992     return retSocket;
993 }
994 
listenToClient(int totalNumPorts)995 void ChSocketTCP::listenToClient(int totalNumPorts) {
996     try {
997         if (listen(socketId, totalNumPorts) == -1) {
998 #ifdef WINDOWS_XP
999             int errorCode = 0;
1000             std::string errorMsg = "error calling listen():\n";
1001             detectErrorListen(&errorCode, errorMsg);
1002             ChExceptionSocket* socketListenException = new ChExceptionSocket(errorCode, errorMsg);
1003             throw socketListenException;
1004 #endif
1005 
1006 #ifdef UNIX
1007             ChExceptionSocket* unixSocketListenException = new ChExceptionSocket(0, "unix: error calling listen()");
1008             throw unixSocketListenException;
1009 #endif
1010         }
1011     } catch (ChExceptionSocket* excp) {
1012         excp->response();
1013         delete excp;
1014         exit(1);
1015     }
1016 }
1017 
1018 /*
1019 int ChSocketTCP::sendMessage(std::string& message)
1020 {
1021     int numBytes;  // the number of bytes sent
1022 
1023 
1024     char msgLength[MSG_HEADER_LEN+1];
1025     sprintf(msgLength,"%6d",message.size());
1026     std::string sendMsg = std::string(msgLength);
1027     sendMsg += message;
1028 
1029     // Sends the message to the connected host
1030     try
1031     {
1032         if (numBytes = send(socketId,sendMsg.c_str(),sendMsg.size(),0) == -1)
1033         {
1034             #ifdef WINDOWS_XP
1035                 int errorCode = 0;
1036                 std::string errorMsg = "error calling send():\n";
1037                 detectErrorSend(&errorCode,errorMsg);
1038                 ChExceptionSocket* socketSendException = new ChExceptionSocket(errorCode,errorMsg);
1039                 throw socketSendException;
1040             #endif
1041 
1042             #ifdef UNIX
1043                 ChExceptionSocket* unixSocketSendException = new ChExceptionSocket(0,"unix: error calling send()");
1044                 throw unixSocketSendException;
1045             #endif
1046         }
1047     }
1048     catch(ChExceptionSocket* excp)
1049     {
1050         excp->response();
1051         delete excp;
1052         exit(1);
1053     }
1054 
1055     return numBytes;
1056 }
1057 */
sendMessage(std::string & message)1058 int ChSocketTCP::sendMessage(std::string& message) {
1059     int numBytes;  // the number of bytes sent
1060 
1061     /*
1062        for each message to be sent, add a header which shows how long this message
1063        is. This header, regardless how long the real message is, will always be
1064        of the length MSG_HEADER_LEN.
1065     */
1066 
1067     char msgLength[MSG_HEADER_LEN + 1];
1068     sprintf(msgLength, "%6d", static_cast<int>(message.size()));
1069     std::string sendMsg = std::string(msgLength);
1070     sendMsg += message;
1071 
1072     // Sends the message to the connected host
1073     try {
1074         numBytes = send(socketId, sendMsg.c_str(), (int)sendMsg.size(), 0);
1075         if (numBytes == -1) {
1076 #ifdef WINDOWS_XP
1077             int errorCode = 0;
1078             std::string errorMsg = "error calling send():\n";
1079             detectErrorSend(&errorCode, errorMsg);
1080             ChExceptionSocket* socketSendException = new ChExceptionSocket(errorCode, errorMsg);
1081             throw socketSendException;
1082 #endif
1083 
1084 #ifdef UNIX
1085             ChExceptionSocket* unixSocketSendException = new ChExceptionSocket(0, "unix: error calling send()");
1086             throw unixSocketSendException;
1087 #endif
1088         }
1089     } catch (ChExceptionSocket* excp) {
1090         excp->response();
1091         delete excp;
1092         exit(1);
1093     }
1094 
1095     return numBytes;
1096 }
1097 
1098 #ifdef WINDOWS_XP
1099 /*
1100 int ChSocketTCP::XPrecieveMessage(std::string& message)
1101 {
1102     int numBytes = 0;                 // The number of bytes received
1103     int currentSize = MSG_HEADER_LEN; // The number of bytes wanted to receive
1104     int offsetSize = 0;               // The number of bytes currently received
1105 
1106     // retrieve the length of the message received
1107 
1108     char msgLength[MSG_HEADER_LEN+1];
1109     memset(msgLength,0,sizeof(msgLength));
1110 
1111     try
1112     {
1113         while ( numBytes < currentSize )
1114         {
1115             numBytes = recv(socketId,msgLength+offsetSize,currentSize,MSG_PEEK);
1116             if (numBytes == -1)
1117             {
1118                 int errorCode = 0;
1119                 std::string errorMsg = "error calling recv():\n";
1120                 detectErrorRecv(&errorCode,errorMsg);
1121                 ChExceptionSocket* socketRecvException = new ChExceptionSocket(errorCode,errorMsg);
1122                 throw socketRecvException;
1123             }
1124             else if ( numBytes < currentSize )
1125             {
1126                 offsetSize += numBytes;
1127                 currentSize -= numBytes;
1128             }
1129         }
1130 
1131     }
1132     catch(ChExceptionSocket* excp)
1133     {
1134         excp->response();
1135         delete excp;
1136         exit(1);
1137     }
1138 
1139     // recieve the real message
1140     currentSize = atoi(msgLength);
1141     offsetSize = 0;
1142 
1143     cout   << "[RECV:message length] " << msgLength << std::endl;
1144     winLog << "[RECV:message length] " << msgLength << std::endl;
1145 
1146     try
1147     {
1148         while ( numBytes < currentSize )
1149         {
1150             numBytes = recv(socketId,(char*)(message.c_str())+offsetSize,currentSize,0);
1151             if (numBytes == -1)
1152             {
1153                 int errorCode = 0;
1154                 std::string errorMsg = "error calling recv():\n";
1155                 detectErrorRecv(&errorCode,errorMsg);
1156                 ChExceptionSocket* socketRecvException = new ChExceptionSocket(errorCode,errorMsg);
1157                 throw socketRecvException;
1158             }
1159             else if ( numBytes < currentSize )
1160             {
1161                 offsetSize += numBytes;
1162                 currentSize -= numBytes;
1163             }
1164         }
1165 
1166     }
1167     catch(ChExceptionSocket* excp)
1168     {
1169         excp->response();
1170         delete excp;
1171         exit(1);
1172     }
1173 
1174     cout   << "[RECV:message] " << message << std::endl;
1175     winLog << "[RECV:message] " << message << std::endl;
1176 
1177     return atoi(msgLength);
1178 }
1179 */
1180 
XPrecieveMessage(std::string & message)1181 int ChSocketTCP::XPrecieveMessage(std::string& message) {
1182     int received = 0;            // The number of bytes received
1183     int msgSize = MAX_RECV_LEN;  // The number of bytes wanted to receive
1184     bool headerFinished = false;
1185 
1186     char charMsg[MAX_RECV_LEN + 1];
1187     char msgLength[MSG_HEADER_LEN + 1];
1188     memset(charMsg, 0, sizeof(charMsg));
1189     memset(msgLength, 0, sizeof(msgLength));
1190 
1191     try {
1192         while (received < msgSize) {
1193             int numBytes = recv(socketId, charMsg + received, 1, 0);
1194             if (numBytes == -1) {
1195                 int errorCode = 0;
1196                 std::string errorMsg = "error calling recv():\n";
1197                 detectErrorRecv(&errorCode, errorMsg);
1198                 ChExceptionSocket* socketRecvException = new ChExceptionSocket(errorCode, errorMsg);
1199                 throw socketRecvException;
1200             }
1201 
1202             if (!headerFinished) {
1203                 msgLength[received] = *(charMsg + received);
1204                 received++;
1205 
1206                 if (received == MSG_HEADER_LEN) {
1207                     headerFinished = true;
1208                     received = 0;
1209                     memset(charMsg, 0, sizeof(charMsg));
1210                     msgSize = atoi(msgLength);
1211                 }
1212             } else
1213                 received++;
1214         }
1215     } catch (ChExceptionSocket* excp) {
1216         if (excp->getErrCode() == WSAECONNRESET) {
1217             std::cout << "!! your party has shut down the connection... \n";
1218             // winLog << "!! your party has shut down the connection... \n";
1219             return -99;
1220         }
1221         excp->response();
1222         delete excp;
1223         exit(1);
1224     }
1225 
1226     message.append(std::string(charMsg));
1227     return msgSize;
1228 }
1229 
1230 #endif
1231 
receiveMessage(std::string & message)1232 int ChSocketTCP::receiveMessage(std::string& message) {
1233     int numBytes;  // The number of bytes received
1234 
1235 #ifdef WINDOWS_XP
1236     return XPrecieveMessage(message);
1237 #endif
1238 
1239     // retrieve the length of the message received
1240 
1241     char msgLength[MSG_HEADER_LEN + 1];
1242     memset(msgLength, 0, sizeof(msgLength));
1243     try {
1244         numBytes = recv(socketId, msgLength, MSG_HEADER_LEN, 0);
1245         if (numBytes == -1) {
1246             ChExceptionSocket* unixSocketRecvException = new ChExceptionSocket(0, "unix: error calling recv()");
1247             throw unixSocketRecvException;
1248         }
1249     } catch (ChExceptionSocket* excp) {
1250         excp->response();
1251         delete excp;
1252         exit(1);
1253     }
1254 
1255     // receive the real message
1256 
1257     try {
1258         numBytes = recv(socketId, (char*)(message.c_str()), atoi(msgLength), 0);
1259         if (numBytes == -1) {
1260             ChExceptionSocket* unixSocketRecvException = new ChExceptionSocket(0, "unix: error calling recv()");
1261             throw unixSocketRecvException;
1262         }
1263     } catch (ChExceptionSocket* excp) {
1264         excp->response();
1265         delete excp;
1266         exit(1);
1267     }
1268 
1269     return numBytes;
1270 }
1271 
SendBuffer(std::vector<char> & source_buf)1272 int ChSocketTCP::SendBuffer(std::vector<char>& source_buf) {
1273     int nbytes = (int)source_buf.size();
1274     const char* data;
1275     if (nbytes)
1276         data = (char*)&(source_buf[0]);  // stl vectors are assured to be sequential
1277     else
1278         data = "";  // stub, in case null length messages, stl vector has no [0] element address
1279 
1280     // Sends the message to the connected host
1281     int sentBytes = send(socketId, data, nbytes, 0);
1282     if (sentBytes == -1) {
1283 #ifdef WINDOWS_XP
1284         int errorCode = 0;
1285         std::string errorMsg = "error calling send():\n";
1286         detectErrorRecv(&errorCode, errorMsg);
1287         throw ChExceptionSocket(errorCode, errorMsg);
1288 #endif
1289 
1290 #ifdef UNIX
1291         throw ChExceptionSocket(0, "unix: error calling send()");
1292 #endif
1293     }
1294 
1295     return sentBytes;
1296 }
1297 
ReceiveBuffer(std::vector<char> & dest_buf,int bsize)1298 int ChSocketTCP::ReceiveBuffer(std::vector<char>& dest_buf, int bsize) {
1299     int nbytes = bsize;
1300 
1301     dest_buf.resize(nbytes);
1302 
1303     void* data;
1304     if (nbytes)
1305         data = (char*)&(dest_buf[0]);  // stl vectors are assured to be sequential. // should not access directly
1306                                        // std::vector data, but this is efficient!
1307     else
1308         data = (char*)"";  // stub, in case null length messages, stl vector has no [0] element address
1309 
1310     int receivedBytes = recv(socketId, (char*)data, nbytes, 0);
1311     if (receivedBytes == -1) {
1312 #ifdef WINDOWS_XP
1313         int errorCode = 0;
1314         std::string errorMsg = "error calling recv():\n";
1315         detectErrorRecv(&errorCode, errorMsg);
1316         throw ChExceptionSocket(errorCode, errorMsg);
1317 #endif
1318 
1319 #ifdef UNIX
1320         throw ChExceptionSocket(0, "Error calling recv() in buffer receive:");
1321 #endif
1322     }
1323 
1324     return receivedBytes;
1325 }
1326 
1327 }  // end namespace cosimul
1328 }  // end namespace chrono
1329