Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/foreign/tcpip/socket.cpp
169678 views
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
Socket::
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
// ----------------------------------------------------------------------
85
Socket::
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
99
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
}
114
115
116
int
117
Socket::
118
getFreeSocketPort()
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
// ----------------------------------------------------------------------
147
Socket::
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
162
::close( server_socket_ );
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
177
Socket::
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
191
Socket::
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
205
Socket::
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*
233
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
283
set_blocking(blocking_);
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
304
Socket::
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
331
Socket::
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
364
Socket::
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
382
Socket::
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
412
Socket::
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
431
Socket::
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
451
Socket::
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
466
Socket::
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>
484
Socket::
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
509
Socket::
510
receiveExact( Storage &msg )
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
541
Socket::
542
has_client_connection()
543
const
544
{
545
return socket_ >= 0;
546
}
547
548
// ----------------------------------------------------------------------
549
bool
550
Socket::
551
is_blocking()
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
*-----------------------------------------------------------------------*/
634
635