Eclipse SUMO - Simulation of Urban MObility
Loading...
Searching...
No Matches
socket.cpp
Go to the documentation of this file.
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
61namespace 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 // ----------------------------------------------------------------------
73 Socket(std::string host, int port)
74 : host_( host ),
75 port_( port ),
76 socket_(-1),
77 server_socket_(-1),
78 blocking_(true),
79 verbose_(false)
80 {
81 init();
82 }
83
84 // ----------------------------------------------------------------------
86 Socket(int port)
87 : host_(""),
88 port_( port ),
89 socket_(-1),
90 server_socket_(-1),
91 blocking_(true),
92 verbose_(false)
93 {
94 init();
95 }
96
97 // ----------------------------------------------------------------------
98 void
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 }
114
115
116 int
119 {
120 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 int sock = static_cast<int>(socket( AF_INET, SOCK_STREAM, 0 ));
123 struct sockaddr_in self;
124 memset(&self, 0, sizeof(self));
125 self.sin_family = AF_INET;
126 self.sin_port = htons(0);
127 self.sin_addr.s_addr = htonl(INADDR_ANY);
128
129 socklen_t address_len = sizeof(self);
130 // bind with port==0 assigns free port
131 if ( bind(sock, (struct sockaddr*) &self, address_len) < 0)
132 BailOnSocketError("tcpip::Socket::getFreeSocketPort() Unable to bind socket");
133 // get the assigned port with getsockname
134 if ( getsockname(sock, (struct sockaddr*) &self, &address_len) < 0)
135 BailOnSocketError("tcpip::Socket::getFreeSocketPort() Unable to get socket name");
136 const int port = ntohs(self.sin_port);
137#ifdef WIN32
138 ::closesocket( sock );
139#else
140 ::close( sock );
141#endif
142 return port;
143 }
144
145
146 // ----------------------------------------------------------------------
148 ~Socket()
149 {
150 // Close first an existing client connection ...
151 close();
152#ifdef WIN32
153 instance_count_--;
154#endif
155
156 // ... then the server socket
157 if( server_socket_ >= 0 )
158 {
159#ifdef WIN32
160 ::closesocket( server_socket_ );
161#else
163#endif
164 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 }
174
175 // ----------------------------------------------------------------------
176 void
178 BailOnSocketError( std::string context)
179 {
180#ifdef WIN32
181 int e = WSAGetLastError();
182 std::string msg = GetWinsockErrorString( e );
183#else
184 std::string msg = strerror( errno );
185#endif
186 throw SocketException( context + ": " + msg );
187 }
188
189 // ----------------------------------------------------------------------
190 int
192 port()
193 {
194 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
206 datawaiting(int sock)
207 const
208 {
209 fd_set fds;
210 FD_ZERO( &fds );
211 FD_SET( (unsigned int)sock, &fds );
212
213 struct timeval tv;
214 tv.tv_sec = 0;
215 tv.tv_usec = 0;
216
217 int r = select( sock+1, &fds, nullptr, nullptr, &tv);
218
219 if (r < 0)
220 BailOnSocketError("tcpip::Socket::datawaiting @ select");
221
222 if( FD_ISSET( sock, &fds ) )
223 return true;
224 else
225 return false;
226 }
227#ifdef _MSC_VER
228#pragma warning(pop)
229#endif
230
231 // ----------------------------------------------------------------------
232 Socket*
234 accept(const bool create)
235 {
236 if( socket_ >= 0 )
237 return nullptr;
238
239 struct sockaddr_in client_addr;
240#ifdef WIN32
241 int addrlen = sizeof(client_addr);
242#else
243 socklen_t addrlen = sizeof(client_addr);
244#endif
245
246 if( server_socket_ < 0 )
247 {
248 struct sockaddr_in self;
249
250 //Create the server socket
251 server_socket_ = static_cast<int>(socket( AF_INET, SOCK_STREAM, 0 ));
252 if( server_socket_ < 0 )
253 BailOnSocketError("tcpip::Socket::accept() @ socket");
254
255 //"Address already in use" error protection
256 {
257
258 #ifdef WIN32
259 //setsockopt(server_socket_, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuseaddr, sizeof(reuseaddr));
260 // No address reuse in Windows!!!
261 #else
262 int reuseaddr = 1;
263 setsockopt(server_socket_, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, sizeof(reuseaddr));
264 #endif
265 }
266
267 // Initialize address/port structure
268 memset(&self, 0, sizeof(self));
269 self.sin_family = AF_INET;
270 self.sin_port = htons((unsigned short)port_);
271 self.sin_addr.s_addr = htonl(INADDR_ANY);
272
273 // Assign a port number to the socket
274 if ( bind(server_socket_, (struct sockaddr*)&self, sizeof(self)) != 0 )
275 BailOnSocketError("tcpip::Socket::accept() Unable to create listening socket");
276
277
278 // Make it a "listening socket"
279 if ( listen(server_socket_, 10) == -1 )
280 BailOnSocketError("tcpip::Socket::accept() Unable to listen on server socket");
281
282 // Make the newly created socket blocking or not
284 }
285
286 socket_ = static_cast<int>(::accept(server_socket_, (struct sockaddr*)&client_addr, &addrlen));
287
288 if( socket_ >= 0 )
289 {
290 int x = 1;
291 setsockopt(socket_, IPPROTO_TCP, TCP_NODELAY, (const char*)&x, sizeof(x));
292 if (create) {
293 Socket* result = new Socket(0);
294 result->socket_ = socket_;
295 socket_ = -1;
296 return result;
297 }
298 }
299 return nullptr;
300 }
301
302 // ----------------------------------------------------------------------
303 void
305 set_blocking(bool blocking)
306 {
307 blocking_ = blocking;
308
309 if( server_socket_ > 0 )
310 {
311#ifdef WIN32
312 ULONG NonBlock = blocking_ ? 0 : 1;
313 if (ioctlsocket(server_socket_, FIONBIO, &NonBlock) == SOCKET_ERROR)
314 BailOnSocketError("tcpip::Socket::set_blocking() Unable to initialize non blocking I/O");
315#else
316 long arg = fcntl(server_socket_, F_GETFL, NULL);
317 if (blocking_)
318 {
319 arg &= ~O_NONBLOCK;
320 } else {
321 arg |= O_NONBLOCK;
322 }
323 fcntl(server_socket_, F_SETFL, arg);
324#endif
325 }
326
327 }
328
329 // ----------------------------------------------------------------------
330 void
332 connect()
333 {
334 struct addrinfo* servinfo; // will point to the results
335 struct addrinfo hints;
336 memset(&hints, 0, sizeof hints); // make sure the struct is empty
337 hints.ai_family = AF_UNSPEC; // IP4 and IP6 are possible
338 hints.ai_socktype = SOCK_STREAM; // TCP stream sockets
339 hints.ai_flags = AI_PASSIVE; // fill in my IP for me
340
341 if (getaddrinfo(host_.c_str(), std::to_string(port_).c_str(), &hints, &servinfo) != 0) {
342 BailOnSocketError("tcpip::Socket::connect() @ Invalid network address");
343 }
344 socket_ = -1;
345 for (struct addrinfo* p = servinfo; p != nullptr; p = p->ai_next) {
346 socket_ = (int)socket(p->ai_family, p->ai_socktype, p->ai_protocol);
347 if (socket_ >= 0) {
348 if (::connect(socket_, p->ai_addr, (int)p->ai_addrlen) == 0) {
349 int x = 1;
350 setsockopt(socket_, IPPROTO_TCP, TCP_NODELAY, (const char*)&x, sizeof(x));
351 break;
352 }
353 close();
354 }
355 }
356 freeaddrinfo(servinfo); // free the linked list
357 if (socket_ < 0) {
358 BailOnSocketError("tcpip::Socket::connect() @ socket");
359 }
360 }
361
362 // ----------------------------------------------------------------------
363 void
365 close()
366 {
367 // Close client-connection
368 if( socket_ >= 0 )
369 {
370#ifdef WIN32
371 ::closesocket( socket_ );
372#else
373 ::close( socket_ );
374#endif
375
376 socket_ = -1;
377 }
378 }
379
380 // ----------------------------------------------------------------------
381 void
383 send( const std::vector<unsigned char> &buffer)
384 {
385 if( socket_ < 0 )
386 return;
387
388 printBufferOnVerbose(buffer, "Send");
389
390 size_t numbytes = buffer.size();
391 unsigned char const *bufPtr = &buffer[0];
392 while( numbytes > 0 )
393 {
394#ifdef WIN32
395 int bytesSent = ::send( socket_, (const char*)bufPtr, static_cast<int>(numbytes), 0 );
396#else
397 int bytesSent = ::send( socket_, bufPtr, numbytes, 0 );
398#endif
399 if( bytesSent < 0 )
400 BailOnSocketError( "send failed" );
401
402 numbytes -= bytesSent;
403 bufPtr += bytesSent;
404 }
405 }
406
407
408
409 // ----------------------------------------------------------------------
410
411 void
413 sendExact( const Storage &b)
414 {
415 int length = static_cast<int>(b.size());
416 Storage length_storage;
417 length_storage.writeInt(lengthLen + length);
418
419 // Sending length_storage and b independently would probably be possible and
420 // avoid some copying here, but both parts would have to go through the
421 // TCP/IP stack on their own which probably would cost more performance.
422 std::vector<unsigned char> msg;
423 msg.insert(msg.end(), length_storage.begin(), length_storage.end());
424 msg.insert(msg.end(), b.begin(), b.end());
425 send(msg);
426 }
427
428
429 // ----------------------------------------------------------------------
430 size_t
432 recvAndCheck(unsigned char * const buffer, std::size_t len)
433 const
434 {
435#ifdef WIN32
436 const int bytesReceived = recv( socket_, (char*)buffer, static_cast<int>(len), 0 );
437#else
438 const int bytesReceived = static_cast<int>(recv( socket_, buffer, len, 0 ));
439#endif
440 if( bytesReceived == 0 )
441 throw SocketException( "tcpip::Socket::recvAndCheck @ recv: peer shutdown" );
442 if( bytesReceived < 0 )
443 BailOnSocketError( "tcpip::Socket::recvAndCheck @ recv" );
444
445 return static_cast<size_t>(bytesReceived);
446 }
447
448
449 // ----------------------------------------------------------------------
450 void
452 receiveComplete(unsigned char * buffer, size_t len)
453 const
454 {
455 while (len > 0)
456 {
457 const size_t bytesReceived = recvAndCheck(buffer, len);
458 len -= bytesReceived;
459 buffer += bytesReceived;
460 }
461 }
462
463
464 // ----------------------------------------------------------------------
465 void
467 printBufferOnVerbose(const std::vector<unsigned char> buffer, const std::string &label)
468 const
469 {
470 if (verbose_)
471 {
472 std::cerr << label << " " << buffer.size() << " bytes via tcpip::Socket: [";
473 // cache end iterator for performance
474 const std::vector<unsigned char>::const_iterator end = buffer.end();
475 for (std::vector<unsigned char>::const_iterator it = buffer.begin(); end != it; ++it)
476 std::cerr << " " << static_cast<int>(*it) << " ";
477 std::cerr << "]" << std::endl;
478 }
479 }
480
481
482 // ----------------------------------------------------------------------
483 std::vector<unsigned char>
485 receive(int bufSize)
486 {
487 std::vector<unsigned char> buffer;
488
489 if( socket_ < 0 )
490 connect();
491
492 if( !datawaiting( socket_) )
493 return buffer;
494
495 buffer.resize(bufSize);
496 const size_t bytesReceived = recvAndCheck(&buffer[0], bufSize);
497
498 buffer.resize(bytesReceived);
499
500 printBufferOnVerbose(buffer, "Rcvd");
501
502 return buffer;
503 }
504
505 // ----------------------------------------------------------------------
506
507
508 bool
511 {
512 // buffer for received bytes
513 // According to the C++ standard elements of a std::vector are stored
514 // contiguously. Explicitly &buffer[n] == &buffer[0] + n for 0 <= n < buffer.size().
515 std::vector<unsigned char> buffer(lengthLen);
516
517 // receive length of TraCI message
518 receiveComplete(&buffer[0], lengthLen);
519 Storage length_storage(&buffer[0], lengthLen);
520 const int totalLen = length_storage.readInt();
521 assert(totalLen > lengthLen);
522
523 // extent buffer
524 buffer.resize(totalLen);
525
526 // receive remaining TraCI message
527 receiveComplete(&buffer[lengthLen], totalLen - lengthLen);
528
529 // copy message content into passed Storage
530 msg.reset();
531 msg.writePacket(&buffer[lengthLen], totalLen - lengthLen);
532
533 printBufferOnVerbose(buffer, "Rcvd Storage with");
534
535 return true;
536 }
537
538
539 // ----------------------------------------------------------------------
540 bool
543 const
544 {
545 return socket_ >= 0;
546 }
547
548 // ----------------------------------------------------------------------
549 bool
552 {
553 return blocking_;
554 }
555
556
557#ifdef WIN32
558 // ----------------------------------------------------------------------
559 std::string
560 Socket::
561 GetWinsockErrorString(int err)
562 {
563
564 switch( err)
565 {
566 case 0: return "No error";
567 case WSAEINTR: return "Interrupted system call";
568 case WSAEBADF: return "Bad file number";
569 case WSAEACCES: return "Permission denied";
570 case WSAEFAULT: return "Bad address";
571 case WSAEINVAL: return "Invalid argument";
572 case WSAEMFILE: return "Too many open sockets";
573 case WSAEWOULDBLOCK: return "Operation would block";
574 case WSAEINPROGRESS: return "Operation now in progress";
575 case WSAEALREADY: return "Operation already in progress";
576 case WSAENOTSOCK: return "Socket operation on non-socket";
577 case WSAEDESTADDRREQ: return "Destination address required";
578 case WSAEMSGSIZE: return "Message too long";
579 case WSAEPROTOTYPE: return "Protocol wrong type for socket";
580 case WSAENOPROTOOPT: return "Bad protocol option";
581 case WSAEPROTONOSUPPORT: return "Protocol not supported";
582 case WSAESOCKTNOSUPPORT: return "Socket type not supported";
583 case WSAEOPNOTSUPP: return "Operation not supported on socket";
584 case WSAEPFNOSUPPORT: return "Protocol family not supported";
585 case WSAEAFNOSUPPORT: return "Address family not supported";
586 case WSAEADDRINUSE: return "Address already in use";
587 case WSAEADDRNOTAVAIL: return "Can't assign requested address";
588 case WSAENETDOWN: return "Network is down";
589 case WSAENETUNREACH: return "Network is unreachable";
590 case WSAENETRESET: return "Net Socket reset";
591 case WSAECONNABORTED: return "Software caused tcpip::Socket abort";
592 case WSAECONNRESET: return "Socket reset by peer";
593 case WSAENOBUFS: return "No buffer space available";
594 case WSAEISCONN: return "Socket is already connected";
595 case WSAENOTCONN: return "Socket is not connected";
596 case WSAESHUTDOWN: return "Can't send after socket shutdown";
597 case WSAETOOMANYREFS: return "Too many references, can't splice";
598 case WSAETIMEDOUT: return "Socket timed out";
599 case WSAECONNREFUSED: return "Socket refused";
600 case WSAELOOP: return "Too many levels of symbolic links";
601 case WSAENAMETOOLONG: return "File name too long";
602 case WSAEHOSTDOWN: return "Host is down";
603 case WSAEHOSTUNREACH: return "No route to host";
604 case WSAENOTEMPTY: return "Directory not empty";
605 case WSAEPROCLIM: return "Too many processes";
606 case WSAEUSERS: return "Too many users";
607 case WSAEDQUOT: return "Disc quota exceeded";
608 case WSAESTALE: return "Stale NFS file handle";
609 case WSAEREMOTE: return "Too many levels of remote in path";
610 case WSASYSNOTREADY: return "Network system is unavailable";
611 case WSAVERNOTSUPPORTED: return "Winsock version out of range";
612 case WSANOTINITIALISED: return "WSAStartup not yet called";
613 case WSAEDISCON: return "Graceful shutdown in progress";
614 case WSAHOST_NOT_FOUND: return "Host not found";
615 case WSANO_DATA: return "No host data of that type was found";
616 }
617
618 return "unknown";
619 }
620
621#endif // WIN32
622
623} // namespace tcpip
624
625#endif // BUILD_TCPIP
626
627/*-----------------------------------------------------------------------
628* Source $Source: $
629* Version $Revision: 645 $
630* Date $Date: 2012-04-27 14:03:33 +0200 (Fri, 27 Apr 2012) $
631*-----------------------------------------------------------------------
632* $Log: $
633*-----------------------------------------------------------------------*/
void printBufferOnVerbose(const std::vector< unsigned char > buffer, const std::string &label) const
Print label and buffer to stderr if Socket::verbose_ is set.
Definition socket.cpp:467
bool receiveExact(Storage &)
Receive a complete TraCI message from Socket::socket_.
Definition socket.cpp:510
void init()
Definition socket.cpp:100
std::vector< unsigned char > receive(int bufSize=2048)
Receive up to bufSize available bytes from Socket::socket_.
Definition socket.cpp:485
bool blocking_
Definition socket.h:122
bool datawaiting(int sock) const
Definition socket.cpp:206
size_t recvAndCheck(unsigned char *const buffer, std::size_t len) const
Receive up to len available bytes from Socket::socket_.
Definition socket.cpp:432
static void BailOnSocketError(std::string context)
Definition socket.cpp:178
static int getFreeSocketPort()
Returns an free port on the system.
Definition socket.cpp:118
bool verbose_
Definition socket.h:124
bool is_blocking()
Definition socket.cpp:551
int server_socket_
Definition socket.h:121
~Socket()
Destructor.
Definition socket.cpp:148
void sendExact(const Storage &)
Definition socket.cpp:413
bool has_client_connection() const
Definition socket.cpp:542
void connect()
Connects to host_:port_.
Definition socket.cpp:332
static const int lengthLen
Length of the message length part of a TraCI message.
Definition socket.h:101
std::string host_
Definition socket.h:118
void set_blocking(bool)
Definition socket.cpp:305
Socket * accept(const bool create=false)
Wait for a incoming connection to port_.
Definition socket.cpp:234
void receiveComplete(unsigned char *const buffer, std::size_t len) const
Receive len bytes from Socket::socket_.
Definition socket.cpp:452
void send(const std::vector< unsigned char > &buffer)
Definition socket.cpp:383
Socket(std::string host, int port)
Constructor that prepare to connect to host:port.
Definition socket.cpp:73
void close()
Definition socket.cpp:365
virtual void writePacket(unsigned char *packet, int length)
Definition storage.cpp:372
StorageType::const_iterator begin() const
Definition storage.h:121
virtual void writeInt(int)
Definition storage.cpp:321
StorageType::const_iterator end() const
Definition storage.h:122
StorageType::size_type size() const
Definition storage.h:119
virtual int readInt()
Definition storage.cpp:311