00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
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
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
00094
00095
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 )
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 }