Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | Related Pages

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

Generated on Mon Oct 13 10:45:12 2008 for gloox by  doxygen 1.4.1