def test(q, bus, conn, stream, bytestream_cls, address_type, access_control, access_control_param): if bytestream_cls in [BytestreamS5BRelay, BytestreamS5BRelayBugged]: # disable SOCKS5 relay tests because proxy can't be used with muc # contacts atm return iq_event = q.expect('stream-iq', to=None, query_ns='vcard-temp', query_name='vCard') acknowledge_iq(stream, iq_event.stanza) t.check_conn_properties(q, conn) bob_handle = conn.get_contact_handle_sync('[email protected]/bob') address = t.create_server(q, address_type) def new_chan_predicate(e): types = [] for _, props in e.args[0]: types.append(props[cs.CHANNEL_TYPE]) return cs.CHANNEL_TYPE_STREAM_TUBE in types def find_stream_tube(channels): for path, props in channels: if props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_STREAM_TUBE: return path, props return None, None # offer a stream tube to another room (new API) address = t.create_server(q, address_type, block_reading=True) request = { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_STREAM_TUBE, cs.TARGET_HANDLE_TYPE: cs.HT_ROOM, cs.TARGET_ID: '*****@*****.**', cs.STREAM_TUBE_SERVICE: 'newecho', } _, new_tube_path, new_tube_props = \ join_muc(q, bus, conn, stream, '*****@*****.**', request) e = q.expect('dbus-signal', signal='NewChannels', predicate=new_chan_predicate) path, prop = find_stream_tube(e.args[0]) assert prop[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_STREAM_TUBE assert prop[cs.INITIATOR_ID] == '[email protected]/test' assert prop[cs.REQUESTED] == True assert prop[cs.TARGET_HANDLE_TYPE] == cs.HT_ROOM assert prop[cs.TARGET_ID] == '*****@*****.**' assert prop[cs.STREAM_TUBE_SERVICE] == 'newecho' # check that the tube channel is in the channels list all_channels = conn.Get(cs.CONN_IFACE_REQUESTS, 'Channels', dbus_interface=cs.PROPERTIES_IFACE, byte_arrays=True) assertContains((path, prop), all_channels) tube_chan = wrap_channel(bus.get_object(conn.bus_name, path), 'StreamTube') tube_props = tube_chan.GetAll(cs.CHANNEL_IFACE_TUBE, dbus_interface=cs.PROPERTIES_IFACE) assert tube_props['State'] == cs.TUBE_CHANNEL_STATE_NOT_OFFERED # offer the tube call_async(q, tube_chan.StreamTube, 'Offer', address_type, address, access_control, {'foo': 'bar'}) stream_event, _, status_event = q.expect_many( EventPattern('stream-presence', to='[email protected]/test', predicate=lambda e: t.presence_contains_tube(e)), EventPattern('dbus-return', method='Offer'), EventPattern('dbus-signal', signal='TubeChannelStateChanged', args=[cs.TUBE_CHANNEL_STATE_OPEN])) tube_self_handle = tube_chan.Properties.Get(cs.CHANNEL_IFACE_GROUP, 'SelfHandle') assert conn.inspect_contact_sync( tube_self_handle) == '[email protected]/test' presence = stream_event.stanza tubes_nodes = xpath.queryForNodes( '/presence/tubes[@xmlns="%s"]' % ns.TUBES, presence) assert tubes_nodes is not None assert len(tubes_nodes) == 1 stream_tube_id = 666 tube_nodes = xpath.queryForNodes('/tubes/tube', tubes_nodes[0]) assert tube_nodes is not None assert len(tube_nodes) == 1 for tube in tube_nodes: assert tube['type'] == 'stream' assert not tube.hasAttribute('initiator') assert tube['service'] == 'newecho' assert not tube.hasAttribute('stream-id') assert not tube.hasAttribute('dbus-name') stream_tube_id = int(tube['id']) params = {} parameter_nodes = xpath.queryForNodes('/tube/parameters/parameter', tube) for node in parameter_nodes: assert node['name'] not in params params[node['name']] = (node['type'], str(node)) assert params == {'foo': ('str', 'bar')} bob_handle = conn.get_contact_handle_sync('[email protected]/bob') bytestream = connect_to_tube(stream, q, bytestream_cls, '*****@*****.**', stream_tube_id) iq_event, socket_event, conn_event = q.expect_many( EventPattern('stream-iq', iq_type='result'), EventPattern('socket-connected'), EventPattern('dbus-signal', signal='NewRemoteConnection', interface=cs.CHANNEL_TYPE_STREAM_TUBE)) handle, access, conn_id = conn_event.args assert handle == bob_handle protocol = socket_event.protocol # start to read from the transport so we can read the control byte protocol.transport.startReading() t.check_new_connection_access(q, access_control, access, protocol) # handle iq_event bytestream.check_si_reply(iq_event.stanza) tube = xpath.queryForNodes('/iq//si/tube[@xmlns="%s"]' % ns.TUBES, iq_event.stanza) assert len(tube) == 1 use_tube(q, bytestream, protocol, conn_id) tube_chan.Channel.Close() q.expect_many(EventPattern('dbus-signal', signal='Closed'), EventPattern('dbus-signal', signal='ChannelClosed')) t.cleanup()
def test(q, bus, conn, stream, bytestream_cls, address_type, access_control, access_control_param): address1 = t.set_up_echo(q, address_type, True, streamfile='stream') address2 = t.set_up_echo(q, address_type, True, streamfile='stream2') t.check_conn_properties(q, conn) vcard_event, roster_event = q.expect_many( EventPattern('stream-iq', to=None, query_ns='vcard-temp', query_name='vCard'), EventPattern('stream-iq', query_ns=ns.ROSTER)) self_handle = conn.GetSelfHandle() acknowledge_iq(stream, vcard_event.stanza) roster = roster_event.stanza roster['type'] = 'result' item = roster_event.query.addElement('item') item['jid'] = 'bob@localhost' # Bob can do tubes item['subscription'] = 'both' stream.send(roster) bob_full_jid = 'bob@localhost/Bob' self_full_jid = 'test@localhost/Resource' # Send Bob presence and his tube caps presence = domish.Element(('jabber:client', 'presence')) presence['from'] = bob_full_jid presence['to'] = self_full_jid c = presence.addElement('c') c['xmlns'] = 'http://jabber.org/protocol/caps' c['node'] = 'http://example.com/ICantBelieveItsNotTelepathy' c['ver'] = '1.2.3' stream.send(presence) event = q.expect('stream-iq', iq_type='get', query_ns='http://jabber.org/protocol/disco#info', to=bob_full_jid) assert event.query['node'] == \ 'http://example.com/ICantBelieveItsNotTelepathy#1.2.3' result = make_result_iq(stream, event.stanza) query = result.firstChildElement() feature = query.addElement('feature') feature['var'] = ns.TUBES stream.send(result) # A tube request can be done only if the contact has tube capabilities # Ensure that Bob's caps have been received sync_stream(q, stream) # Also ensure that all the new contact list channels have been announced, # so that the NewChannel(s) signals we look for after calling # RequestChannel are the ones we wanted. sync_dbus(bus, q, conn) # Test tubes with Bob. Bob has tube capabilities. bob_handle = conn.RequestHandles(1, ['bob@localhost'])[0] # old tubes API call_async(q, conn, 'RequestChannel', cs.CHANNEL_TYPE_TUBES, cs.HT_CONTACT, bob_handle, True) ret, old_sig, new_sig = q.expect_many( EventPattern('dbus-return', method='RequestChannel'), EventPattern('dbus-signal', signal='NewChannel'), EventPattern('dbus-signal', signal='NewChannels'), ) assert len(ret.value) == 1 chan_path = ret.value[0] t.check_NewChannel_signal(old_sig.args, cs.CHANNEL_TYPE_TUBES, chan_path, bob_handle, True) t.check_NewChannels_signal(conn, new_sig.args, cs.CHANNEL_TYPE_TUBES, chan_path, bob_handle, 'bob@localhost', self_handle) old_tubes_channel_properties = new_sig.args[0][0] t.check_conn_properties(q, conn, [old_tubes_channel_properties]) # Try CreateChannel with correct properties # Gabble must succeed call_async(q, conn.Requests, 'CreateChannel', {cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_STREAM_TUBE, cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT, cs.TARGET_HANDLE: bob_handle, cs.STREAM_TUBE_SERVICE: "newecho", }) # the NewTube signal (old API) is not fired now as the tube wasn't offered # yet ret, old_sig, new_sig = q.expect_many( EventPattern('dbus-return', method='CreateChannel'), EventPattern('dbus-signal', signal='NewChannel'), EventPattern('dbus-signal', signal='NewChannels'), ) assert len(ret.value) == 2 # CreateChannel returns 2 values: o, a{sv} new_chan_path = ret.value[0] new_chan_prop_asv = ret.value[1] # State and Parameters are mutables so not announced assert cs.TUBE_STATE not in new_chan_prop_asv assert cs.TUBE_PARAMETERS not in new_chan_prop_asv assert new_chan_path.find("StreamTube") != -1, new_chan_path assert new_chan_path.find("SITubesChannel") == -1, new_chan_path # The path of the Channel.Type.Tubes object MUST be different to the path # of the Channel.Type.StreamTube object ! assert chan_path != new_chan_path new_tube_chan = bus.get_object(conn.bus_name, new_chan_path) new_tube_iface = dbus.Interface(new_tube_chan, cs.CHANNEL_TYPE_STREAM_TUBE) # check State and Parameters new_tube_props = new_tube_chan.GetAll(cs.CHANNEL_IFACE_TUBE, dbus_interface=cs.PROPERTIES_IFACE) # the tube created using the new API is in the "not offered" state assert new_tube_props['State'] == cs.TUBE_CHANNEL_STATE_NOT_OFFERED t.check_NewChannel_signal(old_sig.args, cs.CHANNEL_TYPE_STREAM_TUBE, new_chan_path, bob_handle, True) t.check_NewChannels_signal(conn, new_sig.args, cs.CHANNEL_TYPE_STREAM_TUBE, new_chan_path, bob_handle, 'bob@localhost', self_handle) stream_tube_channel_properties = new_sig.args[0][0] assert cs.TUBE_STATE not in stream_tube_channel_properties assert cs.TUBE_PARAMETERS not in stream_tube_channel_properties t.check_conn_properties(q, conn, [old_tubes_channel_properties, stream_tube_channel_properties]) tubes_chan = bus.get_object(conn.bus_name, chan_path) tubes_iface = dbus.Interface(tubes_chan, cs.CHANNEL_TYPE_TUBES) t.check_channel_properties(q, bus, conn, tubes_chan, cs.CHANNEL_TYPE_TUBES, bob_handle, "bob@localhost") # Create another tube using old API call_async(q, tubes_iface, 'OfferStreamTube', 'echo', sample_parameters, address_type, address1, access_control, access_control_param) event, return_event, new_chan, new_chans = q.expect_many( EventPattern('stream-message'), EventPattern('dbus-return', method='OfferStreamTube'), EventPattern('dbus-signal', signal='NewChannel'), EventPattern('dbus-signal', signal='NewChannels')) message = event.stanza assert message['to'] == bob_full_jid tube_nodes = xpath.queryForNodes('/message/tube[@xmlns="%s"]' % ns.TUBES, message) assert tube_nodes is not None assert len(tube_nodes) == 1 tube = tube_nodes[0] assert tube['service'] == 'echo' assert tube['type'] == 'stream' assert not tube.hasAttribute('initiator') stream_tube_id = long(tube['id']) params = {} parameter_nodes = xpath.queryForNodes('/tube/parameters/parameter', tube) for node in parameter_nodes: assert node['name'] not in params params[node['name']] = (node['type'], str(node)) assert params == {'ay': ('bytes', 'aGVsbG8='), 's': ('str', 'hello'), 'i': ('int', '-123'), 'u': ('uint', '123'), } # the tube channel (new API) is announced t.check_NewChannel_signal(new_chan.args, cs.CHANNEL_TYPE_STREAM_TUBE, None, bob_handle, False) t.check_NewChannels_signal(conn, new_chans.args, cs.CHANNEL_TYPE_STREAM_TUBE, new_chan.args[0], bob_handle, "bob@localhost", self_handle) props = new_chans.args[0][0][1] assert cs.TUBE_STATE not in props assert cs.TUBE_PARAMETERS not in props # We offered a tube using the old tube API and created one with the new # API, so there are 2 tubes. Check the new tube API works assert len(filter(lambda x: x[1] == cs.CHANNEL_TYPE_TUBES, conn.ListChannels())) == 1 channels = filter(lambda x: x[1] == cs.CHANNEL_TYPE_STREAM_TUBE and x[0] == new_chan_path, conn.ListChannels()) assert len(channels) == 1 assert new_chan_path == channels[0][0] old_tube_chan = bus.get_object(conn.bus_name, new_chan.args[0]) tube_basic_props = old_tube_chan.GetAll(cs.CHANNEL, dbus_interface=cs.PROPERTIES_IFACE) assert tube_basic_props.get("InitiatorHandle") == self_handle stream_tube_props = old_tube_chan.GetAll(cs.CHANNEL_TYPE_STREAM_TUBE, dbus_interface=cs.PROPERTIES_IFACE) assert stream_tube_props.get("Service") == "echo", stream_tube_props old_tube_props = old_tube_chan.GetAll(cs.CHANNEL_IFACE_TUBE, dbus_interface=cs.PROPERTIES_IFACE, byte_arrays=True) assert old_tube_props.get("Parameters") == dbus.Dictionary(sample_parameters) # Tube have been created using the old API and so is already offered assert old_tube_props['State'] == cs.TUBE_CHANNEL_STATE_REMOTE_PENDING t.check_channel_properties(q, bus, conn, tubes_chan, cs.CHANNEL_TYPE_TUBES, bob_handle, "bob@localhost") t.check_channel_properties(q, bus, conn, old_tube_chan, cs.CHANNEL_TYPE_STREAM_TUBE, bob_handle, "bob@localhost", cs.TUBE_CHANNEL_STATE_REMOTE_PENDING) # Offer the first tube created (new API) call_async(q, new_tube_iface, 'Offer', address_type, address2, access_control, new_sample_parameters) msg_event, new_tube_sig, state_event = q.expect_many( EventPattern('stream-message'), EventPattern('dbus-signal', signal='NewTube'), EventPattern('dbus-signal', signal='TubeChannelStateChanged')) assert state_event.args[0] == cs.TUBE_CHANNEL_STATE_REMOTE_PENDING message = msg_event.stanza assert message['to'] == bob_full_jid tube_nodes = xpath.queryForNodes('/message/tube[@xmlns="%s"]' % ns.TUBES, message) assert tube_nodes is not None assert len(tube_nodes) == 1 tube = tube_nodes[0] assert tube['service'] == 'newecho' assert tube['type'] == 'stream' assert not tube.hasAttribute('initiator') new_stream_tube_id = long(tube['id']) params = {} parameter_nodes = xpath.queryForNodes('/tube/parameters/parameter', tube) for node in parameter_nodes: assert node['name'] not in params params[node['name']] = (node['type'], str(node)) assert params == {'ay': ('bytes', 'bmV3aGVsbG8='), 's': ('str', 'newhello'), 'i': ('int', '-123'), 'u': ('uint', '123'), } # check NewTube signal (old API) id, initiator_handle, type, service, params, state = new_tube_sig.args assert initiator_handle == self_handle assert type == 1 # stream assert service == 'newecho' assert params == new_sample_parameters assert state == 1 # remote pending # The new tube has been offered, the parameters cannot be changed anymore # We need to use call_async to check the error tube_prop_iface = dbus.Interface(old_tube_chan, cs.PROPERTIES_IFACE) call_async(q, tube_prop_iface, 'Set', cs.CHANNEL_IFACE_TUBE, 'Parameters', dbus.Dictionary( {dbus.String(u'foo2'): dbus.String(u'bar2')}, signature=dbus.Signature('sv')), dbus_interface=cs.PROPERTIES_IFACE) set_error = q.expect('dbus-error') # check it is *not* correctly changed new_tube_props = new_tube_chan.GetAll(cs.CHANNEL_IFACE_TUBE, dbus_interface=cs.PROPERTIES_IFACE, byte_arrays=True) assert new_tube_props.get("Parameters") == new_sample_parameters, \ new_tube_props.get("Parameters") # The CM is the server, so fake a client wanting to talk to it # Old API tube bytestream1 = bytestream_cls(stream, q, 'alpha', bob_full_jid, self_full_jid, True) iq, si = bytestream1.create_si_offer(ns.TUBES) stream_node = si.addElement((ns.TUBES, 'stream')) stream_node['tube'] = str(stream_tube_id) stream.send(iq) si_reply_event, _, _, new_conn_event, socket_event = q.expect_many( EventPattern('stream-iq', iq_type='result'), EventPattern('dbus-signal', signal='TubeStateChanged', args=[stream_tube_id, cs.TUBE_STATE_OPEN]), EventPattern('dbus-signal', signal='StreamTubeNewConnection', args=[stream_tube_id, bob_handle]), EventPattern('dbus-signal', signal='NewRemoteConnection'), EventPattern('socket-connected')) bytestream1.check_si_reply(si_reply_event.stanza) tube = xpath.queryForNodes('/iq/si/tube[@xmlns="%s"]' % ns.TUBES, si_reply_event.stanza) assert len(tube) == 1 handle, access, id = new_conn_event.args assert handle == bob_handle protocol = socket_event.protocol # we don't want to echo the access control byte protocol.echoed = False # start to read from the transport so we can read the control byte protocol.transport.startReading() t.check_new_connection_access(q, access_control, access, protocol) protocol.echoed = True expected_tube = (stream_tube_id, self_handle, cs.TUBE_TYPE_STREAM, 'echo', sample_parameters, cs.TUBE_STATE_OPEN) tubes = tubes_iface.ListTubes(byte_arrays=True) t.check_tube_in_tubes(expected_tube, tubes) # The CM is the server, so fake a client wanting to talk to it # New API tube bytestream2 = bytestream_cls(stream, q, 'beta', bob_full_jid, self_full_jid, True) iq, si = bytestream2.create_si_offer(ns.TUBES) stream_node = si.addElement((ns.TUBES, 'stream')) stream_node['tube'] = str(new_stream_tube_id) stream.send(iq) si_reply_event, _, new_conn_event, socket_event = q.expect_many( EventPattern('stream-iq', iq_type='result'), EventPattern('dbus-signal', signal='TubeChannelStateChanged', args=[cs.TUBE_STATE_OPEN]), EventPattern('dbus-signal', signal='NewRemoteConnection'), EventPattern('socket-connected')) bytestream2.check_si_reply(si_reply_event.stanza) tube = xpath.queryForNodes('/iq/si/tube[@xmlns="%s"]' % ns.TUBES, si_reply_event.stanza) assert len(tube) == 1 handle, access, conn_id = new_conn_event.args assert handle == bob_handle protocol = socket_event.protocol # we don't want to echo the access control byte protocol.echoed = False # start to read from the transport so we can read the control byte protocol.transport.startReading() t.check_new_connection_access(q, access_control, access, protocol) protocol.echoed = True expected_tube = (new_stream_tube_id, self_handle, cs.TUBE_TYPE_STREAM, 'newecho', new_sample_parameters, cs.TUBE_STATE_OPEN) t.check_tube_in_tubes (expected_tube, tubes_iface.ListTubes(byte_arrays=True)) # have the fake client open the stream bytestream1.open_bytestream() # have the fake client send us some data data = 'hello, world' bytestream1.send_data(data) binary = bytestream1.get_data(len(data)) assert binary == data, binary # have the fake client open the stream bytestream2.open_bytestream() # have the fake client send us some data data = 'hello, new world' bytestream2.send_data(data) binary = bytestream2.get_data(len(data)) assert binary == data, binary # peer closes the bytestream bytestream2.close() e = q.expect('dbus-signal', signal='ConnectionClosed') assertEquals(conn_id, e.args[0]) assertEquals(cs.CONNECTION_LOST, e.args[1]) t.cleanup()
def test(q, bus, conn, stream): vcard_event, roster_event = q.expect_many( EventPattern('stream-iq', to=None, query_ns='vcard-temp', query_name='vCard'), EventPattern('stream-iq', query_ns=ns.ROSTER)) acknowledge_iq(stream, vcard_event.stanza) # Send a roster with one member, Joe. roster = roster_event.stanza roster['type'] = 'result' item = roster_event.query.addElement('item') item['jid'] = 'joe@localhost' item['subscription'] = 'both' stream.send(roster) # Send Joe's presence. presence = domish.Element(('jabber:client', 'presence')) presence['from'] = 'joe@localhost/Joe' presence['to'] = 'test@localhost/Resource' c = presence.addElement('c') c['xmlns'] = 'http://jabber.org/protocol/caps' c['node'] = 'http://example.com/IDontSupportTubes' c['ver'] = '1.0' stream.send(presence) # Gabble discoes Joe, because it doesn't know his client's caps event = q.expect('stream-iq', iq_type='get', query_ns='http://jabber.org/protocol/disco#info', to='joe@localhost/Joe') assert event.query['node'] == 'http://example.com/IDontSupportTubes#1.0' # Send a "Joe doesn't have any caps" response. result = event.stanza result['type'] = 'result' stream.send(result) # Ensure Joe's caps have been received. # FIXME: we shouldn't need to do this, the tubes code should wait for the # caps to appear, just like the StreamedMedia channel does. sync_stream(q, stream) address = t.create_server(q, cs.SOCKET_ADDRESS_TYPE_IPV4) # Now we try making new-style DBusTube and StreamTube channels, and calling # the relevant Offer method on them; this should fail with NotAvailable. # FIXME: I think this should be NotCapable st_path, _ = conn.Requests.CreateChannel( props(cs.CHANNEL_TYPE_STREAM_TUBE, {cs.STREAM_TUBE_SERVICE: "newecho"})) st_chan = bus.get_object(conn.bus_name, st_path) st = dbus.Interface(st_chan, cs.CHANNEL_TYPE_STREAM_TUBE) call_async(q, st, 'Offer', cs.SOCKET_ADDRESS_TYPE_IPV4, address, cs.SOCKET_ACCESS_CONTROL_LOCALHOST, {}) e = q.expect('dbus-error', method='Offer').error assert e.get_dbus_name() == cs.NOT_AVAILABLE, e.get_dbus_name() dt_path, _ = conn.Requests.CreateChannel( props(cs.CHANNEL_TYPE_DBUS_TUBE, {cs.DBUS_TUBE_SERVICE_NAME: "com.newecho"})) dt_chan = bus.get_object(conn.bus_name, dt_path) dt = dbus.Interface(dt_chan, cs.CHANNEL_TYPE_DBUS_TUBE) call_async(q, dt, 'Offer', {}, cs.SOCKET_ACCESS_CONTROL_CREDENTIALS) e = q.expect('dbus-error', method='Offer').error assert e.get_dbus_name() == cs.NOT_AVAILABLE, e.get_dbus_name() t.cleanup()
def test(q, bus, conn, stream, bytestream_cls, address_type, access_control, access_control_param): if bytestream_cls in [BytestreamS5BRelay, BytestreamS5BRelayBugged]: # disable SOCKS5 relay tests because proxy can't be used with muc # contacts atm return iq_event = q.expect('stream-iq', to=None, query_ns='vcard-temp', query_name='vCard') acknowledge_iq(stream, iq_event.stanza) t.check_conn_properties(q, conn) bob_handle = conn.get_contact_handle_sync('[email protected]/bob') address = t.create_server(q, address_type) def new_chan_predicate(e): types = [] for _, props in e.args[0]: types.append(props[cs.CHANNEL_TYPE]) return cs.CHANNEL_TYPE_STREAM_TUBE in types def find_stream_tube(channels): for path, props in channels: if props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_STREAM_TUBE: return path, props return None, None # offer a stream tube to another room (new API) address = t.create_server(q, address_type, block_reading=True) request = { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_STREAM_TUBE, cs.TARGET_HANDLE_TYPE: cs.HT_ROOM, cs.TARGET_ID: '*****@*****.**', cs.STREAM_TUBE_SERVICE: 'newecho', } _, new_tube_path, new_tube_props = \ join_muc(q, bus, conn, stream, '*****@*****.**', request) e = q.expect('dbus-signal', signal='NewChannels', predicate=new_chan_predicate) path, prop = find_stream_tube(e.args[0]) assert prop[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_STREAM_TUBE assert prop[cs.INITIATOR_ID] == '[email protected]/test' assert prop[cs.REQUESTED] == True assert prop[cs.TARGET_HANDLE_TYPE] == cs.HT_ROOM assert prop[cs.TARGET_ID] == '*****@*****.**' assert prop[cs.STREAM_TUBE_SERVICE] == 'newecho' # check that the tube channel is in the channels list all_channels = conn.Get(cs.CONN_IFACE_REQUESTS, 'Channels', dbus_interface=cs.PROPERTIES_IFACE, byte_arrays=True) assertContains((path, prop), all_channels) tube_chan = wrap_channel(bus.get_object(conn.bus_name, path), 'StreamTube') tube_props = tube_chan.GetAll(cs.CHANNEL_IFACE_TUBE, dbus_interface=cs.PROPERTIES_IFACE) assert tube_props['State'] == cs.TUBE_CHANNEL_STATE_NOT_OFFERED # offer the tube call_async(q, tube_chan.StreamTube, 'Offer', address_type, address, access_control, {'foo': 'bar'}) stream_event, _, status_event = q.expect_many( EventPattern('stream-presence', to='[email protected]/test', predicate=lambda e: t.presence_contains_tube(e)), EventPattern('dbus-return', method='Offer'), EventPattern('dbus-signal', signal='TubeChannelStateChanged', args=[cs.TUBE_CHANNEL_STATE_OPEN])) tube_self_handle = tube_chan.Properties.Get(cs.CHANNEL_IFACE_GROUP, 'SelfHandle') assert conn.inspect_contact_sync(tube_self_handle) == '[email protected]/test' presence = stream_event.stanza tubes_nodes = xpath.queryForNodes('/presence/tubes[@xmlns="%s"]' % ns.TUBES, presence) assert tubes_nodes is not None assert len(tubes_nodes) == 1 stream_tube_id = 666 tube_nodes = xpath.queryForNodes('/tubes/tube', tubes_nodes[0]) assert tube_nodes is not None assert len(tube_nodes) == 1 for tube in tube_nodes: assert tube['type'] == 'stream' assert not tube.hasAttribute('initiator') assert tube['service'] == 'newecho' assert not tube.hasAttribute('stream-id') assert not tube.hasAttribute('dbus-name') stream_tube_id = int(tube['id']) params = {} parameter_nodes = xpath.queryForNodes('/tube/parameters/parameter', tube) for node in parameter_nodes: assert node['name'] not in params params[node['name']] = (node['type'], str(node)) assert params == {'foo': ('str', 'bar')} bob_handle = conn.get_contact_handle_sync('[email protected]/bob') bytestream = connect_to_tube(stream, q, bytestream_cls, '*****@*****.**', stream_tube_id) iq_event, socket_event, conn_event = q.expect_many( EventPattern('stream-iq', iq_type='result'), EventPattern('socket-connected'), EventPattern('dbus-signal', signal='NewRemoteConnection', interface=cs.CHANNEL_TYPE_STREAM_TUBE)) handle, access, conn_id = conn_event.args assert handle == bob_handle protocol = socket_event.protocol # start to read from the transport so we can read the control byte protocol.transport.startReading() t.check_new_connection_access(q, access_control, access, protocol) # handle iq_event bytestream.check_si_reply(iq_event.stanza) tube = xpath.queryForNodes('/iq//si/tube[@xmlns="%s"]' % ns.TUBES, iq_event.stanza) assert len(tube) == 1 use_tube(q, bytestream, protocol, conn_id) tube_chan.Channel.Close() q.expect_many( EventPattern('dbus-signal', signal='Closed'), EventPattern('dbus-signal', signal='ChannelClosed')) t.cleanup()
def test(q, bus, conn, stream, bytestream_cls, address_type, access_control, access_control_param): address1 = t.set_up_echo(q, address_type, True, streamfile='stream') address2 = t.set_up_echo(q, address_type, True, streamfile='stream2') t.check_conn_properties(q, conn) vcard_event, roster_event = q.expect_many( EventPattern('stream-iq', to=None, query_ns='vcard-temp', query_name='vCard'), EventPattern('stream-iq', query_ns=ns.ROSTER)) self_handle = conn.Properties.Get(cs.CONN, "SelfHandle") acknowledge_iq(stream, vcard_event.stanza) roster = roster_event.stanza roster['type'] = 'result' item = roster_event.query.addElement('item') item['jid'] = 'bob@localhost' # Bob can do tubes item['subscription'] = 'both' stream.send(roster) bob_full_jid = 'bob@localhost/Bob' self_full_jid = 'test@localhost/Resource' # Send Bob presence and his tube caps presence = domish.Element(('jabber:client', 'presence')) presence['from'] = bob_full_jid presence['to'] = self_full_jid c = presence.addElement('c') c['xmlns'] = 'http://jabber.org/protocol/caps' c['node'] = 'http://example.com/ICantBelieveItsNotTelepathy' c['ver'] = '1.2.3' stream.send(presence) event = q.expect('stream-iq', iq_type='get', query_ns='http://jabber.org/protocol/disco#info', to=bob_full_jid) assert event.query['node'] == \ 'http://example.com/ICantBelieveItsNotTelepathy#1.2.3' result = make_result_iq(stream, event.stanza) query = result.firstChildElement() feature = query.addElement('feature') feature['var'] = ns.TUBES stream.send(result) # A tube request can be done only if the contact has tube capabilities # Ensure that Bob's caps have been received sync_stream(q, stream) # Also ensure that all the new contact list channels have been announced, # so that the NewChannel(s) signals we look for after calling # RequestChannel are the ones we wanted. sync_dbus(bus, q, conn) # Test tubes with Bob. Bob has tube capabilities. bob_handle = conn.get_contact_handle_sync('bob@localhost') # Try CreateChannel with correct properties # Gabble must succeed call_async( q, conn.Requests, 'CreateChannel', { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_STREAM_TUBE, cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT, cs.TARGET_HANDLE: bob_handle, cs.STREAM_TUBE_SERVICE: "newecho", }) def find_stream_tube(channels): for path, props in channels: if props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_STREAM_TUBE: return path, props return None, None def new_chan_predicate(e): path, _ = find_stream_tube(e.args[0]) return path is not None ret, new_sig = q.expect_many( EventPattern('dbus-return', method='CreateChannel'), EventPattern('dbus-signal', signal='NewChannels', predicate=new_chan_predicate), ) new_chan_path = ret.value[0] new_chan_prop_asv = ret.value[1] # State and Parameters are mutables so not announced assert cs.TUBE_STATE not in new_chan_prop_asv assert cs.TUBE_PARAMETERS not in new_chan_prop_asv assert new_chan_path.find("StreamTube") != -1, new_chan_path assert new_chan_path.find("SITubesChannel") == -1, new_chan_path new_tube_chan = bus.get_object(conn.bus_name, new_chan_path) new_tube_iface = dbus.Interface(new_tube_chan, cs.CHANNEL_TYPE_STREAM_TUBE) # check State and Parameters new_tube_props = new_tube_chan.GetAll(cs.CHANNEL_IFACE_TUBE, dbus_interface=cs.PROPERTIES_IFACE) # the tube created using the new API is in the "not offered" state assert new_tube_props['State'] == cs.TUBE_CHANNEL_STATE_NOT_OFFERED _, stream_tube_channel_properties = find_stream_tube(new_sig.args[0]) assert cs.TUBE_STATE not in stream_tube_channel_properties assert cs.TUBE_PARAMETERS not in stream_tube_channel_properties # Offer the first tube created call_async(q, new_tube_iface, 'Offer', address_type, address2, access_control, new_sample_parameters) msg_event, state_event = q.expect_many( EventPattern('stream-message'), EventPattern('dbus-signal', signal='TubeChannelStateChanged')) assert state_event.args[0] == cs.TUBE_CHANNEL_STATE_REMOTE_PENDING message = msg_event.stanza assert message['to'] == bob_full_jid tube_nodes = xpath.queryForNodes('/message/tube[@xmlns="%s"]' % ns.TUBES, message) assert tube_nodes is not None assert len(tube_nodes) == 1 tube = tube_nodes[0] assert tube['service'] == 'newecho' assert tube['type'] == 'stream' assert not tube.hasAttribute('initiator') stream_tube_id = long(tube['id']) params = {} parameter_nodes = xpath.queryForNodes('/tube/parameters/parameter', tube) for node in parameter_nodes: assert node['name'] not in params params[node['name']] = (node['type'], str(node)) assert params == { 'ay': ('bytes', 'bmV3aGVsbG8='), 's': ('str', 'newhello'), 'i': ('int', '-123'), 'u': ('uint', '123'), } # The new tube has been offered, the parameters cannot be changed anymore # We need to use call_async to check the error tube_prop_iface = dbus.Interface(new_tube_chan, cs.PROPERTIES_IFACE) call_async(q, tube_prop_iface, 'Set', cs.CHANNEL_IFACE_TUBE, 'Parameters', dbus.Dictionary({dbus.String(u'foo2'): dbus.String(u'bar2')}, signature=dbus.Signature('sv')), dbus_interface=cs.PROPERTIES_IFACE) set_error = q.expect('dbus-error') # check it is *not* correctly changed new_tube_props = new_tube_chan.GetAll(cs.CHANNEL_IFACE_TUBE, dbus_interface=cs.PROPERTIES_IFACE, byte_arrays=True) assert new_tube_props.get("Parameters") == new_sample_parameters, \ new_tube_props.get("Parameters") # The CM is the server, so fake a client wanting to talk to it # Old API tube bytestream1 = bytestream_cls(stream, q, 'alpha', bob_full_jid, self_full_jid, True) iq, si = bytestream1.create_si_offer(ns.TUBES) stream_node = si.addElement((ns.TUBES, 'stream')) stream_node['tube'] = str(stream_tube_id) stream.send(iq) si_reply_event, _, new_conn_event, socket_event = q.expect_many( EventPattern('stream-iq', iq_type='result'), EventPattern('dbus-signal', signal='TubeChannelStateChanged', args=[cs.TUBE_STATE_OPEN]), EventPattern('dbus-signal', signal='NewRemoteConnection'), EventPattern('socket-connected')) bytestream1.check_si_reply(si_reply_event.stanza) tube = xpath.queryForNodes('/iq/si/tube[@xmlns="%s"]' % ns.TUBES, si_reply_event.stanza) assert len(tube) == 1 handle, access, id = new_conn_event.args assert handle == bob_handle protocol = socket_event.protocol # we don't want to echo the access control byte protocol.echoed = False # start to read from the transport so we can read the control byte protocol.transport.startReading() t.check_new_connection_access(q, access_control, access, protocol) protocol.echoed = True # The CM is the server, so fake a client wanting to talk to it # New API tube bytestream2 = bytestream_cls(stream, q, 'beta', bob_full_jid, self_full_jid, True) iq, si = bytestream2.create_si_offer(ns.TUBES) stream_node = si.addElement((ns.TUBES, 'stream')) stream_node['tube'] = str(stream_tube_id) stream.send(iq) si_reply_event, new_conn_event, socket_event = q.expect_many( EventPattern('stream-iq', iq_type='result'), EventPattern('dbus-signal', signal='NewRemoteConnection'), EventPattern('socket-connected')) bytestream2.check_si_reply(si_reply_event.stanza) tube = xpath.queryForNodes('/iq/si/tube[@xmlns="%s"]' % ns.TUBES, si_reply_event.stanza) assert len(tube) == 1 handle, access, conn_id = new_conn_event.args assert handle == bob_handle protocol = socket_event.protocol # we don't want to echo the access control byte protocol.echoed = False # start to read from the transport so we can read the control byte protocol.transport.startReading() t.check_new_connection_access(q, access_control, access, protocol) protocol.echoed = True # have the fake client open the stream bytestream1.open_bytestream() # have the fake client send us some data data = 'hello, world' bytestream1.send_data(data) binary = bytestream1.get_data(len(data)) assert binary == data, binary # have the fake client open the stream bytestream2.open_bytestream() # have the fake client send us some data data = 'hello, new world' bytestream2.send_data(data) binary = bytestream2.get_data(len(data)) assert binary == data, binary # peer closes the bytestream bytestream2.close() e = q.expect('dbus-signal', signal='ConnectionClosed') assertEquals(conn_id, e.args[0]) assertEquals(cs.CONNECTION_LOST, e.args[1]) t.cleanup()
def test(q, bus, conn, stream): vcard_event, roster_event = q.expect_many( EventPattern('stream-iq', to=None, query_ns='vcard-temp', query_name='vCard'), EventPattern('stream-iq', query_ns=ns.ROSTER)) acknowledge_iq(stream, vcard_event.stanza) # Send a roster with one member, Joe. roster = roster_event.stanza roster['type'] = 'result' item = roster_event.query.addElement('item') item['jid'] = 'joe@localhost' item['subscription'] = 'both' stream.send(roster) # Send Joe's presence. presence = domish.Element(('jabber:client', 'presence')) presence['from'] = 'joe@localhost/Joe' presence['to'] = 'test@localhost/Resource' c = presence.addElement('c') c['xmlns'] = 'http://jabber.org/protocol/caps' c['node'] = 'http://example.com/IDontSupportTubes' c['ver'] = '1.0' stream.send(presence) # Gabble discoes Joe, because it doesn't know his client's caps event = q.expect('stream-iq', iq_type='get', query_ns='http://jabber.org/protocol/disco#info', to='joe@localhost/Joe') assert event.query['node'] == 'http://example.com/IDontSupportTubes#1.0' # Send a "Joe doesn't have any caps" response. result = event.stanza result['type'] = 'result' stream.send(result) # Ensure Joe's caps have been received. # FIXME: we shouldn't need to do this, the tubes code should wait for the # caps to appear, just like the StreamedMedia channel does. sync_stream(q, stream) requests = dbus.Interface(conn, cs.CONN_IFACE_REQUESTS) # First, we make an old-style Tubes channel, which should work; calling # OfferStreamTube or OfferDBusTube on it, however, should fail with # NotAvailable path, _ = requests.CreateChannel(props(cs.CHANNEL_TYPE_TUBES)) tubes = make_channel_proxy(conn, path, 'Channel.Type.Tubes') call_async(q, tubes, 'OfferDBusTube', 'com.example.monkeys', {}) e = q.expect('dbus-error', method='OfferDBusTube').error assert e.get_dbus_name() == cs.NOT_AVAILABLE, e.get_dbus_name() address = t.create_server(q, cs.SOCKET_ADDRESS_TYPE_IPV4) call_async(q, tubes, 'OfferStreamTube', 'echo', {}, cs.SOCKET_ADDRESS_TYPE_IPV4, address, cs.SOCKET_ACCESS_CONTROL_LOCALHOST, "") e = q.expect('dbus-error', method='OfferStreamTube').error assert e.get_dbus_name() == cs.NOT_AVAILABLE, e.get_dbus_name() # Now we try making new-style DBusTube and StreamTube channels, and calling # the relevant Offer method on them; this should fail with NotAvailable. # FIXME: I think this should be NotCapable st_path, _ = requests.CreateChannel(props(cs.CHANNEL_TYPE_STREAM_TUBE, {cs.STREAM_TUBE_SERVICE: "newecho"})) st_chan = bus.get_object(conn.bus_name, st_path) st = dbus.Interface(st_chan, cs.CHANNEL_TYPE_STREAM_TUBE) call_async(q, st, 'Offer', cs.SOCKET_ADDRESS_TYPE_IPV4, address, cs.SOCKET_ACCESS_CONTROL_LOCALHOST, {}) e = q.expect('dbus-error', method='Offer').error assert e.get_dbus_name() == cs.NOT_AVAILABLE, e.get_dbus_name() dt_path, _ = requests.CreateChannel(props(cs.CHANNEL_TYPE_DBUS_TUBE, { cs.DBUS_TUBE_SERVICE_NAME: "com.newecho" })) dt_chan = bus.get_object(conn.bus_name, dt_path) dt = dbus.Interface(dt_chan, cs.CHANNEL_TYPE_DBUS_TUBE) call_async(q, dt, 'Offer', {}, cs.SOCKET_ACCESS_CONTROL_CREDENTIALS) e = q.expect('dbus-error', method='Offer').error assert e.get_dbus_name() == cs.NOT_AVAILABLE, e.get_dbus_name() t.cleanup()
def test(q, bus, conn, stream, bytestream_cls, address_type, access_control, access_control_param): if bytestream_cls in [BytestreamS5BRelay, BytestreamS5BRelayBugged]: # disable SOCKS5 relay tests because proxy can't be used with muc # contacts atm return iq_event = q.expect('stream-iq', to=None, query_ns='vcard-temp', query_name='vCard') acknowledge_iq(stream, iq_event.stanza) self_handle = conn.GetSelfHandle() self_name = conn.InspectHandles(cs.HT_CONTACT, [self_handle])[0] t.check_conn_properties(q, conn) room_handle, tubes_chan, tubes_iface = get_muc_tubes_channel(q, bus, conn, stream, '*****@*****.**') tubes_self_handle = tubes_chan.GetSelfHandle(dbus_interface=cs.CHANNEL_IFACE_GROUP) bob_handle = conn.RequestHandles(cs.HT_CONTACT, ['[email protected]/bob'])[0] address = t.create_server(q, address_type) # offer stream tube (old API) using an Unix socket call_async(q, tubes_iface, 'OfferStreamTube', 'echo', sample_parameters, address_type, address, access_control, access_control_param) new_tube_event, stream_event, _, new_channels_event = q.expect_many( EventPattern('dbus-signal', signal='NewTube'), EventPattern('stream-presence', to='[email protected]/test'), EventPattern('dbus-return', method='OfferStreamTube'), EventPattern('dbus-signal', signal='NewChannels')) # handle new_tube_event stream_tube_id = new_tube_event.args[0] assert new_tube_event.args[1] == tubes_self_handle assert new_tube_event.args[2] == 1 # Stream assert new_tube_event.args[3] == 'echo' assert new_tube_event.args[4] == sample_parameters assert new_tube_event.args[5] == cs.TUBE_CHANNEL_STATE_OPEN # handle stream_event # We announce our newly created tube in our muc presence presence = stream_event.stanza tubes_nodes = xpath.queryForNodes('/presence/tubes[@xmlns="%s"]' % ns.TUBES, presence) assert tubes_nodes is not None assert len(tubes_nodes) == 1 tube_nodes = xpath.queryForNodes('/tubes/tube', tubes_nodes[0]) assert tube_nodes is not None assert len(tube_nodes) == 1 for tube in tube_nodes: assert tube['type'] == 'stream' assert not tube.hasAttribute('initiator') assert tube['service'] == 'echo' assert not tube.hasAttribute('stream-id') assert not tube.hasAttribute('dbus-name') assert tube['id'] == str(stream_tube_id) params = {} parameter_nodes = xpath.queryForNodes('/tube/parameters/parameter', tube) for node in parameter_nodes: assert node['name'] not in params params[node['name']] = (node['type'], str(node)) assert params == {'ay': ('bytes', 'aGVsbG8='), 's': ('str', 'hello'), 'i': ('int', '-123'), 'u': ('uint', '123'), } # tube is also announced using new API channels = new_channels_event.args[0] assert len(channels) == 1 path, props = channels[0] assert props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_STREAM_TUBE assert props[cs.INITIATOR_HANDLE] == tubes_self_handle assert props[cs.INITIATOR_ID] == '[email protected]/test' assert props[cs.INTERFACES] == [cs.CHANNEL_IFACE_GROUP, cs.CHANNEL_IFACE_TUBE] assert props[cs.REQUESTED] == True assert props[cs.TARGET_HANDLE] == room_handle assert props[cs.TARGET_ID] == '*****@*****.**' assert props[cs.STREAM_TUBE_SERVICE] == 'echo' tube_chan = bus.get_object(conn.bus_name, path) tube_props = tube_chan.GetAll(cs.CHANNEL_IFACE_TUBE, dbus_interface=cs.PROPERTIES_IFACE, byte_arrays=True) assert tube_props['Parameters'] == sample_parameters assert tube_props['State'] == cs.TUBE_CHANNEL_STATE_OPEN tubes = tubes_iface.ListTubes(byte_arrays=True) assert tubes == [( stream_tube_id, tubes_self_handle, 1, # Stream 'echo', sample_parameters, cs.TUBE_CHANNEL_STATE_OPEN )] assert len(tubes) == 1, unwrap(tubes) expected_tube = (stream_tube_id, tubes_self_handle, cs.TUBE_TYPE_STREAM, 'echo', sample_parameters, cs.TUBE_STATE_OPEN) t.check_tube_in_tubes(expected_tube, tubes) # FIXME: if we use an unknown JID here, everything fails # (the code uses lookup where it should use ensure) bytestream = connect_to_tube(stream, q, bytestream_cls, '*****@*****.**', stream_tube_id) iq_event, socket_event, _, conn_event = q.expect_many( EventPattern('stream-iq', iq_type='result'), EventPattern('socket-connected'), EventPattern('dbus-signal', signal='StreamTubeNewConnection', args=[stream_tube_id, bob_handle], interface=cs.CHANNEL_TYPE_TUBES), EventPattern('dbus-signal', signal='NewRemoteConnection', interface=cs.CHANNEL_TYPE_STREAM_TUBE)) protocol = socket_event.protocol # handle iq_event bytestream.check_si_reply(iq_event.stanza) tube = xpath.queryForNodes('/iq//si/tube[@xmlns="%s"]' % ns.TUBES, iq_event.stanza) assert len(tube) == 1 handle, access, conn_id = conn_event.args assert handle == bob_handle use_tube(q, bytestream, protocol, conn_id) # offer a stream tube to another room (new API) address = t.create_server(q, address_type, block_reading=True) request = { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_STREAM_TUBE, cs.TARGET_HANDLE_TYPE: cs.HT_ROOM, cs.TARGET_ID: '*****@*****.**', cs.STREAM_TUBE_SERVICE: 'newecho', } _, _, new_tube_path, new_tube_props = \ join_muc(q, bus, conn, stream, '*****@*****.**', request) # The order in which the NewChannels signals are fired is # undefined -- it could be the (tubes, text) channels first, or it # could be the tube channel first; so let's accept either order # here. first, second = q.expect_many( EventPattern('dbus-signal', signal='NewChannels'), EventPattern('dbus-signal', signal='NewChannels')) # NewChannels signal with the text and tubes channels together. def nc_textandtubes(event): channels = event.args[0] assert len(channels) == 2 path1, prop1 = channels[0] path2, prop2 = channels[1] assert sorted([prop1[cs.CHANNEL_TYPE], prop2[cs.CHANNEL_TYPE]]) == \ [cs.CHANNEL_TYPE_TEXT, cs.CHANNEL_TYPE_TUBES] got_text, got_tubes = False, False for path, props in channels: if props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_TEXT: got_text = True elif props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_TUBES: got_tubes = True else: assert False assert props[cs.INITIATOR_HANDLE] == self_handle assert props[cs.INITIATOR_ID] == self_name assert cs.CHANNEL_IFACE_GROUP in props[cs.INTERFACES] assert props[cs.TARGET_ID] == '*****@*****.**' assert props[cs.REQUESTED] == False assert (got_text, got_tubes) == (True, True) # NewChannels signal with the tube channel. def nc_tube(event): # FIXME: in this case, all channels should probably be announced together channels = event.args[0] assert len(channels) == 1 path, prop = channels[0] assert prop[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_STREAM_TUBE assert prop[cs.INITIATOR_ID] == '[email protected]/test' assert prop[cs.REQUESTED] == True assert prop[cs.TARGET_HANDLE_TYPE] == cs.HT_ROOM assert prop[cs.TARGET_ID] == '*****@*****.**' assert prop[cs.STREAM_TUBE_SERVICE] == 'newecho' return path, prop if len(first.args[0]) == 1: path, prop = nc_tube(first) nc_textandtubes(second) else: nc_textandtubes(first) path, prop = nc_tube(second) # check that the tube channel is in the channels list all_channels = conn.Get(cs.CONN_IFACE_REQUESTS, 'Channels', dbus_interface=cs.PROPERTIES_IFACE, byte_arrays=True) assertContains((path, prop), all_channels) tube_chan = bus.get_object(conn.bus_name, path) stream_tube_iface = dbus.Interface(tube_chan, cs.CHANNEL_TYPE_STREAM_TUBE) chan_iface = dbus.Interface(tube_chan, cs.CHANNEL) tube_props = tube_chan.GetAll(cs.CHANNEL_IFACE_TUBE, dbus_interface=cs.PROPERTIES_IFACE) assert tube_props['State'] == cs.TUBE_CHANNEL_STATE_NOT_OFFERED # offer the tube call_async(q, stream_tube_iface, 'Offer', address_type, address, access_control, {'foo': 'bar'}) new_tube_event, stream_event, _, status_event = q.expect_many( EventPattern('dbus-signal', signal='NewTube'), EventPattern('stream-presence', to='[email protected]/test'), EventPattern('dbus-return', method='Offer'), EventPattern('dbus-signal', signal='TubeChannelStateChanged', args=[cs.TUBE_CHANNEL_STATE_OPEN])) tube_self_handle = tube_chan.GetSelfHandle(dbus_interface=cs.CHANNEL_IFACE_GROUP) assert conn.InspectHandles(cs.HT_CONTACT, [tube_self_handle]) == ['[email protected]/test'] # handle new_tube_event stream_tube_id = new_tube_event.args[0] assert new_tube_event.args[2] == 1 # Stream assert new_tube_event.args[3] == 'newecho' assert new_tube_event.args[4] == {'foo': 'bar'} assert new_tube_event.args[5] == cs.TUBE_CHANNEL_STATE_OPEN presence = stream_event.stanza tubes_nodes = xpath.queryForNodes('/presence/tubes[@xmlns="%s"]' % ns.TUBES, presence) assert tubes_nodes is not None assert len(tubes_nodes) == 1 tube_nodes = xpath.queryForNodes('/tubes/tube', tubes_nodes[0]) assert tube_nodes is not None assert len(tube_nodes) == 1 for tube in tube_nodes: assert tube['type'] == 'stream' assert not tube.hasAttribute('initiator') assert tube['service'] == 'newecho' assert not tube.hasAttribute('stream-id') assert not tube.hasAttribute('dbus-name') assert tube['id'] == str(stream_tube_id) params = {} parameter_nodes = xpath.queryForNodes('/tube/parameters/parameter', tube) for node in parameter_nodes: assert node['name'] not in params params[node['name']] = (node['type'], str(node)) assert params == {'foo': ('str', 'bar')} bob_handle = conn.RequestHandles(cs.HT_CONTACT, ['[email protected]/bob'])[0] bytestream = connect_to_tube(stream, q, bytestream_cls, '*****@*****.**', stream_tube_id) iq_event, socket_event, conn_event = q.expect_many( EventPattern('stream-iq', iq_type='result'), EventPattern('socket-connected'), EventPattern('dbus-signal', signal='NewRemoteConnection', interface=cs.CHANNEL_TYPE_STREAM_TUBE)) handle, access, conn_id = conn_event.args assert handle == bob_handle protocol = socket_event.protocol # start to read from the transport so we can read the control byte protocol.transport.startReading() t.check_new_connection_access(q, access_control, access, protocol) # handle iq_event bytestream.check_si_reply(iq_event.stanza) tube = xpath.queryForNodes('/iq//si/tube[@xmlns="%s"]' % ns.TUBES, iq_event.stanza) assert len(tube) == 1 use_tube(q, bytestream, protocol, conn_id) chan_iface.Close() q.expect_many( EventPattern('dbus-signal', signal='Closed'), EventPattern('dbus-signal', signal='ChannelClosed')) t.cleanup()