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