00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #include "socks5bytestreammanager.h"
00015 #include "socks5bytestreamhandler.h"
00016 #include "socks5bytestreamserver.h"
00017 #include "socks5bytestream.h"
00018 #include "clientbase.h"
00019 #include "disco.h"
00020 #include "connectionbase.h"
00021 #include "sha.h"
00022
00023 #include <cstdlib>
00024
00025 namespace gloox
00026 {
00027
00028 SOCKS5BytestreamManager::SOCKS5BytestreamManager( ClientBase *parent, SOCKS5BytestreamHandler* s5bh )
00029 : m_parent( parent ), m_socks5BytestreamHandler( s5bh )
00030 {
00031 if( m_parent )
00032 m_parent->registerIqHandler( this, XMLNS_BYTESTREAMS );
00033 }
00034
00035 SOCKS5BytestreamManager::~SOCKS5BytestreamManager()
00036 {
00037 if( m_parent )
00038 m_parent->removeIqHandler( XMLNS_BYTESTREAMS );
00039
00040 S5BMap::iterator it = m_s5bMap.begin();
00041 for( ; it != m_s5bMap.end(); ++it )
00042 {
00043 delete (*it).second;
00044 (*it).second = 0;
00045 }
00046 }
00047
00048 void SOCKS5BytestreamManager::addStreamHost( const JID& jid, const std::string& host, int port )
00049 {
00050 StreamHost sh;
00051 sh.jid = jid;
00052 sh.host = host;
00053 sh.port = port;
00054 m_hosts.push_back( sh );
00055 }
00056
00057 bool SOCKS5BytestreamManager::requestSOCKS5Bytestream( const JID& to, S5BMode ,
00058 const std::string& sid )
00059 {
00060 if( !m_parent )
00061 return false;
00062
00063 if( m_hosts.empty() )
00064 {
00065 m_parent->logInstance().log( LogLevelWarning, LogAreaClassS5BManager,
00066 "No stream hosts set, cannot request bytestream." );
00067 return false;
00068 }
00069
00070 const std::string& msid = sid.empty() ? m_parent->getID() : sid;
00071 const std::string& id = m_parent->getID();
00072 Tag *iq = new Tag( "iq" );
00073 iq->addAttribute( "type", "set" );
00074 iq->addAttribute( "to", to.full() );
00075 iq->addAttribute( "id", id );
00076 Tag *q = new Tag( iq, "query", "xmlns", XMLNS_BYTESTREAMS );
00077 q->addAttribute( "sid", msid );
00078 q->addAttribute( "mode", "tcp" );
00079
00080 StreamHostList::const_iterator it = m_hosts.begin();
00081 for( ; it != m_hosts.end(); ++it )
00082 {
00083 Tag* s = new Tag( q, "streamhost", "jid", (*it).jid.full() );
00084 s->addAttribute( "host", (*it).host );
00085 s->addAttribute( "port", (*it).port );
00086 }
00087
00088 if( m_server )
00089 {
00090 SHA sha;
00091 sha.feed( msid );
00092 sha.feed( m_parent->jid().full() );
00093 sha.feed( to.full() );
00094 m_server->registerHash( sha.hex() );
00095 }
00096
00097 AsyncS5BItem asi;
00098 asi.sHosts = m_hosts;
00099 asi.id = id;
00100 asi.from = to;
00101 asi.incoming = false;
00102 m_asyncTrackMap[msid] = asi;
00103
00104 m_trackMap[id] = msid;
00105 m_parent->trackID( this, id, S5BOpenStream );
00106 m_parent->send( iq );
00107
00108 return true;
00109 }
00110
00111 void SOCKS5BytestreamManager::acknowledgeStreamHost( bool success, const JID& jid,
00112 const std::string& sid )
00113 {
00114 AsyncTrackMap::const_iterator it = m_asyncTrackMap.find( sid );
00115 if( it == m_asyncTrackMap.end() || !m_parent )
00116 return;
00117
00118 Tag *iq = new Tag( "iq" );
00119
00120 if( (*it).second.incoming )
00121 {
00122 iq->addAttribute( "to", (*it).second.from.full() );
00123 iq->addAttribute( "id", (*it).second.id );
00124
00125 if( success )
00126 {
00127 iq->addAttribute( "type", "result" );
00128 Tag* q = new Tag( iq, "query", "xmlns", XMLNS_BYTESTREAMS );
00129 new Tag( q, "streamhost-used", "jid", jid.full() );
00130 }
00131 else
00132 {
00133 iq->addAttribute( "type", "error" );
00134 Tag* e = new Tag( iq, "error" );
00135 e->addAttribute( "code", "404" );
00136 e->addAttribute( "type", "cancel" );
00137 new Tag( e, "item-not-found", "xmlns", XMLNS_XMPP_STANZAS );
00138 }
00139 }
00140 else
00141 {
00142 if( success )
00143 {
00144 const std::string& id = m_parent->getID();
00145 iq->addAttribute( "to", jid.full() );
00146 iq->addAttribute( "id", id );
00147 iq->addAttribute( "type", "set" );
00148 Tag* q = new Tag( iq, "query", "xmlns", XMLNS_BYTESTREAMS );
00149 q->addAttribute( "sid", sid );
00150 new Tag( q, "activate", (*it).second.from.full() );
00151
00152 m_trackMap[id] = sid;
00153 m_parent->trackID( this, id, S5BActivateStream );
00154 }
00155 }
00156
00157 m_parent->send( iq );
00158 }
00159
00160 bool SOCKS5BytestreamManager::handleIq( Stanza *stanza )
00161 {
00162 Tag* q = stanza->findChild( "query", "xmlns", XMLNS_BYTESTREAMS );
00163 if( !q || !m_socks5BytestreamHandler )
00164 return false;
00165
00166 if( m_trackMap.find( stanza->id() ) != m_trackMap.end() )
00167 return false;
00168
00169 switch( stanza->subtype() )
00170 {
00171 case StanzaIqSet:
00172 {
00173 const std::string& sid = q->findAttribute( "sid" );
00174 const std::string& mode = q->findAttribute( "mode" );
00175 if( haveStream( stanza->from() ) || sid.empty() || mode == "udp" )
00176 {
00177 rejectSOCKS5Bytestream( stanza->from(), stanza->id(), StanzaErrorNotAcceptable );
00178 return true;
00179 }
00180 AsyncS5BItem asi;
00181 Tag::TagList& l = q->children();
00182 Tag::TagList::const_iterator it = l.begin();
00183 for( ; it != l.end(); ++it )
00184 {
00185 if( (*it)->name() == "streamhost" && (*it)->hasAttribute( "jid" )
00186 && (*it)->hasAttribute( "host" ) && (*it)->hasAttribute( "port" ) )
00187 {
00188 StreamHost sh;
00189 sh.jid = (*it)->findAttribute( "jid" );
00190 sh.host = (*it)->findAttribute( "host" );
00191 sh.port = atoi( (*it)->findAttribute( "port" ).c_str() );
00192 asi.sHosts.push_back( sh );
00193 }
00194 }
00195 asi.id = stanza->id();
00196 asi.from = stanza->from();
00197 asi.incoming = true;
00198 m_asyncTrackMap[sid] = asi;
00199 m_socks5BytestreamHandler->handleIncomingSOCKS5BytestreamRequest( sid, stanza->from() );
00200 break;
00201 }
00202 case StanzaIqError:
00203 m_socks5BytestreamHandler->handleSOCKS5BytestreamError( stanza, std::string() );
00204 break;
00205 default:
00206 break;
00207 }
00208
00209 return true;
00210 }
00211
00212 const StreamHost* SOCKS5BytestreamManager::findProxy( const JID& from, const std::string& hostjid,
00213 const std::string& sid )
00214 {
00215 AsyncTrackMap::const_iterator it = m_asyncTrackMap.find( sid );
00216 if( it == m_asyncTrackMap.end() )
00217 return 0;
00218
00219 if( (*it).second.from == from )
00220 {
00221 StreamHostList::const_iterator it2 = (*it).second.sHosts.begin();
00222 for( ; it2 != (*it).second.sHosts.end(); ++it2 )
00223 {
00224 if( (*it2).jid == hostjid )
00225 {
00226 return &(*it2);
00227 }
00228 }
00229 }
00230
00231 return 0;
00232 }
00233
00234 bool SOCKS5BytestreamManager::haveStream( const JID& from )
00235 {
00236 S5BMap::const_iterator it = m_s5bMap.begin();
00237 for( ; it != m_s5bMap.end(); ++it )
00238 {
00239 if( (*it).second && (*it).second->target() == from )
00240 return true;
00241 }
00242 return false;
00243 }
00244
00245 void SOCKS5BytestreamManager::acceptSOCKS5Bytestream( const std::string& sid )
00246 {
00247 AsyncTrackMap::iterator it = m_asyncTrackMap.find( sid );
00248 if( it == m_asyncTrackMap.end() || !m_socks5BytestreamHandler )
00249 return;
00250
00251 SOCKS5Bytestream* s5b = new SOCKS5Bytestream( this, m_parent->connectionImpl()->newInstance(),
00252 m_parent->logInstance(),
00253 (*it).second.from, m_parent->jid(), sid );
00254 s5b->setStreamHosts( (*it).second.sHosts );
00255 m_s5bMap[sid] = s5b;
00256 m_socks5BytestreamHandler->handleIncomingSOCKS5Bytestream( s5b );
00257 }
00258
00259 void SOCKS5BytestreamManager::rejectSOCKS5Bytestream( const std::string& sid )
00260 {
00261 AsyncTrackMap::iterator it = m_asyncTrackMap.find( sid );
00262 if( it != m_asyncTrackMap.end() )
00263 {
00264 rejectSOCKS5Bytestream( (*it).second.from, (*it).second.id, StanzaErrorNotAcceptable );
00265 m_asyncTrackMap.erase( it );
00266 }
00267 }
00268
00269 void SOCKS5BytestreamManager::rejectSOCKS5Bytestream( const JID& from, const std::string& id,
00270 StanzaError reason )
00271 {
00272 Tag *iq = new Tag( "iq" );
00273 iq->addAttribute( "type", "error" );
00274 iq->addAttribute( "to", from.full() );
00275 iq->addAttribute( "id", id );
00276 Tag *e = new Tag( iq, "error" );
00277 switch( reason )
00278 {
00279 case StanzaErrorForbidden:
00280 {
00281 new Tag( iq, "query", "xmlns", XMLNS_BYTESTREAMS );
00282 e->addAttribute( "code", "403" );
00283 e->addAttribute( "type", "auth" );
00284 Tag *f = new Tag( e, "forbidden" );
00285 f->addAttribute( "xmlns", XMLNS_XMPP_STANZAS );
00286 break;
00287 }
00288 case StanzaErrorFeatureNotImplemented:
00289 {
00290 e->addAttribute( "code", "404" );
00291 e->addAttribute( "type", "cancel" );
00292 Tag *f = new Tag( e, "item-not-found" );
00293 f->addAttribute( "xmlns", XMLNS_XMPP_STANZAS );
00294 break;
00295 }
00296 case StanzaErrorNotAllowed:
00297 {
00298 new Tag( iq, "query", "xmlns", XMLNS_BYTESTREAMS );
00299 e->addAttribute( "code", "405" );
00300 e->addAttribute( "type", "cancel" );
00301 Tag *f = new Tag( e, "not-allowed" );
00302 f->addAttribute( "xmlns", XMLNS_XMPP_STANZAS );
00303 break;
00304 }
00305 case StanzaErrorNotAcceptable:
00306 default:
00307 {
00308 e->addAttribute( "code", "406" );
00309 e->addAttribute( "type", "auth" );
00310 Tag *f = new Tag( e, "not-acceptable" );
00311 f->addAttribute( "xmlns", XMLNS_XMPP_STANZAS );
00312 break;
00313 }
00314 }
00315 m_parent->send( iq );
00316 }
00317
00318 bool SOCKS5BytestreamManager::handleIqID( Stanza *stanza, int context )
00319 {
00320 StringMap::iterator it = m_trackMap.find( stanza->id() );
00321 if( it == m_trackMap.end() )
00322 return false;
00323
00324 switch( context )
00325 {
00326 case S5BOpenStream:
00327 {
00328 switch( stanza->subtype() )
00329 {
00330 case StanzaIqResult:
00331 {
00332 Tag* q = stanza->findChild( "query", "xmlns", XMLNS_BYTESTREAMS );
00333 if( !q || !m_socks5BytestreamHandler )
00334 return false;
00335
00336 Tag* s = q->findChild( "streamhost-used" );
00337 if( !s || !s->hasAttribute( "jid" ) )
00338 return false;
00339
00340 const std::string & proxy = s->findAttribute( "jid" );
00341 const StreamHost* sh = findProxy( stanza->from(), proxy, (*it).second );
00342 if( sh )
00343 {
00344 SOCKS5Bytestream* s5b = 0;
00345 bool selfProxy = ( proxy == m_parent->jid().full() && m_server );
00346 if( selfProxy )
00347 {
00348 SHA sha;
00349 sha.feed( (*it).second );
00350 sha.feed( m_parent->jid().full() );
00351 sha.feed( stanza->from().full() );
00352 s5b = new SOCKS5Bytestream( this, m_server->getConnection( sha.hex() ),
00353 m_parent->logInstance(),
00354 m_parent->jid(), stanza->from(),
00355 (*it).second );
00356 }
00357 else
00358 {
00359 s5b = new SOCKS5Bytestream( this, m_parent->connectionImpl()->newInstance(),
00360 m_parent->logInstance(),
00361 m_parent->jid(), stanza->from(),
00362 (*it).second );
00363 StreamHostList shl;
00364 shl.push_back( *sh );
00365 s5b->setStreamHosts( shl );
00366 }
00367 m_s5bMap[(*it).second] = s5b;
00368 m_socks5BytestreamHandler->handleOutgoingSOCKS5Bytestream( s5b );
00369 if( selfProxy )
00370 s5b->activate();
00371 }
00372 break;
00373 }
00374 case StanzaIqError:
00375 m_socks5BytestreamHandler->handleSOCKS5BytestreamError( stanza, (*it).second );
00376 break;
00377 default:
00378 break;
00379 }
00380 break;
00381 }
00382 case S5BActivateStream:
00383 {
00384 switch( stanza->subtype() )
00385 {
00386 case StanzaIqResult:
00387 {
00388 S5BMap::const_iterator it5 = m_s5bMap.find( (*it).second );
00389 if( it5 != m_s5bMap.end() )
00390 (*it5).second->activate();
00391 break;
00392 }
00393 case StanzaIqError:
00394 m_socks5BytestreamHandler->handleSOCKS5BytestreamError( stanza, (*it).second );
00395 break;
00396 default:
00397 break;
00398 }
00399 break;
00400 }
00401 default:
00402 break;
00403 }
00404 m_trackMap.erase( it );
00405
00406 return false;
00407 }
00408
00409 bool SOCKS5BytestreamManager::dispose( SOCKS5Bytestream* s5b )
00410 {
00411 S5BMap::iterator it = m_s5bMap.find( s5b->sid() );
00412 if( it != m_s5bMap.end() )
00413 {
00414 delete s5b;
00415 m_s5bMap.erase( it );
00416 return true;
00417 }
00418
00419 return false;
00420 }
00421
00422 }