gloox
1.0
|
00001 /* 00002 Copyright (c) 2006-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 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 // ---- SOCKS5BytestreamManager::Query ---- 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 // ---- ~SOCKS5BytestreamManager::Query ---- 00146 00147 // ---- SOCKS5BytestreamManager ---- 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 // FIXME What is haveStream() good for? 00282 if( /*haveStream( iq.from() ) ||*/ 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 }