Пример #1
0
    def test_mt_sms_queue_full(self):
        smpp_helper = yield self.get_smpp_helper()
        transport_config = smpp_helper.transport.get_static_config()
        msg = self.tx_helper.make_outbound('hello world')

        yield self.tx_helper.dispatch_outbound(msg)
        [submit_sm_pdu] = yield smpp_helper.wait_for_pdus(1)
        yield smpp_helper.handle_pdu(
            SubmitSMResp(sequence_number=seq_no(submit_sm_pdu),
                         message_id='foo',
                         command_status='ESME_RMSGQFUL'))

        self.clock.advance(transport_config.throttle_delay)

        [submit_sm_pdu_retry] = yield smpp_helper.wait_for_pdus(1)
        yield smpp_helper.handle_pdu(
            SubmitSMResp(sequence_number=seq_no(submit_sm_pdu_retry),
                         message_id='bar',
                         command_status='ESME_ROK'))

        self.assertTrue(seq_no(submit_sm_pdu_retry) > seq_no(submit_sm_pdu))
        self.assertEqual(short_message(submit_sm_pdu), 'hello world')
        self.assertEqual(short_message(submit_sm_pdu_retry), 'hello world')
        [event] = yield self.tx_helper.wait_for_dispatched_events(1)
        self.assertEqual(event['event_type'], 'ack')
        self.assertEqual(event['user_message_id'], msg['message_id'])
Пример #2
0
    def test_mt_sms_queue_full(self):
        smpp_helper = yield self.get_smpp_helper()
        transport_config = smpp_helper.transport.get_static_config()
        msg = self.tx_helper.make_outbound('hello world')

        yield self.tx_helper.dispatch_outbound(msg)
        [submit_sm_pdu] = yield smpp_helper.wait_for_pdus(1)
        yield smpp_helper.handle_pdu(
            SubmitSMResp(sequence_number=seq_no(submit_sm_pdu),
                         message_id='foo',
                         command_status='ESME_RMSGQFUL'))

        self.clock.advance(transport_config.throttle_delay)

        [submit_sm_pdu_retry] = yield smpp_helper.wait_for_pdus(1)
        yield smpp_helper.handle_pdu(
            SubmitSMResp(sequence_number=seq_no(submit_sm_pdu_retry),
                         message_id='bar',
                         command_status='ESME_ROK'))

        self.assertTrue(seq_no(submit_sm_pdu_retry) > seq_no(submit_sm_pdu))
        self.assertEqual(short_message(submit_sm_pdu), 'hello world')
        self.assertEqual(short_message(submit_sm_pdu_retry), 'hello world')
        [event] = yield self.tx_helper.wait_for_dispatched_events(1)
        self.assertEqual(event['event_type'], 'ack')
        self.assertEqual(event['user_message_id'], msg['message_id'])
Пример #3
0
 def test_unbind(self):
     calls = []
     self.patch(EsmeTransceiver, 'handle_unbind_resp',
                lambda p, pdu: calls.append(pdu))
     transport, protocol = yield self.setup_bind()
     yield protocol.unbind()
     [unbind_pdu] = yield wait_for_pdus(transport, 1)
     protocol.dataReceived(UnbindResp(seq_no(unbind_pdu)).get_bin())
     [unbind_resp_pdu] = calls
     self.assertEqual(seq_no(unbind_resp_pdu), seq_no(unbind_pdu))
Пример #4
0
 def test_unbind(self):
     protocol = yield self.get_protocol()
     calls = []
     protocol.handle_unbind_resp = calls.append
     yield self.fake_smsc.bind()
     yield protocol.unbind()
     unbind_pdu = yield self.fake_smsc.await_pdu()
     protocol.dataReceived(UnbindResp(seq_no(unbind_pdu)).get_bin())
     [unbind_resp_pdu] = calls
     self.assertEqual(seq_no(unbind_resp_pdu), seq_no(unbind_pdu))
Пример #5
0
    def test_mt_sms_throttle_while_throttled(self):
        smpp_helper = yield self.get_smpp_helper()
        transport_config = smpp_helper.transport.get_static_config()
        msg1 = self.tx_helper.make_outbound('hello world 1')
        msg2 = self.tx_helper.make_outbound('hello world 2')

        yield self.tx_helper.dispatch_outbound(msg1)
        yield self.tx_helper.dispatch_outbound(msg2)
        [ssm_pdu1, ssm_pdu2] = yield smpp_helper.wait_for_pdus(2)
        yield smpp_helper.handle_pdu(
            SubmitSMResp(sequence_number=seq_no(ssm_pdu1),
                         message_id='foo1',
                         command_status='ESME_RTHROTTLED'))
        yield smpp_helper.handle_pdu(
            SubmitSMResp(sequence_number=seq_no(ssm_pdu2),
                         message_id='foo2',
                         command_status='ESME_RTHROTTLED'))

        # Advance clock, still throttled.
        self.clock.advance(transport_config.throttle_delay)
        [ssm_pdu1_retry1] = yield smpp_helper.wait_for_pdus(1)
        yield smpp_helper.handle_pdu(
            SubmitSMResp(sequence_number=seq_no(ssm_pdu1_retry1),
                         message_id='bar1',
                         command_status='ESME_RTHROTTLED'))

        # Advance clock, message no longer throttled.
        self.clock.advance(transport_config.throttle_delay)
        [ssm_pdu2_retry1] = yield smpp_helper.wait_for_pdus(1)
        yield smpp_helper.handle_pdu(
            SubmitSMResp(sequence_number=seq_no(ssm_pdu2_retry1),
                         message_id='bar2',
                         command_status='ESME_ROK'))

        # Prod clock, message no longer throttled.
        self.clock.advance(0)
        [ssm_pdu1_retry2] = yield smpp_helper.wait_for_pdus(1)
        yield smpp_helper.handle_pdu(
            SubmitSMResp(sequence_number=seq_no(ssm_pdu1_retry2),
                         message_id='baz1',
                         command_status='ESME_ROK'))

        self.assertEqual(short_message(ssm_pdu1), 'hello world 1')
        self.assertEqual(short_message(ssm_pdu2), 'hello world 2')
        self.assertEqual(short_message(ssm_pdu1_retry1), 'hello world 1')
        self.assertEqual(short_message(ssm_pdu2_retry1), 'hello world 2')
        self.assertEqual(short_message(ssm_pdu1_retry2), 'hello world 1')
        [event2, event1] = yield self.tx_helper.wait_for_dispatched_events(2)
        self.assertEqual(event1['event_type'], 'ack')
        self.assertEqual(event1['user_message_id'], msg1['message_id'])
        self.assertEqual(event2['event_type'], 'ack')
        self.assertEqual(event2['user_message_id'], msg2['message_id'])
Пример #6
0
    def test_mt_sms_throttle_while_throttled(self):
        smpp_helper = yield self.get_smpp_helper()
        transport_config = smpp_helper.transport.get_static_config()
        msg1 = self.tx_helper.make_outbound('hello world 1')
        msg2 = self.tx_helper.make_outbound('hello world 2')

        yield self.tx_helper.dispatch_outbound(msg1)
        yield self.tx_helper.dispatch_outbound(msg2)
        [ssm_pdu1, ssm_pdu2] = yield smpp_helper.wait_for_pdus(2)
        yield smpp_helper.handle_pdu(
            SubmitSMResp(sequence_number=seq_no(ssm_pdu1),
                         message_id='foo1',
                         command_status='ESME_RTHROTTLED'))
        yield smpp_helper.handle_pdu(
            SubmitSMResp(sequence_number=seq_no(ssm_pdu2),
                         message_id='foo2',
                         command_status='ESME_RTHROTTLED'))

        # Advance clock, still throttled.
        self.clock.advance(transport_config.throttle_delay)
        [ssm_pdu1_retry1] = yield smpp_helper.wait_for_pdus(1)
        yield smpp_helper.handle_pdu(
            SubmitSMResp(sequence_number=seq_no(ssm_pdu1_retry1),
                         message_id='bar1',
                         command_status='ESME_RTHROTTLED'))

        # Advance clock, message no longer throttled.
        self.clock.advance(transport_config.throttle_delay)
        [ssm_pdu2_retry1] = yield smpp_helper.wait_for_pdus(1)
        yield smpp_helper.handle_pdu(
            SubmitSMResp(sequence_number=seq_no(ssm_pdu2_retry1),
                         message_id='bar2',
                         command_status='ESME_ROK'))

        # Prod clock, message no longer throttled.
        self.clock.advance(0)
        [ssm_pdu1_retry2] = yield smpp_helper.wait_for_pdus(1)
        yield smpp_helper.handle_pdu(
            SubmitSMResp(sequence_number=seq_no(ssm_pdu1_retry2),
                         message_id='baz1',
                         command_status='ESME_ROK'))

        self.assertEqual(short_message(ssm_pdu1), 'hello world 1')
        self.assertEqual(short_message(ssm_pdu2), 'hello world 2')
        self.assertEqual(short_message(ssm_pdu1_retry1), 'hello world 1')
        self.assertEqual(short_message(ssm_pdu2_retry1), 'hello world 2')
        self.assertEqual(short_message(ssm_pdu1_retry2), 'hello world 1')
        [event2, event1] = yield self.tx_helper.wait_for_dispatched_events(2)
        self.assertEqual(event1['event_type'], 'ack')
        self.assertEqual(event1['user_message_id'], msg1['message_id'])
        self.assertEqual(event2['event_type'], 'ack')
        self.assertEqual(event2['user_message_id'], msg2['message_id'])
Пример #7
0
    def handle_deliver_sm(self, pdu):
        # These operate before the PDUs ``short_message`` or
        # ``message_payload`` fields have been string decoded.
        # NOTE: order is important!
        pdu_handler_chain = [
            self.dr_processor.handle_delivery_report_pdu,
            self.deliver_sm_processor.handle_multipart_pdu,
            self.deliver_sm_processor.handle_ussd_pdu,
        ]
        for handler in pdu_handler_chain:
            handled = yield handler(pdu)
            if handled:
                self.send_pdu(DeliverSMResp(seq_no(pdu),
                              command_status='ESME_ROK'))
                return

        # At this point we either have a DR in the message payload
        # or have a normal SMS that needs to be decoded and handled.
        content_parts = self.deliver_sm_processor.decode_pdus([pdu])
        if not all([isinstance(part, unicode) for part in content_parts]):
            command_status = self.config.deliver_sm_decoding_error
            self.log.msg(
                'Not all parts of the PDU were able to be decoded. '
                'Responding with %s.' % (command_status,),
                parts=content_parts)
            self.send_pdu(DeliverSMResp(seq_no(pdu),
                          command_status=command_status))
            return

        content = u''.join(content_parts)
        was_cdr = yield self.dr_processor.handle_delivery_report_content(
            content)
        if was_cdr:
            self.send_pdu(DeliverSMResp(seq_no(pdu),
                          command_status='ESME_ROK'))
            return

        handled = yield self.deliver_sm_processor.handle_short_message_pdu(pdu)
        if handled:
            self.send_pdu(DeliverSMResp(seq_no(pdu),
                          command_status="ESME_ROK"))
            return

        command_status = self.config.deliver_sm_decoding_error
        self.log.warning(
            'Unable to process message. '
            'Responding with %s.' % (command_status,),
            content=content, pdu=pdu.get_obj())

        self.send_pdu(DeliverSMResp(seq_no(pdu),
                      command_status=command_status))
Пример #8
0
    def handle_deliver_sm(self, pdu):
        # These operate before the PDUs ``short_message`` or
        # ``message_payload`` fields have been string decoded.
        # NOTE: order is important!
        pdu_handler_chain = [
            self.dr_processor.handle_delivery_report_pdu,
            self.deliver_sm_processor.handle_multipart_pdu,
            self.deliver_sm_processor.handle_ussd_pdu,
        ]
        for handler in pdu_handler_chain:
            handled = yield handler(pdu)
            if handled:
                self.send_pdu(
                    DeliverSMResp(seq_no(pdu), command_status='ESME_ROK'))
                return

        # At this point we either have a DR in the message payload
        # or have a normal SMS that needs to be decoded and handled.
        content_parts = self.deliver_sm_processor.decode_pdus([pdu])
        if not all([isinstance(part, unicode) for part in content_parts]):
            command_status = self.config.deliver_sm_decoding_error
            log.msg('Not all parts of the PDU were able to be decoded. '
                    'Responding with %s.' % (command_status, ),
                    parts=content_parts)
            self.send_pdu(
                DeliverSMResp(seq_no(pdu), command_status=command_status))
            return

        content = u''.join(content_parts)
        was_cdr = yield self.dr_processor.handle_delivery_report_content(
            content)
        if was_cdr:
            self.send_pdu(DeliverSMResp(seq_no(pdu),
                                        command_status='ESME_ROK'))
            return

        handled = yield self.deliver_sm_processor.handle_short_message_pdu(pdu)
        if handled:
            self.send_pdu(DeliverSMResp(seq_no(pdu),
                                        command_status="ESME_ROK"))
            return

        command_status = self.config.deliver_sm_decoding_error
        log.warning('Unable to process message. '
                    'Responding with %s.' % (command_status, ),
                    content=content,
                    pdu=pdu.get_obj())

        self.send_pdu(DeliverSMResp(seq_no(pdu),
                                    command_status=command_status))
Пример #9
0
def bind_protocol(transport, protocol, clear=True):
    [bind_pdu] = yield wait_for_pdus(transport, 1)
    resp_pdu_class = {
        BindTransceiver: BindTransceiverResp,
        BindReceiver: BindReceiverResp,
        BindTransmitter: BindTransmitterResp,
    }.get(protocol.bind_pdu)
    protocol.dataReceived(
        resp_pdu_class(seq_no(bind_pdu)).get_bin())
    [enquire_link] = yield wait_for_pdus(transport, 1)
    protocol.dataReceived(
        EnquireLinkResp(seq_no(enquire_link)).get_bin())
    if clear:
        transport.clear()
    returnValue(bind_pdu)
Пример #10
0
    def test_submit_and_deliver_ussd_close(self):
        smpp_helper = yield self.get_smpp_helper()

        yield self.tx_helper.make_dispatch_outbound(
            "hello world", transport_type="ussd",
            session_event=TransportUserMessage.SESSION_CLOSE)

        [submit_sm_pdu] = yield smpp_helper.wait_for_pdus(1)
        self.assertEqual(command_id(submit_sm_pdu), 'submit_sm')
        self.assertEqual(pdu_tlv(submit_sm_pdu, 'ussd_service_op'), '02')
        self.assertEqual(pdu_tlv(submit_sm_pdu, 'its_session_info'), '0001')

        # Server delivers a USSD message to the Client
        pdu = DeliverSM(seq_no(submit_sm_pdu) + 1, short_message="reply!")
        pdu.add_optional_parameter('ussd_service_op', '02')
        pdu.add_optional_parameter('its_session_info', '0001')

        yield smpp_helper.handle_pdu(pdu)

        [mess] = yield self.tx_helper.wait_for_dispatched_inbound(1)

        self.assertEqual(mess['content'], "reply!")
        self.assertEqual(mess['transport_type'], "ussd")
        self.assertEqual(mess['session_event'],
                         TransportUserMessage.SESSION_CLOSE)
Пример #11
0
 def _submit_sm_resp(self, submit_sm_pdu, message_id, **kw):
     self.assert_command_id(submit_sm_pdu, 'submit_sm')
     sequence_number = seq_no(submit_sm_pdu)
     if message_id is None:
         message_id = "id%s" % (sequence_number, )
     # We use handle_pdu here to avoid complications with all the async.
     return self.handle_pdu(SubmitSMResp(sequence_number, message_id, **kw))
Пример #12
0
    def test_submit_and_deliver_ussd_close(self):
        smpp_helper = yield self.get_smpp_helper()

        yield self.tx_helper.make_dispatch_outbound(
            "hello world",
            transport_type="ussd",
            session_event=TransportUserMessage.SESSION_CLOSE)

        [submit_sm_pdu] = yield smpp_helper.wait_for_pdus(1)
        self.assertEqual(command_id(submit_sm_pdu), 'submit_sm')
        self.assertEqual(pdu_tlv(submit_sm_pdu, 'ussd_service_op'), '02')
        self.assertEqual(pdu_tlv(submit_sm_pdu, 'its_session_info'), '0001')

        # Server delivers a USSD message to the Client
        pdu = DeliverSM(seq_no(submit_sm_pdu) + 1, short_message="reply!")
        pdu.add_optional_parameter('ussd_service_op', '02')
        pdu.add_optional_parameter('its_session_info', '0001')

        yield smpp_helper.handle_pdu(pdu)

        [mess] = yield self.tx_helper.wait_for_dispatched_inbound(1)

        self.assertEqual(mess['content'], "reply!")
        self.assertEqual(mess['transport_type'], "ussd")
        self.assertEqual(mess['session_event'],
                         TransportUserMessage.SESSION_CLOSE)
Пример #13
0
 def _submit_sm_resp(self, submit_sm_pdu, message_id, **kw):
     self.assert_command_id(submit_sm_pdu, 'submit_sm')
     sequence_number = seq_no(submit_sm_pdu)
     if message_id is None:
         message_id = "id%s" % (sequence_number,)
     # We use handle_pdu here to avoid complications with all the async.
     return self.handle_pdu(SubmitSMResp(sequence_number, message_id, **kw))
Пример #14
0
    def handle_bind_receiver_resp(self, pdu):
        if not pdu_ok(pdu):
            log.warning('Unable to bind: %r' % (command_status(pdu), ))
            self.transport.loseConnection()
            return

        self.state = self.BOUND_STATE_RX
        return self.on_smpp_bind(seq_no(pdu))
Пример #15
0
    def handle_bind_receiver_resp(self, pdu):
        if not pdu_ok(pdu):
            self.log.warning('Unable to bind: %r' % (command_status(pdu),))
            self.transport.loseConnection()
            return

        self.state = self.BOUND_STATE_RX
        return self.on_smpp_bind(seq_no(pdu))
Пример #16
0
 def test_on_enquire_link_resp(self):
     protocol = yield self.get_protocol()
     calls = []
     protocol.handle_enquire_link_resp = calls.append
     yield self.fake_smsc.bind()
     [pdu] = calls
     # bind_transceiver is sequence_number 1
     self.assertEqual(seq_no(pdu), 2)
     self.assertEqual(command_id(pdu), 'enquire_link_resp')
Пример #17
0
 def test_mt_sms_multipart_fail_second_part(self):
     smpp_helper = yield self.get_smpp_helper(config={
         'submit_short_message_processor_config': {
             'send_multipart_udh': True,
         }
     })
     content = '1' * 161
     msg = self.tx_helper.make_outbound(content)
     yield self.tx_helper.dispatch_outbound(msg)
     [submit_sm1, submit_sm2] = yield smpp_helper.wait_for_pdus(2)
     smpp_helper.send_pdu(
         SubmitSMResp(sequence_number=seq_no(submit_sm1), message_id='foo'))
     smpp_helper.send_pdu(
         SubmitSMResp(sequence_number=seq_no(submit_sm2),
                      message_id='bar', command_status='ESME_RSUBMITFAIL'))
     [event] = yield self.tx_helper.wait_for_dispatched_events(1)
     self.assertEqual(event['event_type'], 'nack')
     self.assertEqual(event['user_message_id'], msg['message_id'])
Пример #18
0
 def test_on_enquire_link_resp(self):
     calls = []
     self.patch(EsmeTransceiver, 'handle_enquire_link_resp',
                lambda p, pdu: calls.append(pdu))
     transport, protocol = yield self.setup_bind()
     [pdu] = calls
     # bind_transceiver is sequence_number 1
     self.assertEqual(seq_no(pdu), 2)
     self.assertEqual(command_id(pdu), 'enquire_link_resp')
Пример #19
0
    def test_out_of_order_responses(self):
        smpp_helper = yield self.get_smpp_helper()
        yield self.tx_helper.make_dispatch_outbound("msg 1", message_id='444')
        [submit_sm1] = yield smpp_helper.wait_for_pdus(1)
        response1 = SubmitSMResp(seq_no(submit_sm1), "3rd_party_id_1")

        yield self.tx_helper.make_dispatch_outbound("msg 2", message_id='445')
        [submit_sm2] = yield smpp_helper.wait_for_pdus(1)
        response2 = SubmitSMResp(seq_no(submit_sm2), "3rd_party_id_2")

        # respond out of order - just to keep things interesting
        yield smpp_helper.handle_pdu(response2)
        yield smpp_helper.handle_pdu(response1)

        [ack1, ack2] = yield self.tx_helper.wait_for_dispatched_events(2)
        self.assertEqual(ack1['user_message_id'], '445')
        self.assertEqual(ack1['sent_message_id'], '3rd_party_id_2')
        self.assertEqual(ack2['user_message_id'], '444')
        self.assertEqual(ack2['sent_message_id'], '3rd_party_id_1')
Пример #20
0
 def test_mt_sms_multipart_ack(self):
     smpp_helper = yield self.get_smpp_helper(
         config={
             'submit_short_message_processor_config': {
                 'send_multipart_udh': True,
             }
         })
     content = '1' * 161
     msg = self.tx_helper.make_outbound(content)
     yield self.tx_helper.dispatch_outbound(msg)
     [submit_sm1, submit_sm2] = yield smpp_helper.wait_for_pdus(2)
     smpp_helper.send_pdu(
         SubmitSMResp(sequence_number=seq_no(submit_sm1), message_id='foo'))
     smpp_helper.send_pdu(
         SubmitSMResp(sequence_number=seq_no(submit_sm2), message_id='bar'))
     [event] = yield self.tx_helper.wait_for_dispatched_events(1)
     self.assertEqual(event['event_type'], 'ack')
     self.assertEqual(event['user_message_id'], msg['message_id'])
     self.assertEqual(event['sent_message_id'], 'bar,foo')
Пример #21
0
    def test_out_of_order_responses(self):
        smpp_helper = yield self.get_smpp_helper()
        yield self.tx_helper.make_dispatch_outbound("msg 1", message_id='444')
        [submit_sm1] = yield smpp_helper.wait_for_pdus(1)
        response1 = SubmitSMResp(seq_no(submit_sm1), "3rd_party_id_1")

        yield self.tx_helper.make_dispatch_outbound("msg 2", message_id='445')
        [submit_sm2] = yield smpp_helper.wait_for_pdus(1)
        response2 = SubmitSMResp(seq_no(submit_sm2), "3rd_party_id_2")

        # respond out of order - just to keep things interesting
        yield smpp_helper.handle_pdu(response2)
        yield smpp_helper.handle_pdu(response1)

        [ack1, ack2] = yield self.tx_helper.wait_for_dispatched_events(2)
        self.assertEqual(ack1['user_message_id'], '445')
        self.assertEqual(ack1['sent_message_id'], '3rd_party_id_2')
        self.assertEqual(ack2['user_message_id'], '444')
        self.assertEqual(ack2['sent_message_id'], '3rd_party_id_1')
Пример #22
0
 def test_drop_link(self):
     protocol = yield self.get_protocol()
     bind_pdu = yield self.fake_smsc.await_pdu()
     self.assertCommand(bind_pdu, 'bind_transceiver')
     self.assertFalse(protocol.is_bound())
     self.assertEqual(protocol.state, EsmeProtocol.OPEN_STATE)
     self.clock.advance(protocol.config.smpp_bind_timeout + 1)
     unbind_pdu = yield self.fake_smsc.await_pdu()
     self.assertCommand(unbind_pdu, 'unbind')
     yield self.fake_smsc.send_pdu(UnbindResp(seq_no(unbind_pdu)))
     yield self.fake_smsc.await_disconnect()
Пример #23
0
 def _bind_resp(self, bind_pdu):
     resp_pdu_classes = {
         'bind_transceiver': BindTransceiverResp,
         'bind_receiver': BindReceiverResp,
         'bind_transmitter': BindTransmitterResp,
     }
     self.assert_command_id(bind_pdu, *resp_pdu_classes)
     resp_pdu_class = resp_pdu_classes.get(command_id(bind_pdu))
     self.send_pdu(resp_pdu_class(seq_no(bind_pdu)))
     eq_d = self.respond_to_enquire_link()
     return eq_d.addCallback(self._bound_d.callback)
Пример #24
0
 def _bind_resp(self, bind_pdu):
     resp_pdu_classes = {
         'bind_transceiver': BindTransceiverResp,
         'bind_receiver': BindReceiverResp,
         'bind_transmitter': BindTransmitterResp,
     }
     self.assert_command_id(bind_pdu, *resp_pdu_classes)
     resp_pdu_class = resp_pdu_classes.get(command_id(bind_pdu))
     self.send_pdu(resp_pdu_class(seq_no(bind_pdu)))
     eq_d = self.respond_to_enquire_link()
     return eq_d.addCallback(self._bound_d.callback)
Пример #25
0
 def test_mt_sms_ack(self):
     smpp_helper = yield self.get_smpp_helper()
     msg = self.tx_helper.make_outbound('hello world')
     yield self.tx_helper.dispatch_outbound(msg)
     [submit_sm_pdu] = yield smpp_helper.wait_for_pdus(1)
     smpp_helper.send_pdu(
         SubmitSMResp(sequence_number=seq_no(submit_sm_pdu),
                      message_id='foo'))
     [event] = yield self.tx_helper.wait_for_dispatched_events(1)
     self.assertEqual(event['event_type'], 'ack')
     self.assertEqual(event['user_message_id'], msg['message_id'])
     self.assertEqual(event['sent_message_id'], 'foo')
Пример #26
0
 def test_mt_sms_nack(self):
     smpp_helper = yield self.get_smpp_helper()
     msg = self.tx_helper.make_outbound('hello world')
     yield self.tx_helper.dispatch_outbound(msg)
     [submit_sm_pdu] = yield smpp_helper.wait_for_pdus(1)
     smpp_helper.send_pdu(
         SubmitSMResp(sequence_number=seq_no(submit_sm_pdu),
                      message_id='foo', command_status='ESME_RINVDSTADR'))
     [event] = yield self.tx_helper.wait_for_dispatched_events(1)
     self.assertEqual(event['event_type'], 'nack')
     self.assertEqual(event['user_message_id'], msg['message_id'])
     self.assertEqual(event['nack_reason'], 'ESME_RINVDSTADR')
Пример #27
0
    def test_mo_sms_multipart_long(self):
        smpp_helper = yield self.get_smpp_helper()
        content = '1' * 255

        pdu = DeliverSM(sequence_number=1)
        pdu.add_optional_parameter('message_payload', content.encode('hex'))
        smpp_helper.send_pdu(pdu)

        [deliver_sm_resp] = yield smpp_helper.wait_for_pdus(1)
        self.assertEqual(1, seq_no(deliver_sm_resp))
        self.assertTrue(pdu_ok(deliver_sm_resp))
        [msg] = yield self.tx_helper.wait_for_dispatched_inbound(1)
        self.assertEqual(msg['content'], content)
Пример #28
0
    def test_mo_sms_multipart_long(self):
        smpp_helper = yield self.get_smpp_helper()
        content = '1' * 255

        pdu = DeliverSM(sequence_number=1)
        pdu.add_optional_parameter('message_payload', content.encode('hex'))
        smpp_helper.send_pdu(pdu)

        [deliver_sm_resp] = yield smpp_helper.wait_for_pdus(1)
        self.assertEqual(1, seq_no(deliver_sm_resp))
        self.assertTrue(pdu_ok(deliver_sm_resp))
        [msg] = yield self.tx_helper.wait_for_dispatched_inbound(1)
        self.assertEqual(msg['content'], content)
Пример #29
0
 def test_drop_link(self):
     protocol = yield self.get_protocol()
     transport = yield connect_transport(protocol)
     [bind_pdu] = yield wait_for_pdus(transport, 1)
     self.assertCommand(bind_pdu, 'bind_transceiver')
     self.assertFalse(protocol.is_bound())
     self.assertEqual(protocol.state, EsmeTransceiver.OPEN_STATE)
     self.assertFalse(transport.disconnecting)
     self.clock.advance(protocol.config.smpp_bind_timeout + 1)
     [unbind_pdu] = yield wait_for_pdus(transport, 1)
     self.assertCommand(unbind_pdu, 'unbind')
     unbind_resp_pdu = UnbindResp(sequence_number=seq_no(unbind_pdu))
     yield protocol.on_pdu(unpack_pdu(unbind_resp_pdu.get_bin()))
     self.assertTrue(transport.disconnecting)
Пример #30
0
    def test_mt_sms_throttled(self):
        smpp_helper = yield self.get_smpp_helper()
        transport_config = smpp_helper.transport.get_static_config()
        msg = self.tx_helper.make_outbound('hello world')

        yield self.tx_helper.dispatch_outbound(msg)
        [submit_sm_pdu] = yield smpp_helper.wait_for_pdus(1)
        with LogCatcher(message="Throttling outbound messages.") as lc:
            yield smpp_helper.handle_pdu(
                SubmitSMResp(sequence_number=seq_no(submit_sm_pdu),
                             message_id='foo',
                             command_status='ESME_RTHROTTLED'))
        [logmsg] = lc.logs
        self.assertEqual(logmsg['logLevel'], logging.WARNING)

        self.clock.advance(transport_config.throttle_delay)

        [submit_sm_pdu_retry] = yield smpp_helper.wait_for_pdus(1)
        yield smpp_helper.handle_pdu(
            SubmitSMResp(sequence_number=seq_no(submit_sm_pdu_retry),
                         message_id='bar',
                         command_status='ESME_ROK'))

        self.assertTrue(seq_no(submit_sm_pdu_retry) > seq_no(submit_sm_pdu))
        self.assertEqual(short_message(submit_sm_pdu), 'hello world')
        self.assertEqual(short_message(submit_sm_pdu_retry), 'hello world')
        [event] = yield self.tx_helper.wait_for_dispatched_events(1)
        self.assertEqual(event['event_type'], 'ack')
        self.assertEqual(event['user_message_id'], msg['message_id'])

        # We're still throttled until our next attempt to unthrottle finds no
        # messages to retry.
        with LogCatcher(message="No longer throttling outbound") as lc:
            self.clock.advance(transport_config.throttle_delay)
        [logmsg] = lc.logs
        self.assertEqual(logmsg['logLevel'], logging.WARNING)
Пример #31
0
    def test_mt_sms_throttled(self):
        smpp_helper = yield self.get_smpp_helper()
        transport_config = smpp_helper.transport.get_static_config()
        msg = self.tx_helper.make_outbound('hello world')

        yield self.tx_helper.dispatch_outbound(msg)
        [submit_sm_pdu] = yield smpp_helper.wait_for_pdus(1)
        with LogCatcher(message="Throttling outbound messages.") as lc:
            yield smpp_helper.handle_pdu(
                SubmitSMResp(sequence_number=seq_no(submit_sm_pdu),
                             message_id='foo',
                             command_status='ESME_RTHROTTLED'))
        [logmsg] = lc.logs
        self.assertEqual(logmsg['logLevel'], logging.WARNING)

        self.clock.advance(transport_config.throttle_delay)

        [submit_sm_pdu_retry] = yield smpp_helper.wait_for_pdus(1)
        yield smpp_helper.handle_pdu(
            SubmitSMResp(sequence_number=seq_no(submit_sm_pdu_retry),
                         message_id='bar',
                         command_status='ESME_ROK'))

        self.assertTrue(seq_no(submit_sm_pdu_retry) > seq_no(submit_sm_pdu))
        self.assertEqual(short_message(submit_sm_pdu), 'hello world')
        self.assertEqual(short_message(submit_sm_pdu_retry), 'hello world')
        [event] = yield self.tx_helper.wait_for_dispatched_events(1)
        self.assertEqual(event['event_type'], 'ack')
        self.assertEqual(event['user_message_id'], msg['message_id'])

        # We're still throttled until our next attempt to unthrottle finds no
        # messages to retry.
        with LogCatcher(message="No longer throttling outbound") as lc:
            self.clock.advance(transport_config.throttle_delay)
        [logmsg] = lc.logs
        self.assertEqual(logmsg['logLevel'], logging.WARNING)
Пример #32
0
 def test_partial_pdu_data_received(self):
     calls = []
     self.patch(EsmeTransceiver, 'handle_deliver_sm',
                lambda p, pdu: calls.append(pdu))
     transport, protocol = yield self.setup_bind()
     deliver_sm = DeliverSM(sequence_number=1, short_message='foo')
     pdu = deliver_sm.get_bin()
     half = len(pdu) / 2
     pdu_part1, pdu_part2 = pdu[:half], pdu[half:]
     protocol.dataReceived(pdu_part1)
     self.assertEqual([], calls)
     protocol.dataReceived(pdu_part2)
     [handled_pdu] = calls
     self.assertEqual(command_id(handled_pdu), 'deliver_sm')
     self.assertEqual(seq_no(handled_pdu), 1)
     self.assertEqual(short_message(handled_pdu), 'foo')
Пример #33
0
    def test_enquire_link_looping(self):
        transport, protocol = yield self.setup_bind(clear=False)
        enquire_link_resp = EnquireLinkResp(1)

        protocol.clock.advance(protocol.idle_timeout - 1)
        protocol.dataReceived(enquire_link_resp.get_bin())

        protocol.clock.advance(protocol.idle_timeout - 1)
        self.assertFalse(transport.disconnecting)
        protocol.clock.advance(1)

        [unbind_pdu] = yield wait_for_pdus(transport, 1)
        self.assertCommand(unbind_pdu, 'unbind')
        unbind_resp_pdu = UnbindResp(sequence_number=seq_no(unbind_pdu))
        yield protocol.on_pdu(unpack_pdu(unbind_resp_pdu.get_bin()))
        self.assertTrue(transport.disconnecting)
Пример #34
0
 def test_partial_pdu_data_received(self):
     protocol = yield self.get_protocol()
     calls = []
     protocol.handle_deliver_sm = calls.append
     yield self.fake_smsc.bind()
     deliver_sm = DeliverSM(1, short_message='foo')
     pdu = deliver_sm.get_bin()
     half = len(pdu) / 2
     pdu_part1, pdu_part2 = pdu[:half], pdu[half:]
     yield self.fake_smsc.send_bytes(pdu_part1)
     self.assertEqual([], calls)
     yield self.fake_smsc.send_bytes(pdu_part2)
     [handled_pdu] = calls
     self.assertEqual(command_id(handled_pdu), 'deliver_sm')
     self.assertEqual(seq_no(handled_pdu), 1)
     self.assertEqual(short_message(handled_pdu), 'foo')
Пример #35
0
    def test_submit_and_deliver_ussd_continue(self):
        user_msisdn = 'msisdn'
        session_identifier = 12345
        vumi_session_identifier = make_vumi_session_identifier(
            user_msisdn, session_identifier)
        transport = yield self.get_transport()

        deliver_sm_processor = transport.deliver_sm_processor
        session_manager = deliver_sm_processor.session_manager
        yield session_manager.create_session(vumi_session_identifier,
                                             ussd_code='*123#')

        yield self.tx_helper.make_dispatch_outbound(
            "hello world",
            transport_type="ussd",
            transport_metadata={
                'session_info': {
                    'session_identifier': session_identifier
                }
            },
            to_addr=user_msisdn)

        submit_sm_pdu = yield self.fake_smsc.await_pdu()
        self.assertEqual(command_id(submit_sm_pdu), 'submit_sm')
        self.assertEqual(pdu_tlv(submit_sm_pdu, 'ussd_service_op'), '02')
        self.assertEqual(pdu_tlv(submit_sm_pdu, 'user_message_reference'),
                         session_identifier)

        # Server delivers a USSD message to the Client
        pdu = DeliverSM(seq_no(submit_sm_pdu) + 1,
                        short_message="reply!",
                        source_addr=user_msisdn)
        # 0x12 is 'continue'
        pdu.add_optional_parameter('ussd_service_op', '12')
        pdu.add_optional_parameter('user_message_reference',
                                   session_identifier)

        yield self.fake_smsc.handle_pdu(pdu)

        [mess] = yield self.tx_helper.wait_for_dispatched_inbound(1)

        self.assertEqual(mess['content'], "reply!")
        self.assertEqual(mess['transport_type'], "ussd")
        self.assertEqual(mess['to_addr'], '*123#')
        self.assertEqual(mess['session_event'],
                         TransportUserMessage.SESSION_RESUME)
Пример #36
0
    def test_mt_sms_failure(self):
        smpp_helper = yield self.get_smpp_helper()
        message = yield self.tx_helper.make_dispatch_outbound(
            "message", message_id='446')
        [submit_sm] = yield smpp_helper.wait_for_pdus(1)
        response = SubmitSMResp(seq_no(submit_sm), "3rd_party_id_3",
                                command_status="ESME_RSUBMITFAIL")
        # A failure PDU might not have a body.
        response.obj.pop('body')
        smpp_helper.send_pdu(response)

        # There should be a nack
        [nack] = yield self.tx_helper.wait_for_dispatched_events(1)

        [failure] = yield self.tx_helper.get_dispatched_failures()
        self.assertEqual(failure['reason'], 'ESME_RSUBMITFAIL')
        self.assertEqual(failure['message'], message.payload)
Пример #37
0
    def test_mt_sms_failure(self):
        smpp_helper = yield self.get_smpp_helper()
        message = yield self.tx_helper.make_dispatch_outbound("message",
                                                              message_id='446')
        [submit_sm] = yield smpp_helper.wait_for_pdus(1)
        response = SubmitSMResp(seq_no(submit_sm),
                                "3rd_party_id_3",
                                command_status="ESME_RSUBMITFAIL")
        # A failure PDU might not have a body.
        response.obj.pop('body')
        smpp_helper.send_pdu(response)

        # There should be a nack
        [nack] = yield self.tx_helper.wait_for_dispatched_events(1)

        [failure] = yield self.tx_helper.get_dispatched_failures()
        self.assertEqual(failure['reason'], 'ESME_RSUBMITFAIL')
        self.assertEqual(failure['message'], message.payload)
Пример #38
0
    def test_link_remote_message_id(self):
        smpp_helper = yield self.get_smpp_helper()
        transport = smpp_helper.transport
        config = transport.get_static_config()

        msg = self.tx_helper.make_outbound('hello world')
        yield self.tx_helper.dispatch_outbound(msg)

        [pdu] = yield smpp_helper.wait_for_pdus(1)
        yield smpp_helper.handle_pdu(
            SubmitSMResp(sequence_number=seq_no(pdu),
                         message_id='foo',
                         command_status='ESME_ROK'))
        self.assertEqual(
            msg['message_id'],
            (yield transport.message_stash.get_internal_message_id('foo')))

        ttl = yield transport.redis.ttl(remote_message_key('foo'))
        self.assertTrue(0 < ttl <= config.third_party_id_expiry)
Пример #39
0
    def assertCommand(self, pdu, cmd_id, sequence_number=None,
                      status=None, params={}):
        self.assertEqual(command_id(pdu), cmd_id)
        if sequence_number is not None:
            self.assertEqual(seq_no(pdu), sequence_number)
        if status is not None:
            self.assertEqual(command_status(pdu), status)

        pdu_params = {}
        if params:
            if 'body' not in pdu:
                raise Exception('Body does not have parameters.')

            mandatory_parameters = pdu['body']['mandatory_parameters']
            for key in params:
                if key in mandatory_parameters:
                    pdu_params[key] = mandatory_parameters[key]

            self.assertEqual(params, pdu_params)
Пример #40
0
    def test_submit_and_deliver_ussd_continue(self):
        user_msisdn = 'msisdn'
        session_identifier = 12345
        vumi_session_identifier = make_vumi_session_identifier(
            user_msisdn, session_identifier)
        smpp_helper = yield self.get_smpp_helper()

        deliver_sm_processor = smpp_helper.transport.deliver_sm_processor
        session_manager = deliver_sm_processor.session_manager
        yield session_manager.create_session(
            vumi_session_identifier, ussd_code='*123#')

        yield self.tx_helper.make_dispatch_outbound(
            "hello world", transport_type="ussd", transport_metadata={
                'session_info': {
                    'session_identifier': session_identifier
                }
            }, to_addr=user_msisdn)

        [submit_sm_pdu] = yield smpp_helper.wait_for_pdus(1)
        self.assertEqual(command_id(submit_sm_pdu), 'submit_sm')
        self.assertEqual(pdu_tlv(submit_sm_pdu, 'ussd_service_op'), '02')
        self.assertEqual(
            pdu_tlv(submit_sm_pdu, 'user_message_reference'),
            session_identifier)

        # Server delivers a USSD message to the Client
        pdu = DeliverSM(seq_no(submit_sm_pdu) + 1, short_message="reply!",
                        source_addr=user_msisdn)
        # 0x12 is 'continue'
        pdu.add_optional_parameter('ussd_service_op', '12')
        pdu.add_optional_parameter('user_message_reference',
                                   session_identifier)

        yield smpp_helper.handle_pdu(pdu)

        [mess] = yield self.tx_helper.wait_for_dispatched_inbound(1)

        self.assertEqual(mess['content'], "reply!")
        self.assertEqual(mess['transport_type'], "ussd")
        self.assertEqual(mess['to_addr'], '*123#')
        self.assertEqual(mess['session_event'],
                         TransportUserMessage.SESSION_RESUME)
Пример #41
0
    def test_link_remote_message_id(self):
        smpp_helper = yield self.get_smpp_helper()
        transport = smpp_helper.transport
        config = transport.get_static_config()

        msg = self.tx_helper.make_outbound('hello world')
        yield self.tx_helper.dispatch_outbound(msg)

        [pdu] = yield smpp_helper.wait_for_pdus(1)
        yield smpp_helper.handle_pdu(
            SubmitSMResp(sequence_number=seq_no(pdu),
                         message_id='foo',
                         command_status='ESME_ROK'))
        self.assertEqual(
            msg['message_id'],
            (yield transport.message_stash.get_internal_message_id('foo')))

        ttl = yield transport.redis.ttl(remote_message_key('foo'))
        self.assertTrue(0 < ttl <= config.third_party_id_expiry)
Пример #42
0
    def test_mt_sms_failure_with_no_reason(self):

        smpp_helper = yield self.get_smpp_helper()
        message = yield self.tx_helper.make_dispatch_outbound("message",
                                                              message_id='446')
        [submit_sm] = yield smpp_helper.wait_for_pdus(1)

        yield smpp_helper.handle_pdu(
            SubmitSMResp(sequence_number=seq_no(submit_sm),
                         message_id='foo',
                         command_status=None))

        # There should be a nack
        [nack] = yield self.tx_helper.wait_for_dispatched_events(1)
        self.assertEqual(nack['user_message_id'], message['message_id'])
        self.assertEqual(nack['nack_reason'], 'Unspecified')

        [failure] = yield self.tx_helper.get_dispatched_failures()
        self.assertEqual(failure['reason'], 'Unspecified')
Пример #43
0
    def test_mt_sms_failure_with_no_reason(self):

        smpp_helper = yield self.get_smpp_helper()
        message = yield self.tx_helper.make_dispatch_outbound(
            "message", message_id='446')
        [submit_sm] = yield smpp_helper.wait_for_pdus(1)

        yield smpp_helper.handle_pdu(
            SubmitSMResp(sequence_number=seq_no(submit_sm),
                         message_id='foo',
                         command_status=None))

        # There should be a nack
        [nack] = yield self.tx_helper.wait_for_dispatched_events(1)
        self.assertEqual(nack['user_message_id'], message['message_id'])
        self.assertEqual(nack['nack_reason'], 'Unspecified')

        [failure] = yield self.tx_helper.get_dispatched_failures()
        self.assertEqual(failure['reason'], 'Unspecified')
Пример #44
0
    def test_submit_and_deliver_ussd_continue(self):
        session = SessionInfo()
        smpp_helper = yield self.get_smpp_helper()

        deliver_sm_processor = smpp_helper.transport.deliver_sm_processor
        session_manager = deliver_sm_processor.session_manager
        yield session_manager.create_session(session.vumi_id,
                                             ussd_code='*123#')

        yield self.tx_helper.make_dispatch_outbound(
            "hello world",
            transport_type="ussd",
            transport_metadata={
                'session_info': {
                    'session_identifier': session.sixdee_id,
                }
            },
            to_addr=session.addr)

        [submit_sm_pdu] = yield smpp_helper.wait_for_pdus(1)
        self.assertEqual(command_id(submit_sm_pdu), 'submit_sm')
        self.assertEqual(pdu_tlv(submit_sm_pdu, 'ussd_service_op'), '02')
        self.assertEqual(pdu_tlv(submit_sm_pdu, 'its_session_info'),
                         session.its_info)

        # Server delivers a USSD message to the Client
        pdu = DeliverSM(seq_no(submit_sm_pdu) + 1,
                        short_message="reply!",
                        source_addr=session.addr)
        # 0x12 is 'continue'
        pdu.add_optional_parameter('ussd_service_op', '12')
        pdu.add_optional_parameter('its_session_info', session.its_info)

        yield smpp_helper.handle_pdu(pdu)

        [mess] = yield self.tx_helper.wait_for_dispatched_inbound(1)

        self.assertEqual(mess['content'], "reply!")
        self.assertEqual(mess['transport_type'], "ussd")
        self.assertEqual(mess['to_addr'], '*123#')
        self.assertEqual(mess['session_event'],
                         TransportUserMessage.SESSION_RESUME)
Пример #45
0
    def test_submit_and_deliver_ussd_continue(self):
        session = SessionInfo()
        transport = yield self.get_transport()

        deliver_sm_processor = transport.deliver_sm_processor
        session_manager = deliver_sm_processor.session_manager
        yield session_manager.create_session(
            session.vumi_id, ussd_code='*123#')

        yield self.tx_helper.make_dispatch_outbound(
            "hello world", transport_type="ussd", transport_metadata={
                'session_info': {
                    'session_identifier': session.sixdee_id,
                }
            }, to_addr=session.addr)

        submit_sm_pdu = yield self.fake_smsc.await_pdu()
        self.assertEqual(command_id(submit_sm_pdu), 'submit_sm')
        self.assertEqual(pdu_tlv(submit_sm_pdu, 'ussd_service_op'), '02')
        self.assertEqual(pdu_tlv(submit_sm_pdu, 'its_session_info'),
                         session.its_info)

        # Server delivers a USSD message to the Client
        pdu = DeliverSM(seq_no(submit_sm_pdu) + 1, short_message="reply!",
                        source_addr=session.addr)
        # 0x12 is 'continue'
        pdu.add_optional_parameter('ussd_service_op', '12')
        pdu.add_optional_parameter('its_session_info', session.its_info)

        yield self.fake_smsc.handle_pdu(pdu)

        [mess] = yield self.tx_helper.wait_for_dispatched_inbound(1)

        self.assertEqual(mess['content'], "reply!")
        self.assertEqual(mess['transport_type'], "ussd")
        self.assertEqual(mess['to_addr'], '*123#')
        self.assertEqual(mess['session_event'],
                         TransportUserMessage.SESSION_RESUME)
Пример #46
0
    def test_enquire_link_looping(self):
        self.fake_smsc.auto_unbind = False
        protocol = yield self.get_protocol()
        yield self.fake_smsc.bind()
        self.assertEqual(self.fake_smsc.connected, True)

        # Respond to a few enquire_link cycles.
        for i in range(5):
            self.clock.advance(protocol.idle_timeout - 1)
            pdu = yield self.fake_smsc.await_pdu()
            self.assertCommand(pdu, 'enquire_link')
            yield self.fake_smsc.respond_to_enquire_link(pdu)

        # Fail to respond, so we disconnect.
        self.clock.advance(protocol.idle_timeout - 1)
        pdu = yield self.fake_smsc.await_pdu()
        self.assertCommand(pdu, 'enquire_link')
        self.clock.advance(1)
        unbind_pdu = yield self.fake_smsc.await_pdu()
        self.assertCommand(unbind_pdu, 'unbind')
        yield self.fake_smsc.send_pdu(
            UnbindResp(seq_no(unbind_pdu)))
        yield self.fake_smsc.await_disconnect()
Пример #47
0
    def test_submit_and_deliver_ussd_continue(self):
        user_msisdn = "msisdn"
        session_identifier = 12345
        vumi_session_identifier = make_vumi_session_identifier(user_msisdn, session_identifier)
        transport = yield self.get_transport()

        deliver_sm_processor = transport.deliver_sm_processor
        session_manager = deliver_sm_processor.session_manager
        yield session_manager.create_session(vumi_session_identifier, ussd_code="*123#")

        yield self.tx_helper.make_dispatch_outbound(
            "hello world",
            transport_type="ussd",
            transport_metadata={"session_info": {"session_identifier": session_identifier}},
            to_addr=user_msisdn,
        )

        submit_sm_pdu = yield self.fake_smsc.await_pdu()
        self.assertEqual(command_id(submit_sm_pdu), "submit_sm")
        self.assertEqual(pdu_tlv(submit_sm_pdu, "ussd_service_op"), "02")
        self.assertEqual(pdu_tlv(submit_sm_pdu, "user_message_reference"), session_identifier)

        # Server delivers a USSD message to the Client
        pdu = DeliverSM(seq_no(submit_sm_pdu) + 1, short_message="reply!", source_addr=user_msisdn)
        # 0x12 is 'continue'
        pdu.add_optional_parameter("ussd_service_op", "12")
        pdu.add_optional_parameter("user_message_reference", session_identifier)

        yield self.fake_smsc.handle_pdu(pdu)

        [mess] = yield self.tx_helper.wait_for_dispatched_inbound(1)

        self.assertEqual(mess["content"], "reply!")
        self.assertEqual(mess["transport_type"], "ussd")
        self.assertEqual(mess["to_addr"], "*123#")
        self.assertEqual(mess["session_event"], TransportUserMessage.SESSION_RESUME)
Пример #48
0
 def handle_enquire_link(self, pdu):
     return self.send_pdu(EnquireLinkResp(seq_no(pdu)))