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