Line data Source code
1 : // $Id: SystemSocket.cpp 7418 2009-12-16 22:08:43Z pgrenz $
2 : ////////////////////////////////////////////////////////////////////////////////
3 :
4 : #include "SystemSocket.hpp"
5 : #include <unistd.h>
6 : #include <errno.h>
7 : #include <iostream>
8 : #include <sstream>
9 : #include <sstream>
10 : #include <sys/types.h>
11 : #include <string.h> // For 'memset'.
12 : #include <stdlib.h> // For 'malloc', 'free', etc.
13 : // For the "TCP_NODELAY" constant.
14 : #include <netinet/tcp.h>
15 : // For the "geLocalIP" function:
16 : #include <sys/socket.h>
17 : #include <net/if.h>
18 : #include <sys/ioctl.h>
19 : #include <net/if_arp.h>
20 : #include <arpa/inet.h> // for inet_addr
21 : // End of includes for the "getLocalIP" function.
22 :
23 : using ::std::string;
24 : using ::std::vector;
25 : using pcf::SystemSocket;
26 :
27 : // On the MAC, there is no "MSG_NOSIGNAL" flag. The equivalent is
28 : // "SO_NOSIGPIPE" (on version 10.2 and later)
29 : #if defined(__APPLE__)
30 : //#ifdef __FreeBSD__
31 : //# if __FreeBSD_version >= 400014
32 : //# define s6_addr16 __u6_addr.__u6_addr16
33 : # if !defined(MSG_NOSIGNAL)
34 : # define MSG_NOSIGNAL SO_NOSIGPIPE
35 : # endif
36 : //# endif
37 : #endif
38 :
39 : ////////////////////////////////////////////////////////////////////////////////
40 : /// Basic constructor.
41 :
42 0 : SystemSocket::SystemSocket() : m_tType(UnknownType), m_nLastError(0), m_nSocket(-1),
43 0 : m_nConnectTimeout(1000), m_nPort(-1), m_oIsNagleDisabled(false), m_oIsBound(false)
44 : {
45 0 : }
46 :
47 : ////////////////////////////////////////////////////////////////////////////////
48 : /// Constructor which sets the socket parameters.
49 :
50 0 : SystemSocket::SystemSocket( const Type &tType,
51 : const int &nPort,
52 0 : const string &szHost ) : m_tType(tType), m_nLastError(0), m_nSocket(-1),
53 0 : m_nConnectTimeout(1000), m_szHost(szHost), m_nPort(nPort),
54 0 : m_oIsNagleDisabled(false), m_oIsBound(false)
55 : {
56 0 : }
57 :
58 : ////////////////////////////////////////////////////////////////////////////////
59 : /// Basic destructor.
60 :
61 0 : SystemSocket::~SystemSocket()
62 : {
63 0 : if ( isValid() == true )
64 0 : close();
65 0 : }
66 :
67 : ////////////////////////////////////////////////////////////////////////////////
68 : /// Copy constructor. Initialize this SystemSocket from another one.
69 :
70 0 : SystemSocket::SystemSocket( const SystemSocket &rhs )
71 : {
72 0 : m_tType = rhs.m_tType;
73 0 : m_nPort = rhs.m_nPort;
74 0 : m_szHost = rhs.m_szHost;
75 : // The socket file descriptor should not be copied,
76 : // since each must be unique.
77 0 : m_nSocket = -1;
78 0 : m_nConnectTimeout = rhs.m_nConnectTimeout;
79 : // The Nagle algorithm is enabled by default.
80 0 : m_oIsNagleDisabled = false;
81 : // 'bind' has not been called.
82 0 : m_oIsBound = false;
83 : // No errors yet!
84 0 : m_nLastError = 0;
85 0 : }
86 :
87 : ////////////////////////////////////////////////////////////////////////////////
88 : /// Assignment operator. Assigns this object from another SystemSocket object.
89 :
90 0 : const SystemSocket &SystemSocket::operator= ( const SystemSocket &rhs )
91 : {
92 0 : if ( &rhs != this )
93 : {
94 : // We don't want to keep an fd by mistake.
95 0 : if ( isValid() == true )
96 0 : close();
97 :
98 0 : m_tType = rhs.m_tType;
99 0 : m_nPort = rhs.m_nPort;
100 0 : m_szHost = rhs.m_szHost;
101 : // The socket file descriptor should not be copied,
102 : // since each must be unique.
103 0 : m_nSocket = -1;
104 0 : m_nConnectTimeout = rhs.m_nConnectTimeout;
105 : // The Nagle algorithm is enabled by default.
106 0 : m_oIsNagleDisabled = false;
107 : // 'bind' has not been called.
108 0 : m_oIsBound = false;
109 : // No errors yet!
110 0 : m_nLastError = 0;
111 : }
112 0 : return *this;
113 : }
114 :
115 : ////////////////////////////////////////////////////////////////////////////////
116 : // Returns the type of the socket.
117 :
118 0 : SystemSocket::Type SystemSocket::getType() const
119 : {
120 0 : return m_tType;
121 : }
122 :
123 : ////////////////////////////////////////////////////////////////////////////////
124 : // Returns the last error that occurred when maniplating the socket.
125 :
126 0 : int SystemSocket::getLastError() const
127 : {
128 0 : return m_nLastError;
129 : }
130 :
131 : ////////////////////////////////////////////////////////////////////////////////
132 : // Returns the socket descriptor.
133 :
134 0 : int SystemSocket::getFd() const
135 : {
136 0 : return m_nSocket;
137 : }
138 :
139 : ////////////////////////////////////////////////////////////////////////////////
140 : // Returns true if the socket file descriptor is valid, false otherwise.
141 :
142 0 : bool SystemSocket::isValid() const
143 : {
144 0 : return ( bool )( m_nSocket >= 0 );
145 : }
146 :
147 : ////////////////////////////////////////////////////////////////////////////////
148 : // Returns true if the socket is bound to a port.
149 :
150 0 : bool SystemSocket::isBound() const
151 : {
152 0 : return m_oIsBound;
153 : }
154 :
155 : ////////////////////////////////////////////////////////////////////////////////
156 : // Set the connect timeout in milliseconds.
157 :
158 0 : void SystemSocket::setConnectTimeout( const int &nTimeout )
159 : {
160 0 : m_nConnectTimeout = nTimeout;
161 0 : }
162 :
163 : ////////////////////////////////////////////////////////////////////////////////
164 : // returns the socket host address.
165 :
166 0 : string SystemSocket::getHost() const
167 : {
168 0 : return m_szHost;
169 : }
170 :
171 : ////////////////////////////////////////////////////////////////////////////////
172 : // returns the socket port.
173 :
174 0 : int SystemSocket::getPort() const
175 : {
176 0 : return m_nPort;
177 : }
178 :
179 : ////////////////////////////////////////////////////////////////////////////////
180 : /// Makes a socket call to create a certain type of socket.
181 :
182 0 : void SystemSocket::create()
183 : {
184 : try
185 : {
186 : // We don't want to keep an fd by mistake.
187 0 : if ( isValid() == true )
188 0 : close();
189 :
190 : // The domain parameter specifies a communication domain; this selects
191 : // the protocol family which will be used for communication.
192 : // These families are defined in <sys/socket.h>
193 : // PF_INET:
194 : // IPv4 Internet protocols.
195 : // SOCK_STREAM
196 : // Provides sequenced, reliable, two-way, connection-based byte streams.
197 : // An out-of-band data transmission mechanism may be supported.
198 :
199 0 : int nTrue = 1;
200 :
201 0 : switch ( m_tType )
202 : {
203 0 : case Stream:
204 0 : if ( ( m_nSocket = ::socket( AF_INET, SOCK_STREAM, 0 ) ) < 0 )
205 : {
206 0 : m_nLastError = errno;
207 0 : throw ( Error( string( ": " ) + strerror( m_nLastError ) ) );
208 : }
209 0 : m_oIsBound = false;
210 0 : break;
211 0 : case Datagram:
212 0 : if ( ( m_nSocket = ::socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP ) ) < 0 )
213 : {
214 0 : m_nLastError = errno;
215 0 : throw ( Error( string( ": " ) + strerror( m_nLastError ) ) );
216 : }
217 0 : setOption( SOL_SOCKET, SO_BROADCAST, &nTrue, sizeof ( nTrue ) );
218 0 : m_oIsBound = false;
219 0 : break;
220 0 : case enumMulticast:
221 0 : if ( ( m_nSocket = ::socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP ) ) < 0 )
222 : {
223 0 : m_nLastError = errno;
224 0 : throw ( Error( string( ": " ) + strerror( m_nLastError ) ) );
225 : }
226 0 : setOption( SOL_SOCKET, SO_REUSEADDR, &nTrue, sizeof ( nTrue ) );
227 0 : m_oIsBound = false;
228 0 : break;
229 0 : default:
230 : case UnknownType:
231 0 : m_nSocket = -1;
232 0 : m_oIsBound = false;
233 : }
234 :
235 : }
236 0 : catch ( const Error &err )
237 : {
238 0 : throw Error( string( "::create" ) + err.what() );
239 0 : }
240 0 : }
241 :
242 : ////////////////////////////////////////////////////////////////////////////////
243 : /// This function creates a sockaddr_in struct based on the arguments
244 : /// passed in. "sockaddr_in.sin_addr.s_addr" == INADDR_NONE if there was an error.
245 :
246 0 : sockaddr_in SystemSocket::createSockAddr( const int &nPort,
247 : const string &szHost )
248 : {
249 : try
250 : {
251 : sockaddr_in saAddr;
252 0 : memset( &saAddr, 0, sizeof ( saAddr ) );
253 :
254 0 : saAddr.sin_family = AF_INET;
255 0 : saAddr.sin_port = htons( nPort );
256 0 : saAddr.sin_addr.s_addr = ( szHost.size() == 0 ) ?
257 0 : htonl( INADDR_ANY ) : ::inet_addr( szHost.c_str() );
258 :
259 : // Did 'inet_addr' fail?
260 0 : if ( saAddr.sin_addr.s_addr == INADDR_NONE )
261 0 : throw ( Error( string( ": " ) + strerror( EINVAL ) ) );
262 :
263 0 : return saAddr;
264 : }
265 0 : catch ( const Error &err )
266 : {
267 0 : throw Error( string( "::createSockAddr" ) + err.what() );
268 0 : }
269 : }
270 :
271 : ////////////////////////////////////////////////////////////////////////////////
272 : // This function converts the character string szHost into a network address
273 : // structure in the af address family, then copies the network address
274 : // structure to psaAddr.
275 :
276 0 : sockaddr_in SystemSocket::convertStrToAddr( const string &szHost )
277 : {
278 : try
279 : {
280 : sockaddr_in saAddr;
281 :
282 0 : if ( szHost.length() == 0 )
283 : {
284 : // no host specified - use all available interface.
285 0 : saAddr.sin_addr.s_addr = htonl( INADDR_ANY );
286 : }
287 : else
288 : {
289 : #ifdef WIN32
290 : char[256] pcAddr;
291 : memset( pcAddr, 0, 256 );
292 : int nRet = WSAStringToAddress( szHost.c_str(), AF_INET, NULL,
293 : pcAddr, 256 );
294 : memcpy( saAddr.sin_addr, pcAddr, 256 )
295 : switch ( nRet )
296 : {
297 : // no error
298 : case 0:
299 : break;
300 : // The specified Address buffer is too small.
301 : case WSAEFAULT:
302 : throw ( Error( string( "SystemSocket::convertStrToAddr: " ) + strerror( EDQUOT ) ) );
303 : break;
304 : // Unable to translate the string into a sockaddr.
305 : case WSAEINVAL:
306 : throw ( Error( string( "SystemSocket::convertStrToAddr: " ) + strerror( EINVAL ) ) );
307 : break;
308 : // The WS2_32.DLL has not been initialized. Call "WSAStartup".
309 : case WSANOTINITIALISED:
310 : throw ( Error( string( "SystemSocket::convertStrToAddr: " ) + strerror( EBADF ) ) );
311 : break;
312 : // There was insufficient memory to perform the operation.
313 : case WSA_NOT_ENOUGH_MEMORY:
314 : throw ( Error( string( "SystemSocket::create: " ) + strerror( ENOMEM ) ) );
315 : break;
316 : }
317 : #else // assume linux
318 0 : int nRet = inet_pton( AF_INET, szHost.c_str(), static_cast<void *>(&(saAddr.sin_addr)) );
319 0 : int nErr = errno;
320 :
321 : // Is the input not IPv4 dotted decimal string?
322 0 : if ( nRet == 0 )
323 0 : throw ( Error( string( ": " ) + strerror( EINVAL ) ) );
324 :
325 0 : if ( nRet == -1 )
326 0 : throw ( Error( string( ": " ) + strerror( nErr ) ) );
327 : #endif
328 : }
329 0 : return saAddr;
330 : }
331 0 : catch ( const Error &err )
332 : {
333 0 : throw Error( string( "::convertStrToAddr" ) + err.what() );
334 0 : }
335 : }
336 :
337 : ////////////////////////////////////////////////////////////////////////////////
338 : /// Tries to bind a socket to a port.
339 :
340 0 : void SystemSocket::bind()
341 : {
342 : try
343 : {
344 0 : if ( isValid() == false )
345 0 : create();
346 :
347 : // SO_REUSEADDR
348 : // Indicates that the rules used in validating addresses supplied
349 : // in a bind(2) call should allow reuse of local addresses.
350 : // For PF_INET sockets this means that a socket may bind, except when
351 : // there is an active listening socket bound to the address. When the
352 : // listening socket is bound to INADDR_ANY with a specific port then it
353 : // is not possible to bind to this port for any local address.
354 :
355 : // try to set a reusable address.
356 0 : int nTrue = 1;
357 0 : setOption( SOL_SOCKET, SO_REUSEADDR, &nTrue, sizeof( nTrue ) );
358 :
359 : // bind gives the socket 'm_nSocket' the local address 'm_saAddr' .
360 : // my_addr is addrlen bytes long. Traditionally, this is called
361 : // "assigning a name to a socket." When a socket is created with
362 : // socket(2) , it exists in a name space (address family) but has no
363 : // name assigned.
364 : // It is normally necessary to assign a local address using bind before
365 : // a SOCK_STREAM socket may receive connections (see accept(2) ).
366 : // The rules used in name binding vary between address families.
367 : // Consult the manual entries in Section 7 for detailed information.
368 : // For AF_INET see ip(7) , for AF_UNIX see unix(7) ,
369 : // for AF_APPLETALK see ddp(7) , for AF_PACKET see packet(7) ,
370 : // for AF_X25 see x25(7) and for AF_NETLINK see netlink(7) .
371 :
372 0 : sockaddr_in saAddr = createSockAddr( m_nPort, m_szHost );
373 :
374 0 : if ( ::bind( m_nSocket, reinterpret_cast<sockaddr *>(&saAddr), sizeof( saAddr ) ) == -1 )
375 : {
376 0 : m_nLastError = errno;
377 0 : throw ( Error( string( ": " ) + strerror( m_nLastError ) ) );
378 : }
379 :
380 : // If we got here, there was no error.
381 0 : m_oIsBound = true;
382 : }
383 0 : catch ( const Error &err )
384 : {
385 0 : throw Error( string( "::bind" ) + err.what() );
386 0 : }
387 0 : }
388 :
389 : ////////////////////////////////////////////////////////////////////////////////
390 : /// Listens for TCP connections.
391 :
392 0 : void SystemSocket::listen()
393 : {
394 : try
395 : {
396 0 : if ( isBound() == false )
397 0 : bind();
398 :
399 : // To accept connections, a socket is first created with socket(2) ,
400 : // a willingness to accept incoming connections and a queue limit for
401 : // incoming connections are specified with listen , and then the
402 : // connections are accepted with accept(2) . The listen call applies
403 : // only to sockets of type SOCK_STREAM or SOCK_SEQPACKET .
404 :
405 0 : if ( ::listen( m_nSocket, enumMaxConnections ) == -1 )
406 : {
407 0 : m_nLastError = errno;
408 0 : throw ( Error( string( ": " ) + strerror( m_nLastError ) ) );
409 : }
410 : }
411 0 : catch ( const Error &err )
412 : {
413 0 : throw Error( string( "::listen" ) + err.what() );
414 0 : }
415 0 : }
416 :
417 : ////////////////////////////////////////////////////////////////////////////////
418 : /// Accepts a new connection, passes it to another socket.
419 :
420 0 : void SystemSocket::accept( SystemSocket &socNew )
421 : {
422 : try
423 : {
424 0 : if ( isBound() == false )
425 0 : bind();
426 :
427 : // The accept function is used with connection-based socket types
428 : // SOCK_SEQPACKET and SOCK_RDM ). It extracts the first connection request
429 : // on the queue of pending connections, creates a new connected socket with
430 : // mostly the same properties as, and allocates a new file descriptor
431 : // for the socket, which is returned. The newly created socket is no longer
432 : // in the listening state. The original socket is unaffected by this call.
433 : // Note that any per file descriptor flags (everything that can be set with
434 : // the F_SETFL fcntl, like non blocking or async state) are not inherited
435 : // across an accept .
436 :
437 : sockaddr_in saAddr;
438 0 : memset( &saAddr, 0, sizeof ( saAddr ) );
439 0 : int nAddrLen = sizeof( saAddr );
440 :
441 0 : if ( ( socNew.m_nSocket = ::accept( m_nSocket, reinterpret_cast<sockaddr *>(&saAddr),
442 0 : reinterpret_cast<socklen_t *>(&nAddrLen) ) ) == -1 )
443 : {
444 0 : m_nLastError = errno;
445 0 : throw ( Error( string( ": " ) + strerror( m_nLastError ) ) );
446 : }
447 : }
448 0 : catch ( const Error &err )
449 : {
450 0 : throw Error( string( "::accept" ) + err.what() );
451 0 : }
452 0 : }
453 :
454 : ////////////////////////////////////////////////////////////////////////////////
455 : /// Sends a fixed-size chunk. Returns any error encountered.
456 : /// nNumBytes will be modified to reflect the number of bytes actually sent.
457 :
458 0 : void SystemSocket::sendChunk( char *pcData,
459 : int &nNumBytes )
460 : {
461 : try
462 : {
463 0 : if ( isValid() == false )
464 : {
465 0 : m_nLastError = EBADF;
466 0 : throw ( Error( string( ": " ) + strerror( m_nLastError ) ) );
467 : }
468 :
469 : // The send call may be used only when the socket is in a connected state
470 : // (so that the intended recipient is known). The only difference between
471 : // send and write is the presence of flags . With zero flags parameter,
472 : // send is equivalent to write . Also, send( s , buf , len ) is equivalent
473 : // to sendto( s, buf, len, NULL, 0 ).
474 : // MSG_NOSIGNAL
475 : // Requests not to send SIGPIPE on errors on stream oriented sockets when
476 : // the other end breaks the connection. The EPIPE error is still returned.
477 :
478 0 : int nSent = 0;
479 0 : int nTotalSent = 0;
480 0 : for ( nTotalSent = 0; nTotalSent < nNumBytes; nTotalSent += nSent )
481 : {
482 0 : nSent = ::send( m_nSocket, pcData + nTotalSent,
483 0 : nNumBytes - nTotalSent, MSG_NOSIGNAL );
484 0 : m_nLastError = errno;
485 :
486 : // Was there an error?
487 0 : if ( nSent == -1 && m_nLastError != EAGAIN )
488 0 : throw ( Error( string( ": " ) + strerror( m_nLastError ) ) );
489 :
490 : // If we got EAGAIN, go around again, otherwise drop out.
491 0 : if ( nSent == -1 && m_nLastError == EAGAIN )
492 0 : nSent = 0;
493 : }
494 :
495 : // If we got here, nTotalSent holds how many bytes were sent,
496 : // So update nNumBytes to this value. This may not be all the bytes
497 : // desired, so this value should be checked.
498 0 : nNumBytes = nTotalSent;
499 : }
500 0 : catch ( const Error &err )
501 : {
502 0 : throw Error( string( "::sendChunk" ) + err.what() );
503 0 : }
504 0 : }
505 :
506 : ////////////////////////////////////////////////////////////////////////////////
507 : /// Sends a fixed-size chunk. Returns any error encountered.
508 : /// nNumBytes will be modified to reflect the number of bytes actually sent.
509 :
510 0 : void SystemSocket::sendChunkTo( char *pcData,
511 : int &nNumBytes )
512 : {
513 : try
514 : {
515 0 : if ( isValid() == false )
516 0 : create();
517 :
518 : // we need the sockaddr struct to pass the port and host.
519 0 : sockaddr_in saAddr = createSockAddr( m_nPort, m_szHost );
520 :
521 : // The sendto() function shall send a message through a connection-mode
522 : // or connectionless-mode socket. If the socket is connectionless-mode,
523 : // the message shall be sent to the address specified by dest_addr. If
524 : // the socket is connection-mode, dest_addr shall be ignored.
525 :
526 0 : int nRet = ::sendto( m_nSocket, pcData, nNumBytes, 0,
527 0 : reinterpret_cast<const sockaddr *>( &saAddr ), sizeof( saAddr ) );
528 0 : m_nLastError = errno;
529 :
530 : // Was there an error?
531 0 : if ( nRet == -1 )
532 0 : throw ( Error( string( ": " ) + strerror( m_nLastError ) ) );
533 :
534 : // Otherwise, we sent some data, but did we send it all?
535 0 : if ( nRet < nNumBytes )
536 0 : throw ( Error( string( ": " ) + strerror( EMSGSIZE ) ) );
537 :
538 : // If we got here, we sent all the bytes.
539 0 : nNumBytes = nRet;
540 : }
541 0 : catch ( const Error &err )
542 : {
543 0 : throw Error( string( "::sendChunkTo" ) + err.what() );
544 0 : }
545 0 : }
546 :
547 : ////////////////////////////////////////////////////////////////////////////////
548 : /// Receives a fixed-size chunk. Returns any error encountered. nNumBytes will
549 : /// be modified to reflect the number of bytes received.
550 :
551 0 : void SystemSocket::recvChunk( char *pcData,
552 : int &nNumBytes )
553 : {
554 : try
555 : {
556 0 : if ( isValid() == false )
557 : {
558 0 : m_nLastError = EBADF;
559 0 : throw ( Error( string( ": " ) + strerror( m_nLastError ) ) );
560 : }
561 :
562 : // The recvfrom and recvmsg calls are used to receive messages from a
563 : // socket, and may be used to receive data on a socket whether or not it is
564 : // connection-oriented.
565 : // If from is not NULL, and the underlying protocol provides the source
566 : // address, this source address is filled in. The argument fromlen is a
567 : // value-result parameter, initialized to the size of the buffer associated
568 : // with from , and modified on return to indicate the actual size of the
569 : // address stored there.
570 : // The recv call is normally used only on a connected socket (see connect(2))
571 : // and is identical to recvfrom with a NULL from parameter.
572 : // a flag of EAGAIN can be used to indicate a timeout.
573 :
574 0 : memset( pcData, 0, nNumBytes );
575 0 : int nBytesRead = 0;
576 0 : int nBytesLeft = nNumBytes;
577 :
578 : // read all the data.
579 0 : int nRet = 0;
580 0 : while ( nBytesLeft > 0 &&
581 0 : ( nRet = ::recv( m_nSocket, pcData + nBytesRead, nBytesLeft, 0 ) ) > 0 )
582 : {
583 0 : nBytesRead += nRet;
584 0 : nBytesLeft -= nRet;
585 : }
586 :
587 0 : m_nLastError = errno;
588 :
589 : // Was there an error?
590 0 : if ( nRet == -1 )
591 0 : throw ( Error( string( ": " ) + strerror( m_nLastError ) ) );
592 :
593 : // Did the peer shut down?
594 0 : if ( nRet == 0 )
595 0 : throw ( Error( string( ": " ) + strerror( ECONNRESET ) ) );
596 :
597 : // If we got here, nBytesRead holds how many bytes were read,
598 : // So update nNumBytes to this value. This may not be all the bytes
599 : // requested, so this value should be checked.
600 0 : nNumBytes = nBytesRead;
601 : }
602 0 : catch ( const Error &err )
603 : {
604 0 : throw Error( string( "::recvChunk" ) + err.what() );
605 0 : }
606 0 : }
607 :
608 : ////////////////////////////////////////////////////////////////////////////////
609 : /// Receives a fixed-size chunk. Returns any error encountered. nNumBytes will
610 : /// be modified to reflect the number of bytes received. In the case of a
611 : /// multicast, szHost should be "".
612 :
613 0 : void SystemSocket::recvChunkFrom( char *pcData,
614 : int &nNumBytes )
615 : {
616 : try
617 : {
618 0 : if ( isValid() == false )
619 0 : create();
620 :
621 : // We need the sockaddr struct to pass the port and host.
622 : sockaddr_in saAddr;
623 0 : if ( getType() == SystemSocket::enumMulticast )
624 0 : saAddr = createSockAddr( m_nPort, "" );
625 : else
626 0 : saAddr = createSockAddr( m_nPort, m_szHost );
627 :
628 : // Make sure the data is cleared out.
629 0 : memset( pcData, 0, nNumBytes );
630 :
631 : // The recvfrom() function shall receive a message from a connection-
632 : // mode or connectionless-mode socket. It is normally used with
633 : // connectionless-mode sockets because it permits the application to
634 : // retrieve the source address of received data.
635 :
636 0 : socklen_t tSockLen = sizeof( saAddr );
637 0 : int nRet = ::recvfrom( m_nSocket, pcData, nNumBytes, MSG_WAITALL,
638 0 : reinterpret_cast<sockaddr *>( &saAddr ), &tSockLen );
639 0 : m_nLastError = errno;
640 :
641 : // Was there an error?
642 0 : if ( nRet == -1 )
643 0 : throw ( Error( string( ": " ) + strerror( m_nLastError ) ) );
644 :
645 : // Did the peer shut down?
646 0 : if ( nRet == 0 )
647 0 : throw ( Error( string( ": " ) + strerror( ECONNRESET ) ) );
648 :
649 : // If we got here, nRet holds how many bytes were read,
650 : // So update nNumBytes to this value. This may not be all the bytes
651 : // requested, so this value should be checked.
652 0 : nNumBytes = nRet;
653 : }
654 0 : catch ( const Error &err )
655 : {
656 0 : throw Error( string( "::recvChunkFrom" ) + err.what() );
657 0 : }
658 0 : }
659 :
660 : ////////////////////////////////////////////////////////////////////////////////
661 : /// attempts to send data. Returns an error code.
662 :
663 0 : void SystemSocket::send( const string &szData )
664 : {
665 : try
666 : {
667 0 : if ( isValid() == false )
668 : {
669 0 : m_nLastError = EBADF;
670 0 : throw ( Error( string( ": " ) + strerror( m_nLastError ) ) );
671 : }
672 :
673 : // The send call may be used only when the socket is in a connected state
674 : // (so that the intended recipient is known). The only difference between
675 : // send and write is the presence of flags . With zero flags parameter,
676 : // send is equivalent to write . Also, send( s , buf , len ) is equivalent
677 : // to sendto( s, buf, len, NULL, 0 ).
678 : // MSG_NOSIGNAL
679 : // Requests not to send SIGPIPE on errors on stream oriented sockets when
680 : // the other end breaks the connection. The EPIPE error is still returned.
681 :
682 : // nRet will now hold the number of bytes sent or an error code.
683 0 : int nRet = ::send( m_nSocket, szData.c_str(), szData.size(), MSG_NOSIGNAL );
684 :
685 0 : m_nLastError = errno;
686 :
687 : // Was there an error?
688 0 : if ( nRet == -1 )
689 0 : throw ( Error( string( ": " ) + strerror( m_nLastError ) ) );
690 :
691 : // Otherwise, we sent some data, but did we send it all?
692 0 : if ( static_cast<unsigned int>( nRet ) < szData.length() )
693 0 : throw ( Error( string( ": " ) + strerror( EMSGSIZE ) ) );
694 : }
695 0 : catch ( const Error &err )
696 : {
697 0 : throw Error( string( "::send" ) + err.what() );
698 0 : }
699 0 : }
700 :
701 : ////////////////////////////////////////////////////////////////////////////////
702 : /// attempts to send data. Returns an error code.
703 :
704 0 : void SystemSocket::sendTo( const string &szData )
705 : {
706 : try
707 : {
708 0 : if ( isValid() == false )
709 0 : create();
710 :
711 : // we need the sockaddr struct to pass the port and host.
712 0 : sockaddr_in saAddr = createSockAddr( m_nPort, m_szHost );
713 :
714 : // The sendto() function shall send a message through a connection-
715 : // mode or connectionless-mode socket. If the socket is connectionless-
716 : // mode, the message shall be sent to the address specified by dest_addr.
717 : // If the socket is connection-mode, dest_addr shall be ignored.
718 :
719 : // nRet will now hold the number of bytes sent or an error code.
720 0 : int nRet = ::sendto( m_nSocket, szData.c_str(), szData.size(), 0,
721 0 : reinterpret_cast<sockaddr *>( &saAddr ), sizeof( saAddr ) );
722 0 : m_nLastError = errno;
723 :
724 : // Was there an error?
725 0 : if ( nRet == -1 )
726 0 : throw ( Error( string( ": " ) + strerror( m_nLastError ) ) );
727 :
728 : // Otherwise, we sent some data, but did we send it all?
729 0 : if ( static_cast<unsigned int>( nRet ) < szData.length() )
730 0 : throw ( Error( string( ": " ) + strerror( EMSGSIZE ) ) );
731 : }
732 0 : catch ( const Error &err )
733 : {
734 0 : throw Error( string( "::sendTo" ) + err.what() );
735 0 : }
736 0 : }
737 :
738 : ////////////////////////////////////////////////////////////////////////////////
739 :
740 0 : string SystemSocket::recv()
741 : {
742 : try
743 : {
744 0 : if ( isValid() == false )
745 : {
746 0 : m_nLastError = EBADF;
747 0 : throw ( Error( string( ": " ) + strerror( m_nLastError ) ) );
748 : }
749 :
750 : // The recvfrom and recvmsg calls are used to receive messages from a
751 : // socket, and may be used to receive data on a socket whether or not it is
752 : // connection-oriented.
753 : // If from is not NULL, and the underlying protocol provides the source
754 : // address, this source address is filled in. The argument fromlen is a
755 : // value-result parameter, initialized to the size of the buffer associated
756 : // with from , and modified on return to indicate the actual size of the
757 : // address stored there.
758 : // The recv call is normally used only on a connected socket (see connect(2))
759 : // and is identical to recvfrom with a NULL from parameter.
760 : // a flag of EAGAIN can be used to indicate a timeout.
761 :
762 : // Get some memory to hold the data.
763 : char pcBuf[ enumMaxRecv + 1 ];
764 0 : memset( pcBuf, 0, enumMaxRecv + 1 );
765 :
766 0 : int nRet = ::recv( m_nSocket, pcBuf, enumMaxRecv, 0 );
767 :
768 0 : m_nLastError = errno;
769 :
770 : // Was there an error?
771 0 : if ( nRet == -1 )
772 0 : throw ( Error( string( ": " ) + strerror( m_nLastError ) ) );
773 :
774 : // Did the peer shut down?
775 0 : if ( nRet == 0 )
776 0 : throw ( Error( string( ": " ) + strerror( ECONNRESET ) ) );
777 :
778 : // Otherwise, this is the number of bytes received.
779 0 : return string( pcBuf, nRet );
780 : }
781 0 : catch ( const Error &err )
782 : {
783 0 : throw Error( string( "::recv" ) + err.what() );
784 0 : }
785 : }
786 :
787 : ////////////////////////////////////////////////////////////////////////////////
788 :
789 0 : std::string SystemSocket::recvFrom()
790 : {
791 : try
792 : {
793 0 : if ( isValid() == false )
794 0 : create();
795 :
796 : // we need the sockaddr struct to pass the port and host.
797 : sockaddr_in saAddr;
798 0 : if ( getType() == SystemSocket::enumMulticast )
799 0 : saAddr = createSockAddr( m_nPort, "" );
800 : else
801 0 : saAddr = createSockAddr( m_nPort, m_szHost );
802 :
803 : // The recvfrom() function shall receive a message from a connection-
804 : // mode or connectionless-mode socket. It is normally used with
805 : // connectionless-mode sockets because it permits the application to
806 : // retrieve the source address of received data.
807 :
808 : // get some memory to hold the data.
809 : char pcBuf[ enumMaxRecv + 1 ];
810 0 : memset( pcBuf, 0, enumMaxRecv + 1 );
811 :
812 0 : socklen_t tSockLen = sizeof( saAddr );
813 0 : int nRet = ::recvfrom( m_nSocket, pcBuf, enumMaxRecv, MSG_WAITALL,
814 0 : ( sockaddr * )( &saAddr ), &tSockLen );
815 0 : m_nLastError = errno;
816 :
817 : // Was there an error?
818 0 : if ( nRet == -1 )
819 0 : throw ( Error( string( ": " ) + strerror( m_nLastError ) ) );
820 :
821 : // Did the peer shut down? - this is okay - just return empty data.
822 0 : if ( nRet == 0 )
823 0 : throw ( Error( string( ": " ) + strerror( ECONNRESET ) ) );
824 :
825 : // Otherwise, nRet is the number of bytes received.
826 0 : return string( pcBuf, nRet );
827 : }
828 0 : catch ( const Error &err )
829 : {
830 0 : throw Error( string( "::recvFrom" ) + err.what() );
831 0 : }
832 : }
833 :
834 : ////////////////////////////////////////////////////////////////////////////////
835 :
836 0 : void SystemSocket::connect()
837 : {
838 : try
839 : {
840 0 : if ( isValid() == false )
841 0 : create();
842 :
843 : // we need the sockaddr struct to pass the port and host.
844 0 : sockaddr_in saAddr = createSockAddr( m_nPort, m_szHost );
845 :
846 : // we need a set to use with 'select' so we can time-out.
847 : fd_set setRead;
848 0 : FD_ZERO( &setRead );
849 0 : FD_SET( m_nSocket, &setRead );
850 :
851 : fd_set setWrite;
852 0 : FD_ZERO ( &setWrite );
853 0 : FD_SET ( m_nSocket, &setWrite );
854 :
855 : // we need a timeval struct to hold our timeout value.
856 : timeval tvTimeout;
857 0 : tvTimeout.tv_sec = 3;//m_nConnectTimeout / 1000;
858 0 : tvTimeout.tv_usec = m_nConnectTimeout % 1000;
859 : // set the socket descriptor to non-blocking BEFORE we call 'connect'.
860 0 : setNonBlocking( true );
861 :
862 : // The file descriptor sockfd must refer to a socket. If the socket
863 : // is of type SOCK_DGRAM then the serv_addr address is the address to
864 : // which datagrams are sent by default, and the only address from which
865 : // datagrams are received. If the socket is of type SOCK_STREAM or
866 : // SOCK_SEQPACKET, this call attempts to make a connection to another
867 : // socket. The other socket is specified by serv_addr, which is an
868 : // address (of length addrlen) in the communications space of the
869 : // socket. Each communications space interprets the serv_addr
870 : // parameter in its own way.
871 : // Generally, connection-based protocol sockets may successfully
872 : // connect only once; connectionless protocol sockets may use connect
873 : // multiple times to change their association. Connectionless
874 : // sockets may dissolve the association by connecting to an address
875 : // with the sa_family member of sockaddr set to AF_UNSPEC.
876 :
877 : // Will we connect immediately?
878 0 : if ( ::connect( m_nSocket, reinterpret_cast<sockaddr *>(&saAddr), sizeof( saAddr ) ) == -1 )
879 : {
880 0 : m_nLastError = errno;
881 :
882 : // The only acceptable error is 'in progress'.
883 0 : if ( m_nLastError != EINPROGRESS )
884 0 : throw ( Error( string( ": " ) + strerror( m_nLastError ) ) );
885 :
886 : // Wait for the connection to complete.
887 0 : int nNum = ::select( m_nSocket + 1,
888 : &setRead, &setWrite, NULL, &tvTimeout );
889 :
890 0 : m_nLastError = errno;
891 :
892 : // Did select have an error?
893 0 : if ( nNum < 0 )
894 0 : throw ( Error( string( ": " ) + strerror( m_nLastError ) ) );
895 : // Did we timeout (no descriptors are ready)?
896 0 : if ( nNum == 0 )
897 0 : throw ( Error( string( ": " ) + strerror( ETIMEDOUT ) ) );
898 : // n > 0 - Are we possibly connected?
899 0 : if ( FD_ISSET( m_nSocket, &setWrite ) || FD_ISSET( m_nSocket, &setRead ) )
900 : {
901 0 : m_nLastError = 0;
902 0 : socklen_t nSizeErr = sizeof( m_nLastError );
903 0 : getOption( SOL_SOCKET, SO_ERROR, &m_nLastError, nSizeErr );
904 0 : if ( m_nLastError != 0 )
905 : {
906 0 : throw ( Error( string( ": " ) + strerror( m_nLastError ) ) );
907 : }
908 : }
909 : }
910 : }
911 0 : catch ( const Error &err )
912 : {
913 : // Make sure we clean up.
914 0 : close();
915 0 : throw Error( string( "::connect" ) + err.what() );
916 0 : }
917 0 : }
918 :
919 : ////////////////////////////////////////////////////////////////////////////////
920 : /// Join a multicast group in order to receive data.
921 :
922 0 : void SystemSocket::join()
923 : {
924 : try
925 : {
926 0 : if ( isBound() == false )
927 0 : bind();
928 :
929 : // use setsockopt() to request that the kernel join a multicast group.
930 : struct ip_mreq mreq;
931 0 : mreq.imr_multiaddr.s_addr = ::inet_addr( m_szHost.c_str() );
932 0 : mreq.imr_interface.s_addr = htonl( INADDR_ANY );
933 :
934 0 : setOption( IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof( mreq ) );
935 : }
936 0 : catch ( const Error &err )
937 : {
938 0 : throw Error( string( "::join" ) + err.what() );
939 0 : }
940 0 : }
941 :
942 : ////////////////////////////////////////////////////////////////////////////////
943 :
944 0 : void SystemSocket::close()
945 : {
946 : try
947 : {
948 0 : if ( isValid() == false )
949 : {
950 0 : m_nLastError = EBADF;
951 0 : throw ( Error( string( ": " ) + strerror( m_nLastError ) ) );
952 : }
953 :
954 : // close closes a file descriptor, so that it no longer refers to any file
955 : // and may be reused. Any locks held on the file it was associated with,
956 : // and owned by the process, are removed (regardless of the file
957 : // descriptor that was used to obtain the lock).
958 :
959 : #ifdef WIN32
960 : if ( closesocket( m_nSocket ) == -1 )
961 : #else
962 0 : if ( ::close( m_nSocket ) == -1 )
963 : #endif
964 : {
965 : // convert to our error code as necessary.
966 0 : m_nLastError = errno;
967 0 : throw ( Error( string( ": " ) + strerror( m_nLastError ) ) );
968 : }
969 0 : m_nSocket = -1;
970 0 : m_oIsBound = false;
971 : }
972 0 : catch ( const Error &err )
973 : {
974 0 : throw Error( string( "::close" ) + err.what() );
975 0 : }
976 0 : }
977 :
978 : ////////////////////////////////////////////////////////////////////////////////
979 :
980 0 : void SystemSocket::getOption( const int &nLevel,
981 : const int &nOption,
982 : void *pvOptionValue,
983 : socklen_t &nOptionLength )
984 : {
985 : try
986 : {
987 0 : if ( isValid() == false )
988 : {
989 0 : m_nLastError = EBADF;
990 0 : throw ( Error( string( ": " ) + strerror( m_nLastError ) ) );
991 : }
992 :
993 0 : if ( ::getsockopt( m_nSocket, nLevel, nOption,
994 0 : static_cast<char *>( pvOptionValue ), &nOptionLength ) == -1 )
995 : {
996 0 : m_nLastError = errno;
997 0 : throw ( Error( string( ": " ) + strerror( m_nLastError ) ) );
998 : }
999 : }
1000 0 : catch ( const Error &err )
1001 : {
1002 0 : throw Error( string( "::setOption" ) + err.what() );
1003 0 : }
1004 0 : }
1005 :
1006 : ////////////////////////////////////////////////////////////////////////////////
1007 :
1008 0 : void SystemSocket::setOption(const int &nLevel,
1009 : const int &nOption,
1010 : void *pvOptionValue,
1011 : const socklen_t &nOptionLength )
1012 : {
1013 : try
1014 : {
1015 0 : if ( isValid() == false )
1016 : {
1017 0 : m_nLastError = EBADF;
1018 0 : throw ( Error( string( ": " ) + strerror( m_nLastError ) ) );
1019 : }
1020 :
1021 0 : if ( ::setsockopt( m_nSocket, nLevel, nOption,
1022 0 : static_cast<char *>( pvOptionValue ), nOptionLength ) == -1 )
1023 : {
1024 0 : m_nLastError = errno;
1025 0 : throw ( Error( string( ": " ) + strerror( m_nLastError ) ) );
1026 : }
1027 : }
1028 0 : catch ( const Error &err )
1029 : {
1030 0 : throw Error( string( "::setOption" ) + err.what() );
1031 0 : }
1032 0 : }
1033 :
1034 : ////////////////////////////////////////////////////////////////////////////////
1035 :
1036 0 : void SystemSocket::setRecvTimeout( const int &nMillis )
1037 : {
1038 : try
1039 : {
1040 0 : if ( isValid() == false )
1041 : {
1042 0 : m_nLastError = EBADF;
1043 0 : throw ( Error( string( ": " ) + strerror( m_nLastError ) ) );
1044 : }
1045 :
1046 : // create the timeval structure.
1047 : timeval tvTimeout;
1048 0 : tvTimeout.tv_sec = nMillis / 1000;
1049 0 : tvTimeout.tv_usec = nMillis * 1000 - tvTimeout.tv_sec * 1000000;
1050 :
1051 0 : setOption( SOL_SOCKET, SO_RCVTIMEO, &tvTimeout, sizeof( tvTimeout ) );
1052 : }
1053 0 : catch ( const Error &err )
1054 : {
1055 0 : throw Error( string( "::setRecvTimeout" ) + err.what() );
1056 0 : }
1057 0 : }
1058 :
1059 : ////////////////////////////////////////////////////////////////////////////////
1060 :
1061 0 : void SystemSocket::setNonBlocking( const bool &oIsNonBlocking )
1062 : {
1063 : try
1064 : {
1065 0 : if ( isValid() == false )
1066 : {
1067 0 : m_nLastError = EBADF;
1068 0 : throw ( Error( string( ": " ) + strerror( m_nLastError ) ) );
1069 : }
1070 :
1071 : #ifdef WIN32
1072 : // Set the socket I/O mode: In this case FIONBIO
1073 : // enables or disables the blocking mode for the
1074 : // socket based on the numerical value of iMode.
1075 : // If uiMode = 0, blocking is enabled;
1076 : // If uiMode != 0, non-blocking mode is enabled.
1077 : unsigned int uiMode = ( oIsNonBlocking == true ) ? ( 1 ) : ( 0 );
1078 : ioctlsocket( m_nSocket, FIONBIO, &uiMode );
1079 : #else
1080 : // fcntl performs one of various miscellaneous operations on fd.
1081 : // The operation in question is determined by cmd.
1082 : // F_GETFL
1083 : // Read the file descriptor's flags.
1084 0 : int nOpts = -1;
1085 0 : if ( ( nOpts = ::fcntl( m_nSocket, F_GETFL ) ) == -1 )
1086 : {
1087 0 : m_nLastError = errno;
1088 0 : throw ( Error( string( ": " ) + strerror( m_nLastError ) ) );
1089 : }
1090 :
1091 : // Flip the correct bit in the read value.
1092 0 : nOpts = ( oIsNonBlocking == true ) ?
1093 : ( nOpts | O_NONBLOCK ) : ( nOpts & ~O_NONBLOCK );
1094 :
1095 : // write this updated setting.
1096 0 : if ( ::fcntl ( m_nSocket, F_SETFL, nOpts ) == -1 )
1097 : {
1098 0 : m_nLastError = errno;
1099 0 : throw ( Error( string( ": " ) + strerror( m_nLastError ) ) );
1100 : }
1101 : #endif
1102 : }
1103 0 : catch ( const Error &err )
1104 : {
1105 0 : throw Error( string( "::setNonBlocking" ) + err.what() );
1106 0 : }
1107 0 : }
1108 :
1109 : ////////////////////////////////////////////////////////////////////////////////
1110 : /// Returns true if the nagle algorithm is disabled, false otherwise.
1111 :
1112 0 : bool SystemSocket::isNagleDisabled() const
1113 : {
1114 0 : return m_oIsNagleDisabled;
1115 : }
1116 :
1117 : ////////////////////////////////////////////////////////////////////////////////
1118 : /// Disables the algorithm that conglomerates lots of
1119 : /// small sends into a large one.
1120 :
1121 0 : void SystemSocket::disableNagle( const bool &oDisable )
1122 : {
1123 : try
1124 : {
1125 0 : if ( isValid() == false )
1126 : {
1127 0 : m_nLastError = EBADF;
1128 0 : throw ( Error( string( ": " ) + strerror( m_nLastError ) ) );
1129 : }
1130 :
1131 : #ifdef WIN32
1132 : // todo: Look up the way to do this in windows.
1133 : #else
1134 0 : int nFlag = ( oDisable == true ) ? ( 1 ) : ( 0 );
1135 0 : setOption( IPPROTO_TCP, TCP_NODELAY, &nFlag, sizeof( int ) );
1136 : #endif
1137 :
1138 : // If we got here, the state of the nagle algorithm has been updated.
1139 0 : m_oIsNagleDisabled = oDisable;
1140 : }
1141 0 : catch ( const Error &err )
1142 : {
1143 0 : throw Error( string( "::disableNagle" ) + err.what() );
1144 0 : }
1145 0 : }
1146 :
1147 : ////////////////////////////////////////////////////////////////////////////////
1148 : // this function will block until data is ready to be read on the socket.
1149 : /*
1150 : int SystemSocket::waitForData()
1151 : {
1152 : try
1153 : {
1154 : if ( isValid() == false )
1155 : {
1156 : m_nLastError = EBADF;
1157 : throw ( Error( string( ": " ) + strerror( m_nLastError ) ) );
1158 : }
1159 :
1160 : fd_set ReadSet;
1161 : FD_ZERO( &ReadSet );
1162 : FD_SET( m_nSocket, &ReadSet );
1163 :
1164 : // The functions select and pselect wait for a number of file
1165 : // descriptors to change status.
1166 : int nRet = ::select( m_nSocket+1, &ReadSet, NULL, NULL, NULL );
1167 :
1168 : m_nLastError = errno;
1169 :
1170 : if ( nRet == -1 && m_nLastError == EINTR )
1171 : {
1172 : }
1173 : // there is possibly data available -
1174 : // or the connection may have been closed.
1175 : else if ( FD_ISSET( m_nSocket, &ReadSet ) )
1176 : {
1177 : }
1178 : else if ( nRet < 0 )
1179 : {
1180 : }
1181 : else
1182 : {
1183 : }
1184 : }
1185 : catch ( const Error &err )
1186 : {
1187 : throw Error( string( "::disableNagle" ) + err.what() );
1188 : }
1189 : }
1190 : */
1191 : ////////////////////////////////////////////////////////////////////////////////
1192 : /// return the message concerning the error.
1193 : /*
1194 : string SystemSocket::getErrorMsg( const int &nError )
1195 : {
1196 : switch ( nError )
1197 : {
1198 : case enumNoError:
1199 : return string( "No Error" );
1200 : break;
1201 : case -EBUSY:
1202 : return string( "Unwilling to accept connections" );
1203 : break;
1204 : case -EEXIST:
1205 : return string( "Shut down or already bound to an address" );
1206 : break;
1207 : case -EADDRINUSE:
1208 : return string( "Address already in use" );
1209 : break;
1210 : case -EADDRNOTAVAIL:
1211 : return string( "Address not available" );
1212 : break;
1213 : case -EAFNOSUPPORT:
1214 : return string( "Address not supported" );
1215 : break;
1216 : case -ECONNABORTED:
1217 : return string( "Connection aborted" );
1218 : break;
1219 : case -ECONNRESET:
1220 : return string( "Connection reset by peer" );
1221 : break;
1222 : case -EALREADY:
1223 : return string( "A previous connection attempt has not been completed" );
1224 : break;
1225 : case -EINPROGRESS:
1226 : return string( "Connection cannot be completed immediately" );
1227 : break;
1228 : case -ECONNREFUSED:
1229 : return string( "Connection refused" );
1230 : break;
1231 : case -ENOTSOCK:
1232 : return string( "Descriptor not a socket" );
1233 : break;
1234 : case -EISDIR:
1235 : return string( "An empty pathname was specified" );
1236 : break;
1237 : case -EDESTADDRREQ:
1238 : return string( "Destination address required or socket not bound" );
1239 : break;
1240 : case -EHOSTUNREACH:
1241 : return string( "Host unreachable" );
1242 : break;
1243 : case EINVAL:
1244 : return string( "Invalid parameter" );
1245 : break;
1246 : case -EBADF:
1247 : return string( "Invalid socket descriptor" );
1248 : break;
1249 : case -EIO:
1250 : return string( "IO error" );
1251 : break;
1252 : case -EPIPE:
1253 : return string( "Local shutdown" );
1254 : break;
1255 : case -EMFILE:
1256 : return string( "Max descriptors already open" );
1257 : break;
1258 : case -ENETDOWN:
1259 : return string( "Network down" );
1260 : break;
1261 : case -ENETUNREACH:
1262 : return string( "Network unreachable" );
1263 : break;
1264 : case -EACCES:
1265 : return string( "No Access" );
1266 : break;
1267 : case -ENOBUFS:
1268 : return string( "No buffers available" );
1269 : break;
1270 : case -ENODATA:
1271 : return string( "No out-of-band data available" );
1272 : break;
1273 : case -ENOTCONN:
1274 : return string( "Not connected" );
1275 : break;
1276 : case -ENOMEM:
1277 : return string( "Not enough memory" );
1278 : break;
1279 : case -EOPNOTSUPP:
1280 : return string( "Type and/or protocol is not supported for this operation" );
1281 : break;
1282 : case -EDQUOT:
1283 : return string( "Message too big" );
1284 : break;
1285 : case -EFBIG:
1286 : return string( "Only partial data was received" );
1287 : break;
1288 : case -EMSGSIZE:
1289 : return string( "Only partial data was sent" );
1290 : break;
1291 : case -ENAMETOOLONG:
1292 : return string( "Path name too long" );
1293 : break;
1294 : case -ENOENT:
1295 : return string( "Path does not exist" );
1296 : break;
1297 : case -ENOTDIR:
1298 : return string( "Path is not a directory" );
1299 : break;
1300 : case -EPROTO:
1301 : return string( "Protocol error" );
1302 : break;
1303 : case -EROFS:
1304 : return string( "Read-only file system" );
1305 : break;
1306 : case -EINTR:
1307 : return string( "Interrupt signal received" );
1308 : break;
1309 : case -EISCONN:
1310 : return string( "Socket is already connected" );
1311 : break;
1312 : case -ELOOP:
1313 : return string( "Symbolic loop exists" );
1314 : break;
1315 : case -EDOM:
1316 : return string( "Timeout field too big" );
1317 : break;
1318 : case -ETIMEDOUT:
1319 : return string( "Timed out" );
1320 : break;
1321 : case -EAGAIN:
1322 : return string( "Would block (or timed out)" );
1323 : break;
1324 : case -EPROTOTYPE:
1325 : return string( "Wrong address type" );
1326 : break;
1327 : case enumUnknownError:
1328 : return string( "Unknown error" );
1329 : break;
1330 : }
1331 : return string( "" );
1332 : }
1333 : */
1334 : ////////////////////////////////////////////////////////////////////////////////
1335 : /// Return the standard host name for the current machine.
1336 :
1337 0 : string SystemSocket::getLocalHostName()
1338 : {
1339 : try
1340 : {
1341 : char pcHostName[256];
1342 0 : memset( pcHostName, 0, 256 );
1343 0 : if ( ::gethostname( pcHostName, 255 ) == -1 )
1344 : {
1345 0 : int nErr = errno;
1346 0 : throw ( Error( string( ": " ) + strerror( nErr ) ) );
1347 : }
1348 :
1349 : // if we got here, we got a good hostname.
1350 0 : return string( pcHostName );
1351 : }
1352 0 : catch ( const Error &err )
1353 : {
1354 0 : throw Error( string( "::getLocalHostName" ) + err.what() );
1355 0 : }
1356 : }
1357 :
1358 : ////////////////////////////////////////////////////////////////////////////////
1359 : /// Get the interface named 'szName'.
1360 : /// @param szName The name of the interface.
1361 : /// @return The interface which corresponds to the name 'szName', or the
1362 : /// loopback if it is not found.
1363 :
1364 0 : SystemSocket::Interface SystemSocket::getInterface( const string &szName )
1365 : {
1366 : // As a default, our interface is undefined.
1367 0 : Interface interface( "", "127.0.0.1", "255.0.0.0" );
1368 :
1369 : // First, get a vector of all the interfaces.
1370 0 : vector<Interface> vecInterfaces;
1371 0 : SystemSocket::getInterfaces( vecInterfaces );
1372 :
1373 : // find the one with the name we want.
1374 0 : for ( unsigned int ii = 0; ii < vecInterfaces.size(); ii++ )
1375 : {
1376 0 : if ( vecInterfaces[ii].getName() == szName )
1377 : {
1378 0 : interface = vecInterfaces[ii];
1379 0 : break;
1380 : }
1381 : }
1382 :
1383 0 : return interface;
1384 0 : }
1385 :
1386 : ////////////////////////////////////////////////////////////////////////////////
1387 : /// This returns the local interfaces as a vector.
1388 : /// The return value is the number of interfaces found.
1389 :
1390 0 : int SystemSocket::getInterfaces( vector<SystemSocket::Interface> &vecInterfaces )
1391 : {
1392 : /**
1393 : SIOCGIFCONF
1394 : Return a list of interface (transport layer) addresses. This currently means
1395 : only addresses of the AF_INET (IPv4) family for compatibility. The user
1396 : passes a ifconf structure as argument to the ioctl. It contains a pointer to
1397 : an array of ifreq structures in ifc_req and its length in bytes in ifc_len.
1398 : The kernel fills the ifreqs with all current L3 interface addresses that are
1399 : running: ifr_name contains the interface name (eth0:1 etc.), ifr_addr the
1400 : address. The kernel returns with the actual length in ifc_len. If ifc_len is
1401 : equal to the original length the buffer probably has overflowed and you
1402 : should retry with a bigger buffer to get all addresses. When no error occurs
1403 : the ioctl returns 0; otherwise -1. Overflow is not an error.
1404 :
1405 : See: http://www.die.net/doc/linux/man/man7/netdevice.7.html
1406 : **/
1407 :
1408 : // This will be an error (<0) or the number of interfaces (>0).
1409 0 : int nError = 0;
1410 : ifconf ifc;
1411 : sockaddr_in addrSock;
1412 :
1413 : // Make sure the list is empty.
1414 0 : vecInterfaces.clear();
1415 :
1416 : // Create a fd with the correct protocol.
1417 0 : int fdSock = ::socket( AF_INET, SOCK_DGRAM, 0 );
1418 :
1419 0 : if ( fdSock < 0 )
1420 : {
1421 0 : nError = -1;
1422 : }
1423 : else
1424 : {
1425 0 : int nRetVal = 0;
1426 0 : unsigned int uiAmt = 0;
1427 0 : memset( &ifc, 0, sizeof( ifc ) );
1428 :
1429 : // Repeat the ioctl call and resize the data structure until
1430 : // it is more than big enough to hold information for all the network
1431 : // interfaces. Of course, we will stop if we have an error.
1432 0 : while ( nRetVal == 0 &&
1433 0 : sizeof( struct ifreq ) * uiAmt <= ( unsigned int )( ifc.ifc_len ) )
1434 : {
1435 : // Try an increment of 10....
1436 0 : uiAmt += 10;
1437 0 : ifc.ifc_len = sizeof( struct ifreq ) * uiAmt;
1438 0 : ifc.ifc_buf = static_cast<char *>( realloc( ifc.ifc_buf, ifc.ifc_len ) );
1439 : // Make the call.
1440 0 : nRetVal = ::ioctl( fdSock, SIOCGIFCONF, &ifc );
1441 : }
1442 :
1443 0 : if ( nRetVal < 0 )
1444 : {
1445 0 : nError = -1;
1446 : }
1447 : else
1448 : {
1449 : //std::cout << "Final size is: " << uiAmt << std::endl;
1450 0 : ifreq *ifr = ifc.ifc_req;
1451 0 : for ( unsigned int ii = 0; ii < uiAmt; ii++ )
1452 : {
1453 : // The name is set in the struct.
1454 0 : string szName( ifr->ifr_name );
1455 :
1456 : // The IP address is set in the struct.
1457 0 : struct in_addr *psia1 = reinterpret_cast<struct in_addr *>( &( ifr->ifr_addr.sa_data[sizeof addrSock.sin_port] ) );
1458 :
1459 0 : string szIP( string( ::inet_ntoa( *psia1 ) ) );
1460 :
1461 : // Overwrite the same piece of memory with the broadcast address.
1462 0 : nRetVal = ::ioctl( fdSock, SIOCGIFBRDADDR, ifr );
1463 :
1464 : // The broadcast address has replaced the IP address in the struct.
1465 0 : struct in_addr *psia2 = reinterpret_cast<struct in_addr *>( &( ifr->ifr_broadaddr.sa_data[sizeof addrSock.sin_port] ) );
1466 0 : string szBCast( string( ::inet_ntoa( *psia2 ) ) );
1467 :
1468 : // Add this info to our vector.
1469 0 : vecInterfaces.push_back( Interface( szName, szIP, szBCast ) );
1470 :
1471 : //std::cout << "adding: '" << szName << "' '" << szIP
1472 : // << "' '" << szBCast <<"'." << std::endl;
1473 0 : ifr++;
1474 0 : }
1475 : // Return a positive size as the error value (no error).
1476 0 : nError = vecInterfaces.size();
1477 : }
1478 : // Free the memory we allocated.
1479 0 : free( ifc.ifc_buf );
1480 : }
1481 0 : return nError;
1482 : }
1483 :
1484 : ////////////////////////////////////////////////////////////////////////////////
|