Ejemplo n.º 1
0
    def write_message_to_other_limpet(self, msg):
        """Write a Message to the other Limpet.
        """
        # We know enough to sort out the network order of the integers in
        # the Replier Bind Event's data
        if msg.name == '$.KBUS.ReplierBindEvent':
            data = convert_ReplierBindEvent_data_to_network(msg.data)
            msg = Message.from_message(msg, data=data)

        header = serialise_message_header(msg)
        self.sock.sendall(header)

        self.sock.sendall(msg.name)
        padded_name_len = calc_padded_name_len(msg.msg.name_len)
        if len(msg.name) != padded_name_len:
            self.sock.sendall('\0'*(padded_name_len - len(msg.name)))

        if msg.msg.data_len:
            self.sock.sendall(msg.data)
            padded_data_len = calc_padded_data_len(msg.msg.data_len)
            if len(msg.data) != padded_data_len:
                self.sock.sendall('\0'*(padded_data_len - len(msg.data)))

        ##end_guard = struct.pack('!L', header[-1])
        end_guard = struct.pack('!L', Message.END_GUARD)
        self.sock.sendall(end_guard)       # end guard again
Ejemplo n.º 2
0
    def read_message_from_other_limpet(self):
        """Read a message from the other Limpet.

        Returns the corresponding Message instance.
        """

        # First, read the message header
        header = self.sock.recv(_SERIALISED_MESSAGE_HEADER_LEN * 4,
                                socket.MSG_WAITALL)
        if header == '':
            raise OtherLimpetGoneAway()

        name_len, data_len, array = unserialise_message_header(header)

        if array[0] != Message.START_GUARD:
            raise BadMessage('Message data start guard is %08x,'
                             ' not %08x' % (array[0], Message.START_GUARD))

        if array[-1] != Message.END_GUARD:
            raise BadMessage('Message data end guard is %08x,'
                             ' not %08x' % (array[-1], Message.END_GUARD))

        name = self.sock.recv(calc_padded_name_len(name_len),
                              socket.MSG_WAITALL)
        if name == '':
            raise OtherLimpetGoneAway()

        if data_len:
            data = self.sock.recv(calc_padded_data_len(data_len),
                                  socket.MSG_WAITALL)
            if data == '':
                raise OtherLimpetGoneAway()
        else:
            data = None

        end = self.sock.recv(4, socket.MSG_WAITALL)
        #value = struct.unpack('!L', end)   # unsigned long, network order
        #end = ntohl(value[0])
        end = struct.unpack('!L', end)[0]  # unsigned long, network order
        if end != Message.END_GUARD:
            raise BadMessage('Final message data end guard is %08x,'
                             ' not %08x' % (end, Message.END_GUARD))

        # We know enough to sort out the network order of the integers in
        # the Replier Bind Event's data
        if name[:name_len] == '$.KBUS.ReplierBindEvent':
            data = convert_ReplierBindEvent_data_from_network(data, data_len)

        return Message(name[:name_len],
                       data=data[:data_len] if data else None,
                       id=MessageId(array[1], array[2]),
                       in_reply_to=MessageId(array[3], array[4]),
                       to=array[5],
                       from_=array[6],
                       orig_from=OrigFrom(array[7], array[8]),
                       final_to=OrigFrom(array[9], array[10]),
                       flags=array[12])
Ejemplo n.º 3
0
def run_server(listen_address):
    """Listen for connections, and deal with them.
  """

    keep_listening = True

    print 'Listening on', listen_address
    sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
    # Try to allow address reuse as soon as possible after we've finished
    # with it
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    sock.bind(listen_address)
    try:
        while keep_listening:
            sock.listen(1)
            connection, address = sock.accept()
            print 'Connected to by (%s, %s)' % (connection, address)

            generator = message_generator(connection)
            for msg in generator:
                if msg is None:
                    keep_listening = False
                    break
                else:
                    print 'Received: Message %s %s from %s = %s' % (
                        msg.id, msg.name, msg.from_, msg.data)
                    connection.sendall(
                        Message('$.Test.Result', 'OK').to_string())

            print 'Closing connection'
            connection.close()
    except BadMessage as err:
        print err
        connection.sendall(Message('$.Test.Result', str(err)).to_string())
    finally:
        print 'Closing server'
        sock.close()
        remove_socket_file(listen_address)
Ejemplo n.º 4
0
def teardown_module():
    with Ksock(1, 'rw') as sender:
        sender.send_msg(Message(TERMINATION_MESSAGE))

    print 'Limpet termination message sent'

    g_server.join()
    g_client.join()

    print 'Limpet server and client both finished'

    retcode = system('sudo rmmod kbus')
    assert retcode == 0
    # Via the magic of hotplugging, that should cause our device to go away
    # ...eventually
    time.sleep(1)
    assert not os.path.exists("/dev/kbus0")
Ejemplo n.º 5
0
    def test_the_first(self):
        """An establishing test, to check we can send a single message.
        """
        with Ksock(KBUS_SENDER, 'rw') as sender:
            with Ksock(KBUS_LISTENER, 'rw') as listener:

                listener.bind('$.Fred')

                this = Message('$.Fred')
                this_id = sender.send_msg(this)
                print 'Sent', this

                # Wait for the message to penetrate the labyrinth
                that = listener.wait_for_msg(TIMEOUT)
                print 'Read', that

                assert this.equivalent(that)
                assert this_id.serial_num == that.id.serial_num
Ejemplo n.º 6
0
    def test_simple_listening(self):
        """Test simple listening.
        """
        with Ksock(KBUS_LISTENER, 'rw') as this:
            with Ksock(KBUS_SENDER, 'rw') as that:

                print 'this', str(this)
                print 'that', str(that)

                # that is listening for someone to say 'Hello'
                that.bind('$.Hello')

                # this says 'Hello' to anyone listening
                m = Message('$.Hello', 'dada')
                this.send_msg(m)

                # We read the next message - it's a 'Hello'
                r = that.wait_for_msg()
                assert r.name == '$.Hello'
                print r
Ejemplo n.º 7
0
    def test_reply_to_specific_id(self):
        """Test replying to a specific id.
        """
        with Ksock(KBUS_LISTENER, 'rw') as replier:
            with Ksock(KBUS_SENDER, 'rw') as sender:
                with Ksock(KBUS_LISTENER, 'rw') as listener:

                    print 'Participants:'
                    print '  sender  ', str(sender)
                    print '  replier ', str(replier)
                    print '  listener', str(listener)

                    sender.bind('$.KBUS.ReplierBindEvent')

                    # sender is listening for someone to say 'Hello'
                    sender.bind('$.Hello')

                    # replier says 'Hello' to anyone listening
                    m = Message('$.Hello', 'dada')
                    replier.send_msg(m)

                    # We read the next message - it's a 'Hello'
                    r = sender.wait_for_msg()
                    assert r.name == '$.Hello'
                    print r

                    # Two interfaces decide to listen to '$.Reponse'
                    replier.bind('$.Response', True)
                    listener.bind('$.Response')

                    # Synchronise...
                    b = sender.wait_for_msg()
                    assert b.name == '$.KBUS.ReplierBindEvent'

                    # However, sender *cares* that replier should receive its
                    # response, and is not worried about anyone else
                    # doing so. First it needs to get the contact information
                    # for replier. The normal way to do that is to send a
                    # request (this makes sense as "the normal way", since by
                    # definition a stateful request wants a Replier at the
                    # other end, and doing the Request/Reply thing establishes
                    # that that is what we have).
                    req = Request('$.Response')
                    sender.send_msg(req)

                    # The listener gets a plain request
                    a = listener.wait_for_msg()
                    assert not r.wants_us_to_reply()

                    # The replier gets the request-for-reply
                    b = replier.wait_for_msg()
                    assert b.wants_us_to_reply()
                    # and should thus reply to it
                    r = reply_to(b)
                    replier.send_msg(r)

                    # listener receives the reply, because it has the same name
                    c = listener.wait_for_msg()
                    assert c.is_reply()

                    # sender receives the reply
                    m = sender.wait_for_msg()
                    print
                    print '*' * 60
                    print 'STATEFUL REQUEST'
                    print 'Sender received  ', str(m)
                    # and uses *that* to construct a stateful request
                    s = stateful_request(m, '$.Response', 'Aha!')
                    print 'Sender requests  ', str(s)
                    sender.send_msg(s)
                    print '*' * 60

                    # Both recipients should "see" that stateful request
                    r = replier.wait_for_msg()
                    print 'Replier receives ', str(r)
                    assert r.wants_us_to_reply()
                    assert r.to == replier.ksock_id()
                    assert r.data == 'Aha!'

                    l = listener.wait_for_msg()
                    print 'Listener receives', str(l)
                    assert not l.wants_us_to_reply()
                    assert l.to == replier.ksock_id()
                    assert l.data == 'Aha!'
                    assert l.id == r.id

                    # But if replier should stop listening to the responses
                    # (either because it "goes away", or because it unbinds)
                    # then we want to know about this...
                    replier.unbind('$.Response', True)
                    # But the Limpet's have to commnicate that fact. So the
                    # sender has no way of knowing (until that has happened)
                    # that it can't still connect to the same replier...
                    sent_id = sender.send_msg(s)
                    m = sender.wait_for_msg()
                    print 'Replier unbind event', str(m)
                    assert m.name == '$.KBUS.ReplierBindEvent'

                    m = sender.wait_for_msg()
                    print 'Expect complaint that Replier did go away', str(m)
                    assert m.to == sender.ksock_id()
                    assert m.in_reply_to == sent_id

                    # And if someone different starts to reply, we want to
                    # know about that as well
                    listener.bind('$.Response', True)

                    # Synchronise...
                    b = sender.wait_for_msg()
                    print 'Expect new binder', str(b)
                    assert b.name == '$.KBUS.ReplierBindEvent'

                    # And sending our Request again should fail
                    # because it's the wrong replier
                    sent_id = sender.send_msg(s)
                    m = sender.wait_for_msg(5)
                    print 'Finally, got', str(m)
                    assert m.name == '$.KBUS.Replier.NotSameKsock'
Ejemplo n.º 8
0
    def _amend_request_from_socket(self, hdr, msg):
        """Do whatever is necessary to a Stateful Request from the other Limpet.

        Returns the amended message, or raises ErrorMessage(<error message>),
        where <error message> is appropriate for sending to the other
        Limpet to report the problem.
        """
        # The Request will have been marked "to" our Limpet pair
        # (otherwise we would not have received it).

        # If the 'final_to' has a network id that matches ours,
        # then we need to unset that, as it has clearly now come
        # into its "local" network.
        if self.verbosity > 1:
            print '%s *** final_to.network_id %u, network_id %u' % (
                hdr, msg._final_to.network_id, self.network_id)
        if msg._final_to.network_id == self.network_id:
            msg._final_to.network_id = 0  # XXX Do we need to do this?
            is_local = True
        else:
            is_local = False

        # Find out who KBUS thinks is replying to this message name
        replier_id = self.find_replier(msg.name)
        if replier_id is None:
            # Oh dear - there is no replier
            if self.verbosity > 1:
                print '%s *** There is no Replier - Replier gone away' % hdr
            error = Message('$.KBUS.Replier.GoneAway',
                            to=msg.from_,
                            in_reply_to=msg.id)
            raise ErrorMessage(error)

        if self.verbosity > 1:
            print '%s *** %s, kbus replier %u' % (hdr, 'Local' if is_local else
                                                  'Nonlocal', replier_id)

        if is_local:
            # The KBUS we're going to write the message to is
            # the final KBUS. Thus the replier id must match
            # that of the original Replier
            if replier_id != msg._final_to.local_id:
                # Oops - wrong replier - someone rebound
                if self.verbosity > 1:
                    print '%s *** Replier is %u, wanted %u - ' \
                          'Replier gone away'%(hdr,replier_id,msg._final_to.local_id)
                error = Message(
                    '$.KBUS.Replier.NotSameKsock',  # XXX New message name
                    to=msg.from_,
                    in_reply_to=msg.id)
                raise ErrorMessage(error)

        # Regardless, we believe the message is OK, so need to
        # adjust who it is meant to go to (locally)
        if is_local:
            # If we're in our final stage, then we insist that the
            # Replier we deliver to be the Replier we expected
            msg.msg.to = msg._final_to.local_id
        else:
            # If we're just passing through, then just deliver it to
            # whoever is listening, on the assumption that they in turn
            # will pass it along, until it reaches its destination.
            # XXX What happens if they are not a Limpet?
            # XXX That would be bad - but I'm not sure how we could
            # XXX tell (short of allowing Limpets to register with
            # XXX KBUS, so that we can ask - and then a non-Limpet
            # XXX could presumably *pretend* to be a Limpet anyway)
            # XXX - a potentially infinite shell game then ensues...
            msg.msg.to = replier_id

        if self.verbosity > 1:
            print '%s Adjusted the msg.to field' % hdr

        return msg