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