// listen.h /* Copyright 2009 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include "sock.h" namespace mongo { class MessagingPort; class Listener : boost::noncopyable { public: Listener(const string& name, const string &ip, int port, bool logConnect=true ); virtual ~Listener(); #ifdef MONGO_SSL /** * make this an ssl socket * ownership of SSLManager remains with the caller */ void secure( SSLManager* manager ); void addSecurePort( SSLManager* manager , int additionalPort ); #endif void initAndListen(); // never returns unless error (start a thread) /* spawn a thread, etc., then return */ virtual void accepted(Socket socket); virtual void accepted(MessagingPort *mp); const int _port; /** * @return a rough estimate of elapsed time since the server started */ long long getMyElapsedTimeMillis() const { return _elapsedTime; } void setAsTimeTracker() { _timeTracker = this; } static const Listener* getTimeTracker() { return _timeTracker; } static long long getElapsedTimeMillis() { if ( _timeTracker ) return _timeTracker->getMyElapsedTimeMillis(); // should this assert or throw? seems like callers may not expect to get zero back, certainly not forever. return 0; } private: string _name; string _ip; bool _logConnect; long long _elapsedTime; #ifdef MONGO_SSL SSLManager* _ssl; int _sslPort; #endif /** * @return true iff everything went ok */ bool _setupSockets( const vector& mine , vector& socks ); void _logListen( int port , bool ssl ); static const Listener* _timeTracker; virtual bool useUnixSockets() const { return false; } }; /** * keep track of elapsed time * after a set amount of time, tells you to do something * only in this file because depends on Listener */ class ElapsedTracker { public: ElapsedTracker( int hitsBetweenMarks , int msBetweenMarks ) : _h( hitsBetweenMarks ) , _ms( msBetweenMarks ) , _pings(0) { _last = Listener::getElapsedTimeMillis(); } /** * call this for every iteration * returns true if one of the triggers has gone off */ bool ping() { if ( ( ++_pings % _h ) == 0 ) { _last = Listener::getElapsedTimeMillis(); return true; } long long now = Listener::getElapsedTimeMillis(); if ( now - _last > _ms ) { _last = now; return true; } return false; } private: int _h; int _ms; unsigned long long _pings; long long _last; }; class ListeningSockets { public: ListeningSockets() : _mutex("ListeningSockets") , _sockets( new set() ) , _socketPaths( new set() ) { } void add( int sock ) { scoped_lock lk( _mutex ); _sockets->insert( sock ); } void addPath( string path ) { scoped_lock lk( _mutex ); _socketPaths->insert( path ); } void remove( int sock ) { scoped_lock lk( _mutex ); _sockets->erase( sock ); } void closeAll() { set* sockets; set* paths; { scoped_lock lk( _mutex ); sockets = _sockets; _sockets = new set(); paths = _socketPaths; _socketPaths = new set(); } for ( set::iterator i=sockets->begin(); i!=sockets->end(); i++ ) { int sock = *i; log() << "closing listening socket: " << sock << endl; closesocket( sock ); } for ( set::iterator i=paths->begin(); i!=paths->end(); i++ ) { string path = *i; log() << "removing socket file: " << path << endl; ::remove( path.c_str() ); } } static ListeningSockets* get(); private: mongo::mutex _mutex; set* _sockets; set* _socketPaths; // for unix domain sockets static ListeningSockets* _instance; }; extern TicketHolder connTicketHolder; }