1 // Copyright 2009 The Archiveopteryx Developers <info@aox.org>
5 #include "connection.h"
21 // struct timeval, fd_set
23 #include <sys/types.h>
24 #include <sys/select.h>
25 // getsockopt, SOL_SOCKET, SO_ERROR
26 #include <sys/socket.h>
30 #include <sys/ioctl.h>
32 // memset (for FD_* under OpenBSD)
36 static bool freeMemorySoon;
39 static EventLoop * loop;
47 : log( new Log ), startup( false ),
48 stop( false ), limit( 16 * 1024 * 1024 )
54 List< Connection > connections;
62 Stopper( uint s ): stage2( false ) {
63 (void)new Timer( this, s );
68 if ( !EventLoop::global() || EventLoop::global()->inShutdown() )
71 EventLoop::global()->stop();
73 EventLoop::global()->stop( 10 );
80 /*! \class EventLoop eventloop.h
81 This class dispatches event notifications to a list of Connections.
83 An EventLoop maintains a list of participating Connection objects,
84 and periodically informs them about any events (e.g., read/write,
85 errors, timeouts) that occur. The loop continues until something
90 /*! Creates the global EventLoop object or, if \a l is non-zero, sets
91 the global EventLoop to \a l. This function expects to be called
92 very early during the startup sequence.
95 void EventLoop::setup( EventLoop * l )
99 ::loop = new EventLoop;
100 Allocator::addEternal( ::loop, "global event loop" );
104 /*! Creates a new EventLoop. */
106 EventLoop::EventLoop()
112 /*! Exists only to avoid compiler warnings. */
114 EventLoop::~EventLoop()
119 /*! Adds \a c to this EventLoop's list of active Connections.
121 If shutdown() has been called already, addConnection() ignores \a
122 c, so that shutdown proceeds unhampered. This is likely to disturb
123 \a c a little, but it's better than the alternative: Aborting the
127 void EventLoop::addConnection( Connection * c )
130 log( "Cannot add new Connection objects during shutdown",
137 if ( d->connections.find( c ) )
140 d->connections.prepend( c );
141 setConnectionCounts();
145 /*! Removes \a c from this EventLoop's list of active
149 void EventLoop::removeConnection( Connection * c )
153 if ( d->connections.remove( c ) == 0 )
155 setConnectionCounts();
157 // if this is a server, with external connections, and we just
158 // closed the last external connection, then we shut down
159 // nicely. otherwise, we just remove the specified connection,
162 if ( c->hasProperty( Connection::Internal ) )
168 List< Connection >::Iterator it( d->connections );
170 if ( !it->hasProperty( Connection::Internal ) )
178 /*! Returns a (non-zero) pointer to the list of Connections that have
179 been added to this EventLoop.
182 List< Connection > *EventLoop::connections() const
184 return &d->connections;
188 static GraphableNumber * sizeinram = 0;
190 static const uint gcDelay = 30;
193 /*! Starts the EventLoop and runs it until stop() is called. */
195 void EventLoop::start()
199 bool haveLoggedStartup = false;
201 log( "Starting event loop", Log::Debug );
203 while ( !d->stop && !Log::disastersYet() ) {
204 if ( !haveLoggedStartup && !inStartup() ) {
205 if ( !Server::name().isEmpty() )
206 log( Server::name() + ": Server startup complete",
208 haveLoggedStartup = true;
213 uint timeout = gcDelay;
220 // Figure out what events each connection wants.
222 List< Connection >::Iterator it( d->connections );
229 removeConnection( c );
231 else if ( c->type() == Connection::Listener && inStartup() ) {
232 // we don't accept new connections until we've
239 if ( c->canWrite() ||
240 c->state() == Connection::Connecting ||
241 c->state() == Connection::Closing )
243 if ( c->timeout() > 0 && c->timeout() < timeout )
244 timeout = c->timeout();
248 // Figure out whether any timers need attention soon
250 List< Timer >::Iterator t( d->timers );
252 if ( t->active() && t->timeout() < timeout )
253 timeout = t->timeout();
257 // Look for interesting input
260 tv.tv_sec = timeout - time( 0 );
265 if ( tv.tv_sec > 60 )
268 // we never ask the OS to sleep shorter than .2 seconds
272 if ( select( maxfd+1, &r, &w, 0, &tv ) < 0 ) {
273 // r and w are undefined. we clear them, and dispatch()
274 // won't jump to conclusions
278 time_t now = time( 0 );
280 // Graph our size before processing events
282 sizeinram = new GraphableNumber( "memory-used" );
283 sizeinram->setValue( Allocator::inUse() + Allocator::allocated() );
285 // Any interesting timers?
287 if ( !d->timers.isEmpty() ) {
288 uint now = time( 0 );
289 t = d->timers.first();
293 if ( tmp->active() && tmp->timeout() <= now )
298 // Figure out what each connection cares about.
300 it = d->connections.first();
306 dispatch( c, FD_ISSET( fd, &r ), FD_ISSET( fd, &w ), now );
311 removeConnection( c );
315 // Graph our size after processing all the events too
317 sizeinram->setValue( Allocator::inUse() + Allocator::allocated() );
319 // Collect garbage if someone asks for it, or if we've passed
320 // the memory usage goal. This has to be at the end of the
321 // scope, since anything referenced by local variables might
325 if ( !::freeMemorySoon ) {
326 uint a = Allocator::inUse() + Allocator::allocated();
328 // time went backwards, best to be paranoid
329 ::freeMemorySoon = true;
332 // if we're below the limit, we don't modify the
333 // limit. if we're above, but below 2x, we halve
334 // the period (right-shift by one bit). if we're at
335 // 2-3x, we right-shift by two. if we're at 3-4x,
336 // we right-shift by three, etc.
338 // if memory usage is extreme enough we'll collect
339 // garbage every second.
340 uint factor = a / d->limit;
341 uint period = gcDelay >> factor;
342 if ( (uint)(now - gc) > period )
343 ::freeMemorySoon = true;
346 if ( ::freeMemorySoon ) {
349 ::freeMemorySoon = false;
354 // This is for event loop shutdown. A little brutal. With any
355 // luck, the listeners have been closed long ago and this is just
356 // for those who wouldn't disconnect voluntarily.
357 log( "Shutting down event loop", Log::Debug );
358 List< Connection >::Iterator it( d->connections );
364 if ( c->state() == Connection::Connected )
365 c->react( Connection::Shutdown );
366 if ( c->state() == Connection::Connected )
368 if ( c->writeBuffer()->size() > 0 )
369 c->log( "Still have " +
370 EString::humanNumber( c->writeBuffer()->size() ) +
371 " bytes to write", Log::Debug );
372 } catch ( Exception e ) {
373 // we don't really care at this point, do we?
377 log( "Event loop stopped", Log::Debug );
381 /*! Calls Allocator::free() and does any necessary pre- and
385 void EventLoop::freeMemory()
388 List<Connection>::Iterator i( d->connections );
391 if ( !(c->hasProperty( Connection::Listens )) )
395 Garbage * biggest = Allocator::free( &x );
396 // x now points to free memory
397 i = d->connections.first();
398 Connection * victim = 0;
406 if ( victim && Allocator::inUse() > d->limit ) {
407 ::log( "Closing connection due to memory overload: " +
408 victim->description() );
409 victim->react( Connection::Shutdown );
415 /*! Dispatches events to the connection \a c, based on its current
416 state, the time \a now and the results from select: \a r is true
417 if the FD may be read, and \a w is true if we know that the FD may
418 be written to. If \a now is past that Connection's timeout, we
419 must send a Timeout event.
422 void EventLoop::dispatch( Connection * c, bool r, bool w, uint now )
426 dummy2 = sizeof(dummy1);
427 if ( ::getsockopt( c->fd(), SOL_SOCKET, SO_RCVBUF,
428 &dummy1, &dummy2 ) < 0 ) {
430 removeConnection( c );
436 if ( c->timeout() != 0 && now >= c->timeout() ) {
438 c->react( Connection::Timeout );
441 if ( c->state() == Connection::Connecting ) {
443 bool connected = false;
445 if ( ( w && !r ) || c->isPending( Connection::Connect ) ) {
448 else if ( c->isPending( Connection::Error ) ) {
452 // This might indicate a connection error, or a successful
453 // connection with outstanding data. (Stevens suggests the
454 // getsockopt to disambiguate the two, cf. UNPv1 15.4.)
456 int errlen = sizeof( int );
457 ::getsockopt( c->fd(), SOL_SOCKET, SO_ERROR, (void *)&errval,
458 (socklen_t *)&errlen );
467 c->setState( Connection::Connected );
468 c->react( Connection::Connect );
471 c->react( Connection::Error );
472 c->setState( Connection::Closing );
479 if ( !c->hasProperty( Connection::Listens ) ) {
481 int r = ioctl( c->fd(), FIONREAD, &a );
482 if ( r >= 0 && a == 0 )
487 c->react( Connection::Read );
490 c->setState( Connection::Closing );
491 c->react( Connection::Close );
495 uint s = c->writeBuffer()->size();
497 // if we're closing anyway, and we can't write any of what we
498 // want to write, then just forget the buffered data and go on
500 if ( c->state() == Connection::Closing &&
501 s && s == c->writeBuffer()->size() )
502 c->writeBuffer()->remove( s );
504 catch ( Exception e ) {
508 s = "Invariant failed";
517 s.append( " while processing " + c->description() );
518 d->log->log( s, Log::Error );
519 if ( !c->hasProperty( Connection::Listens ) )
523 if ( c->state() == Connection::Closing && !c->canWrite() )
526 removeConnection( c );
530 /*! Instructs this EventLoop to perform an orderly shutdown in \a s
531 seconds, by sending each participating Connection a Shutdown event
534 Listener connections are closed right away, some/all external
535 connections get a Shutdown event at once, everyone get a Shutdown
536 event at final shutdown.
539 void EventLoop::stop( uint s )
546 (void)new LoopData::Stopper( s );
547 List<Connection>::Iterator i( d->connections );
553 if ( c->hasProperty( Connection::Listens ) ) {
554 c->react( Connection::Shutdown );
557 else if ( s <= 10 && !c->hasProperty( Connection::Internal ) ) {
558 c->react( Connection::Shutdown );
560 } catch ( Exception e ) {
561 removeConnection( c );
567 /*! Closes all Connections except \a c1 and \a c2. This helps TlsProxy
571 void EventLoop::closeAllExcept( Connection * c1, Connection * c2 )
573 List< Connection >::Iterator it( d->connections );
577 if ( c != c1 && c != c2 )
583 /*! Closes all Connection except Listeners. When we fork, this allows
584 us to keep the connections on one side of the fence.
587 void EventLoop::closeAllExceptListeners()
589 List< Connection >::Iterator it( d->connections );
593 if ( c->type() != Connection::Listener )
599 /*! Flushes the write buffer of all connections. */
601 void EventLoop::flushAll()
603 List< Connection >::Iterator it( d->connections );
612 /*! Returns true if this EventLoop is still attending to startup chores,
613 and not yet processing Listener requests.
616 bool EventLoop::inStartup() const
622 /*! Sets the startup state of this EventLoop to \a p. If \a p is true,
623 then Listeners will not be processed until this function is called
624 again with \a p set to false.
627 void EventLoop::setStartup( bool p )
633 /*! Returns true if this EventLoop is shutting down (ie. stop() has
634 been called), and false if it's starting up or operating normally.
637 bool EventLoop::inShutdown() const
643 /*! Returns a pointer to the global event loop, or 0 if setup() has not
647 EventLoop * EventLoop::global()
653 /*! This static function is just a convenient shorthand for calling
654 stop() on the global() EventLoop.
657 void EventLoop::shutdown()
663 /*! Records that \a t exists, so that the event loop will process \a
667 void EventLoop::addTimer( Timer * t )
669 d->timers.append( t );
673 /*! Forgets that \a t exists. The event loop will henceforth never
677 void EventLoop::removeTimer( Timer * t )
679 List<Timer>::Iterator i( d->timers.find( t ) );
684 static GraphableNumber * imapgraph = 0;
685 static GraphableNumber * pop3graph = 0;
686 static GraphableNumber * smtpgraph = 0;
687 static GraphableNumber * othergraph = 0;
688 static GraphableNumber * internalgraph = 0;
689 static GraphableNumber * httpgraph = 0;
690 static GraphableNumber * dbgraph = 0;
694 /*! Scans the event loop and stores the current number of different
695 connections using GraphableNumber.
698 void EventLoop::setConnectionCounts()
707 bool listeners = false;
708 List<Connection>::Iterator c( d->connections );
710 switch( c->type() ) {
711 case Connection::Client:
712 case Connection::LogServer:
713 case Connection::GraphDumper:
714 case Connection::LogClient:
715 case Connection::TlsProxy:
716 case Connection::TlsClient:
717 case Connection::RecorderClient:
718 case Connection::RecorderServer:
719 case Connection::Pipe:
722 case Connection::DatabaseClient:
725 case Connection::ImapServer:
728 case Connection::SmtpServer:
731 case Connection::SmtpClient:
732 case Connection::ManageSieveServer:
733 case Connection::EGDServer:
734 case Connection::LdapRelay:
737 case Connection::Pop3Server:
740 case Connection::HttpServer:
743 case Connection::Listener:
745 // we don't count these, we only count connections
753 imapgraph = new GraphableNumber( "imap-connections" );
754 pop3graph = new GraphableNumber( "pop3-connections" );
755 smtpgraph = new GraphableNumber( "smtp-connections" );
756 othergraph = new GraphableNumber( "other-connections" );
757 internalgraph = new GraphableNumber( "internal-connections" );
758 httpgraph = new GraphableNumber( "http-connections" );
759 dbgraph = new GraphableNumber( "db-connections" );
761 imapgraph->setValue( imap );
762 pop3graph->setValue( pop3 );
763 smtpgraph->setValue( smtp );
764 othergraph->setValue( other );
765 internalgraph->setValue( internal );
766 httpgraph->setValue( http );
767 dbgraph->setValue( db );
771 /*! Stops all the SSL-enabled Listeners. */
773 void EventLoop::shutdownSSL()
775 log( "Shutting down SSL-enabled Listeners", Log::Error );
776 List< Connection >::Iterator it( d->connections );
780 if ( c->hasProperty( Connection::Listens ) &&
781 c->hasProperty( Connection::StartsSSL ) )
787 /*! Requests the event loop to collect garbage and clear any caches at
788 the earliest opportunity. Used for debugging.
791 void EventLoop::freeMemorySoon()
793 ::freeMemorySoon = true;
797 /*! Instructs this event loop to collect garbage when memory usage
798 passes \a limit bytes. The default is 0, which means to collect
799 garbage even if very little is being used.
802 void EventLoop::setMemoryUsage( uint limit )
808 /*! Returns whatever setMemoryUsage() has recorded, or 0 meaning to
809 collect garbage often.
812 uint EventLoop::memoryUsage() const