Class Jabber::Bytestreams::IBB
In: lib/xmpp4r/bytestreams/helper/ibb/base.rb
Parent: Object
Message Presence XMPPStanza Iq XMPPElement ErrorResponse X IqQuery JabberError ComponentAuthenticationFailure ArgumentError InvalidChatState SOCKS5Error ServerError NoNameXmlnsRegistered ServerDisconnected ClientAuthenticationFailure Connection Client Component Connection Client Singleton IdGenerator Comparable JID Enumerable CallbackList Items Publish StandardError REXML::Element Stream XMPPElement Location IqFeature StreamHost IqSiFile IqSiFileRange IqSi StreamHostUsed XRosterItem RosterItem C Body HTML UserItem XMUCUserInvite Configuration Retract IqPubSub Item IqPubSubOwner Event Subscription Unsubscribe Tune XDataField XDataReported XDataTitle XDataInstructions Feature Item Identity IqVcard PubSub::ServiceHelper Helper Helper SOCKS5Bytestreams SOCKS5BytestreamsTarget SOCKS5BytestreamsInitiator SOCKS5BytestreamsServerStreamHost TCPSocket SOCKS5Socket IqQuery IqQueryBytestreams IqQueryRoster IqQueryVersion IqQueryRPC IqQueryMUCOwner IqQueryMUCAdmin IqQueryDiscoItems IqQueryDiscoInfo IqQueryLastActivity IBB IBBTarget IBBInitiator RosterXItem XRoster RosterX X XDelay XMUC XMUCUser XData Responder SimpleResponder Iq IqCommand XMLRPC::ParserWriterChooseMixin Client Server XMLRPC::ParseContentType XMLRPC::BasicServer MUCClient SimpleMUCClient MUC::UserItem XMUCUserItem IqQueryMUCAdminItem XParent SubscriptionConfig NodeConfig OwnerNodeConfig EventItems ServiceHelper OAuthServiceHelper NodeHelper EventItem Base Anonymous DigestMD5 Plain FileSource Base Bot Callback StreamParser Semaphore SOCKS5BytestreamsPeer SOCKS5BytestreamsServer IBBQueueItem Helper Responder Helper Listener MUCBrowser NodeBrowser ListenerMocker Helper Responder Helper Helper Helper lib/xmpp4r/message.rb lib/xmpp4r/connection.rb lib/xmpp4r/xmppstanza.rb lib/xmpp4r/iq.rb lib/xmpp4r/callbacks.rb lib/xmpp4r/idgenerator.rb lib/xmpp4r/stream.rb lib/xmpp4r/client.rb lib/xmpp4r/jid.rb lib/xmpp4r/x.rb lib/xmpp4r/streamparser.rb lib/xmpp4r/semaphore.rb lib/xmpp4r/errors.rb lib/xmpp4r/component.rb lib/xmpp4r/presence.rb lib/xmpp4r/xmppelement.rb lib/xmpp4r/query.rb XParent lib/xmpp4r/location/helper/helper.rb lib/xmpp4r/location/location.rb UserLocation lib/xmpp4r/feature_negotiation/iq/feature.rb FeatureNegotiation lib/xmpp4r/bytestreams/iq/si.rb lib/xmpp4r/bytestreams/helper/ibb/initiator.rb lib/xmpp4r/bytestreams/helper/socks5bytestreams/base.rb lib/xmpp4r/bytestreams/iq/bytestreams.rb lib/xmpp4r/bytestreams/helper/socks5bytestreams/initiator.rb lib/xmpp4r/bytestreams/helper/socks5bytestreams/target.rb lib/xmpp4r/bytestreams/helper/socks5bytestreams/socks5.rb lib/xmpp4r/bytestreams/helper/ibb/target.rb lib/xmpp4r/bytestreams/helper/socks5bytestreams/server.rb lib/xmpp4r/bytestreams/helper/ibb/base.rb Bytestreams lib/xmpp4r/roster/x/roster.rb lib/xmpp4r/roster/helper/roster.rb lib/xmpp4r/roster/iq/roster.rb Roster lib/xmpp4r/version/helper/responder.rb lib/xmpp4r/version/helper/simpleresponder.rb lib/xmpp4r/version/iq/version.rb Version lib/xmpp4r/command/iq/command.rb lib/xmpp4r/command/helper/responder.rb Command lib/xmpp4r/caps/helper/helper.rb lib/xmpp4r/caps/c.rb Caps lib/xmpp4r/reliable.rb Reliable lib/xmpp4r/delay/x/delay.rb Delay lib/xmpp4r/xhtml/html.rb XHTML lib/xmpp4r/rpc/helper/server.rb lib/xmpp4r/rpc/helper/client.rb lib/xmpp4r/rpc/iq/rpc.rb RPC lib/xmpp4r/muc/iq/mucadminitem.rb lib/xmpp4r/muc/x/muc.rb lib/xmpp4r/muc/item.rb lib/xmpp4r/muc/helper/simplemucclient.rb lib/xmpp4r/muc/iq/mucadmin.rb lib/xmpp4r/muc/helper/mucbrowser.rb lib/xmpp4r/muc/x/mucuseritem.rb lib/xmpp4r/muc/x/mucuserinvite.rb lib/xmpp4r/muc/iq/mucowner.rb lib/xmpp4r/muc/helper/mucclient.rb MUC lib/xmpp4r/pubsub/children/item.rb lib/xmpp4r/pubsub/children/configuration.rb lib/xmpp4r/pubsub/children/subscription.rb lib/xmpp4r/pubsub/helper/servicehelper.rb lib/xmpp4r/pubsub/children/unsubscribe.rb lib/xmpp4r/pubsub/children/publish.rb lib/xmpp4r/pubsub/helper/oauth_service_helper.rb lib/xmpp4r/pubsub/children/event.rb lib/xmpp4r/pubsub/iq/pubsub.rb lib/xmpp4r/pubsub/children/retract.rb lib/xmpp4r/pubsub/helper/nodebrowser.rb lib/xmpp4r/pubsub/helper/nodehelper.rb lib/xmpp4r/pubsub/children/items.rb lib/xmpp4r/pubsub/children/subscription_config.rb lib/xmpp4r/pubsub/children/node_config.rb OAuthPubSubStreamHelper PubSub lib/xmpp4r/httpbinding/client.rb HTTPBinding lib/xmpp4r/tune/helper/helper.rb lib/xmpp4r/tune/tune.rb UserTune lib/xmpp4r/sasl.rb SASL lib/xmpp4r/test/listener_mocker.rb Test lib/xmpp4r/dataforms/x/data.rb Dataforms lib/xmpp4r/discovery/helper/helper.rb lib/xmpp4r/discovery/iq/discoinfo.rb lib/xmpp4r/discovery/helper/responder.rb lib/xmpp4r/discovery/iq/discoitems.rb Discovery lib/xmpp4r/bytestreams/helper/filetransfer.rb TransferSource FileTransfer lib/xmpp4r/last/helper/helper.rb lib/xmpp4r/last/iq/last.rb LastActivity lib/xmpp4r/framework/base.rb lib/xmpp4r/framework/bot.rb Framework lib/xmpp4r/vcard/helper/vcard.rb lib/xmpp4r/vcard/iq/vcard.rb Vcard Jabber dot/m_110_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 ServerError

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

[Source]

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

Send data directly

data:[String]

[Source]

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

[Validate]