SocketMonitor.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 "SocketMonitor.h"
00027 #include "Utility.h"
00028 #include <exception>
00029 #include <set>
00030 #include <algorithm>
00031 #include <iostream>
00032 
00033 namespace FIX
00034 {
00035 SocketMonitor::SocketMonitor( int timeout )
00036 : m_timeout( timeout )
00037 {
00038   socket_init();
00039 
00040   std::pair<int, int> sockets = socket_createpair();
00041   m_signal = sockets.first;
00042   m_interrupt = sockets.second;
00043   socket_setnonblock( m_signal );
00044   socket_setnonblock( m_interrupt );
00045   m_readSockets.insert( m_interrupt );
00046 
00047   m_timeval.tv_sec = 0;
00048   m_timeval.tv_usec = 0;
00049 #ifndef SELECT_DECREMENTS_TIME
00050   m_ticks = clock();
00051 #endif
00052 }
00053 
00054 SocketMonitor::~SocketMonitor()
00055 {
00056   Sockets::iterator i;
00057   for ( i = m_readSockets.begin(); i != m_readSockets.end(); ++i ) {
00058     socket_close( *i );
00059   }
00060 
00061   socket_close( m_signal );
00062   socket_term();
00063 }
00064 
00065 bool SocketMonitor::addConnect( int s )
00066 {
00067   socket_setnonblock( s );
00068   Sockets::iterator i = m_connectSockets.find( s );
00069   if( i != m_connectSockets.end() ) return false;
00070 
00071   m_connectSockets.insert( s );
00072   return true;
00073 }
00074 
00075 bool SocketMonitor::addRead( int s )
00076 {
00077   socket_setnonblock( s );
00078   Sockets::iterator i = m_readSockets.find( s );
00079   if( i != m_readSockets.end() ) return false;
00080 
00081   m_readSockets.insert( s );
00082   return true;
00083 }
00084 
00085 bool SocketMonitor::addWrite( int s )
00086 {
00087   if( m_readSockets.find(s) == m_readSockets.end() )
00088     return false;
00089 
00090   socket_setnonblock( s );
00091   Sockets::iterator i = m_writeSockets.find( s );
00092   if( i != m_writeSockets.end() ) return false;
00093 
00094   m_writeSockets.insert( s );
00095   return true;
00096 }
00097 
00098 bool SocketMonitor::drop( int s )
00099 {
00100   Sockets::iterator i = m_readSockets.find( s );
00101   Sockets::iterator j = m_writeSockets.find( s );
00102   Sockets::iterator k = m_connectSockets.find( s );
00103 
00104   if ( i != m_readSockets.end() || 
00105        j != m_writeSockets.end() ||
00106        k != m_connectSockets.end() )
00107   {
00108     socket_close( s );
00109     m_readSockets.erase( s );
00110     m_writeSockets.erase( s );
00111     m_connectSockets.erase( s );
00112     m_dropped.push( s );
00113     return true;
00114   }
00115   return false;
00116 }
00117 
00118 inline timeval* SocketMonitor::getTimeval( bool poll, double timeout )
00119 {
00120   if ( poll )
00121   {
00122     m_timeval.tv_sec = 0;
00123     m_timeval.tv_usec = 0;
00124     return &m_timeval;
00125   }
00126 
00127   timeout = m_timeout;
00128 
00129   if ( !timeout )
00130     return 0;
00131 #ifdef SELECT_MODIFIES_TIMEVAL
00132   if ( !m_timeval.tv_sec && !m_timeval.tv_usec && timeout )
00133     m_timeval.tv_sec = timeout;
00134   return &m_timeval;
00135 #else
00136 double elapsed = ( double ) ( clock() - m_ticks ) / ( double ) CLOCKS_PER_SEC;
00137   if ( elapsed >= timeout || elapsed == 0.0 )
00138   {
00139     m_ticks = clock();
00140     m_timeval.tv_sec = 0;
00141     m_timeval.tv_usec = (timeout * 1000000);
00142   }
00143   else
00144   {
00145     m_timeval.tv_sec = 0;
00146     m_timeval.tv_usec = ( ( timeout - elapsed ) * 1000000 );
00147   }
00148   return &m_timeval;
00149 #endif
00150 }
00151 
00152 bool SocketMonitor::sleepIfEmpty( bool poll )
00153 {
00154   if( poll )
00155     return false;
00156 
00157   if ( m_readSockets.empty() && 
00158        m_writeSockets.empty() &&
00159        m_connectSockets.empty() )
00160   {
00161     process_sleep( m_timeout );
00162     return true;
00163   }
00164   else
00165     return false;
00166 }
00167 
00168 void SocketMonitor::signal( int socket )
00169 {
00170   socket_send( m_signal, (char*)&socket, sizeof(socket) );
00171 }
00172 
00173 void SocketMonitor::unsignal( int s )
00174 {
00175   Sockets::iterator i = m_writeSockets.find( s );
00176   if( i == m_writeSockets.end() ) return;
00177 
00178   m_writeSockets.erase( s );
00179 }
00180 
00181 void SocketMonitor::block( Strategy& strategy, bool poll, double timeout )
00182 {
00183   while ( m_dropped.size() )
00184   {
00185     strategy.onError( *this, m_dropped.front() );
00186     m_dropped.pop();
00187     if ( m_dropped.size() == 0 )
00188       return ;
00189   }
00190 
00191   fd_set readSet;
00192   FD_ZERO( &readSet );
00193   buildSet( m_readSockets, readSet );
00194   fd_set writeSet;
00195   FD_ZERO( &writeSet );
00196   buildSet( m_connectSockets, writeSet );
00197   buildSet( m_writeSockets, writeSet );
00198   fd_set exceptSet;
00199   FD_ZERO( &exceptSet );
00200   buildSet( m_connectSockets, exceptSet );
00201 
00202   if ( sleepIfEmpty(poll) )
00203   {
00204     strategy.onTimeout( *this );
00205     return;
00206   }
00207 
00208   int result = select( FD_SETSIZE, &readSet, &writeSet, &exceptSet, getTimeval(poll, timeout) );
00209 
00210   if ( result == 0 )
00211   {
00212     strategy.onTimeout( *this );
00213     return;
00214   }
00215   else if ( result > 0 )
00216   {
00217     processExceptSet( strategy, exceptSet );
00218     processWriteSet( strategy, writeSet );
00219     processReadSet( strategy, readSet );
00220   }
00221   else
00222   {
00223     strategy.onError( *this );
00224   }
00225 }
00226 
00227 void SocketMonitor::processReadSet( Strategy& strategy, fd_set& readSet )
00228 {
00229 #ifdef _MSC_VER
00230   for ( unsigned i = 0; i < readSet.fd_count; ++i )
00231   {
00232     int s = readSet.fd_array[ i ];
00233     if( s == m_interrupt )
00234     {
00235       int socket = 0;
00236       recv( s, (char*)&socket, sizeof(socket), 0 );
00237       addWrite( socket );
00238     }
00239     else
00240     {
00241       strategy.onEvent( *this, s );
00242     }
00243   }
00244 #else
00245     Sockets::iterator i;
00246     Sockets sockets = m_readSockets;
00247     for ( i = sockets.begin(); i != sockets.end(); ++i )
00248     {
00249       int s = *i;
00250       if ( !FD_ISSET( *i, &readSet ) )
00251         continue;
00252       if( s == m_interrupt )
00253       {
00254         int socket = 0;
00255         recv( s, (char*)&socket, sizeof(socket), 0 );
00256         addWrite( socket );
00257       }
00258       else
00259       {
00260         strategy.onEvent( *this, s );
00261       }
00262     }
00263 #endif
00264 }
00265 
00266 void SocketMonitor::processWriteSet( Strategy& strategy, fd_set& writeSet )
00267 {
00268 #ifdef _MSC_VER
00269   for ( unsigned i = 0; i < writeSet.fd_count; ++i )
00270   {
00271     int s = writeSet.fd_array[ i ];
00272     if( m_connectSockets.find(s) != m_connectSockets.end() )
00273     {
00274       m_connectSockets.erase( s );
00275       m_readSockets.insert( s );
00276       strategy.onConnect( *this, s );
00277     }
00278     else
00279     {
00280       strategy.onWrite( *this, s );
00281     }
00282   }
00283 #else
00284   Sockets::iterator i;
00285   Sockets sockets = m_connectSockets;
00286   for( i = sockets.begin(); i != sockets.end(); ++i )
00287   {
00288     int s = *i;
00289     if ( !FD_ISSET( *i, &writeSet ) )
00290       continue;
00291     m_connectSockets.erase( s );
00292     m_readSockets.insert( s );
00293     strategy.onConnect( *this, s );
00294   }
00295 
00296   sockets = m_writeSockets;
00297   for( i = sockets.begin(); i != sockets.end(); ++i )
00298   {
00299     int s = *i;
00300     if ( !FD_ISSET( *i, &writeSet ) )
00301       continue;
00302     strategy.onWrite( *this, s );
00303   }
00304 #endif
00305 }
00306 
00307 void SocketMonitor::processExceptSet( Strategy& strategy, fd_set& exceptSet )
00308 {
00309 #ifdef _MSC_VER
00310   for ( unsigned i = 0; i < exceptSet.fd_count; ++i )
00311   {
00312     int s = exceptSet.fd_array[ i ];
00313     strategy.onError( *this, s );
00314   }
00315 #else
00316     Sockets::iterator i;
00317     Sockets sockets = m_connectSockets;
00318     for ( i = sockets.begin(); i != sockets.end(); ++i )
00319     {
00320       int s = *i;
00321       if ( !FD_ISSET( *i, &exceptSet ) )
00322         continue;
00323       strategy.onError( *this, s );
00324     }
00325 #endif
00326 }
00327 
00328 void SocketMonitor::buildSet( const Sockets& sockets, fd_set& watchSet )
00329 {
00330   Sockets::const_iterator iter;
00331   for ( iter = sockets.begin(); iter != sockets.end(); ++iter ) {
00332     FD_SET( *iter, &watchSet );
00333   }
00334 }
00335 }

Generated on Mon Sep 15 2014 01:23:55 for QuickFIX by doxygen 1.7.6.1 written by Dimitri van Heesch, © 1997-2001