Line data Source code
1 :
2 : /* Copyright (c) 2005-2014, Stefan Eilemann <eile@equalizergraphics.com>
3 : * 2010, Daniel Nachbaur <danielnachbaur@gmail.com>
4 : *
5 : * This file is part of Collage <https://github.com/Eyescale/Collage>
6 : *
7 : * This library is free software; you can redistribute it and/or modify it under
8 : * the terms of the GNU Lesser General Public License version 2.1 as published
9 : * by the Free Software Foundation.
10 : *
11 : * This library is distributed in the hope that it will be useful, but WITHOUT
12 : * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13 : * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
14 : * details.
15 : *
16 : * You should have received a copy of the GNU Lesser General Public License
17 : * along with this library; if not, write to the Free Software Foundation, Inc.,
18 : * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 : */
20 :
21 : #include "socketConnection.h"
22 :
23 : #include "connectionDescription.h"
24 : #include "exception.h"
25 : #include "global.h"
26 :
27 : #include <lunchbox/os.h>
28 : #include <lunchbox/log.h>
29 : #include <lunchbox/sleep.h>
30 : #include <co/exception.h>
31 :
32 : #include <limits>
33 : #include <sstream>
34 : #include <string.h>
35 : #include <sys/types.h>
36 :
37 : #ifdef _WIN32
38 : # include <mswsock.h>
39 : # ifndef WSA_FLAG_SDP
40 : # define WSA_FLAG_SDP 0x40
41 : # endif
42 : # define CO_RECV_TIMEOUT 250 /*ms*/
43 : #else
44 : # include <arpa/inet.h>
45 : # include <netdb.h>
46 : # include <netinet/tcp.h>
47 : # include <sys/errno.h>
48 : # include <sys/socket.h>
49 : # ifndef AF_INET_SDP
50 : # define AF_INET_SDP 27
51 : # endif
52 : #endif
53 :
54 : namespace co
55 : {
56 140 : SocketConnection::SocketConnection( const ConnectionType type )
57 : #ifdef _WIN32
58 : : _overlappedAcceptData( 0 )
59 : , _overlappedSocket( INVALID_SOCKET )
60 : , _overlappedDone( 0 )
61 : #endif
62 : {
63 : #ifdef _WIN32
64 : memset( &_overlappedRead, 0, sizeof( _overlappedRead ));
65 : memset( &_overlappedWrite, 0, sizeof( _overlappedWrite ));
66 : #endif
67 :
68 140 : LBASSERT( type == CONNECTIONTYPE_TCPIP || type == CONNECTIONTYPE_SDP );
69 140 : ConnectionDescriptionPtr description = _getDescription();
70 140 : description->type = type;
71 140 : description->bandwidth = (type == CONNECTIONTYPE_TCPIP) ?
72 140 : 102400 : 819200; // 100MB : 800 MB
73 :
74 140 : LBVERB << "New SocketConnection @" << (void*)this << std::endl;
75 140 : }
76 :
77 420 : SocketConnection::~SocketConnection()
78 : {
79 140 : _close();
80 280 : }
81 :
82 : namespace
83 : {
84 94 : static bool _parseAddress( ConstConnectionDescriptionPtr description,
85 : sockaddr_in& address )
86 : {
87 94 : address.sin_family = AF_INET;
88 94 : address.sin_addr.s_addr = htonl( INADDR_ANY );
89 94 : address.sin_port = htons( description->port );
90 94 : memset( &(address.sin_zero), 0, 8 ); // zero the rest
91 :
92 94 : const std::string& hostname = description->getHostname();
93 94 : if( !hostname.empty( ))
94 : {
95 65 : hostent *hptr = gethostbyname( hostname.c_str( ));
96 65 : if( hptr )
97 65 : memcpy( &address.sin_addr.s_addr, hptr->h_addr, hptr->h_length );
98 : else
99 : {
100 0 : LBWARN << "Can't resolve host " << hostname << std::endl;
101 0 : return false;
102 : }
103 : }
104 :
105 94 : LBVERB << "Address " << inet_ntoa( address.sin_addr ) << ":"
106 94 : << ntohs( address.sin_port ) << std::endl;
107 94 : return true;
108 : }
109 : }
110 :
111 : //----------------------------------------------------------------------
112 : // connect
113 : //----------------------------------------------------------------------
114 46 : bool SocketConnection::connect()
115 : {
116 46 : ConnectionDescriptionPtr description = _getDescription();
117 46 : LBASSERT( description->type == CONNECTIONTYPE_TCPIP ||
118 : description->type == CONNECTIONTYPE_SDP );
119 46 : if( !isClosed() )
120 0 : return false;
121 :
122 46 : if( description->port == 0 )
123 0 : return false;
124 :
125 46 : if( description->getHostname().empty( ))
126 25 : description->setHostname( "127.0.0.1" );
127 :
128 : sockaddr_in address;
129 46 : if( !_parseAddress( description, address ))
130 : {
131 0 : LBWARN << "Can't parse connection parameters" << std::endl;
132 0 : return false;
133 : }
134 :
135 46 : _setState( STATE_CONNECTING );
136 :
137 46 : if( !_createSocket( ))
138 0 : return false;
139 :
140 46 : if( address.sin_addr.s_addr == 0 )
141 : {
142 0 : LBWARN << "Refuse to connect to 0.0.0.0" << std::endl;
143 0 : close();
144 0 : return false;
145 : }
146 :
147 : #ifdef _WIN32
148 : const bool connected = WSAConnect( _readFD, (sockaddr*)&address,
149 : sizeof( address ), 0, 0, 0, 0 ) == 0;
150 : #else
151 46 : int nTries = 10;
152 92 : while( nTries-- )
153 : {
154 : const bool connected = (::connect( _readFD, (sockaddr*)&address,
155 46 : sizeof( address )) == 0);
156 46 : if( connected )
157 46 : break;
158 :
159 0 : switch( errno )
160 : {
161 : case EINTR: // Happens sometimes, but looks harmless
162 0 : LBINFO << "connect: " << lunchbox::sysError << ", retrying"
163 0 : << std::endl;
164 0 : lunchbox::sleep( 5 /*ms*/ );
165 0 : break;
166 :
167 : default:
168 0 : nTries = 0;
169 0 : break;
170 : }
171 : }
172 46 : const bool connected = nTries > 0;
173 : #endif
174 :
175 46 : if( !connected )
176 : {
177 0 : LBINFO << "Could not connect to '" << description->getHostname() << ":"
178 0 : << description->port << "': " << lunchbox::sysError << std::endl;
179 0 : close();
180 0 : return false;
181 : }
182 :
183 46 : _initAIORead();
184 46 : _setState( STATE_CONNECTED );
185 46 : LBINFO << "Connected " << description->toString() << std::endl;
186 46 : return true;
187 : }
188 :
189 279 : void SocketConnection::_close()
190 : {
191 279 : if( isClosed( ))
192 418 : return;
193 :
194 140 : if( isListening( ))
195 48 : _exitAIOAccept();
196 92 : else if( isConnected( ))
197 92 : _exitAIORead();
198 :
199 140 : LBASSERT( _readFD > 0 );
200 :
201 : #ifdef _WIN32
202 : const bool closed = ( ::closesocket(_readFD) == 0 );
203 : #else
204 140 : const bool closed = ( ::close(_readFD) == 0 );
205 : #endif
206 :
207 140 : if( !closed )
208 0 : LBWARN << "Could not close socket: " << lunchbox::sysError
209 0 : << std::endl;
210 :
211 140 : _readFD = INVALID_SOCKET;
212 140 : _writeFD = INVALID_SOCKET;
213 140 : _setState( STATE_CLOSED );
214 : }
215 :
216 : //----------------------------------------------------------------------
217 : // Async IO handles
218 : //----------------------------------------------------------------------
219 : #ifdef _WIN32
220 : void SocketConnection::_initAIORead()
221 : {
222 : _overlappedRead.hEvent = CreateEvent( 0, FALSE, FALSE, 0 );
223 : LBASSERT( _overlappedRead.hEvent );
224 :
225 : _overlappedWrite.hEvent = CreateEvent( 0, FALSE, FALSE, 0 );
226 : LBASSERT( _overlappedWrite.hEvent );
227 : if( !_overlappedRead.hEvent )
228 : LBERROR << "Can't create event for AIO notification: "
229 : << lunchbox::sysError << std::endl;
230 : }
231 :
232 : void SocketConnection::_initAIOAccept()
233 : {
234 : _initAIORead();
235 : _overlappedAcceptData = malloc( 2*( sizeof( sockaddr_in ) + 16 ));
236 : }
237 :
238 : void SocketConnection::_exitAIOAccept()
239 : {
240 : if( _overlappedAcceptData )
241 : {
242 : free( _overlappedAcceptData );
243 : _overlappedAcceptData = 0;
244 : }
245 :
246 : _exitAIORead();
247 : }
248 : void SocketConnection::_exitAIORead()
249 : {
250 : if( _overlappedRead.hEvent )
251 : {
252 : CloseHandle( _overlappedRead.hEvent );
253 : _overlappedRead.hEvent = 0;
254 : }
255 :
256 : if( _overlappedWrite.hEvent )
257 : {
258 : CloseHandle( _overlappedWrite.hEvent );
259 : _overlappedWrite.hEvent = 0;
260 : }
261 : }
262 : #else
263 48 : void SocketConnection::_initAIOAccept(){ /* NOP */ }
264 48 : void SocketConnection::_exitAIOAccept(){ /* NOP */ }
265 46 : void SocketConnection::_initAIORead(){ /* NOP */ }
266 92 : void SocketConnection::_exitAIORead(){ /* NOP */ }
267 : #endif
268 :
269 : //----------------------------------------------------------------------
270 : // accept
271 : //----------------------------------------------------------------------
272 : #ifdef _WIN32
273 : void SocketConnection::acceptNB()
274 : {
275 : LBASSERT( isListening() );
276 :
277 : // Create new accept socket
278 : const DWORD flags = getDescription()->type == CONNECTIONTYPE_SDP ?
279 : WSA_FLAG_OVERLAPPED | WSA_FLAG_SDP :
280 : WSA_FLAG_OVERLAPPED;
281 :
282 : LBASSERT( _overlappedAcceptData );
283 : LBASSERT( _overlappedSocket == INVALID_SOCKET );
284 : _overlappedSocket = WSASocket( AF_INET, SOCK_STREAM, IPPROTO_TCP, 0, 0,
285 : flags );
286 :
287 : if( _overlappedSocket == INVALID_SOCKET )
288 : {
289 : LBERROR << "Could not create accept socket: " << lunchbox::sysError
290 : << ", closing listening socket" << std::endl;
291 : close();
292 : return;
293 : }
294 :
295 : const int on = 1;
296 : setsockopt( _overlappedSocket, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT,
297 : reinterpret_cast<const char*>( &on ), sizeof( on ));
298 :
299 : // Start accept
300 : ResetEvent( _overlappedRead.hEvent );
301 : DWORD got;
302 : if( !AcceptEx( _readFD, _overlappedSocket, _overlappedAcceptData, 0,
303 : sizeof( sockaddr_in ) + 16, sizeof( sockaddr_in ) + 16,
304 : &got, &_overlappedRead ) &&
305 : GetLastError() != WSA_IO_PENDING )
306 : {
307 : LBERROR << "Could not start accept operation: "
308 : << lunchbox::sysError << ", closing connection" << std::endl;
309 : close();
310 : }
311 : }
312 :
313 : ConnectionPtr SocketConnection::acceptSync()
314 : {
315 : LB_TS_THREAD( _recvThread );
316 : if( !isListening( ))
317 : return 0;
318 :
319 : LBASSERT( _overlappedAcceptData );
320 : LBASSERT( _overlappedSocket != INVALID_SOCKET );
321 : if( _overlappedSocket == INVALID_SOCKET )
322 : return 0;
323 :
324 : // complete accept
325 : DWORD got = 0;
326 : DWORD flags = 0;
327 :
328 : if( !WSAGetOverlappedResult( _readFD, &_overlappedRead, &got, TRUE,
329 : &flags ))
330 : {
331 : LBWARN << "Accept completion failed: " << lunchbox::sysError
332 : << ", closing socket" << std::endl;
333 : close();
334 : return 0;
335 : }
336 :
337 : sockaddr_in* local = 0;
338 : sockaddr_in* remote = 0;
339 : int localLen = 0;
340 : int remoteLen = 0;
341 : GetAcceptExSockaddrs( _overlappedAcceptData, 0, sizeof( sockaddr_in ) + 16,
342 : sizeof( sockaddr_in ) + 16, (sockaddr**)&local,
343 : &localLen, (sockaddr**)&remote, &remoteLen );
344 : _tuneSocket( _overlappedSocket );
345 :
346 : ConstConnectionDescriptionPtr description = getDescription();
347 : SocketConnection* newConnection = new SocketConnection( description->type );
348 : ConnectionPtr connection( newConnection ); // to keep ref-counting correct
349 :
350 : newConnection->_readFD = _overlappedSocket;
351 : newConnection->_writeFD = _overlappedSocket;
352 :
353 : #ifndef _WIN32
354 : //fcntl( _overlappedSocket, F_SETFL, O_NONBLOCK );
355 : #endif
356 :
357 : newConnection->_initAIORead();
358 : _overlappedSocket = INVALID_SOCKET;
359 :
360 : newConnection->_setState( STATE_CONNECTED );
361 : ConnectionDescriptionPtr newDescription = newConnection->_getDescription();
362 : newDescription->bandwidth = description->bandwidth;
363 : newDescription->port = ntohs( remote->sin_port );
364 : newDescription->setHostname( inet_ntoa( remote->sin_addr ));
365 :
366 : LBINFO << "accepted connection from " << inet_ntoa( remote->sin_addr )
367 : << ":" << ntohs( remote->sin_port ) << std::endl;
368 : return connection;
369 : }
370 :
371 : #else // !_WIN32
372 :
373 90 : void SocketConnection::acceptNB(){ /* NOP */ }
374 :
375 46 : ConnectionPtr SocketConnection::acceptSync()
376 : {
377 46 : if( !isListening( ))
378 0 : return 0;
379 :
380 : sockaddr_in newAddress;
381 46 : socklen_t newAddressLen = sizeof( newAddress );
382 :
383 : Socket fd;
384 46 : unsigned nTries = 1000;
385 46 : do
386 46 : fd = ::accept( _readFD, (sockaddr*)&newAddress, &newAddressLen );
387 46 : while( fd == INVALID_SOCKET && errno == EINTR && --nTries );
388 :
389 46 : if( fd == INVALID_SOCKET )
390 : {
391 0 : LBWARN << "accept failed: " << lunchbox::sysError << std::endl;
392 0 : return 0;
393 : }
394 :
395 46 : _tuneSocket( fd );
396 :
397 46 : ConstConnectionDescriptionPtr description = getDescription();
398 46 : SocketConnection* newConnection = new SocketConnection( description->type );
399 :
400 46 : newConnection->_readFD = fd;
401 46 : newConnection->_writeFD = fd;
402 46 : newConnection->_setState( STATE_CONNECTED );
403 92 : ConnectionDescriptionPtr newDescription = newConnection->_getDescription();
404 46 : newDescription->bandwidth = description->bandwidth;
405 46 : newDescription->port = ntohs( newAddress.sin_port );
406 46 : newDescription->setHostname( inet_ntoa( newAddress.sin_addr ));
407 :
408 46 : LBINFO << "Accepted " << newDescription->toString() << std::endl;
409 92 : return newConnection;
410 : }
411 :
412 : #endif // !_WIN32
413 :
414 :
415 :
416 : #ifdef _WIN32
417 : //----------------------------------------------------------------------
418 : // read
419 : //----------------------------------------------------------------------
420 : void SocketConnection::readNB( void* buffer, const uint64_t bytes )
421 : {
422 : if( isClosed() )
423 : return;
424 :
425 : WSABUF wsaBuffer = { LB_MIN( bytes, 65535 ),
426 : reinterpret_cast< char* >( buffer ) };
427 : DWORD flags = 0;
428 :
429 : ResetEvent( _overlappedRead.hEvent );
430 : _overlappedDone = 0;
431 : const int result = WSARecv( _readFD, &wsaBuffer, 1, &_overlappedDone,
432 : &flags, &_overlappedRead, 0 );
433 : if( result == 0 ) // got data already
434 : {
435 : if( _overlappedDone == 0 ) // socket closed
436 : {
437 : LBINFO << "Got EOF, closing connection" << std::endl;
438 : close();
439 : }
440 : SetEvent( _overlappedRead.hEvent );
441 : }
442 : else if( GetLastError() != WSA_IO_PENDING )
443 : {
444 : LBWARN << "Could not start overlapped receive: " << lunchbox::sysError
445 : << ", closing connection" << std::endl;
446 : close();
447 : }
448 : }
449 :
450 : int64_t SocketConnection::readSync( void* buffer, const uint64_t bytes,
451 : const bool block )
452 : {
453 : LB_TS_THREAD( _recvThread );
454 :
455 : if( _readFD == INVALID_SOCKET )
456 : {
457 : LBERROR << "Invalid read handle" << std::endl;
458 : return READ_ERROR;
459 : }
460 :
461 : if( _overlappedDone > 0 )
462 : return _overlappedDone;
463 :
464 : DWORD got = 0;
465 : DWORD flags = 0;
466 : DWORD startTime = 0;
467 :
468 : while( true )
469 : {
470 : if( WSAGetOverlappedResult( _readFD, &_overlappedRead, &got, block,
471 : &flags ))
472 : return got;
473 :
474 : const int err = WSAGetLastError();
475 : if( err == ERROR_SUCCESS || got > 0 )
476 : {
477 : LBWARN << "Got " << lunchbox::sysError << " with " << got
478 : << " bytes on " << getDescription() << std::endl;
479 : return got;
480 : }
481 :
482 : if( startTime == 0 )
483 : startTime = GetTickCount();
484 :
485 : switch( err )
486 : {
487 : case WSA_IO_INCOMPLETE:
488 : return READ_TIMEOUT;
489 :
490 : case WSASYSCALLFAILURE: // happens sometimes!?
491 : case WSA_IO_PENDING:
492 : if( GetTickCount() - startTime > CO_RECV_TIMEOUT ) // timeout
493 : {
494 : LBWARN << "Error timeout " << std::endl;
495 : return READ_ERROR;
496 : }
497 :
498 : LBWARN << "WSAGetOverlappedResult error loop"
499 : << std::endl;
500 : // one millisecond to recover
501 : lunchbox::sleep( 1 );
502 : break;
503 :
504 : default:
505 : LBWARN << "Got " << lunchbox::sysError
506 : << ", closing connection" << std::endl;
507 : close();
508 : return READ_ERROR;
509 : }
510 : }
511 : }
512 :
513 : int64_t SocketConnection::write( const void* buffer, const uint64_t bytes )
514 : {
515 : if( !isConnected() || _writeFD == INVALID_SOCKET )
516 : return -1;
517 :
518 : DWORD wrote;
519 : WSABUF wsaBuffer =
520 : {
521 : LB_MIN( bytes, 65535 ),
522 : const_cast<char*>( static_cast< const char* >( buffer ))
523 : };
524 :
525 : ResetEvent( _overlappedWrite.hEvent );
526 : if( WSASend(_writeFD, &wsaBuffer, 1, &wrote, 0, &_overlappedWrite, 0 ) == 0 )
527 : // ok
528 : return wrote;
529 :
530 : if( WSAGetLastError() != WSA_IO_PENDING )
531 : return -1;
532 :
533 : const DWORD err = WaitForSingleObject( _overlappedWrite.hEvent, INFINITE );
534 : switch( err )
535 : {
536 : case WAIT_FAILED:
537 : case WAIT_ABANDONED:
538 : {
539 : LBWARN << "Write error" << lunchbox::sysError << std::endl;
540 : return -1;
541 : }
542 :
543 : default:
544 : LBWARN << "Unhandled write error " << err << ": " << lunchbox::sysError
545 : << std::endl;
546 : // no break;
547 : case WAIT_OBJECT_0:
548 : break;
549 : }
550 :
551 : DWORD got = 0;
552 : DWORD flags = 0;
553 : if( WSAGetOverlappedResult( _writeFD, &_overlappedWrite, &got, false,
554 : &flags ))
555 : {
556 : return got;
557 : }
558 :
559 : switch( WSAGetLastError() )
560 : {
561 : case WSA_IO_INCOMPLETE:
562 : throw Exception( Exception::TIMEOUT_WRITE );
563 :
564 : default:
565 : {
566 : LBWARN << "Write error : " << lunchbox::sysError << std::endl;
567 : return -1;
568 : }
569 : }
570 :
571 : LBUNREACHABLE;
572 : return -1;
573 : }
574 : #endif // _WIN32
575 :
576 94 : bool SocketConnection::_createSocket()
577 : {
578 94 : ConstConnectionDescriptionPtr description = getDescription();
579 : #ifdef _WIN32
580 : const DWORD flags = description->type == CONNECTIONTYPE_SDP ?
581 : WSA_FLAG_OVERLAPPED | WSA_FLAG_SDP :
582 : WSA_FLAG_OVERLAPPED;
583 :
584 : const SOCKET fd = WSASocket( AF_INET, SOCK_STREAM, IPPROTO_TCP, 0,0,flags );
585 :
586 : if( description->type == CONNECTIONTYPE_SDP )
587 : LBINFO << "Created SDP socket" << std::endl;
588 : #else
589 : Socket fd;
590 94 : if( description->type == CONNECTIONTYPE_SDP )
591 0 : fd = ::socket( AF_INET_SDP, SOCK_STREAM, IPPROTO_TCP );
592 : else
593 94 : fd = ::socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
594 : #endif
595 :
596 94 : if( fd == INVALID_SOCKET )
597 : {
598 0 : LBERROR << "Could not create socket: "
599 0 : << lunchbox::sysError << std::endl;
600 0 : return false;
601 : }
602 :
603 94 : _tuneSocket( fd );
604 :
605 94 : _readFD = fd;
606 94 : _writeFD = fd; // TCP/IP sockets are bidirectional
607 :
608 94 : return true;
609 : }
610 :
611 140 : void SocketConnection::_tuneSocket( const Socket fd )
612 : {
613 140 : const int on = 1;
614 : setsockopt( fd, IPPROTO_TCP, TCP_NODELAY,
615 140 : reinterpret_cast<const char*>( &on ), sizeof( on ));
616 : setsockopt( fd, SOL_SOCKET, SO_REUSEADDR,
617 140 : reinterpret_cast<const char*>( &on ), sizeof( on ));
618 :
619 : #ifdef _WIN32
620 : const int size = 128768;
621 : setsockopt( fd, SOL_SOCKET, SO_RCVBUF,
622 : reinterpret_cast<const char*>( &size ), sizeof( size ));
623 : setsockopt( fd, SOL_SOCKET, SO_SNDBUF,
624 : reinterpret_cast<const char*>( &size ), sizeof( size ));
625 : #endif
626 140 : }
627 :
628 : //----------------------------------------------------------------------
629 : // listen
630 : //----------------------------------------------------------------------
631 : #ifdef LB_GCC_4_5_OR_LATER
632 : # pragma GCC diagnostic ignored "-Wunused-result"
633 : #endif
634 48 : bool SocketConnection::listen()
635 : {
636 48 : ConnectionDescriptionPtr description = _getDescription();
637 48 : LBASSERT( description->type == CONNECTIONTYPE_TCPIP ||
638 : description->type == CONNECTIONTYPE_SDP );
639 :
640 48 : if( !isClosed( ))
641 0 : return false;
642 :
643 48 : _setState( STATE_CONNECTING );
644 :
645 : sockaddr_in address;
646 48 : const size_t size = sizeof( sockaddr_in );
647 :
648 48 : if( !_parseAddress( description, address ))
649 : {
650 0 : LBWARN << "Can't parse connection parameters" << std::endl;
651 0 : return false;
652 : }
653 :
654 48 : if( !_createSocket())
655 0 : return false;
656 :
657 48 : const bool bound = (::bind( _readFD, (sockaddr *)&address, size ) == 0);
658 :
659 48 : if( !bound )
660 : {
661 0 : LBWARN << "Could not bind socket " << _readFD << ": "
662 0 : << lunchbox::sysError << " to " << inet_ntoa( address.sin_addr )
663 0 : << ":" << ntohs( address.sin_port ) << " AF "
664 0 : << (int)address.sin_family << std::endl;
665 :
666 0 : close();
667 0 : return false;
668 : }
669 48 : else if( address.sin_port == 0 )
670 11 : LBINFO << "Bound to port " << _getPort() << std::endl;
671 :
672 48 : const bool listening = (::listen( _readFD, SOMAXCONN ) == 0);
673 :
674 48 : if( !listening )
675 : {
676 0 : LBWARN << "Could not listen on socket: " << lunchbox::sysError
677 0 : << std::endl;
678 0 : close();
679 0 : return false;
680 : }
681 :
682 : // get socket parameters
683 48 : socklen_t used = size;
684 48 : getsockname( _readFD, (struct sockaddr *)&address, &used );
685 :
686 48 : description->port = ntohs( address.sin_port );
687 :
688 96 : std::string hostname = description->getHostname();
689 48 : if( hostname.empty( ))
690 : {
691 29 : if( address.sin_addr.s_addr == INADDR_ANY )
692 : {
693 29 : char cHostname[256] = {0};
694 29 : gethostname( cHostname, 256 );
695 29 : hostname = cHostname;
696 :
697 29 : description->setHostname( hostname );
698 : }
699 : else
700 0 : description->setHostname( inet_ntoa( address.sin_addr ));
701 : }
702 : #ifndef _WIN32
703 : //fcntl( _readFD, F_SETFL, O_NONBLOCK );
704 : #endif
705 48 : _initAIOAccept();
706 48 : _setState( STATE_LISTENING );
707 :
708 192 : LBINFO << "Listening on " << description->getHostname() << "["
709 96 : << inet_ntoa( address.sin_addr ) << "]:" << description->port
710 192 : << " (" << description->toString() << ")" << std::endl;
711 :
712 96 : return true;
713 : }
714 :
715 11 : uint16_t SocketConnection::_getPort() const
716 : {
717 : sockaddr_in address;
718 11 : socklen_t used = sizeof( address );
719 11 : getsockname( _readFD, (struct sockaddr *) &address, &used );
720 11 : return ntohs(address.sin_port);
721 : }
722 :
723 60 : }
|