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

inbandbytestream.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 "inbandbytestream.h"
00015 #include "bytestreamdatahandler.h"
00016 #include "disco.h"
00017 #include "clientbase.h"
00018 #include "base64.h"
00019 #include "util.h"
00020 
00021 #include <cstdlib>
00022 
00023 namespace gloox
00024 {
00025 
00026   // ---- InBandBytestream::IBB ----
00027   static const char* typeValues[] =
00028   {
00029     "open", "data", "close"
00030   };
00031 
00032   InBandBytestream::IBB::IBB( const std::string& sid, int blocksize )
00033     : StanzaExtension( ExtIBB ), m_sid ( sid ), m_seq( 0 ), m_blockSize( blocksize ),
00034       m_type( IBBOpen )
00035   {
00036   }
00037 
00038   InBandBytestream::IBB::IBB( const std::string& sid, int seq, const std::string& data )
00039     : StanzaExtension( ExtIBB ), m_sid ( sid ), m_seq( seq ), m_blockSize( 0 ),
00040       m_data( data ), m_type( IBBData )
00041   {
00042   }
00043 
00044   InBandBytestream::IBB::IBB( const std::string& sid )
00045     : StanzaExtension( ExtIBB ), m_sid ( sid ), m_seq( 0 ), m_blockSize( 0 ),
00046       m_type( IBBClose )
00047   {
00048   }
00049 
00050   InBandBytestream::IBB::IBB( const Tag* tag )
00051     : StanzaExtension( ExtIBB ), m_type( IBBInvalid )
00052   {
00053     if( !tag || tag->xmlns() != XMLNS_IBB )
00054       return;
00055 
00056     m_type = (IBBType)util::lookup( tag->name(), typeValues );
00057     m_blockSize = atoi( tag->findAttribute( "block-size" ).c_str() );
00058     m_seq = atoi( tag->findAttribute( "seq" ).c_str() );
00059     m_sid = tag->findAttribute( "sid" );
00060     m_data = Base64::decode64( tag->cdata() );
00061   }
00062 
00063   InBandBytestream::IBB::~IBB()
00064   {
00065   }
00066 
00067   const std::string& InBandBytestream::IBB::filterString() const
00068   {
00069     static const std::string filter = "/iq/open[@xmlns='" + XMLNS_IBB + "']"
00070                                       "|/iq/data[@xmlns='" + XMLNS_IBB + "']"
00071                                       "|/iq/close[@xmlns='" + XMLNS_IBB + "']";
00072     return filter;
00073   }
00074 
00075   Tag* InBandBytestream::IBB::tag() const
00076   {
00077     if( m_type == IBBInvalid )
00078       return 0;
00079 
00080     Tag* t = new Tag( util::lookup( m_type, typeValues ) );
00081     t->setXmlns( XMLNS_IBB );
00082     t->addAttribute( "sid", m_sid );
00083     if( m_type == IBBData )
00084     {
00085       t->setCData( Base64::encode64( m_data ) );
00086       t->addAttribute( "seq", m_seq );
00087     }
00088     else if( m_type == IBBOpen )
00089       t->addAttribute( "block-size", m_blockSize );
00090 
00091     return t;
00092   }
00093   // ---- ~InBandBytestream::IBB ----
00094 
00095   // ---- InBandBytestream ----
00096   InBandBytestream::InBandBytestream( ClientBase* clientbase, LogSink& logInstance, const JID& initiator,
00097                                       const JID& target, const std::string& sid )
00098     : Bytestream( Bytestream::IBB, logInstance, initiator, target, sid ),
00099       m_clientbase( clientbase ), m_blockSize( 4096 ), m_sequence( -1 ), m_lastChunkReceived( -1 )
00100   {
00101     if( m_clientbase )
00102       m_clientbase->registerIqHandler( this, ExtIBB );
00103 
00104     m_open = false;
00105   }
00106 
00107   InBandBytestream::~InBandBytestream()
00108   {
00109     if( m_open )
00110       close();
00111 
00112     if( m_clientbase )
00113     {
00114       m_clientbase->removeIqHandler( this, ExtIBB );
00115       m_clientbase->removeIDHandler( this );
00116     }
00117   }
00118 
00119   bool InBandBytestream::connect()
00120   {
00121     if( !m_clientbase )
00122       return false;
00123 
00124     if( m_target == m_clientbase->jid() )
00125       return true;
00126 
00127     const std::string& id = m_clientbase->getID();
00128     IQ iq( IQ::Set, m_target, id );
00129     iq.addExtension( new IBB( m_sid, m_blockSize ) );
00130     m_clientbase->send( iq, this, IBBOpen );
00131     return true;
00132   }
00133 
00134   void InBandBytestream::handleIqID( const IQ& iq, int context )
00135   {
00136     switch( iq.subtype() )
00137     {
00138       case IQ::Result:
00139         if( context == IBBOpen && m_handler )
00140         {
00141           m_handler->handleBytestreamOpen( this );
00142           m_open = true;
00143         }
00144         break;
00145       case IQ::Error:
00146         closed();
00147         break;
00148       default:
00149         break;
00150     }
00151   }
00152 
00153   bool InBandBytestream::handleIq( const IQ& iq ) // data or open request, always 'set'
00154   {
00155     const IBB* i = iq.findExtension<IBB>( ExtIBB );
00156     if( !i || !m_handler || iq.subtype() != IQ::Set )
00157       return false;
00158 
00159     if( !m_open )
00160     {
00161       if( i->type() == IBBOpen )
00162       {
00163         returnResult( iq.from(), iq.id() );
00164         m_open = true;
00165         m_handler->handleBytestreamOpen( this );
00166         return true;
00167       }
00168       return false;
00169     }
00170 
00171     if( i->type() == IBBClose )
00172     {
00173       returnResult( iq.from(), iq.id() );
00174       closed();
00175       return true;
00176     }
00177 
00178     if( ++m_lastChunkReceived != i->seq() )
00179     {
00180       m_open = false;
00181       return false;
00182     }
00183 
00184     if( i->data().empty() )
00185     {
00186       m_open = false;
00187       return false;
00188     }
00189 
00190     returnResult( iq.from(), iq.id() );
00191     m_handler->handleBytestreamData( this, i->data() );
00192     return true;
00193   }
00194 
00195   void InBandBytestream::returnResult( const JID& to, const std::string& id )
00196   {
00197     IQ iq( IQ::Result, to, id );
00198     m_clientbase->send( iq );
00199   }
00200 
00201   bool InBandBytestream::send( const std::string& data )
00202   {
00203     if( !m_open || !m_clientbase )
00204       return false;
00205 
00206     int pos = 0;
00207     int len = data.length();
00208     do
00209     {
00210       const std::string& id = m_clientbase->getID();
00211       IQ iq( IQ::Set, m_target, id );
00212       iq.addExtension( new IBB( m_sid, ++m_sequence, data.substr( pos, m_blockSize ) ) );
00213       m_clientbase->send( iq, this, IBBData );
00214 
00215       pos += m_blockSize;
00216       if( m_sequence == 65535 )
00217         m_sequence = -1;
00218     }
00219     while( pos < len );
00220 
00221     return true;
00222   }
00223 
00224   void InBandBytestream::closed()
00225   {
00226     if( !m_open )
00227       return;
00228 
00229     m_open = false;
00230 
00231     if( m_handler )
00232       m_handler->handleBytestreamClose( this );
00233   }
00234 
00235   void InBandBytestream::close()
00236   {
00237     m_open = false;
00238 
00239     if( !m_clientbase )
00240       return;
00241 
00242     const std::string& id = m_clientbase->getID();
00243     IQ iq( IQ::Set, m_target, id );
00244     iq.addExtension( new IBB( m_sid ) );
00245     m_clientbase->send( iq, this, IBBClose );
00246 
00247     if( m_handler )
00248       m_handler->handleBytestreamClose( this );
00249   }
00250 
00251 }

Generated on Mon Jun 23 10:50:18 2008 for gloox by  doxygen 1.4.1