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 )
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 )
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 ), m_server( 0 )
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 util::clearMap( m_s5bMap );
00167 }
00168
00169 void SOCKS5BytestreamManager::addStreamHost( const JID& jid, const std::string& host, int port )
00170 {
00171 StreamHost sh;
00172 sh.jid = jid;
00173 sh.host = host;
00174 sh.port = port;
00175 m_hosts.push_back( sh );
00176 }
00177
00178 bool SOCKS5BytestreamManager::requestSOCKS5Bytestream( const JID& to, S5BMode mode,
00179 const std::string& sid,
00180 const JID& from )
00181 {
00182 if( !m_parent )
00183 {
00184 m_parent->logInstance().warn( LogAreaClassS5BManager,
00185 "No parent (ClientBase) set, cannot request bytestream." );
00186 return false;
00187 }
00188
00189 if( m_hosts.empty() )
00190 {
00191 m_parent->logInstance().warn( LogAreaClassS5BManager,
00192 "No stream hosts set, cannot request bytestream." );
00193 return false;
00194 }
00195
00196 const std::string& msid = sid.empty() ? m_parent->getID() : sid;
00197 const std::string& id = m_parent->getID();
00198 IQ iq( IQ::Set, to, id );
00199 iq.addExtension( new Query( msid, mode, m_hosts ) );
00200 if( from )
00201 iq.setFrom( from );
00202
00203 if( m_server )
00204 {
00205 SHA sha;
00206 sha.feed( msid );
00207 if( from )
00208 sha.feed( from.full() );
00209 else
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.to = from ? from : m_parent->jid();
00220 asi.incoming = false;
00221 m_asyncTrackMap[msid] = asi;
00222
00223 m_trackMap[id] = msid;
00224 m_parent->send( iq, this, S5BOpenStream );
00225
00226 return true;
00227 }
00228
00229 void SOCKS5BytestreamManager::acknowledgeStreamHost( bool success, const JID& jid,
00230 const std::string& sid )
00231 {
00232 AsyncTrackMap::const_iterator it = m_asyncTrackMap.find( sid );
00233 if( it == m_asyncTrackMap.end() || !m_parent )
00234 return;
00235
00236 const AsyncS5BItem& item = (*it).second;
00237
00238 IQ* iq = 0;
00239
00240 if( item.incoming )
00241 {
00242 iq = new IQ( IQ::Result, item.from.full(), item.id );
00243 if( item.to )
00244 iq->setFrom( item.to );
00245
00246 if( success )
00247 iq->addExtension( new Query( jid, sid, false ) );
00248 else
00249 iq->addExtension( new Error( StanzaErrorTypeCancel, StanzaErrorItemNotFound ) );
00250
00251 m_parent->send( *iq );
00252 }
00253 else
00254 {
00255 if( success )
00256 {
00257 const std::string& id = m_parent->getID();
00258 iq = new IQ( IQ::Set, jid.full(), id );
00259 iq->addExtension( new Query( item.from, sid, true ) );
00260
00261 m_trackMap[id] = sid;
00262 m_parent->send( *iq, this, S5BActivateStream );
00263 }
00264 }
00265
00266 delete iq;
00267 }
00268
00269 bool SOCKS5BytestreamManager::handleIq( const IQ& iq )
00270 {
00271 const Query* q = iq.findExtension<Query>( ExtS5BQuery );
00272 if( !q || !m_socks5BytestreamHandler
00273 || m_trackMap.find( iq.id() ) != m_trackMap.end() )
00274 return false;
00275
00276 switch( iq.subtype() )
00277 {
00278 case IQ::Set:
00279 {
00280 const std::string& sid = q->sid();
00281
00282 if( sid.empty() || q->mode() == S5BUDP )
00283 {
00284 rejectSOCKS5Bytestream( iq.from(), iq.id(), StanzaErrorNotAcceptable );
00285 return true;
00286 }
00287 AsyncS5BItem asi;
00288 asi.sHosts = q->hosts();
00289 asi.id = iq.id();
00290 asi.from = iq.from();
00291 asi.to = iq.to();
00292 asi.incoming = true;
00293 m_asyncTrackMap[sid] = asi;
00294 m_socks5BytestreamHandler->handleIncomingBytestreamRequest( sid, iq.from() );
00295 break;
00296 }
00297 case IQ::Error:
00298 m_socks5BytestreamHandler->handleBytestreamError( iq, EmptyString );
00299 break;
00300 default:
00301 break;
00302 }
00303
00304 return true;
00305 }
00306
00307 const StreamHost* SOCKS5BytestreamManager::findProxy( const JID& from, const std::string& hostjid,
00308 const std::string& sid )
00309 {
00310 AsyncTrackMap::const_iterator it = m_asyncTrackMap.find( sid );
00311 if( it == m_asyncTrackMap.end() )
00312 return 0;
00313
00314 if( (*it).second.from == from )
00315 {
00316 StreamHostList::const_iterator it2 = (*it).second.sHosts.begin();
00317 for( ; it2 != (*it).second.sHosts.end(); ++it2 )
00318 {
00319 if( (*it2).jid == hostjid )
00320 {
00321 return &(*it2);
00322 }
00323 }
00324 }
00325
00326 return 0;
00327 }
00328
00329 bool SOCKS5BytestreamManager::haveStream( const JID& from )
00330 {
00331 S5BMap::const_iterator it = m_s5bMap.begin();
00332 for( ; it != m_s5bMap.end(); ++it )
00333 {
00334 if( (*it).second && (*it).second->target() == from )
00335 return true;
00336 }
00337 return false;
00338 }
00339
00340 void SOCKS5BytestreamManager::acceptSOCKS5Bytestream( const std::string& sid )
00341 {
00342 AsyncTrackMap::iterator it = m_asyncTrackMap.find( sid );
00343 if( it == m_asyncTrackMap.end() || !m_socks5BytestreamHandler )
00344 return;
00345
00346 SOCKS5Bytestream* s5b = new SOCKS5Bytestream( this, m_parent->connectionImpl()->newInstance(),
00347 m_parent->logInstance(),
00348 (*it).second.from, (*it).second.to, sid );
00349 s5b->setStreamHosts( (*it).second.sHosts );
00350 m_s5bMap[sid] = s5b;
00351 m_socks5BytestreamHandler->handleIncomingBytestream( s5b );
00352 }
00353
00354 void SOCKS5BytestreamManager::rejectSOCKS5Bytestream( const std::string& sid, StanzaError reason )
00355 {
00356 AsyncTrackMap::iterator it = m_asyncTrackMap.find( sid );
00357 if( it != m_asyncTrackMap.end() )
00358 {
00359 rejectSOCKS5Bytestream( (*it).second.from, (*it).second.id, reason );
00360 m_asyncTrackMap.erase( it );
00361 }
00362 }
00363
00364 void SOCKS5BytestreamManager::rejectSOCKS5Bytestream( const JID& from,
00365 const std::string& id,
00366 StanzaError reason )
00367 {
00368 IQ iq( IQ::Error, from, id );
00369
00370 switch( reason )
00371 {
00372 case StanzaErrorForbidden:
00373 case StanzaErrorNotAcceptable:
00374 {
00375 iq.addExtension( new Error( StanzaErrorTypeAuth, reason ) );
00376 break;
00377 }
00378 case StanzaErrorFeatureNotImplemented:
00379 case StanzaErrorNotAllowed:
00380 default:
00381 {
00382 iq.addExtension( new Error( StanzaErrorTypeCancel, reason ) );
00383 break;
00384 }
00385 }
00386
00387 m_parent->send( iq );
00388 }
00389
00390 void SOCKS5BytestreamManager::handleIqID( const IQ& iq, int context )
00391 {
00392 StringMap::iterator it = m_trackMap.find( iq.id() );
00393 if( it == m_trackMap.end() )
00394 return;
00395
00396 switch( context )
00397 {
00398 case S5BOpenStream:
00399 {
00400 switch( iq.subtype() )
00401 {
00402 case IQ::Result:
00403 {
00404 const Query* q = iq.findExtension<Query>( ExtS5BQuery );
00405 if( q && m_socks5BytestreamHandler )
00406 {
00407 const std::string& proxy = q->jid().full();
00408 const StreamHost* sh = findProxy( iq.from(), proxy, (*it).second );
00409 if( sh )
00410 {
00411 SOCKS5Bytestream* s5b = 0;
00412 bool selfProxy = ( proxy == m_parent->jid().full() && m_server );
00413 if( selfProxy )
00414 {
00415 SHA sha;
00416 sha.feed( (*it).second );
00417 sha.feed( iq.to().full() );
00418 sha.feed( iq.from().full() );
00419 s5b = new SOCKS5Bytestream( this, m_server->getConnection( sha.hex() ),
00420 m_parent->logInstance(),
00421 iq.to(), iq.from(),
00422 (*it).second );
00423 }
00424 else
00425 {
00426 s5b = new SOCKS5Bytestream( this, m_parent->connectionImpl()->newInstance(),
00427 m_parent->logInstance(),
00428 iq.to(), iq.from(),
00429 (*it).second );
00430 s5b->setStreamHosts( StreamHostList( 1, *sh ) );
00431 }
00432 m_s5bMap[(*it).second] = s5b;
00433 m_socks5BytestreamHandler->handleOutgoingBytestream( s5b );
00434 if( selfProxy )
00435 s5b->activate();
00436 }
00437 }
00438 break;
00439 }
00440 case IQ::Error:
00441 m_socks5BytestreamHandler->handleBytestreamError( iq, (*it).second );
00442 break;
00443 default:
00444 break;
00445 }
00446 break;
00447 }
00448 case S5BActivateStream:
00449 {
00450 switch( iq.subtype() )
00451 {
00452 case IQ::Result:
00453 {
00454 S5BMap::const_iterator it5 = m_s5bMap.find( (*it).second );
00455 if( it5 != m_s5bMap.end() )
00456 (*it5).second->activate();
00457 break;
00458 }
00459 case IQ::Error:
00460 m_socks5BytestreamHandler->handleBytestreamError( iq, (*it).second );
00461 break;
00462 default:
00463 break;
00464 }
00465 break;
00466 }
00467 default:
00468 break;
00469 }
00470 m_trackMap.erase( it );
00471 }
00472
00473 bool SOCKS5BytestreamManager::dispose( SOCKS5Bytestream* s5b )
00474 {
00475 S5BMap::iterator it = m_s5bMap.find( s5b->sid() );
00476 if( it != m_s5bMap.end() )
00477 {
00478 delete s5b;
00479 m_s5bMap.erase( it );
00480 return true;
00481 }
00482
00483 return false;
00484 }
00485
00486 }