00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #include "bytestreamhandler.h"
00015 #include "socks5bytestreammanager.h"
00016 #include "socks5bytestreamserver.h"
00017 #include "socks5bytestream.h"
00018 #include "clientbase.h"
00019 #include "disco.h"
00020 #include "error.h"
00021 #include "connectionbase.h"
00022 #include "sha.h"
00023 #include "util.h"
00024
00025 #include <cstdlib>
00026
00027 namespace gloox
00028 {
00029
00030
00031 static const char* s5bModeValues[] =
00032 {
00033 "tcp", "udp"
00034 };
00035
00036 static inline const char* modeString( SOCKS5BytestreamManager::S5BMode mode )
00037 {
00038 return s5bModeValues[mode];
00039 }
00040
00041 SOCKS5BytestreamManager::Query::Query()
00042 : StanzaExtension( ExtS5BQuery ), m_type( TypeInvalid )
00043 {
00044 }
00045
00046 SOCKS5BytestreamManager::Query::Query( const std::string& sid, S5BMode mode,
00047 const StreamHostList& hosts )
00048 : StanzaExtension( ExtS5BQuery ), m_sid( sid ), m_mode( mode ), m_hosts( hosts ), m_type( TypeSH )
00049 {
00050 }
00051
00052 SOCKS5BytestreamManager::Query::Query( const JID& jid, const std::string& sid, bool activate )
00053 : StanzaExtension( ExtS5BQuery ), m_sid( sid ), m_jid( jid ), m_type( activate ? TypeA : TypeSHU )
00054 {
00055 }
00056
00057 SOCKS5BytestreamManager::Query::Query( const Tag* tag )
00058 : StanzaExtension( ExtS5BQuery ), m_type( TypeInvalid )
00059 {
00060 if( !tag || tag->name() != "query" || tag->xmlns() != XMLNS_BYTESTREAMS
00061 || !tag->hasAttribute( "sid" ) )
00062 return;
00063
00064 m_sid = tag->findAttribute( "sid" );
00065 m_mode = static_cast<S5BMode>( util::deflookup( tag->findAttribute( "mode" ), s5bModeValues, S5BTCP ) );
00066
00067 const TagList& l = tag->children();
00068 TagList::const_iterator it = l.begin();
00069 for( ; it != l.end(); ++it )
00070 {
00071 if( (*it)->name() == "streamhost" && (*it)->hasAttribute( "jid" )
00072 && (*it)->hasAttribute( "host" ) && (*it)->hasAttribute( "port" ) )
00073 {
00074 m_type = TypeSH;
00075 StreamHost sh;
00076 sh.jid = (*it)->findAttribute( "jid" );
00077 sh.host = (*it)->findAttribute( "host" );
00078 sh.port = atoi( (*it)->findAttribute( "port" ).c_str() );
00079 m_hosts.push_back( sh );
00080 }
00081 else if( (*it)->name() == "streamhost-used" )
00082 {
00083 m_type = TypeSHU;
00084 m_jid = (*it)->findAttribute( "jid" );
00085 }
00086 else if( (*it)->name() == "activate" )
00087 {
00088 m_type = TypeA;
00089 m_jid = (*it)->cdata();
00090 }
00091 }
00092 }
00093
00094 SOCKS5BytestreamManager::Query::~Query()
00095 {
00096 }
00097
00098 const std::string& SOCKS5BytestreamManager::Query::filterString() const
00099 {
00100 static const std::string& filter = "/iq/query[@xmlns='" + XMLNS_BYTESTREAMS + "']";
00101 return filter;
00102 }
00103
00104 Tag* SOCKS5BytestreamManager::Query::tag() const
00105 {
00106 if( m_type == TypeInvalid || m_sid.empty() )
00107 return 0;
00108
00109 Tag* t = new Tag( "query" );
00110 t->setXmlns( XMLNS_BYTESTREAMS );
00111 t->addAttribute( "sid", m_sid );
00112 switch( m_type )
00113 {
00114 case TypeSH:
00115 {
00116 t->addAttribute( "mode", util::deflookup( m_mode, s5bModeValues, "tcp" ) );
00117 StreamHostList::const_iterator it = m_hosts.begin();
00118 for( ; it != m_hosts.end(); ++it )
00119 {
00120 Tag* s = new Tag( t, "streamhost" );
00121 s->addAttribute( "jid", (*it).jid.full() );
00122 s->addAttribute( "host", (*it).host );
00123 s->addAttribute( "port", (*it).port );
00124 }
00125 break;
00126 }
00127 case TypeSHU:
00128 {
00129 Tag* s = new Tag( t, "streamhost-used" );
00130 s->addAttribute( "jid", m_jid.full() );
00131 break;
00132 }
00133 case TypeA:
00134 {
00135 Tag* c = new Tag( t, "activate" );
00136 c->setCData( m_jid.full() );
00137 break;
00138 }
00139 default:
00140 break;
00141 }
00142
00143 return t;
00144 }
00145
00146
00147
00148 SOCKS5BytestreamManager::SOCKS5BytestreamManager( ClientBase* parent, BytestreamHandler* s5bh )
00149 : m_parent( parent ), m_socks5BytestreamHandler( s5bh )
00150 {
00151 if( m_parent )
00152 {
00153 m_parent->registerStanzaExtension( new Query() );
00154 m_parent->registerIqHandler( this, ExtS5BQuery );
00155 }
00156 }
00157
00158 SOCKS5BytestreamManager::~SOCKS5BytestreamManager()
00159 {
00160 if( m_parent )
00161 {
00162 m_parent->removeIqHandler( this, ExtS5BQuery );
00163 m_parent->removeIDHandler( this );
00164 }
00165
00166
00167
00168 S5BMap::iterator it = m_s5bMap.begin();
00169 S5BMap::iterator it2;
00170 while( it != m_s5bMap.end() )
00171 {
00172 it2 = it++;
00173 delete (*it2).second;
00174 m_s5bMap.erase( it2 );
00175 }
00176
00177 }
00178
00179 void SOCKS5BytestreamManager::addStreamHost( const JID& jid, const std::string& host, int port )
00180 {
00181 StreamHost sh;
00182 sh.jid = jid;
00183 sh.host = host;
00184 sh.port = port;
00185 m_hosts.push_back( sh );
00186 }
00187
00188 bool SOCKS5BytestreamManager::requestSOCKS5Bytestream( const JID& to, S5BMode mode,
00189 const std::string& sid )
00190 {
00191 if( !m_parent )
00192 return false;
00193
00194 if( m_hosts.empty() )
00195 {
00196 m_parent->logInstance().warn( LogAreaClassS5BManager,
00197 "No stream hosts set, cannot request bytestream." );
00198 return false;
00199 }
00200
00201 const std::string& msid = sid.empty() ? m_parent->getID() : sid;
00202 const std::string& id = m_parent->getID();
00203 IQ iq( IQ::Set, to, id );
00204 iq.addExtension( new Query( msid, mode, m_hosts ) );
00205
00206 if( m_server )
00207 {
00208 SHA sha;
00209 sha.feed( msid );
00210 sha.feed( m_parent->jid().full() );
00211 sha.feed( to.full() );
00212 m_server->registerHash( sha.hex() );
00213 }
00214
00215 AsyncS5BItem asi;
00216 asi.sHosts = m_hosts;
00217 asi.id = id;
00218 asi.from = to;
00219 asi.incoming = false;
00220 m_asyncTrackMap[msid] = asi;
00221
00222 m_trackMap[id] = msid;
00223 m_parent->send( iq, this, S5BOpenStream );
00224
00225 return true;
00226 }
00227
00228 void SOCKS5BytestreamManager::acknowledgeStreamHost( bool success, const JID& jid,
00229 const std::string& sid )
00230 {
00231 AsyncTrackMap::const_iterator it = m_asyncTrackMap.find( sid );
00232 if( it == m_asyncTrackMap.end() || !m_parent )
00233 return;
00234
00235 const AsyncS5BItem& item = (*it).second;
00236
00237 IQ* iq = 0;
00238
00239 if( item.incoming )
00240 {
00241 iq = new IQ( IQ::Result, item.from.full(), item.id );
00242 if( success )
00243 iq->addExtension( new Query( jid, sid, false ) );
00244 else
00245 iq->addExtension( new Error( StanzaErrorTypeCancel, StanzaErrorItemNotFound ) );
00246
00247 m_parent->send( *iq );
00248 }
00249 else
00250 {
00251 if( success )
00252 {
00253 const std::string& id = m_parent->getID();
00254 iq = new IQ( IQ::Set, jid.full(), id );
00255 iq->addExtension( new Query( item.from, sid, true ) );
00256
00257 m_trackMap[id] = sid;
00258 m_parent->send( *iq, this, S5BActivateStream );
00259 }
00260 }
00261
00262 delete iq;
00263 }
00264
00265 bool SOCKS5BytestreamManager::handleIq( const IQ& iq )
00266 {
00267 const Query* q = iq.findExtension<Query>( ExtS5BQuery );
00268 if( !q || !m_socks5BytestreamHandler
00269 || m_trackMap.find( iq.id() ) != m_trackMap.end() )
00270 return false;
00271
00272 switch( iq.subtype() )
00273 {
00274 case IQ::Set:
00275 {
00276 const std::string& sid = q->sid();
00277
00278 if( sid.empty() || q->mode() == S5BUDP )
00279 {
00280 rejectSOCKS5Bytestream( iq.from(), iq.id(), StanzaErrorNotAcceptable );
00281 return true;
00282 }
00283 AsyncS5BItem asi;
00284 asi.sHosts = q->hosts();
00285 asi.id = iq.id();
00286 asi.from = iq.from();
00287 asi.incoming = true;
00288 m_asyncTrackMap[sid] = asi;
00289 m_socks5BytestreamHandler->handleIncomingBytestreamRequest( sid, iq.from() );
00290 break;
00291 }
00292 case IQ::Error:
00293 m_socks5BytestreamHandler->handleBytestreamError( iq, EmptyString );
00294 break;
00295 default:
00296 break;
00297 }
00298
00299 return true;
00300 }
00301
00302 const StreamHost* SOCKS5BytestreamManager::findProxy( const JID& from, const std::string& hostjid,
00303 const std::string& sid )
00304 {
00305 AsyncTrackMap::const_iterator it = m_asyncTrackMap.find( sid );
00306 if( it == m_asyncTrackMap.end() )
00307 return 0;
00308
00309 if( (*it).second.from == from )
00310 {
00311 StreamHostList::const_iterator it2 = (*it).second.sHosts.begin();
00312 for( ; it2 != (*it).second.sHosts.end(); ++it2 )
00313 {
00314 if( (*it2).jid == hostjid )
00315 {
00316 return &(*it2);
00317 }
00318 }
00319 }
00320
00321 return 0;
00322 }
00323
00324 bool SOCKS5BytestreamManager::haveStream( const JID& from )
00325 {
00326 S5BMap::const_iterator it = m_s5bMap.begin();
00327 for( ; it != m_s5bMap.end(); ++it )
00328 {
00329 if( (*it).second && (*it).second->target() == from )
00330 return true;
00331 }
00332 return false;
00333 }
00334
00335 void SOCKS5BytestreamManager::acceptSOCKS5Bytestream( const std::string& sid )
00336 {
00337 AsyncTrackMap::iterator it = m_asyncTrackMap.find( sid );
00338 if( it == m_asyncTrackMap.end() || !m_socks5BytestreamHandler )
00339 return;
00340
00341 SOCKS5Bytestream* s5b = new SOCKS5Bytestream( this, m_parent->connectionImpl()->newInstance(),
00342 m_parent->logInstance(),
00343 (*it).second.from, m_parent->jid(), sid );
00344 s5b->setStreamHosts( (*it).second.sHosts );
00345 m_s5bMap[sid] = s5b;
00346 m_socks5BytestreamHandler->handleIncomingBytestream( s5b );
00347 }
00348
00349 void SOCKS5BytestreamManager::rejectSOCKS5Bytestream( const std::string& sid )
00350 {
00351 AsyncTrackMap::iterator it = m_asyncTrackMap.find( sid );
00352 if( it != m_asyncTrackMap.end() )
00353 {
00354 rejectSOCKS5Bytestream( (*it).second.from, (*it).second.id, StanzaErrorNotAcceptable );
00355 m_asyncTrackMap.erase( it );
00356 }
00357 }
00358
00359 void SOCKS5BytestreamManager::rejectSOCKS5Bytestream( const JID& from,
00360 const std::string& id,
00361 StanzaError reason )
00362 {
00363 IQ* iq = 0;
00364 Error* error = 0;
00365
00366 switch( reason )
00367 {
00368 case StanzaErrorForbidden:
00369 {
00370 iq = new IQ( IQ::Error, from, id );
00371 error = new Error( StanzaErrorTypeAuth, StanzaErrorForbidden );
00372 break;
00373 }
00374 case StanzaErrorFeatureNotImplemented:
00375 {
00376 iq = new IQ( IQ::Error, from, id );
00377 error = new Error( StanzaErrorTypeCancel, StanzaErrorItemNotFound );
00378 break;
00379 }
00380 case StanzaErrorNotAllowed:
00381 {
00382 iq = new IQ( IQ::Error, from, id );
00383 error = new Error( StanzaErrorTypeCancel, StanzaErrorNotAllowed );
00384 break;
00385 }
00386 case StanzaErrorNotAcceptable:
00387 default:
00388 {
00389 iq = new IQ( IQ::Error, from, id );
00390 error = new Error( StanzaErrorTypeAuth, StanzaErrorNotAcceptable );
00391 break;
00392 }
00393 }
00394
00395 iq->addExtension( error );
00396 m_parent->send( *iq );
00397 delete iq;
00398 }
00399
00400 void SOCKS5BytestreamManager::handleIqID( const IQ& iq, int context )
00401 {
00402 StringMap::iterator it = m_trackMap.find( iq.id() );
00403 if( it == m_trackMap.end() )
00404 return;
00405
00406 switch( context )
00407 {
00408 case S5BOpenStream:
00409 {
00410 switch( iq.subtype() )
00411 {
00412 case IQ::Result:
00413 {
00414 const Query* q = iq.findExtension<Query>( ExtS5BQuery );
00415 if( q && m_socks5BytestreamHandler )
00416 {
00417 const std::string& proxy = q->jid().full();
00418 const StreamHost* sh = findProxy( iq.from(), proxy, (*it).second );
00419 if( sh )
00420 {
00421 SOCKS5Bytestream* s5b = 0;
00422 bool selfProxy = ( proxy == m_parent->jid().full() && m_server );
00423 if( selfProxy )
00424 {
00425 SHA sha;
00426 sha.feed( (*it).second );
00427 sha.feed( m_parent->jid().full() );
00428 sha.feed( iq.from().full() );
00429 s5b = new SOCKS5Bytestream( this, m_server->getConnection( sha.hex() ),
00430 m_parent->logInstance(),
00431 m_parent->jid(), iq.from(),
00432 (*it).second );
00433 }
00434 else
00435 {
00436 s5b = new SOCKS5Bytestream( this, m_parent->connectionImpl()->newInstance(),
00437 m_parent->logInstance(),
00438 m_parent->jid(), iq.from(),
00439 (*it).second );
00440 s5b->setStreamHosts( StreamHostList( 1, *sh ) );
00441 }
00442 m_s5bMap[(*it).second] = s5b;
00443 m_socks5BytestreamHandler->handleOutgoingBytestream( s5b );
00444 if( selfProxy )
00445 s5b->activate();
00446 }
00447 }
00448 break;
00449 }
00450 case IQ::Error:
00451 m_socks5BytestreamHandler->handleBytestreamError( iq, (*it).second );
00452 break;
00453 default:
00454 break;
00455 }
00456 break;
00457 }
00458 case S5BActivateStream:
00459 {
00460 switch( iq.subtype() )
00461 {
00462 case IQ::Result:
00463 {
00464 S5BMap::const_iterator it5 = m_s5bMap.find( (*it).second );
00465 if( it5 != m_s5bMap.end() )
00466 (*it5).second->activate();
00467 break;
00468 }
00469 case IQ::Error:
00470 m_socks5BytestreamHandler->handleBytestreamError( iq, (*it).second );
00471 break;
00472 default:
00473 break;
00474 }
00475 break;
00476 }
00477 default:
00478 break;
00479 }
00480 m_trackMap.erase( it );
00481 }
00482
00483 bool SOCKS5BytestreamManager::dispose( SOCKS5Bytestream* s5b )
00484 {
00485 S5BMap::iterator it = m_s5bMap.find( s5b->sid() );
00486 if( it != m_s5bMap.end() )
00487 {
00488 delete s5b;
00489 m_s5bMap.erase( it );
00490 return true;
00491 }
00492
00493 return false;
00494 }
00495
00496 }