Line data Source code
1 : /************************************************************************
2 : ** This file is part of the network simulator Shawn. **
3 : ** Copyright (C) 2004-2007 by the SwarmNet (www.swarmnet.de) project **
4 : ** Shawn is free software; you can redistribute it and/or modify it **
5 : ** under the terms of the BSD License. Refer to the shawn-licence.txt **
6 : ** file in the root of the Shawn source tree for further details. **
7 : ************************************************************************/
8 :
9 : #ifdef SHAWN
10 : #include <apps/tcpip/socket.h>
11 : #include <sys/simulation/simulation_controller.h>
12 : #else
13 : #include "socket.h"
14 : #endif
15 :
16 : #ifdef BUILD_TCPIP
17 :
18 :
19 : #ifndef WIN32
20 : #include <sys/types.h>
21 : #include <sys/socket.h>
22 : #include <netinet/in.h>
23 : #include <netinet/tcp.h>
24 : #include <arpa/inet.h>
25 : #include <netdb.h>
26 : #include <errno.h>
27 : #include <fcntl.h>
28 : #include <unistd.h>
29 : #else
30 : #ifdef ERROR
31 : #undef ERROR
32 : #endif
33 :
34 : #include <winsock2.h>
35 : #include <ws2tcpip.h>
36 :
37 : #ifndef vsnprintf
38 : #define vsnprintf _vsnprintf
39 : #endif
40 :
41 : #endif
42 :
43 : #include <cstdio>
44 : #include <cstring>
45 : #include <cstdarg>
46 : #include <cassert>
47 : #include <string>
48 : #include <vector>
49 : #include <string>
50 : #include <algorithm>
51 : #include <string.h>
52 :
53 :
54 : #ifdef SHAWN
55 : extern "C" void init_tcpip( shawn::SimulationController& sc )
56 : {
57 : // std::cout << "tcpip init" << std::endl;
58 : }
59 : #endif
60 :
61 : namespace tcpip
62 : {
63 : const int Socket::lengthLen = 4;
64 :
65 : #ifdef WIN32
66 : bool Socket::init_windows_sockets_ = true;
67 : bool Socket::windows_sockets_initialized_ = false;
68 : int Socket::instance_count_ = 0;
69 : #endif
70 :
71 : // ----------------------------------------------------------------------
72 1812 : Socket::
73 1812 : Socket(std::string host, int port)
74 1812 : : host_( host ),
75 1812 : port_( port ),
76 1812 : socket_(-1),
77 1812 : server_socket_(-1),
78 1812 : blocking_(true),
79 1812 : verbose_(false)
80 : {
81 1812 : init();
82 1812 : }
83 :
84 : // ----------------------------------------------------------------------
85 7078 : Socket::
86 7078 : Socket(int port)
87 7078 : : host_(""),
88 7078 : port_( port ),
89 7078 : socket_(-1),
90 7078 : server_socket_(-1),
91 7078 : blocking_(true),
92 7078 : verbose_(false)
93 : {
94 7078 : init();
95 7078 : }
96 :
97 : // ----------------------------------------------------------------------
98 : void
99 8890 : Socket::
100 : init()
101 : {
102 : #ifdef WIN32
103 : instance_count_++;
104 :
105 : if( init_windows_sockets_ && !windows_sockets_initialized_ )
106 : {
107 : WSAData wsaData;
108 : if( WSAStartup(MAKEWORD(1, 1), &wsaData) != 0 )
109 : BailOnSocketError("Unable to init WSA Sockets");
110 : windows_sockets_initialized_ = true;
111 : }
112 : #endif
113 8890 : }
114 :
115 :
116 : int
117 552 : Socket::
118 : getFreeSocketPort()
119 : {
120 552 : Socket dummy(0); // just to trigger initialization on Windows and cleanup on end
121 : // Create socket to find a random free port that can be handed to the app
122 552 : int sock = static_cast<int>(socket( AF_INET, SOCK_STREAM, 0 ));
123 : struct sockaddr_in self;
124 : memset(&self, 0, sizeof(self));
125 552 : self.sin_family = AF_INET;
126 : self.sin_port = htons(0);
127 : self.sin_addr.s_addr = htonl(INADDR_ANY);
128 :
129 552 : socklen_t address_len = sizeof(self);
130 : // bind with port==0 assigns free port
131 552 : if ( bind(sock, (struct sockaddr*) &self, address_len) < 0)
132 0 : BailOnSocketError("tcpip::Socket::getFreeSocketPort() Unable to bind socket");
133 : // get the assigned port with getsockname
134 552 : if ( getsockname(sock, (struct sockaddr*) &self, &address_len) < 0)
135 0 : BailOnSocketError("tcpip::Socket::getFreeSocketPort() Unable to get socket name");
136 552 : const int port = ntohs(self.sin_port);
137 : #ifdef WIN32
138 : ::closesocket( sock );
139 : #else
140 552 : ::close( sock );
141 : #endif
142 552 : return port;
143 552 : }
144 :
145 :
146 : // ----------------------------------------------------------------------
147 8873 : Socket::
148 : ~Socket()
149 : {
150 : // Close first an existing client connection ...
151 8873 : close();
152 : #ifdef WIN32
153 : instance_count_--;
154 : #endif
155 :
156 : // ... then the server socket
157 8873 : if( server_socket_ >= 0 )
158 : {
159 : #ifdef WIN32
160 : ::closesocket( server_socket_ );
161 : #else
162 3141 : ::close( server_socket_ );
163 : #endif
164 3141 : server_socket_ = -1;
165 : }
166 :
167 : #ifdef WIN32
168 : if( server_socket_ == -1 && socket_ == -1
169 : && init_windows_sockets_ && instance_count_ == 0 )
170 : WSACleanup();
171 : windows_sockets_initialized_ = false;
172 : #endif
173 8873 : }
174 :
175 : // ----------------------------------------------------------------------
176 : void
177 1344 : Socket::
178 : BailOnSocketError( std::string context)
179 : {
180 : #ifdef WIN32
181 : int e = WSAGetLastError();
182 : std::string msg = GetWinsockErrorString( e );
183 : #else
184 1344 : std::string msg = strerror( errno );
185 : #endif
186 2688 : throw SocketException( context + ": " + msg );
187 : }
188 :
189 : // ----------------------------------------------------------------------
190 : int
191 0 : Socket::
192 : port()
193 : {
194 0 : return port_;
195 : }
196 :
197 :
198 : // ----------------------------------------------------------------------
199 : #ifdef _MSC_VER
200 : #pragma warning(push)
201 : /* Disable warning about while (0, 0) in the expansion of FD_SET, see https://developercommunity.visualstudio.com/t/fd-clr-and-fd-set-macros-generate-warning-c4548/172702 */
202 : #pragma warning(disable: 4548)
203 : #endif
204 : bool
205 0 : Socket::
206 : datawaiting(int sock)
207 : const
208 : {
209 : fd_set fds;
210 0 : FD_ZERO( &fds );
211 0 : FD_SET( (unsigned int)sock, &fds );
212 :
213 : struct timeval tv;
214 0 : tv.tv_sec = 0;
215 0 : tv.tv_usec = 0;
216 :
217 0 : int r = select( sock+1, &fds, nullptr, nullptr, &tv);
218 :
219 0 : if (r < 0)
220 0 : BailOnSocketError("tcpip::Socket::datawaiting @ select");
221 :
222 0 : if( FD_ISSET( sock, &fds ) )
223 : return true;
224 : else
225 0 : return false;
226 : }
227 : #ifdef _MSC_VER
228 : #pragma warning(pop)
229 : #endif
230 :
231 : // ----------------------------------------------------------------------
232 : bool
233 2553 : Socket::
234 : atoaddr( std::string address, struct sockaddr_in& addr)
235 : {
236 : int status;
237 : struct addrinfo *servinfo; // will point to the results
238 :
239 : struct addrinfo hints;
240 : memset(&hints, 0, sizeof hints); // make sure the struct is empty
241 2553 : hints.ai_family = AF_INET; // restrict to IPv4?
242 2553 : hints.ai_socktype = SOCK_STREAM; // TCP stream sockets
243 2553 : hints.ai_flags = AI_PASSIVE; // fill in my IP for me
244 :
245 2553 : if ((status = getaddrinfo(address.c_str(), nullptr, &hints, &servinfo)) != 0) {
246 : return false;
247 : }
248 :
249 : bool valid = false;
250 :
251 2553 : for (struct addrinfo *p = servinfo; p != nullptr; p = p->ai_next) {
252 2553 : if (p->ai_family == AF_INET) { // IPv4
253 2553 : addr = *(struct sockaddr_in *)p->ai_addr;
254 2553 : addr.sin_port = htons((unsigned short)port_);
255 : valid = true;
256 2553 : break;
257 : }
258 : }
259 :
260 2553 : freeaddrinfo(servinfo); // free the linked list
261 :
262 2553 : return valid;
263 : }
264 :
265 :
266 : // ----------------------------------------------------------------------
267 : Socket*
268 3391 : Socket::
269 : accept(const bool create)
270 : {
271 3391 : if( socket_ >= 0 )
272 : return nullptr;
273 :
274 : struct sockaddr_in client_addr;
275 : #ifdef WIN32
276 : int addrlen = sizeof(client_addr);
277 : #else
278 3391 : socklen_t addrlen = sizeof(client_addr);
279 : #endif
280 :
281 3391 : if( server_socket_ < 0 )
282 : {
283 : struct sockaddr_in self;
284 :
285 : //Create the server socket
286 3141 : server_socket_ = static_cast<int>(socket( AF_INET, SOCK_STREAM, 0 ));
287 3141 : if( server_socket_ < 0 )
288 0 : BailOnSocketError("tcpip::Socket::accept() @ socket");
289 :
290 : //"Address already in use" error protection
291 : {
292 :
293 : #ifdef WIN32
294 : //setsockopt(server_socket_, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuseaddr, sizeof(reuseaddr));
295 : // No address reuse in Windows!!!
296 : #else
297 3141 : int reuseaddr = 1;
298 3141 : setsockopt(server_socket_, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, sizeof(reuseaddr));
299 : #endif
300 : }
301 :
302 : // Initialize address/port structure
303 : memset(&self, 0, sizeof(self));
304 3141 : self.sin_family = AF_INET;
305 3141 : self.sin_port = htons((unsigned short)port_);
306 : self.sin_addr.s_addr = htonl(INADDR_ANY);
307 :
308 : // Assign a port number to the socket
309 3141 : if ( bind(server_socket_, (struct sockaddr*)&self, sizeof(self)) != 0 )
310 6 : BailOnSocketError("tcpip::Socket::accept() Unable to create listening socket");
311 :
312 :
313 : // Make it a "listening socket"
314 3135 : if ( listen(server_socket_, 10) == -1 )
315 0 : BailOnSocketError("tcpip::Socket::accept() Unable to listen on server socket");
316 :
317 : // Make the newly created socket blocking or not
318 3135 : set_blocking(blocking_);
319 : }
320 :
321 3385 : socket_ = static_cast<int>(::accept(server_socket_, (struct sockaddr*)&client_addr, &addrlen));
322 :
323 3385 : if( socket_ >= 0 )
324 : {
325 3385 : int x = 1;
326 3385 : setsockopt(socket_, IPPROTO_TCP, TCP_NODELAY, (const char*)&x, sizeof(x));
327 3385 : if (create) {
328 3385 : Socket* result = new Socket(0);
329 3385 : result->socket_ = socket_;
330 3385 : socket_ = -1;
331 3385 : return result;
332 : }
333 : }
334 : return nullptr;
335 : }
336 :
337 : // ----------------------------------------------------------------------
338 : void
339 3135 : Socket::
340 : set_blocking(bool blocking)
341 : {
342 3135 : blocking_ = blocking;
343 :
344 3135 : if( server_socket_ > 0 )
345 : {
346 : #ifdef WIN32
347 : ULONG NonBlock = blocking_ ? 0 : 1;
348 : if (ioctlsocket(server_socket_, FIONBIO, &NonBlock) == SOCKET_ERROR)
349 : BailOnSocketError("tcpip::Socket::set_blocking() Unable to initialize non blocking I/O");
350 : #else
351 3135 : long arg = fcntl(server_socket_, F_GETFL, NULL);
352 3135 : if (blocking_)
353 : {
354 3135 : arg &= ~O_NONBLOCK;
355 : } else {
356 0 : arg |= O_NONBLOCK;
357 : }
358 3135 : fcntl(server_socket_, F_SETFL, arg);
359 : #endif
360 : }
361 :
362 3135 : }
363 :
364 : // ----------------------------------------------------------------------
365 : void
366 2553 : Socket::
367 : connect()
368 : {
369 : sockaddr_in address;
370 :
371 5106 : if( !atoaddr( host_.c_str(), address) )
372 0 : BailOnSocketError("tcpip::Socket::connect() @ Invalid network address");
373 :
374 2553 : socket_ = static_cast<int>(socket( PF_INET, SOCK_STREAM, 0 ));
375 2553 : if( socket_ < 0 )
376 0 : BailOnSocketError("tcpip::Socket::connect() @ socket");
377 :
378 2553 : if( ::connect( socket_, (sockaddr const*)&address, sizeof(address) ) < 0 )
379 1334 : BailOnSocketError("tcpip::Socket::connect() @ connect");
380 :
381 1219 : if( socket_ >= 0 )
382 : {
383 1219 : int x = 1;
384 1219 : setsockopt(socket_, IPPROTO_TCP, TCP_NODELAY, (const char*)&x, sizeof(x));
385 : }
386 1219 : }
387 :
388 : // ----------------------------------------------------------------------
389 : void
390 10829 : Socket::
391 : close()
392 : {
393 : // Close client-connection
394 10829 : if( socket_ >= 0 )
395 : {
396 : #ifdef WIN32
397 : ::closesocket( socket_ );
398 : #else
399 5919 : ::close( socket_ );
400 : #endif
401 :
402 5919 : socket_ = -1;
403 : }
404 10829 : }
405 :
406 : // ----------------------------------------------------------------------
407 : void
408 17235498 : Socket::
409 : send( const std::vector<unsigned char> &buffer)
410 : {
411 17235498 : if( socket_ < 0 )
412 : return;
413 :
414 34470996 : printBufferOnVerbose(buffer, "Send");
415 :
416 : size_t numbytes = buffer.size();
417 : unsigned char const *bufPtr = &buffer[0];
418 34470994 : while( numbytes > 0 )
419 : {
420 : #ifdef WIN32
421 : int bytesSent = ::send( socket_, (const char*)bufPtr, static_cast<int>(numbytes), 0 );
422 : #else
423 17235498 : int bytesSent = ::send( socket_, bufPtr, numbytes, 0 );
424 : #endif
425 17235498 : if( bytesSent < 0 )
426 2 : BailOnSocketError( "send failed" );
427 :
428 17235496 : numbytes -= bytesSent;
429 17235496 : bufPtr += bytesSent;
430 : }
431 : }
432 :
433 :
434 :
435 : // ----------------------------------------------------------------------
436 :
437 : void
438 17234854 : Socket::
439 : sendExact( const Storage &b)
440 : {
441 17234854 : int length = static_cast<int>(b.size());
442 17234854 : Storage length_storage;
443 17234854 : length_storage.writeInt(lengthLen + length);
444 :
445 : // Sending length_storage and b independently would probably be possible and
446 : // avoid some copying here, but both parts would have to go through the
447 : // TCP/IP stack on their own which probably would cost more performance.
448 : std::vector<unsigned char> msg;
449 17234854 : msg.insert(msg.end(), length_storage.begin(), length_storage.end());
450 17234854 : msg.insert(msg.end(), b.begin(), b.end());
451 17234854 : send(msg);
452 17234854 : }
453 :
454 :
455 : // ----------------------------------------------------------------------
456 : size_t
457 34469747 : Socket::
458 : recvAndCheck(unsigned char * const buffer, std::size_t len)
459 : const
460 : {
461 : #ifdef WIN32
462 : const int bytesReceived = recv( socket_, (char*)buffer, static_cast<int>(len), 0 );
463 : #else
464 34469747 : const int bytesReceived = static_cast<int>(recv( socket_, buffer, len, 0 ));
465 : #endif
466 34469747 : if( bytesReceived == 0 )
467 50 : throw SocketException( "tcpip::Socket::recvAndCheck @ recv: peer shutdown" );
468 34469722 : if( bytesReceived < 0 )
469 2 : BailOnSocketError( "tcpip::Socket::recvAndCheck @ recv" );
470 :
471 34469720 : return static_cast<size_t>(bytesReceived);
472 : }
473 :
474 :
475 : // ----------------------------------------------------------------------
476 : void
477 34469747 : Socket::
478 : receiveComplete(unsigned char * buffer, size_t len)
479 : const
480 : {
481 68939467 : while (len > 0)
482 : {
483 34469747 : const size_t bytesReceived = recvAndCheck(buffer, len);
484 34469720 : len -= bytesReceived;
485 34469720 : buffer += bytesReceived;
486 : }
487 34469720 : }
488 :
489 :
490 : // ----------------------------------------------------------------------
491 : void
492 34470358 : Socket::
493 : printBufferOnVerbose(const std::vector<unsigned char> buffer, const std::string &label)
494 : const
495 : {
496 34470358 : if (verbose_)
497 : {
498 0 : std::cerr << label << " " << buffer.size() << " bytes via tcpip::Socket: [";
499 : // cache end iterator for performance
500 : const std::vector<unsigned char>::const_iterator end = buffer.end();
501 0 : for (std::vector<unsigned char>::const_iterator it = buffer.begin(); end != it; ++it)
502 0 : std::cerr << " " << static_cast<int>(*it) << " ";
503 : std::cerr << "]" << std::endl;
504 : }
505 34470358 : }
506 :
507 :
508 : // ----------------------------------------------------------------------
509 : std::vector<unsigned char>
510 0 : Socket::
511 : receive(int bufSize)
512 : {
513 : std::vector<unsigned char> buffer;
514 :
515 0 : if( socket_ < 0 )
516 0 : connect();
517 :
518 0 : if( !datawaiting( socket_) )
519 : return buffer;
520 :
521 0 : buffer.resize(bufSize);
522 0 : const size_t bytesReceived = recvAndCheck(&buffer[0], bufSize);
523 :
524 0 : buffer.resize(bytesReceived);
525 :
526 0 : printBufferOnVerbose(buffer, "Rcvd");
527 :
528 0 : return buffer;
529 : }
530 :
531 : // ----------------------------------------------------------------------
532 :
533 :
534 : bool
535 17234887 : Socket::
536 : receiveExact( Storage &msg )
537 : {
538 : // buffer for received bytes
539 : // According to the C++ standard elements of a std::vector are stored
540 : // contiguously. Explicitly &buffer[n] == &buffer[0] + n for 0 <= n < buffer.size().
541 17234887 : std::vector<unsigned char> buffer(lengthLen);
542 :
543 : // receive length of TraCI message
544 17234887 : receiveComplete(&buffer[0], lengthLen);
545 17234860 : Storage length_storage(&buffer[0], lengthLen);
546 17234860 : const int totalLen = length_storage.readInt();
547 : assert(totalLen > lengthLen);
548 :
549 : // extent buffer
550 17234860 : buffer.resize(totalLen);
551 :
552 : // receive remaining TraCI message
553 17234860 : receiveComplete(&buffer[lengthLen], totalLen - lengthLen);
554 :
555 : // copy message content into passed Storage
556 17234860 : msg.reset();
557 17234860 : msg.writePacket(&buffer[lengthLen], totalLen - lengthLen);
558 :
559 34469720 : printBufferOnVerbose(buffer, "Rcvd Storage with");
560 :
561 17234860 : return true;
562 17234860 : }
563 :
564 :
565 : // ----------------------------------------------------------------------
566 : bool
567 718445 : Socket::
568 : has_client_connection()
569 : const
570 : {
571 718445 : return socket_ >= 0;
572 : }
573 :
574 : // ----------------------------------------------------------------------
575 : bool
576 0 : Socket::
577 : is_blocking()
578 : {
579 0 : return blocking_;
580 : }
581 :
582 :
583 : #ifdef WIN32
584 : // ----------------------------------------------------------------------
585 : std::string
586 : Socket::
587 : GetWinsockErrorString(int err)
588 : {
589 :
590 : switch( err)
591 : {
592 : case 0: return "No error";
593 : case WSAEINTR: return "Interrupted system call";
594 : case WSAEBADF: return "Bad file number";
595 : case WSAEACCES: return "Permission denied";
596 : case WSAEFAULT: return "Bad address";
597 : case WSAEINVAL: return "Invalid argument";
598 : case WSAEMFILE: return "Too many open sockets";
599 : case WSAEWOULDBLOCK: return "Operation would block";
600 : case WSAEINPROGRESS: return "Operation now in progress";
601 : case WSAEALREADY: return "Operation already in progress";
602 : case WSAENOTSOCK: return "Socket operation on non-socket";
603 : case WSAEDESTADDRREQ: return "Destination address required";
604 : case WSAEMSGSIZE: return "Message too long";
605 : case WSAEPROTOTYPE: return "Protocol wrong type for socket";
606 : case WSAENOPROTOOPT: return "Bad protocol option";
607 : case WSAEPROTONOSUPPORT: return "Protocol not supported";
608 : case WSAESOCKTNOSUPPORT: return "Socket type not supported";
609 : case WSAEOPNOTSUPP: return "Operation not supported on socket";
610 : case WSAEPFNOSUPPORT: return "Protocol family not supported";
611 : case WSAEAFNOSUPPORT: return "Address family not supported";
612 : case WSAEADDRINUSE: return "Address already in use";
613 : case WSAEADDRNOTAVAIL: return "Can't assign requested address";
614 : case WSAENETDOWN: return "Network is down";
615 : case WSAENETUNREACH: return "Network is unreachable";
616 : case WSAENETRESET: return "Net Socket reset";
617 : case WSAECONNABORTED: return "Software caused tcpip::Socket abort";
618 : case WSAECONNRESET: return "Socket reset by peer";
619 : case WSAENOBUFS: return "No buffer space available";
620 : case WSAEISCONN: return "Socket is already connected";
621 : case WSAENOTCONN: return "Socket is not connected";
622 : case WSAESHUTDOWN: return "Can't send after socket shutdown";
623 : case WSAETOOMANYREFS: return "Too many references, can't splice";
624 : case WSAETIMEDOUT: return "Socket timed out";
625 : case WSAECONNREFUSED: return "Socket refused";
626 : case WSAELOOP: return "Too many levels of symbolic links";
627 : case WSAENAMETOOLONG: return "File name too long";
628 : case WSAEHOSTDOWN: return "Host is down";
629 : case WSAEHOSTUNREACH: return "No route to host";
630 : case WSAENOTEMPTY: return "Directory not empty";
631 : case WSAEPROCLIM: return "Too many processes";
632 : case WSAEUSERS: return "Too many users";
633 : case WSAEDQUOT: return "Disc quota exceeded";
634 : case WSAESTALE: return "Stale NFS file handle";
635 : case WSAEREMOTE: return "Too many levels of remote in path";
636 : case WSASYSNOTREADY: return "Network system is unavailable";
637 : case WSAVERNOTSUPPORTED: return "Winsock version out of range";
638 : case WSANOTINITIALISED: return "WSAStartup not yet called";
639 : case WSAEDISCON: return "Graceful shutdown in progress";
640 : case WSAHOST_NOT_FOUND: return "Host not found";
641 : case WSANO_DATA: return "No host data of that type was found";
642 : }
643 :
644 : return "unknown";
645 : }
646 :
647 : #endif // WIN32
648 :
649 : } // namespace tcpip
650 :
651 : #endif // BUILD_TCPIP
652 :
653 : /*-----------------------------------------------------------------------
654 : * Source $Source: $
655 : * Version $Revision: 645 $
656 : * Date $Date: 2012-04-27 14:03:33 +0200 (Fri, 27 Apr 2012) $
657 : *-----------------------------------------------------------------------
658 : * $Log: $
659 : *-----------------------------------------------------------------------*/
|