gloox 1.0
|
00001 /* 00002 Copyright (c) 2006-2009 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 "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 // ---- InBandBytestream::IBB ---- 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 // ---- ~InBandBytestream::IBB ---- 00097 00098 // ---- InBandBytestream ---- 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 ) // data or open request, always 'set' 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* /*session*/ ) 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 }