socks5bytestreammanager.cpp

00001 /*
00002   Copyright (c) 2006-2007 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       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 /*mode*/,
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", /*( mode == S5BTCP ) ?*/ "tcp" /*: "udp"*/ );
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 }

Generated on Sat Nov 10 08:50:27 2007 for gloox by  doxygen 1.5.3-20071008