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