gloox
1.0
|
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 if( m_connMode == ModeLegacyHTTP ) 00278 { 00279 request += " HTTP/1.0\r\n"; 00280 request += "Connection: close\r\n"; 00281 } 00282 else 00283 request += " HTTP/1.1\r\n"; 00284 00285 request += "Host: " + m_boshedHost + "\r\n"; 00286 request += "Content-Type: text/xml; charset=utf-8\r\n"; 00287 request += "Content-Length: " + util::int2string( xml.length() ) + "\r\n"; 00288 request += "User-Agent: gloox/" + GLOOX_VERSION + "\r\n\r\n"; 00289 request += xml; 00290 00291 00292 if( conn->send( request ) ) 00293 { 00294 m_lastRequestTime = time( 0 ); 00295 ++m_openRequests; 00296 return true; 00297 } 00298 // else // FIXME What to do in this case? 00299 // printf( "Error while trying to send on socket (state: %d)\n", conn->state() ); 00300 00301 return false; 00302 } 00303 00304 bool ci_equal( char ch1, char ch2 ) 00305 { 00306 return std::toupper( (unsigned char)ch1 ) == std::toupper( (unsigned char)ch2 ); 00307 } 00308 00309 std::string::size_type ci_find( const std::string& str1, const std::string& str2 ) 00310 { 00311 std::string::const_iterator pos = std::search( str1.begin(), str1.end(), 00312 str2.begin(), str2.end(), ci_equal ); 00313 if( pos == str1.end() ) 00314 return std::string::npos; 00315 else 00316 return std::distance( str1.begin(), pos ); 00317 } 00318 00319 const std::string ConnectionBOSH::getHTTPField( const std::string& field ) 00320 { 00321 std::string::size_type fp = ci_find( m_bufferHeader, "\r\n" + field + ": " ); 00322 00323 if( fp == std::string::npos ) 00324 return EmptyString; 00325 00326 fp += field.length() + 4; 00327 00328 const std::string::size_type fp2 = m_bufferHeader.find( "\r\n", fp ); 00329 if( fp2 == std::string::npos ) 00330 return EmptyString; 00331 00332 return m_bufferHeader.substr( fp, fp2 - fp ); 00333 } 00334 00335 ConnectionError ConnectionBOSH::receive() 00336 { 00337 ConnectionError err = ConnNoError; 00338 while( m_state != StateDisconnected && ( err = recv( 10 ) ) == ConnNoError ) 00339 ; 00340 return err == ConnNoError ? ConnNotConnected : err; 00341 } 00342 00343 void ConnectionBOSH::cleanup() 00344 { 00345 m_state = StateDisconnected; 00346 00347 util::ForEach( m_activeConnections, &ConnectionBase::cleanup ); 00348 util::ForEach( m_connectionPool, &ConnectionBase::cleanup ); 00349 } 00350 00351 void ConnectionBOSH::getStatistics( long int& totalIn, long int& totalOut ) 00352 { 00353 util::ForEach( m_activeConnections, &ConnectionBase::getStatistics, totalIn, totalOut ); 00354 util::ForEach( m_connectionPool, &ConnectionBase::getStatistics, totalIn, totalOut ); 00355 } 00356 00357 void ConnectionBOSH::handleReceivedData( const ConnectionBase* /*connection*/, 00358 const std::string& data ) 00359 { 00360 m_buffer += data; 00361 std::string::size_type headerLength = 0; 00362 while( ( headerLength = m_buffer.find( "\r\n\r\n" ) ) != std::string::npos ) 00363 { 00364 m_bufferHeader = m_buffer.substr( 0, headerLength+2 ); 00365 00366 const std::string& statusCode = m_bufferHeader.substr( 9, 3 ); 00367 if( statusCode != "200" ) 00368 { 00369 m_logInstance.warn( LogAreaClassConnectionBOSH, 00370 "Received error via legacy HTTP status code: " + statusCode 00371 + ". Disconnecting." ); 00372 m_state = StateDisconnected; // As per XEP, consider connection broken 00373 disconnect(); 00374 } 00375 00376 m_bufferContentLength = atol( getHTTPField( "Content-Length" ).c_str() ); 00377 if( !m_bufferContentLength ) 00378 return; 00379 00380 if( m_connMode != ModeLegacyHTTP && ( getHTTPField( "Connection" ) == "close" 00381 || m_bufferHeader.substr( 0, 8 ) == "HTTP/1.0" ) ) 00382 { 00383 m_logInstance.dbg( LogAreaClassConnectionBOSH, 00384 "Server indicated lack of support for HTTP/1.1 - falling back to HTTP/1.0" ); 00385 m_connMode = ModeLegacyHTTP; 00386 } 00387 00388 if( m_buffer.length() >= ( headerLength + 4 + m_bufferContentLength ) ) 00389 { 00390 putConnection(); 00391 --m_openRequests; 00392 std::string xml = m_buffer.substr( headerLength + 4, m_bufferContentLength ); 00393 m_parser.feed( xml ); 00394 m_buffer.erase( 0, headerLength + 4 + m_bufferContentLength ); 00395 m_bufferContentLength = 0; 00396 m_bufferHeader = EmptyString; 00397 } 00398 else 00399 { 00400 m_logInstance.warn( LogAreaClassConnectionBOSH, "buffer length mismatch" ); 00401 break; 00402 } 00403 } 00404 } 00405 00406 void ConnectionBOSH::handleConnect( const ConnectionBase* /*connection*/ ) 00407 { 00408 if( m_state == StateConnecting ) 00409 { 00410 m_rid = rand() % 100000 + 1728679472; 00411 00412 Tag requestBody( "body" ); 00413 requestBody.setXmlns( XMLNS_HTTPBIND ); 00414 requestBody.setXmlns( XMLNS_XMPP_BOSH, "xmpp" ); 00415 00416 requestBody.addAttribute( "content", "text/xml; charset=utf-8" ); 00417 requestBody.addAttribute( "hold", (long)m_hold ); 00418 requestBody.addAttribute( "rid", (long)m_rid ); 00419 requestBody.addAttribute( "ver", "1.6" ); 00420 requestBody.addAttribute( "wait", (long)m_wait ); 00421 requestBody.addAttribute( "ack", 0 ); 00422 requestBody.addAttribute( "secure", "false" ); 00423 requestBody.addAttribute( "route", "xmpp:" + m_server + ":5222" ); 00424 requestBody.addAttribute( "xml:lang", "en" ); 00425 requestBody.addAttribute( "xmpp:version", "1.0" ); 00426 requestBody.addAttribute( "to", m_server ); 00427 00428 m_logInstance.dbg( LogAreaClassConnectionBOSH, "sending bosh connection request" ); 00429 sendRequest( requestBody.xml() ); 00430 } 00431 } 00432 00433 void ConnectionBOSH::handleDisconnect( const ConnectionBase* /*connection*/, 00434 ConnectionError reason ) 00435 { 00436 if( m_handler && m_state == StateConnecting ) 00437 { 00438 m_state = StateDisconnected; 00439 m_handler->handleDisconnect( this, reason ); 00440 return; 00441 } 00442 00443 switch( m_connMode ) // FIXME avoid that if we're disconnecting on purpose 00444 { 00445 case ModePipelining: 00446 m_connMode = ModeLegacyHTTP; // Server seems not to support pipelining 00447 m_logInstance.dbg( LogAreaClassConnectionBOSH, 00448 "connection closed - falling back to HTTP/1.0 connection method" ); 00449 break; 00450 case ModeLegacyHTTP: 00451 case ModePersistentHTTP: 00452 // FIXME do we need to do anything here? 00453 // printf( "A TCP connection %p was disconnected (reason: %d).\n", connection, reason ); 00454 break; 00455 } 00456 } 00457 00458 void ConnectionBOSH::handleTag( Tag* tag ) 00459 { 00460 if( !m_handler || tag->name() != "body" ) 00461 return; 00462 00463 if( m_streamRestart ) 00464 { 00465 m_streamRestart = false; 00466 m_logInstance.dbg( LogAreaClassConnectionBOSH, "sending spoofed <stream:stream>" ); 00467 m_handler->handleReceivedData( this, "<?xml version='1.0' ?>" 00468 "<stream:stream xmlns:stream='http://etherx.jabber.org/streams'" 00469 " xmlns='" + XMLNS_CLIENT + "' version='" + XMPP_STREAM_VERSION_MAJOR 00470 + "." + XMPP_STREAM_VERSION_MINOR + "' from='" + m_server + "' id ='" 00471 + m_sid + "' xml:lang='en'>" ); 00472 } 00473 00474 if( tag->hasAttribute( "sid" ) ) 00475 { 00476 m_state = StateConnected; 00477 m_sid = tag->findAttribute( "sid" ); 00478 00479 if( tag->hasAttribute( "requests" ) ) 00480 { 00481 const int serverRequests = atoi( tag->findAttribute( "requests" ).c_str() ); 00482 if( serverRequests < m_maxOpenRequests ) 00483 { 00484 m_maxOpenRequests = serverRequests; 00485 m_logInstance.dbg( LogAreaClassConnectionBOSH, 00486 "bosh parameter 'requests' now set to " + tag->findAttribute( "requests" ) ); 00487 } 00488 } 00489 if( tag->hasAttribute( "hold" ) ) 00490 { 00491 const int maxHold = atoi( tag->findAttribute( "hold" ).c_str() ); 00492 if( maxHold < m_hold ) 00493 { 00494 m_hold = maxHold; 00495 m_logInstance.dbg( LogAreaClassConnectionBOSH, 00496 "bosh parameter 'hold' now set to " + tag->findAttribute( "hold" ) ); 00497 } 00498 } 00499 if( tag->hasAttribute( "wait" ) ) 00500 { 00501 const int maxWait = atoi( tag->findAttribute( "wait" ).c_str() ); 00502 if( maxWait < m_wait ) 00503 { 00504 m_wait = maxWait; 00505 m_logInstance.dbg( LogAreaClassConnectionBOSH, 00506 "bosh parameter 'wait' now set to " + tag->findAttribute( "wait" ) 00507 + " seconds" ); 00508 } 00509 } 00510 if( tag->hasAttribute( "polling" ) ) 00511 { 00512 const int minTime = atoi( tag->findAttribute( "polling" ).c_str() ); 00513 m_minTimePerRequest = minTime; 00514 m_logInstance.dbg( LogAreaClassConnectionBOSH, 00515 "bosh parameter 'polling' now set to " + tag->findAttribute( "polling" ) 00516 + " seconds" ); 00517 } 00518 00519 if( m_state < StateConnected ) 00520 m_handler->handleConnect( this ); 00521 00522 m_handler->handleReceivedData( this, "<?xml version='1.0' ?>" // FIXME move to send() so that 00523 // it is more clearly a response 00524 // to the initial stream opener? 00525 "<stream:stream xmlns:stream='http://etherx.jabber.org/streams' " 00526 "xmlns='" + XMLNS_CLIENT 00527 + "' version='" + XMPP_STREAM_VERSION_MAJOR + "." + XMPP_STREAM_VERSION_MINOR 00528 + "' from='" + m_server + "' id ='" + m_sid + "' xml:lang='en'>" ); 00529 } 00530 00531 if( tag->findAttribute( "type" ) == "terminate" ) 00532 { 00533 m_logInstance.dbg( LogAreaClassConnectionBOSH, 00534 "bosh connection closed by server: " + tag->findAttribute( "condition" ) ); 00535 m_state = StateDisconnected; 00536 m_handler->handleDisconnect( this, ConnStreamClosed ); 00537 return; 00538 } 00539 00540 const TagList& stanzas = tag->children(); 00541 TagList::const_iterator it = stanzas.begin(); 00542 for( ; it != stanzas.end(); ++it ) 00543 m_handler->handleReceivedData( this, (*it)->xml() ); 00544 } 00545 00546 ConnectionBase* ConnectionBOSH::getConnection() 00547 { 00548 if( m_openRequests > 0 && m_openRequests >= m_maxOpenRequests ) 00549 { 00550 m_logInstance.warn( LogAreaClassConnectionBOSH, 00551 "Too many requests already open. Cannot send." ); 00552 return 0; 00553 } 00554 00555 ConnectionBase* conn = 0; 00556 switch( m_connMode ) 00557 { 00558 case ModePipelining: 00559 if( !m_activeConnections.empty() ) 00560 { 00561 m_logInstance.dbg( LogAreaClassConnectionBOSH, "Using default connection for Pipelining." ); 00562 return m_activeConnections.front(); 00563 } 00564 else if( !m_connectionPool.empty() ) 00565 { 00566 m_logInstance.warn( LogAreaClassConnectionBOSH, 00567 "Pipelining selected, but no connection open. Opening one." ); 00568 return activateConnection(); 00569 } 00570 else 00571 m_logInstance.warn( LogAreaClassConnectionBOSH, 00572 "No available connections to pipeline on." ); 00573 break; 00574 case ModeLegacyHTTP: 00575 case ModePersistentHTTP: 00576 { 00577 if( !m_connectionPool.empty() ) 00578 { 00579 m_logInstance.dbg( LogAreaClassConnectionBOSH, "LegacyHTTP/PersistentHTTP selected, " 00580 "using connection from pool." ); 00581 return activateConnection(); 00582 } 00583 else if( !m_activeConnections.empty() ) 00584 { 00585 m_logInstance.dbg( LogAreaClassConnectionBOSH, "No connections in pool, creating a new one." ); 00586 conn = m_activeConnections.front()->newInstance(); 00587 conn->registerConnectionDataHandler( this ); 00588 m_connectionPool.push_back( conn ); 00589 conn->connect(); 00590 } 00591 else 00592 m_logInstance.warn( LogAreaClassConnectionBOSH, 00593 "No available connections to send on." ); 00594 break; 00595 } 00596 } 00597 return 0; 00598 } 00599 00600 ConnectionBase* ConnectionBOSH::activateConnection() 00601 { 00602 ConnectionBase* conn = m_connectionPool.front(); 00603 m_connectionPool.pop_front(); 00604 if( conn->state() == StateConnected ) 00605 { 00606 m_activeConnections.push_back( conn ); 00607 return conn; 00608 } 00609 00610 m_logInstance.dbg( LogAreaClassConnectionBOSH, "Connecting pooled connection." ); 00611 m_connectionPool.push_back( conn ); 00612 conn->connect(); 00613 return 0; 00614 } 00615 00616 void ConnectionBOSH::putConnection() 00617 { 00618 ConnectionBase* conn = m_activeConnections.front(); 00619 00620 switch( m_connMode ) 00621 { 00622 case ModeLegacyHTTP: 00623 m_logInstance.dbg( LogAreaClassConnectionBOSH, "Disconnecting LegacyHTTP connection" ); 00624 conn->disconnect(); 00625 conn->cleanup(); // This is necessary 00626 m_activeConnections.pop_front(); 00627 m_connectionPool.push_back( conn ); 00628 break; 00629 case ModePersistentHTTP: 00630 m_logInstance.dbg( LogAreaClassConnectionBOSH, "Deactivating PersistentHTTP connection" ); 00631 m_activeConnections.pop_front(); 00632 m_connectionPool.push_back( conn ); 00633 break; 00634 case ModePipelining: 00635 m_logInstance.dbg( LogAreaClassConnectionBOSH, "Keeping Pipelining connection" ); 00636 default: 00637 break; 00638 } 00639 } 00640 00641 }