Class Jabber::Bytestreams::IBB
In: lib/xmpp4r/bytestreams/helper/ibb/base.rb
Parent: Object
Message Presence XMPPStanza Iq XMPPElement X IqQuery Error Singleton IdGenerator Connection Client Component Client Comparable JID RuntimeError ErrorException AuthenticationFailure NoNameXmlnsRegistered SOCKS5Error REXML::Element Stream SOCKS5Bytestreams SOCKS5BytestreamsTarget SOCKS5BytestreamsInitiator XMPPElement StreamHost IqSiFileRange IqSiFile StreamHostUsed IqSi IqFeature XRosterItem RosterItem XMUCUserItem XMUCUserInvite IqPubSub Items Subscription IqPubSubOwner Item Event Feature Identity Item XDataField XDataReported XDataTitle XDataInstructions IqVcard SOCKS5BytestreamsServerStreamHost TCPSocket SOCKS5Socket IqQuery IqQueryBytestreams IqQueryVersion IqQueryRoster IqQueryRPC IqQueryMUCOwner IqQueryDiscoItems IqQueryDiscoInfo IBB IBBTarget IBBInitiator Responder SimpleResponder Iq IqCommand RosterXItem XRoster RosterX X XMUCUser XMUC XDelay XData XMLRPC::ParserWriterChooseMixin Client Server XMLRPC::ParseContentType XMLRPC::BasicServer XParent MUCClient SimpleMUCClient Base DigestMD5 Plain FileSource ServiceHelper NodeHelper CallbackList Callback Semaphore StreamParser SOCKS5BytestreamsPeer SOCKS5BytestreamsServer IBBQueueItem Responder Helper MUCBrowser Helper NodeBrowser Helper lib/xmpp4r/authenticationfailure.rb lib/xmpp4r/xmppstanza.rb lib/xmpp4r/callbacks.rb lib/xmpp4r/idgenerator.rb lib/xmpp4r/connection.rb lib/xmpp4r/iq.rb lib/xmpp4r/jid.rb lib/xmpp4r/errorexception.rb lib/xmpp4r/semaphore.rb lib/xmpp4r/client.rb lib/xmpp4r/stream.rb lib/xmpp4r/x.rb lib/xmpp4r/streamparser.rb lib/xmpp4r/error.rb lib/xmpp4r/component.rb lib/xmpp4r/query.rb lib/xmpp4r/xmppelement.rb lib/xmpp4r/message.rb lib/xmpp4r/presence.rb lib/xmpp4r/bytestreams/helper/ibb/initiator.rb lib/xmpp4r/bytestreams/iq/si.rb lib/xmpp4r/bytestreams/iq/bytestreams.rb lib/xmpp4r/bytestreams/helper/socks5bytestreams/base.rb lib/xmpp4r/bytestreams/helper/socks5bytestreams/server.rb lib/xmpp4r/bytestreams/helper/socks5bytestreams/target.rb lib/xmpp4r/bytestreams/helper/socks5bytestreams/socks5.rb lib/xmpp4r/bytestreams/helper/socks5bytestreams/initiator.rb lib/xmpp4r/bytestreams/helper/ibb/base.rb lib/xmpp4r/bytestreams/helper/ibb/target.rb Bytestreams XParent lib/xmpp4r/version/iq/version.rb lib/xmpp4r/version/helper/responder.rb lib/xmpp4r/version/helper/simpleresponder.rb Version lib/xmpp4r/command/iq/command.rb lib/xmpp4r/command/helper/responder.rb Command lib/xmpp4r/feature_negotiation/iq/feature.rb FeatureNegotiation lib/xmpp4r/roster/helper/roster.rb lib/xmpp4r/roster/iq/roster.rb lib/xmpp4r/roster/x/roster.rb Roster lib/xmpp4r/rpc/helper/server.rb lib/xmpp4r/rpc/helper/client.rb lib/xmpp4r/rpc/iq/rpc.rb RPC lib/xmpp4r/muc/x/muc.rb lib/xmpp4r/muc/helper/mucclient.rb lib/xmpp4r/muc/x/mucuseritem.rb lib/xmpp4r/muc/helper/mucbrowser.rb lib/xmpp4r/muc/x/mucuserinvite.rb lib/xmpp4r/muc/iq/mucowner.rb lib/xmpp4r/muc/helper/simplemucclient.rb MUC lib/xmpp4r/sasl.rb SASL lib/xmpp4r/bytestreams/helper/filetransfer.rb TransferSource FileTransfer lib/xmpp4r/delay/x/delay.rb Delay lib/xmpp4r/pubsub/stanzas/subscription.rb lib/xmpp4r/pubsub/helper/servicehelper.rb lib/xmpp4r/pubsub/stanzas/item.rb lib/xmpp4r/pubsub/helper/nodehelper.rb lib/xmpp4r/pubsub/iq/pubsub.rb lib/xmpp4r/pubsub/stanzas/event.rb lib/xmpp4r/pubsub/helper/nodebrowser.rb lib/xmpp4r/pubsub/stanzas/items.rb PubSub lib/xmpp4r/httpbinding/client.rb HTTPBinding lib/xmpp4r/discovery/iq/discoinfo.rb lib/xmpp4r/discovery/iq/discoitems.rb Discovery lib/xmpp4r/dataforms/x/data.rb Dataforms lib/xmpp4r/vcard/helper/vcard.rb lib/xmpp4r/vcard/iq/vcard.rb Vcard Jabber dot/m_81_0.png

In-Band Bytestreams (JEP-0047) implementation

Don‘t use directly, use IBBInitiator and IBBTarget

In-Band Bytestreams should only be used when transferring very small amounts of binary data, because it is slow and increases server load drastically.

Note that the constructor takes a lot of arguments. In-Band Bytestreams do not specify a way to initiate the stream, this should be done via Stream Initiation.

Methods

activate   active?   close   deactivate   flush   new   read   send_data   write  

Constants

NS_IBB = 'http://jabber.org/protocol/ibb'

Public Class methods

Create a new bytestream

Will register a <message/> callback to intercept data of this stream. This data will be buffered, you can retrieve it with receive

[Source]

    # File lib/xmpp4r/bytestreams/helper/ibb/base.rb, line 30
30:       def initialize(stream, session_id, my_jid, peer_jid)
31:         @stream = stream
32:         @session_id = session_id
33:         @my_jid = (my_jid.kind_of?(String) ? JID.new(my_jid) : my_jid)
34:         @peer_jid = (peer_jid.kind_of?(String) ? JID.new(peer_jid) : peer_jid)
35: 
36:         @active = false
37:         @seq_send = 0
38:         @seq_recv = 0
39:         @queue = []
40:         @queue_lock = Mutex.new
41:         @pending = Semaphore.new
42:         @sendbuf = ''
43:         @sendbuf_lock = Mutex.new
44: 
45:         @block_size = 4096  # Recommended by JEP0047
46:       end

Public Instance methods

[Source]

    # File lib/xmpp4r/bytestreams/helper/ibb/base.rb, line 48
48:       def active?
49:         @active
50:       end

Close the stream

Waits for acknowledge from peer, may throw ErrorException

[Source]

     # File lib/xmpp4r/bytestreams/helper/ibb/base.rb, line 128
128:       def close
129:         if active?
130:           flush
131:           deactivate
132: 
133:           iq = Iq.new(:set, @peer_jid)
134:           close = iq.add REXML::Element.new('close')
135:           close.add_namespace IBB::NS_IBB
136:           close.attributes['sid'] = @session_id
137: 
138:           @stream.send_with_id(iq) { |answer|
139:             answer.type == :result
140:           }
141:         end
142:       end

Empty the send-buffer by sending remaining data

[Source]

    # File lib/xmpp4r/bytestreams/helper/ibb/base.rb, line 72
72:       def flush
73:         @sendbuf_lock.synchronize {
74:           while @sendbuf.size > 0
75:             send_data(@sendbuf[0..@block_size-1])
76:             @sendbuf = @sendbuf[@block_size..-1].to_s
77:           end
78:         }
79:       end

Receive data

Will wait until the Message with the next sequence number is in the stanza queue.

[Source]

     # File lib/xmpp4r/bytestreams/helper/ibb/base.rb, line 86
 86:       def read
 87:         if active?
 88:           res = nil
 89: 
 90:           while res.nil?
 91:             @queue_lock.synchronize {
 92:               @queue.each { |item|
 93:                 # Find next data
 94:                 if item.type == :data and item.seq == @seq_recv.to_s
 95:                   res = item
 96:                   break
 97:                 # No data? Find close
 98:                 elsif item.type == :close and res.nil?
 99:                   res = item
100:                 end
101:               }
102: 
103:               @queue.delete_if { |item| item == res }
104:             }
105: 
106:             # No data? Wait for next to arrive...
107:             @pending.wait unless res
108:           end
109: 
110:           if res.type == :data
111:             @seq_recv += 1
112:             @seq_recv = 0 if @seq_recv > 65535
113:             res.data
114:           elsif res.type == :close
115:             deactivate
116:             nil # Closed
117:           end
118:         else
119:           nil
120:         end
121:       end

Send data

Data is buffered to match block_size in each packet. If you need the data to be sent immediately, use flush afterwards.

buf:[String]

[Source]

    # File lib/xmpp4r/bytestreams/helper/ibb/base.rb, line 59
59:       def write(buf)
60:         @sendbuf_lock.synchronize {
61:           @sendbuf += buf
62: 
63:           while @sendbuf.size >= @block_size
64:             send_data(@sendbuf[0..@block_size-1])
65:             @sendbuf = @sendbuf[@block_size..-1].to_s
66:           end
67:         }
68:       end

Private Instance methods

[Source]

     # File lib/xmpp4r/bytestreams/helper/ibb/base.rb, line 182
182:       def activate
183:         unless active?
184:           @stream.add_message_callback(200, self) { |msg|
185:             data = msg.first_element('data')
186:             if msg.from == @peer_jid and msg.to == @my_jid and data and data.attributes['sid'] == @session_id
187:               if msg.type == nil
188:                 @queue_lock.synchronize {
189:                   @queue.push IBBQueueItem.new(:data, data.attributes['seq'], data.text.to_s)
190:                   @pending.run
191:                 }
192:               elsif msg.type == :error
193:                 @queue_lock.synchronize {
194:                   @queue << IBBQueueItem.new(:close)
195:                   @pending.run
196:                 }
197:               end
198:               true
199:             else
200:               false
201:             end
202:           }
203: 
204:           @stream.add_iq_callback(200, self) { |iq|
205:             close = iq.first_element('close')
206:             if iq.type == :set and close and close.attributes['sid'] == @session_id
207:               answer = iq.answer(false)
208:               answer.type = :result
209:               @stream.send(answer)
210: 
211:               @queue_lock.synchronize {
212:                 @queue << IBBQueueItem.new(:close)
213:                 @pending.run
214:               }
215:               true
216:             else
217:               false
218:             end
219:           }
220: 
221:           @active = true
222:         end
223:       end

[Source]

     # File lib/xmpp4r/bytestreams/helper/ibb/base.rb, line 225
225:       def deactivate
226:         if active?
227:           @stream.delete_message_callback(self)
228:           @stream.delete_iq_callback(self)
229: 
230:           @active = false
231:         end
232:       end

Send data directly

data:[String]

[Source]

     # File lib/xmpp4r/bytestreams/helper/ibb/base.rb, line 149
149:       def send_data(databuf)
150:         if active?
151:           msg = Message.new
152:           msg.from = @my_jid
153:           msg.to = @peer_jid
154:           
155:           data = msg.add REXML::Element.new('data')
156:           data.add_namespace NS_IBB
157:           data.attributes['sid'] = @session_id
158:           data.attributes['seq'] = @seq_send.to_s
159:           data.text = Base64::encode64 databuf
160: 
161:           # TODO: Implement AMP correctly
162:           amp = msg.add REXML::Element.new('amp')
163:           amp.add_namespace 'http://jabber.org/protocol/amp'
164:           deliver_at = amp.add REXML::Element.new('rule')
165:           deliver_at.attributes['condition'] = 'deliver-at'
166:           deliver_at.attributes['value'] = 'stored'
167:           deliver_at.attributes['action'] = 'error'
168:           match_resource = amp.add REXML::Element.new('rule')
169:           match_resource.attributes['condition'] = 'match-resource'
170:           match_resource.attributes['value'] = 'exact'
171:           match_resource.attributes['action'] = 'error'
172:    
173:           @stream.send(msg)
174: 
175:           @seq_send += 1
176:           @seq_send = 0 if @seq_send > 65535
177:         else
178:           raise 'Attempt to send data when not activated'
179:         end
180:       end

[Validate]