void Listener::initAndListen() { checkTicketNumbers(); vector<SockAddr> mine = ipToAddrs(_ip.c_str(), _port, (!noUnixSocket && useUnixSockets())); vector<int> socks; SOCKET maxfd = 0; // needed for select() for (vector<SockAddr>::iterator it=mine.begin(), end=mine.end(); it != end; ++it) { SockAddr& me = *it; SOCKET sock = ::socket(me.getType(), SOCK_STREAM, 0); if ( sock == INVALID_SOCKET ) { log() << "ERROR: listen(): invalid socket? " << errnoWithDescription() << endl; } if (me.getType() == AF_UNIX) { #if !defined(_WIN32) if (unlink(me.getAddr().c_str()) == -1) { int x = errno; if (x != ENOENT) { log() << "couldn't unlink socket file " << me << errnoWithDescription(x) << " skipping" << endl; continue; } } #endif } else if (me.getType() == AF_INET6) { // IPv6 can also accept IPv4 connections as mapped addresses (::ffff:127.0.0.1) // That causes a conflict if we don't do set it to IPV6_ONLY const int one = 1; setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (const char*) &one, sizeof(one)); } prebindOptions( sock ); if ( ::bind(sock, me.raw(), me.addressSize) != 0 ) { int x = errno; log() << "listen(): bind() failed " << errnoWithDescription(x) << " for socket: " << me.toString() << endl; if ( x == EADDRINUSE ) log() << " addr already in use" << endl; closesocket(sock); return; } #if !defined(_WIN32) if (me.getType() == AF_UNIX) { if (chmod(me.getAddr().c_str(), 0777) == -1) { log() << "couldn't chmod socket file " << me << errnoWithDescription() << endl; } ListeningSockets::get()->addPath( me.getAddr() ); } #endif if ( ::listen(sock, 128) != 0 ) { log() << "listen(): listen() failed " << errnoWithDescription() << endl; closesocket(sock); return; } ListeningSockets::get()->add( sock ); socks.push_back(sock); if (sock > maxfd) maxfd = sock; } static long connNumber = 0; struct timeval maxSelectTime; while ( ! inShutdown() ) { fd_set fds[1]; FD_ZERO(fds); for (vector<int>::iterator it=socks.begin(), end=socks.end(); it != end; ++it) { FD_SET(*it, fds); } maxSelectTime.tv_sec = 0; maxSelectTime.tv_usec = 10000; const int ret = select(maxfd+1, fds, NULL, NULL, &maxSelectTime); if (ret == 0) { #if defined(__linux__) _elapsedTime += ( 10000 - maxSelectTime.tv_usec ) / 1000; #else _elapsedTime += 10; #endif continue; } if (ret < 0) { int x = errno; #ifdef EINTR if ( x == EINTR ) { log() << "select() signal caught, continuing" << endl; continue; } #endif if ( ! inShutdown() ) log() << "select() failure: ret=" << ret << " " << errnoWithDescription(x) << endl; return; } #if defined(__linux__) _elapsedTime += max(ret, (int)(( 10000 - maxSelectTime.tv_usec ) / 1000)); #else _elapsedTime += ret; // assume 1ms to grab connection. very rough #endif for (vector<int>::iterator it=socks.begin(), end=socks.end(); it != end; ++it) { if (! (FD_ISSET(*it, fds))) continue; SockAddr from; int s = accept(*it, from.raw(), &from.addressSize); if ( s < 0 ) { int x = errno; // so no global issues if ( x == ECONNABORTED || x == EBADF ) { log() << "Listener on port " << _port << " aborted" << endl; return; } if ( x == 0 && inShutdown() ) { return; // socket closed } if( !inShutdown() ) log() << "Listener: accept() returns " << s << " " << errnoWithDescription(x) << endl; continue; } if (from.getType() != AF_UNIX) disableNagle(s); if ( _logConnect && ! cmdLine.quiet ) log() << "connection accepted from " << from.toString() << " #" << ++connNumber << endl; accepted(s, from); } } }
void Listener::initAndListen() { checkTicketNumbers(); vector<SOCKET> socks; set<int> sslSocks; { // normal sockets vector<SockAddr> mine = ipToAddrs(_ip.c_str(), _port, (!cmdLine.noUnixSocket && useUnixSockets())); if ( ! _setupSockets( mine , socks ) ) return; } #ifdef MONGO_SSL if ( _ssl && _sslPort > 0 ) { unsigned prev = socks.size(); vector<SockAddr> mine = ipToAddrs(_ip.c_str(), _sslPort, false ); if ( ! _setupSockets( mine , socks ) ) return; for ( unsigned i=prev; i<socks.size(); i++ ) { sslSocks.insert( socks[i] ); } } #endif SOCKET maxfd = 0; // needed for select() for ( unsigned i=0; i<socks.size(); i++ ) { if ( socks[i] > maxfd ) maxfd = socks[i]; } #ifdef MONGO_SSL if ( _ssl == 0 ) { _logListen( _port , false ); } else if ( _sslPort == 0 ) { _logListen( _port , true ); } else { // both _logListen( _port , false ); _logListen( _sslPort , true ); } #else _logListen( _port , false ); #endif static long connNumber = 0; struct timeval maxSelectTime; while ( ! inShutdown() ) { fd_set fds[1]; FD_ZERO(fds); for (vector<SOCKET>::iterator it=socks.begin(), end=socks.end(); it != end; ++it) { FD_SET(*it, fds); } maxSelectTime.tv_sec = 0; maxSelectTime.tv_usec = 10000; const int ret = select(maxfd+1, fds, NULL, NULL, &maxSelectTime); if (ret == 0) { #if defined(__linux__) _elapsedTime += ( 10000 - maxSelectTime.tv_usec ) / 1000; #else _elapsedTime += 10; #endif continue; } if (ret < 0) { int x = errno; #ifdef EINTR if ( x == EINTR ) { log() << "select() signal caught, continuing" << endl; continue; } #endif if ( ! inShutdown() ) log() << "select() failure: ret=" << ret << " " << errnoWithDescription(x) << endl; return; } #if defined(__linux__) _elapsedTime += max(ret, (int)(( 10000 - maxSelectTime.tv_usec ) / 1000)); #else _elapsedTime += ret; // assume 1ms to grab connection. very rough #endif for (vector<SOCKET>::iterator it=socks.begin(), end=socks.end(); it != end; ++it) { if (! (FD_ISSET(*it, fds))) continue; SockAddr from; int s = accept(*it, from.raw(), &from.addressSize); if ( s < 0 ) { int x = errno; // so no global issues if ( x == ECONNABORTED || x == EBADF ) { log() << "Listener on port " << _port << " aborted" << endl; return; } if ( x == 0 && inShutdown() ) { return; // socket closed } if( !inShutdown() ) { log() << "Listener: accept() returns " << s << " " << errnoWithDescription(x) << endl; if (x == EMFILE || x == ENFILE) { // Connection still in listen queue but we can't accept it yet error() << "Out of file descriptors. Waiting one second before trying to accept more connections." << warnings; sleepsecs(1); } } continue; } if (from.getType() != AF_UNIX) disableNagle(s); #ifdef SO_NOSIGPIPE // ignore SIGPIPE signals on osx, to avoid process exit const int one = 1; setsockopt( s , SOL_SOCKET, SO_NOSIGPIPE, &one, sizeof(int)); #endif if ( _logConnect && ! cmdLine.quiet ){ int conns = connTicketHolder.used()+1; const char* word = (conns == 1 ? " connection" : " connections"); log() << "connection accepted from " << from.toString() << " #" << ++connNumber << " (" << conns << word << " now open)" << endl; } boost::shared_ptr<Socket> pnewSock( new Socket(s, from) ); #ifdef MONGO_SSL if ( _ssl && ( _sslPort == 0 || sslSocks.count(*it) ) ) { pnewSock->secureAccepted( _ssl ); } #endif accepted( pnewSock ); } } }
void Listener::setupSockets() { checkTicketNumbers(); #if !defined(_WIN32) _mine = ipToAddrs(_ip.c_str(), _port, (!serverGlobalParams.noUnixSocket && useUnixSockets())); #else _mine = ipToAddrs(_ip.c_str(), _port, false); #endif for (vector<SockAddr>::const_iterator it=_mine.begin(), end=_mine.end(); it != end; ++it) { const SockAddr& me = *it; SOCKET sock = ::socket(me.getType(), SOCK_STREAM, 0); ScopeGuard socketGuard = MakeGuard(&closesocket, sock); massert( 15863 , str::stream() << "listen(): invalid socket? " << errnoWithDescription() , sock >= 0 ); if (me.getType() == AF_UNIX) { #if !defined(_WIN32) if (unlink(me.getAddr().c_str()) == -1) { int x = errno; if (x != ENOENT) { log() << "couldn't unlink socket file " << me << errnoWithDescription(x) << " skipping" << endl; continue; } } #endif } else if (me.getType() == AF_INET6) { // IPv6 can also accept IPv4 connections as mapped addresses (::ffff:127.0.0.1) // That causes a conflict if we don't do set it to IPV6_ONLY const int one = 1; setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (const char*) &one, sizeof(one)); } #if !defined(_WIN32) { const int one = 1; if ( setsockopt( sock , SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) < 0 ) out() << "Failed to set socket opt, SO_REUSEADDR" << endl; } #endif if ( ::bind(sock, me.raw(), me.addressSize) != 0 ) { int x = errno; error() << "listen(): bind() failed " << errnoWithDescription(x) << " for socket: " << me.toString() << endl; if ( x == EADDRINUSE ) error() << " addr already in use" << endl; return; } #if !defined(_WIN32) if (me.getType() == AF_UNIX) { if (chmod(me.getAddr().c_str(), 0777) == -1) { error() << "couldn't chmod socket file " << me << errnoWithDescription() << endl; } ListeningSockets::get()->addPath( me.getAddr() ); } #endif if ( ::listen(sock, 128) != 0 ) { error() << "listen(): listen() failed " << errnoWithDescription() << endl; return; } ListeningSockets::get()->add( sock ); _socks.push_back(sock); socketGuard.Dismiss(); } _setupSocketsSuccessful = true; }