Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | Related Pages

connectionbosh.cpp

00001 /*
00002  * Copyright (c) 2007-2009 by Jakob Schroeter <js@camaya.net>
00003  * This file is part of the gloox library. http://camaya.net/gloox
00004  *
00005  * This software is distributed under a license. The full license
00006  * agreement can be found in the file LICENSE in this distribution.
00007  * This software may not be copied, modified, sold or distributed
00008  * other than expressed in the named license agreement.
00009  *
00010  * This software is distributed without any warranty.
00011  */
00012 
00013 #include "config.h"
00014 
00015 #include "gloox.h"
00016 
00017 #include "connectionbosh.h"
00018 #include "logsink.h"
00019 #include "prep.h"
00020 #include "tag.h"
00021 #include "util.h"
00022 
00023 #include <string>
00024 #include <cstdlib>
00025 #include <cctype>
00026 #include <algorithm>
00027 
00028 namespace gloox
00029 {
00030 
00031   ConnectionBOSH::ConnectionBOSH( ConnectionBase* connection, const LogSink& logInstance,
00032                                   const std::string& boshHost, const std::string& xmppServer,
00033                                   int xmppPort )
00034     : ConnectionBase( 0 ),
00035       m_logInstance( logInstance ), m_parser( this ), m_boshHost( boshHost ), m_path( "/http-bind/" ),
00036       m_rid( 0 ), m_initialStreamSent( false ), m_openRequests( 0 ),
00037       m_maxOpenRequests( 2 ), m_wait( 30 ), m_hold( 2 ), m_streamRestart( false ),
00038       m_lastRequestTime( std::time( 0 ) ), m_minTimePerRequest( 0 ), m_bufferContentLength( 0 ),
00039       m_connMode( ModePipelining )
00040   {
00041     initInstance( connection, xmppServer, xmppPort );
00042   }
00043 
00044   ConnectionBOSH::ConnectionBOSH( ConnectionDataHandler* cdh, ConnectionBase* connection,
00045                                   const LogSink& logInstance, const std::string& boshHost,
00046                                   const std::string& xmppServer, int xmppPort )
00047     : ConnectionBase( cdh ),
00048       m_logInstance( logInstance ), m_parser( this ), m_boshHost( boshHost ), m_path( "/http-bind/" ),
00049       m_rid( 0 ),  m_initialStreamSent( false ), m_openRequests( 0 ),
00050       m_maxOpenRequests( 2 ), m_wait( 30 ), m_hold( 2 ), m_streamRestart( false ),
00051       m_lastRequestTime( std::time( 0 ) ), m_minTimePerRequest( 0 ), m_bufferContentLength( 0 ),
00052       m_connMode( ModePipelining )
00053   {
00054     initInstance( connection, xmppServer, xmppPort );
00055   }
00056 
00057   void ConnectionBOSH::initInstance( ConnectionBase* connection, const std::string& xmppServer,
00058                                      const int xmppPort )
00059   {
00060 // FIXME: check return value
00061     prep::idna( xmppServer, m_server );
00062     m_port = xmppPort;
00063     if( m_port != -1 )
00064     {
00065       m_boshedHost = m_boshHost + ":" + util::int2string( m_port );
00066     }
00067 
00068     // drop this connection into our pool of available connections
00069     if( connection )
00070     {
00071       connection->registerConnectionDataHandler( this );
00072       m_connectionPool.push_back( connection );
00073     }
00074   }
00075 
00076   ConnectionBOSH::~ConnectionBOSH()
00077   {
00078     util::clearList( m_activeConnections );
00079     util::clearList( m_connectionPool );
00080   }
00081 
00082   ConnectionBase* ConnectionBOSH::newInstance() const
00083   {
00084     ConnectionBase* pBaseConn = 0;
00085 
00086     if( !m_connectionPool.empty() )
00087     {
00088       pBaseConn = m_connectionPool.front()->newInstance();
00089     }
00090     else if( !m_activeConnections.empty() )
00091     {
00092       pBaseConn = m_activeConnections.front()->newInstance();
00093     }
00094     else
00095     {
00096       return 0;
00097     }
00098 
00099     return new ConnectionBOSH( m_handler, pBaseConn, m_logInstance,
00100                                m_boshHost, m_server, m_port );
00101   }
00102 
00103   ConnectionError ConnectionBOSH::connect()
00104   {
00105     if( m_state >= StateConnecting )
00106       return ConnNoError;
00107 
00108     if( !m_handler )
00109       return ConnNotConnected;
00110 
00111     m_state = StateConnecting;
00112     m_logInstance.dbg( LogAreaClassConnectionBOSH,
00113                        "bosh initiating connection to server: " +
00114                        ( ( m_connMode == ModePipelining ) ? std::string( "Pipelining" )
00115                          : ( ( m_connMode == ModeLegacyHTTP ) ? std::string( "LegacyHTTP" )
00116                                                               : std::string( "PersistentHTTP" ) ) ) );
00117     getConnection();
00118     return ConnNoError; // FIXME?
00119   }
00120 
00121   void ConnectionBOSH::disconnect()
00122   {
00123     if( ( m_connMode == ModePipelining && m_activeConnections.empty() )
00124         || ( m_connectionPool.empty() && m_activeConnections.empty() ) )
00125       return;
00126 
00127     if( m_state != StateDisconnected )
00128     {
00129       ++m_rid;
00130 
00131       std::string requestBody = "<body rid='" + util::int2string( m_rid ) + "' ";
00132       requestBody += "sid='" + m_sid + "' ";
00133       requestBody += "type='terminal' ";
00134       requestBody += "xml:lang='en' ";
00135       requestBody += "xmlns='" + XMLNS_HTTPBIND + "'";
00136       if( m_sendBuffer.empty() )  // Make sure that any data in the send buffer gets sent
00137         requestBody += "/>";
00138       else
00139       {
00140         requestBody += ">" + m_sendBuffer + "</body>";
00141         m_sendBuffer = EmptyString;
00142       }
00143       sendRequest( requestBody );
00144 
00145       m_logInstance.dbg( LogAreaClassConnectionBOSH, "bosh disconnection request sent" );
00146     }
00147     else
00148     {
00149       m_logInstance.err( LogAreaClassConnectionBOSH,
00150                          "disconnecting from server in a non-graceful fashion" );
00151     }
00152 
00153     util::ForEach( m_activeConnections, &ConnectionBase::disconnect );
00154     util::ForEach( m_connectionPool, &ConnectionBase::disconnect );
00155 
00156     m_state = StateDisconnected;
00157     if( m_handler )
00158       m_handler->handleDisconnect( this, ConnUserDisconnected );
00159   }
00160 
00161   ConnectionError ConnectionBOSH::recv( int timeout )
00162   {
00163     if( m_state == StateDisconnected )
00164       return ConnNotConnected;
00165 
00166     if( !m_connectionPool.empty() )
00167       m_connectionPool.front()->recv( 0 );
00168     if( !m_activeConnections.empty() )
00169       m_activeConnections.front()->recv( timeout );
00170 
00171     // If there are no open requests then the spec allows us to send an empty request...
00172     // (Some CMs do not obey this, it seems)
00173     if( ( m_openRequests == 0 || m_sendBuffer.size() > 0 ) && m_state == StateConnected )
00174     {
00175       m_logInstance.dbg( LogAreaClassConnectionBOSH,
00176                          "Sending empty request (or there is data in the send buffer)" );
00177       sendXML();
00178     }
00179 
00180     return ConnNoError; // FIXME?
00181   }
00182 
00183   bool ConnectionBOSH::send( const std::string& data )
00184   {
00185 
00186     if( m_state == StateDisconnected )
00187       return false;
00188 
00189     if( data.substr( 0, 2 ) == "<?" )
00190     {
00191 //       if( m_initialStreamSent )
00192       {
00193         m_streamRestart = true;
00194         sendXML();
00195         return true;
00196       }
00197 //       else
00198 //       {
00199 //         m_initialStreamSent = true;
00200 //         m_logInstance.dbg( LogAreaClassConnectionBOSH, "initial <stream:stream> dropped" );
00201 //         return true;
00202 //       }
00203     }
00204     else if( data == "</stream:stream>" )
00205       return true;
00206 
00207     m_sendBuffer += data;
00208     sendXML();
00209 
00210     return true;
00211   }
00212 
00213   /* Sends XML. Wraps data in a <body/> tag, and then passes to sendRequest(). */
00214   bool ConnectionBOSH::sendXML()
00215   {
00216     if( m_state != StateConnected )
00217     {
00218       m_logInstance.warn( LogAreaClassConnectionBOSH,
00219                          "Data sent before connection established (will be buffered)" );
00220       return false;
00221     }
00222 
00223     if( m_sendBuffer.empty() )
00224     {
00225       time_t now = time( 0 );
00226       unsigned int delta = (int)(now - m_lastRequestTime);
00227       if( delta < m_minTimePerRequest && m_openRequests > 0 )
00228       {
00229         m_logInstance.dbg( LogAreaClassConnectionBOSH, "Too little time between requests: " + util::int2string( delta ) + " seconds" );
00230         return false;
00231       }
00232       m_logInstance.dbg( LogAreaClassConnectionBOSH, "Send buffer is empty, sending empty request" );
00233     }
00234 
00235     ++m_rid;
00236 
00237     std::string requestBody = "<body rid='" + util::int2string( m_rid ) + "' ";
00238     requestBody += "sid='" + m_sid + "' ";
00239     requestBody += "xmlns='" + XMLNS_HTTPBIND + "'";
00240 
00241     if( m_streamRestart )
00242     {
00243       requestBody += " xmpp:restart='true' to='" + m_server + "' xml:lang='en' xmlns:xmpp='"
00244           + XMLNS_XMPP_BOSH + "' />";
00245       m_logInstance.dbg( LogAreaClassConnectionBOSH, "Restarting stream" );
00246     }
00247     else
00248     {
00249       requestBody += ">" + m_sendBuffer + "</body>";
00250     }
00251     // Send a request. Force if we are not sending an empty request, or if there are no connections open
00252     if( sendRequest( requestBody ) )
00253     {
00254       m_logInstance.dbg( LogAreaClassConnectionBOSH, "Successfully sent m_sendBuffer" );
00255       m_sendBuffer = EmptyString;
00256       m_streamRestart = false;
00257     }
00258     else
00259     {
00260       --m_rid; // I think... (may need to rethink when acks are implemented)
00261       m_logInstance.warn( LogAreaClassConnectionBOSH,
00262                          "Unable to send. Connection not complete, or too many open requests,"
00263                          " so added to buffer.\n" );
00264     }
00265 
00266     return true;
00267   }
00268 
00269   /* Chooses the appropriate connection, or opens a new one if necessary. Wraps xml in HTTP and sends. */
00270   bool ConnectionBOSH::sendRequest( const std::string& xml )
00271   {
00272     ConnectionBase* conn = getConnection();
00273     if( !conn )
00274       return false;
00275 
00276     std::string request = "POST " + m_path;
00277 
00278     if( m_connMode == ModeLegacyHTTP )
00279     {
00280       request += " HTTP/1.0\r\n";
00281       request += "Connection: close\r\n";
00282     }
00283     else
00284     {
00285       request += " HTTP/1.1\r\n";
00286       request += "Connection: keep-alive\r\n";
00287     }
00288 
00289     request += "Host: " + m_boshedHost + "\r\n";
00290     request += "Content-Type: text/xml; charset=utf-8\r\n";
00291     request += "Content-Length: " + util::int2string( xml.length() ) + "\r\n";
00292     request += "User-Agent: gloox/" + GLOOX_VERSION + "\r\n\r\n";
00293     request += xml;
00294 
00295 
00296     if( conn->send( request ) )
00297     {
00298       m_lastRequestTime = time( 0 );
00299       ++m_openRequests;
00300       return true;
00301     }
00302 //     else // FIXME What to do in this case?
00303 //       printf( "Error while trying to send on socket (state: %d)\n", conn->state() );
00304 
00305     return false;
00306   }
00307 
00308   bool ci_equal( char ch1, char ch2 )
00309   {
00310     return std::toupper( (unsigned char)ch1 ) == std::toupper( (unsigned char)ch2 );
00311   }
00312 
00313   std::string::size_type ci_find( const std::string& str1, const std::string& str2 )
00314   {
00315     std::string::const_iterator pos = std::search( str1.begin(), str1.end(),
00316                                                    str2.begin(), str2.end(), ci_equal );
00317     if( pos == str1.end() )
00318       return std::string::npos;
00319     else
00320       return std::distance( str1.begin(), pos );
00321   }
00322 
00323   const std::string ConnectionBOSH::getHTTPField( const std::string& field )
00324   {
00325     std::string::size_type fp = ci_find( m_bufferHeader, "\r\n" + field + ": " );
00326 
00327     if( fp == std::string::npos )
00328       return EmptyString;
00329 
00330     fp += field.length() + 4;
00331 
00332     const std::string::size_type fp2 = m_bufferHeader.find( "\r\n", fp );
00333     if( fp2 == std::string::npos )
00334       return EmptyString;
00335 
00336     return m_bufferHeader.substr( fp, fp2 - fp );
00337   }
00338 
00339   ConnectionError ConnectionBOSH::receive()
00340   {
00341     ConnectionError err = ConnNoError;
00342     while( m_state != StateDisconnected && ( err = recv( 10 ) ) == ConnNoError )
00343       ;
00344     return err == ConnNoError ? ConnNotConnected : err;
00345   }
00346 
00347   void ConnectionBOSH::cleanup()
00348   {
00349     m_state = StateDisconnected;
00350 
00351     util::ForEach( m_activeConnections, &ConnectionBase::cleanup );
00352     util::ForEach( m_connectionPool, &ConnectionBase::cleanup );
00353   }
00354 
00355   void ConnectionBOSH::getStatistics( long int& totalIn, long int& totalOut )
00356   {
00357     util::ForEach( m_activeConnections, &ConnectionBase::getStatistics, totalIn, totalOut );
00358     util::ForEach( m_connectionPool, &ConnectionBase::getStatistics, totalIn, totalOut );
00359   }
00360 
00361   void ConnectionBOSH::handleReceivedData( const ConnectionBase* /*connection*/,
00362                                            const std::string& data )
00363   {
00364     m_buffer += data;
00365 //     printf( "!!!!!!buffer\n\n%s\n\n", m_buffer.c_str() );
00366     std::string::size_type headerLength = 0;
00367     while( ( headerLength = m_buffer.find( "\r\n\r\n" ) ) != std::string::npos )
00368     {
00369       m_bufferHeader = m_buffer.substr( 0, headerLength + 2 );
00370 
00371       const std::string& statusCode = m_bufferHeader.substr( 9, 3 );
00372       if( statusCode != "200" )
00373       {
00374         m_logInstance.warn( LogAreaClassConnectionBOSH,
00375                             "Received error via legacy HTTP status code: " + statusCode
00376                                 + ". Disconnecting." );
00377         m_state = StateDisconnected; // As per XEP, consider connection broken
00378         disconnect();
00379       }
00380 
00381       m_bufferContentLength = strtol( getHTTPField( "Content-Length" ).c_str(), 0, 10 );
00382       if( !m_bufferContentLength )
00383         return;
00384 
00385       if( m_connMode != ModeLegacyHTTP && ( getHTTPField( "Connection" ) == "close"
00386                                             || m_bufferHeader.substr( 0, 8 ) == "HTTP/1.0" ) )
00387       {
00388         m_logInstance.dbg( LogAreaClassConnectionBOSH,
00389                             "Server indicated lack of support for HTTP/1.1 - falling back to HTTP/1.0" );
00390         m_connMode = ModeLegacyHTTP;
00391       }
00392 
00393       if( m_buffer.length() >= ( headerLength + 4 + m_bufferContentLength ) )
00394       {
00395         putConnection();
00396         --m_openRequests;
00397         std::string xml = m_buffer.substr( headerLength + 4, m_bufferContentLength );
00398         m_parser.feed( xml );
00399         m_buffer.erase( 0, headerLength + 4 + m_bufferContentLength );
00400         m_bufferContentLength = 0;
00401         m_bufferHeader = EmptyString;
00402       }
00403       else
00404       {
00405         m_logInstance.warn( LogAreaClassConnectionBOSH, "buffer length mismatch" );
00406         break;
00407       }
00408     }
00409   }
00410 
00411   void ConnectionBOSH::handleConnect( const ConnectionBase* /*connection*/ )
00412   {
00413     if( m_state == StateConnecting )
00414     {
00415       m_rid = rand() % 100000 + 1728679472;
00416 
00417       Tag requestBody( "body" );
00418       requestBody.setXmlns( XMLNS_HTTPBIND );
00419       requestBody.setXmlns( XMLNS_XMPP_BOSH, "xmpp" );
00420 
00421       requestBody.addAttribute( "content", "text/xml; charset=utf-8" );
00422       requestBody.addAttribute( "hold", (long)m_hold );
00423       requestBody.addAttribute( "rid", (long)m_rid );
00424       requestBody.addAttribute( "ver", "1.6" );
00425       requestBody.addAttribute( "wait", (long)m_wait );
00426       requestBody.addAttribute( "ack", 0 );
00427       requestBody.addAttribute( "secure", "false" );
00428       requestBody.addAttribute( "route", "xmpp:" + m_server + ":5222" );
00429       requestBody.addAttribute( "xml:lang", "en" );
00430       requestBody.addAttribute( "xmpp:version", "1.0" );
00431       requestBody.addAttribute( "to", m_server );
00432 
00433       m_logInstance.dbg( LogAreaClassConnectionBOSH, "sending bosh connection request" );
00434       sendRequest( requestBody.xml() );
00435     }
00436   }
00437 
00438   void ConnectionBOSH::handleDisconnect( const ConnectionBase* /*connection*/,
00439                                          ConnectionError reason )
00440   {
00441     if( m_handler && m_state == StateConnecting )
00442     {
00443       m_state = StateDisconnected;
00444       m_handler->handleDisconnect( this, reason );
00445       return;
00446     }
00447 
00448     switch( m_connMode ) // FIXME avoid that if we're disconnecting on purpose
00449     {
00450       case ModePipelining:
00451         m_connMode = ModeLegacyHTTP; // Server seems not to support pipelining
00452         m_logInstance.dbg( LogAreaClassConnectionBOSH,
00453                            "connection closed - falling back to HTTP/1.0 connection method" );
00454         break;
00455       case ModeLegacyHTTP:
00456       case ModePersistentHTTP:
00457         // FIXME do we need to do anything here?
00458 //         printf( "A TCP connection %p was disconnected (reason: %d).\n", connection, reason );
00459         break;
00460     }
00461   }
00462 
00463   void ConnectionBOSH::handleTag( Tag* tag )
00464   {
00465     if( !m_handler || tag->name() != "body" )
00466       return;
00467 
00468     if( m_streamRestart )
00469     {
00470       m_streamRestart = false;
00471       m_logInstance.dbg( LogAreaClassConnectionBOSH, "sending spoofed <stream:stream>" );
00472       m_handler->handleReceivedData( this, "<?xml version='1.0' ?>"
00473           "<stream:stream xmlns:stream='http://etherx.jabber.org/streams'"
00474           " xmlns='" + XMLNS_CLIENT + "' version='" + XMPP_STREAM_VERSION_MAJOR
00475           + "." + XMPP_STREAM_VERSION_MINOR + "' from='" + m_server + "' id ='"
00476           + m_sid + "' xml:lang='en'>" );
00477     }
00478 
00479     if( tag->hasAttribute( "sid" ) )
00480     {
00481       m_state = StateConnected;
00482       m_sid = tag->findAttribute( "sid" );
00483 
00484       if( tag->hasAttribute( "requests" ) )
00485       {
00486         const int serverRequests = atoi( tag->findAttribute( "requests" ).c_str() );
00487         if( serverRequests < m_maxOpenRequests )
00488         {
00489           m_maxOpenRequests = serverRequests;
00490           m_logInstance.dbg( LogAreaClassConnectionBOSH,
00491                               "bosh parameter 'requests' now set to " + tag->findAttribute( "requests" ) );
00492         }
00493       }
00494       if( tag->hasAttribute( "hold" ) )
00495       {
00496         const int maxHold = atoi( tag->findAttribute( "hold" ).c_str() );
00497         if( maxHold < m_hold )
00498         {
00499           m_hold = maxHold;
00500           m_logInstance.dbg( LogAreaClassConnectionBOSH,
00501                               "bosh parameter 'hold' now set to " + tag->findAttribute( "hold" ) );
00502         }
00503       }
00504       if( tag->hasAttribute( "wait" ) )
00505       {
00506         const int maxWait = atoi( tag->findAttribute( "wait" ).c_str() );
00507         if( maxWait < m_wait )
00508         {
00509           m_wait = maxWait;
00510           m_logInstance.dbg( LogAreaClassConnectionBOSH,
00511                               "bosh parameter 'wait' now set to " + tag->findAttribute( "wait" )
00512                                   + " seconds" );
00513         }
00514       }
00515       if( tag->hasAttribute( "polling" ) )
00516       {
00517         const int minTime = atoi( tag->findAttribute( "polling" ).c_str() );
00518         m_minTimePerRequest = minTime;
00519         m_logInstance.dbg( LogAreaClassConnectionBOSH,
00520                             "bosh parameter 'polling' now set to " + tag->findAttribute( "polling" )
00521                                 + " seconds" );
00522       }
00523 
00524       if( m_state < StateConnected )
00525         m_handler->handleConnect( this );
00526 
00527       m_handler->handleReceivedData( this, "<?xml version='1.0' ?>" // FIXME move to send() so that
00528                                                                     // it is more clearly a response
00529                                                                     // to the initial stream opener?
00530                           "<stream:stream xmlns:stream='http://etherx.jabber.org/streams' "
00531                           "xmlns='" + XMLNS_CLIENT
00532                           + "' version='" + XMPP_STREAM_VERSION_MAJOR + "." + XMPP_STREAM_VERSION_MINOR
00533                           + "' from='" + m_server + "' id ='" + m_sid + "' xml:lang='en'>" );
00534     }
00535 
00536     if( tag->findAttribute( "type" ) == "terminate" )
00537     {
00538       m_logInstance.dbg( LogAreaClassConnectionBOSH,
00539                          "bosh connection closed by server: " + tag->findAttribute( "condition" ) );
00540       m_state = StateDisconnected;
00541       m_handler->handleDisconnect( this, ConnStreamClosed );
00542       return;
00543     }
00544 
00545     const TagList& stanzas = tag->children();
00546     TagList::const_iterator it = stanzas.begin();
00547     for( ; it != stanzas.end(); ++it )
00548       m_handler->handleReceivedData( this, (*it)->xml() );
00549   }
00550 
00551   ConnectionBase* ConnectionBOSH::getConnection()
00552   {
00553     if( m_openRequests > 0 && m_openRequests >= m_maxOpenRequests )
00554     {
00555       m_logInstance.warn( LogAreaClassConnectionBOSH,
00556                           "Too many requests already open. Cannot send." );
00557       return 0;
00558     }
00559 
00560     ConnectionBase* conn = 0;
00561     switch( m_connMode )
00562     {
00563       case ModePipelining:
00564         if( !m_activeConnections.empty() )
00565         {
00566           m_logInstance.dbg( LogAreaClassConnectionBOSH, "Using default connection for Pipelining." );
00567           return m_activeConnections.front();
00568         }
00569         else if( !m_connectionPool.empty() )
00570         {
00571           m_logInstance.warn( LogAreaClassConnectionBOSH,
00572                               "Pipelining selected, but no connection open. Opening one." );
00573           return activateConnection();
00574         }
00575         else
00576           m_logInstance.warn( LogAreaClassConnectionBOSH,
00577                               "No available connections to pipeline on." );
00578         break;
00579       case ModeLegacyHTTP:
00580       case ModePersistentHTTP:
00581       {
00582         if( !m_connectionPool.empty() )
00583         {
00584           m_logInstance.dbg( LogAreaClassConnectionBOSH, "LegacyHTTP/PersistentHTTP selected, "
00585                                                          "using connection from pool." );
00586           return activateConnection();
00587         }
00588         else if( !m_activeConnections.empty() )
00589         {
00590           m_logInstance.dbg( LogAreaClassConnectionBOSH, "No connections in pool, creating a new one." );
00591           conn = m_activeConnections.front()->newInstance();
00592           conn->registerConnectionDataHandler( this );
00593           m_connectionPool.push_back( conn );
00594           conn->connect();
00595         }
00596         else
00597           m_logInstance.warn( LogAreaClassConnectionBOSH,
00598                               "No available connections to send on." );
00599         break;
00600       }
00601     }
00602     return 0;
00603   }
00604 
00605   ConnectionBase* ConnectionBOSH::activateConnection()
00606   {
00607     ConnectionBase* conn = m_connectionPool.front();
00608     m_connectionPool.pop_front();
00609     if( conn->state() == StateConnected )
00610     {
00611       m_activeConnections.push_back( conn );
00612       return conn;
00613     }
00614 
00615     m_logInstance.dbg( LogAreaClassConnectionBOSH, "Connecting pooled connection." );
00616     m_connectionPool.push_back( conn );
00617     conn->connect();
00618     return 0;
00619   }
00620 
00621   void ConnectionBOSH::putConnection()
00622   {
00623     ConnectionBase* conn = m_activeConnections.front();
00624 
00625     switch( m_connMode )
00626     {
00627       case ModeLegacyHTTP:
00628         m_logInstance.dbg( LogAreaClassConnectionBOSH, "Disconnecting LegacyHTTP connection" );
00629         conn->disconnect();
00630         conn->cleanup(); // This is necessary
00631         m_activeConnections.pop_front();
00632         m_connectionPool.push_back( conn );
00633         break;
00634       case ModePersistentHTTP:
00635         m_logInstance.dbg( LogAreaClassConnectionBOSH, "Deactivating PersistentHTTP connection" );
00636         m_activeConnections.pop_front();
00637         m_connectionPool.push_back( conn );
00638         break;
00639       case ModePipelining:
00640         m_logInstance.dbg( LogAreaClassConnectionBOSH, "Keeping Pipelining connection" );
00641       default:
00642         break;
00643     }
00644   }
00645 
00646 }

Generated on Tue May 4 16:35:11 2010 for gloox by  doxygen 1.4.1