ThreadedSocketAcceptor.cpp
Go to the documentation of this file.
00001 /****************************************************************************
00002 ** Copyright (c) 2001-2014
00003 **
00004 ** This file is part of the QuickFIX FIX Engine
00005 **
00006 ** This file may be distributed under the terms of the quickfixengine.org
00007 ** license as defined by quickfixengine.org and appearing in the file
00008 ** LICENSE included in the packaging of this file.
00009 **
00010 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
00011 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
00012 **
00013 ** See http://www.quickfixengine.org/LICENSE for licensing information.
00014 **
00015 ** Contact ask@quickfixengine.org if any conditions of this licensing are
00016 ** not clear to you.
00017 **
00018 ****************************************************************************/
00019 
00020 #ifdef _MSC_VER
00021 #include "stdafx.h"
00022 #else
00023 #include "config.h"
00024 #endif
00025 
00026 #include "ThreadedSocketAcceptor.h"
00027 #include "Settings.h"
00028 #include "Utility.h"
00029 
00030 namespace FIX
00031 {
00032 ThreadedSocketAcceptor::ThreadedSocketAcceptor(
00033   Application& application,
00034   MessageStoreFactory& factory,
00035   const SessionSettings& settings ) throw( ConfigError )
00036 : Acceptor( application, factory, settings )
00037 { socket_init(); }
00038 
00039 ThreadedSocketAcceptor::ThreadedSocketAcceptor(
00040   Application& application,
00041   MessageStoreFactory& factory,
00042   const SessionSettings& settings,
00043   LogFactory& logFactory ) throw( ConfigError )
00044 : Acceptor( application, factory, settings, logFactory )
00045 { 
00046   socket_init(); 
00047 }
00048 
00049 ThreadedSocketAcceptor::~ThreadedSocketAcceptor()
00050 { 
00051   socket_term(); 
00052 }
00053 
00054 void ThreadedSocketAcceptor::onConfigure( const SessionSettings& s )
00055 throw ( ConfigError )
00056 {
00057   std::set<SessionID> sessions = s.getSessions();
00058   std::set<SessionID>::iterator i;
00059   for( i = sessions.begin(); i != sessions.end(); ++i )
00060   {
00061     const Dictionary& settings = s.get( *i );
00062     settings.getInt( SOCKET_ACCEPT_PORT );
00063     if( settings.has(SOCKET_REUSE_ADDRESS) )
00064       settings.getBool( SOCKET_REUSE_ADDRESS );
00065     if( settings.has(SOCKET_NODELAY) )
00066       settings.getBool( SOCKET_NODELAY );
00067   }
00068 }
00069 
00070 void ThreadedSocketAcceptor::onInitialize( const SessionSettings& s )
00071 throw ( RuntimeError )
00072 {
00073   short port = 0;
00074   std::set<int> ports;
00075 
00076   std::set<SessionID> sessions = s.getSessions();
00077   std::set<SessionID>::iterator i = sessions.begin();
00078   for( ; i != sessions.end(); ++i )
00079   {
00080     const Dictionary& settings = s.get( *i );
00081     port = (short)settings.getInt( SOCKET_ACCEPT_PORT );
00082 
00083     m_portToSessions[port].insert( *i );
00084 
00085     if( ports.find(port) != ports.end() )
00086       continue;
00087     ports.insert( port );
00088 
00089     const bool reuseAddress = settings.has( SOCKET_REUSE_ADDRESS ) ? 
00090       settings.getBool( SOCKET_REUSE_ADDRESS ) : true;
00091 
00092     const bool noDelay = settings.has( SOCKET_NODELAY ) ? 
00093       settings.getBool( SOCKET_NODELAY ) : false;
00094 
00095     const int sendBufSize = settings.has( SOCKET_SEND_BUFFER_SIZE ) ?
00096       settings.getInt( SOCKET_SEND_BUFFER_SIZE ) : 0;
00097 
00098     const int rcvBufSize = settings.has( SOCKET_RECEIVE_BUFFER_SIZE ) ?
00099       settings.getInt( SOCKET_RECEIVE_BUFFER_SIZE ) : 0;
00100 
00101     int socket = socket_createAcceptor( port, reuseAddress );
00102     if( socket < 0 )
00103     {
00104       SocketException e;
00105       socket_close( socket );
00106       throw RuntimeError( "Unable to create, bind, or listen to port " 
00107                          + IntConvertor::convert( (unsigned short)port ) + " (" + e.what() + ")" );
00108     }
00109     if( noDelay )
00110       socket_setsockopt( socket, TCP_NODELAY );
00111     if( sendBufSize )
00112       socket_setsockopt( socket, SO_SNDBUF, sendBufSize );
00113     if( rcvBufSize )
00114       socket_setsockopt( socket, SO_RCVBUF, rcvBufSize );
00115 
00116     m_socketToPort[socket] = port;
00117     m_sockets.insert( socket );
00118   }    
00119 }
00120 
00121 void ThreadedSocketAcceptor::onStart()
00122 {
00123   Sockets::iterator i;
00124   for( i = m_sockets.begin(); i != m_sockets.end(); ++i )
00125   {
00126     Locker l( m_mutex );
00127     int port = m_socketToPort[*i];
00128     AcceptorThreadInfo* info = new AcceptorThreadInfo( this, *i, port );
00129     thread_id thread;
00130     thread_spawn( &socketAcceptorThread, info, thread );
00131     addThread( *i, thread );
00132   }
00133 }
00134 
00135 bool ThreadedSocketAcceptor::onPoll( double timeout )
00136 {
00137   return false;
00138 }
00139 
00140 void ThreadedSocketAcceptor::onStop()
00141 { 
00142   SocketToThread threads;
00143   SocketToThread::iterator i;
00144 
00145   {
00146     Locker l(m_mutex);
00147 
00148     time_t start = 0;
00149     time_t now = 0;
00150 
00151     ::time( &start );
00152     while ( isLoggedOn() )
00153     {
00154       if( ::time(&now) -5 >= start )
00155         break;
00156     }
00157 
00158     threads = m_threads;
00159     m_threads.clear();
00160   }
00161 
00162   for ( i = threads.begin(); i != threads.end(); ++i )
00163     socket_close( i->first );
00164   for ( i = threads.begin(); i != threads.end(); ++i )
00165     thread_join( i->second );
00166 }
00167 
00168 void ThreadedSocketAcceptor::addThread( int s, thread_id t )
00169 {
00170   Locker l(m_mutex);
00171 
00172   m_threads[ s ] = t;
00173 }
00174 
00175 void ThreadedSocketAcceptor::removeThread( int s )
00176 {
00177   Locker l(m_mutex);
00178   SocketToThread::iterator i = m_threads.find( s );
00179   if ( i != m_threads.end() )
00180   {
00181     thread_detach( i->second );
00182     m_threads.erase( i );
00183   }
00184 }
00185 
00186 THREAD_PROC ThreadedSocketAcceptor::socketAcceptorThread( void* p )
00187 {
00188   AcceptorThreadInfo * info = reinterpret_cast < AcceptorThreadInfo* > ( p );
00189 
00190   ThreadedSocketAcceptor* pAcceptor = info->m_pAcceptor;
00191   int s = info->m_socket;
00192   int port = info->m_port;
00193   delete info;
00194 
00195   int noDelay = 0;
00196   int sendBufSize = 0;
00197   int rcvBufSize = 0;
00198   socket_getsockopt( s, TCP_NODELAY, noDelay );
00199   socket_getsockopt( s, SO_SNDBUF, sendBufSize );
00200   socket_getsockopt( s, SO_RCVBUF, rcvBufSize );
00201 
00202   int socket = 0;
00203   while ( ( !pAcceptor->isStopped() && ( socket = socket_accept( s ) ) >= 0 ) )
00204   {
00205     if( noDelay )
00206       socket_setsockopt( socket, TCP_NODELAY );
00207     if( sendBufSize )
00208       socket_setsockopt( socket, SO_SNDBUF, sendBufSize );
00209     if( rcvBufSize )
00210       socket_setsockopt( socket, SO_RCVBUF, rcvBufSize );
00211 
00212     Sessions sessions = pAcceptor->m_portToSessions[port];
00213 
00214     ThreadedSocketConnection * pConnection =
00215       new ThreadedSocketConnection
00216         ( socket, sessions, pAcceptor->getLog() );
00217 
00218     ConnectionThreadInfo* info = new ConnectionThreadInfo( pAcceptor, pConnection );
00219 
00220     {
00221       Locker l( pAcceptor->m_mutex );
00222 
00223       std::stringstream stream;
00224       stream << "Accepted connection from " << socket_peername( socket ) << " on port " << port;
00225 
00226       if( pAcceptor->getLog() )
00227         pAcceptor->getLog()->onEvent( stream.str() );
00228 
00229       thread_id thread;
00230       if ( !thread_spawn( &socketConnectionThread, info, thread ) )
00231         delete info;
00232       pAcceptor->addThread( socket, thread );
00233     }
00234   }
00235 
00236   if( !pAcceptor->isStopped() )
00237     pAcceptor->removeThread( s );
00238 
00239   return 0;
00240 }
00241 
00242 THREAD_PROC ThreadedSocketAcceptor::socketConnectionThread( void* p )
00243 {
00244   ConnectionThreadInfo * info = reinterpret_cast < ConnectionThreadInfo* > ( p );
00245 
00246   ThreadedSocketAcceptor* pAcceptor = info->m_pAcceptor;
00247   ThreadedSocketConnection* pConnection = info->m_pConnection;
00248   delete info;
00249 
00250   int socket = pConnection->getSocket();
00251 
00252   while ( pConnection->read() ) {}
00253   delete pConnection;
00254   if( !pAcceptor->isStopped() )
00255     pAcceptor->removeThread( socket );
00256   return 0;
00257 }
00258 }

Generated on Mon Jun 23 2014 23:49:38 for QuickFIX by doxygen 1.7.6.1 written by Dimitri van Heesch, © 1997-2001