socks5bytestreammanager.cpp

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

Generated on Sun Apr 27 11:08:13 2008 for gloox by  doxygen 1.5.5