예제 #1
0
def send_payload(peer,
                 response,
                 sender_id=None,
                 sender_EN=None,
                 tag=None,
                 reset_tracker=False):
    global _next_tag, _tracker

    if sender_id is None:  # Not currently used, responder_id is pre-filled
        sender_id = peer.responder_id
    if sender_EN is None:  # Ditto
        sender_EN = peer.responder_EN
    if tag is not None:  # zero-length string can trigger this
        response += ',Tag=%d' % _next_tag
        _tagged[str(_next_tag)] = '%d.%d!%s|%s' % (peer.SID0, peer.CID0,
                                                   response, tag)
        _next_tag += 1

    # Put the tracker on the end where it's easier to find
    if reset_tracker:
        _tracker = 0
    _tracker += 1
    response += '%s%d' % (_TRACKER_TOKEN, _tracker)

    FAMEZ_MailBox.fill(sender_id, response)
    sender_EN.incr()
    return True  # FIXME: is there anything to detect?
예제 #2
0
    def connectionLost(self, reason):
        '''Tell the other peers that this one has died.'''
        if reason.check(TIError.ConnectionDone) is None:  # Dirty
            txt = 'Dirty'
        else:
            txt = 'Clean'
        self.SI.logmsg('%s disconnect from peer id %d' % (txt, self.id))
        if self.id in self.SI.clients:  # Only if everything was completed
            del self.SI.clients[self.id]
        if self.SI.args.recycle:
            self.SI.recycled[self.id] = self
            return

        try:
            for other_peer in self.SI.clients.values():
                ivshmem_send_one_msg(other_peer.transport.socket, self.id)

            for EN in self.EN_list:
                EN.cleanup()

            # For QEMU crashes and shutdowns.  Not the VM, but QEMU itself.
            FAMEZ_MailBox.clear_mailslot(self.id)

        except Exception as e:
            self.SI.logmsg('Closing peer transports failed: %s' % str(e))
예제 #3
0
 def connectionLost(self, reason):
     if reason.check(TIError.ConnectionDone) is None:  # Dirty
         print('Dirty disconnect')
     else:
         print('Clean disconnect')
     FAMEZ_MailBox.clear_mailslot(self.id)  # In particular, nodename
     # FIXME: if reactor.isRunning:
     TIreactor.stop()
예제 #4
0
    def retrieve_initial_info(self, data):
        # 3 longwords: protocol version w/o FD, my (new) ID w/o FD,
        # and then a -1 with the FD of the IVSHMEM file which is
        # delivered before this.
        assert len(data) == 24, 'Initial data needs three quadwords'

        # Enough idiot checks.
        mailbox_fd = self.latest_fd
        version, self.id, minusone = struct.unpack('qqq', data)
        assert version == self.CLIENT_IVSHMEM_PROTOCOL_VERSION, \
            'Unxpected protocol version %d' % version
        assert minusone == -1, \
            'Expected -1 with mailbox fd, got %d' % minuseone
        assert 1 <= self.id, 'My ID is bad: %d' % self.id
        self.nodename = 'z%02d' % self.id
        print('This ID = %2d (%s)' % (self.id, self.nodename))

        # Initialize my mailbox slot.  Get other parameters from the
        # globals because the IVSHMSG protocol doesn't allow values
        # beyond the intial three.  The constructor does some work
        # then returns a few attributes pulled out of the globals,
        # but work is only actually done on the first call.
        mailbox = FAMEZ_MailBox(fd=mailbox_fd,
                                client_id=self.id,
                                nodename=self.nodename)
        self.SI.nClients = mailbox.nClients
        self.SI.nEvents = mailbox.nEvents
        self.SI.server_id = mailbox.server_id
예제 #5
0
    def create_new_peer_id(self):
        '''Determine the lowest unused client ID and set self.id.'''

        self.SID0 = 0  # When queried, the answer is in the context...
        self.CID0 = 0  # ...of the server/switch, NOT the proxy item.
        if len(self.SI.clients) >= self.SI.nClients:
            self.id = -1  # sentinel
            return  # Until a Link RFC is executed

        # dumb: monotonic from 1; smart: random (finds holes in the code).
        # Generate ID sets used by each.
        active_ids = frozenset(self.SI.clients.keys())
        unused_ids = frozenset((range(self.SI.nClients + 2))) - \
                     frozenset((IVSHMEM_UNUSED_ID, self.SI.server_id))
        available_ids = unused_ids - active_ids
        if self.SI.args.smart:
            self.id = random.choice(tuple(available_ids))
        else:
            if not self.SI.clients:  # empty
                self.id = 1
            else:
                self.id = (sorted(available_ids))[0]

        # FIXME: This should have been set up before socket connection made?
        self.nodename, _ = FAMEZ_MailBox.retrieve(self.id, clear=False)
        if self.SI.args.smart:
            self.SID0 = self.SI.default_SID
            self.CID0 = self.id * 100
예제 #6
0
    def ClientCallback(vectorobj):
        requester_id = vectorobj.num
        requester_name, request = FAMEZ_MailBox.retrieve(requester_id)
        responder = vectorobj.cbdata

        # Need to be set each time because of spoof cabability, especiall
        # with destinations like "other" and "all"
        responder.requester_id = requester_id
        responder.responder_id = responder.id  # Not like twisted_server.py

        handle_request(request, requester_name, responder)
예제 #7
0
    def ServerCallback(vectorobj):
        requester_id = vectorobj.num
        requester_name, request = FAMEZ_MailBox.retrieve(requester_id)
        SI = vectorobj.cbdata

        # The requester can die between its request and this callback.
        try:
            responder = SI.clients[requester_id]
        except KeyError as e:
            SI.logmsg('Disappeering act by %d' % requester_id)
            return
        responder.requester_id = requester_id  # FIXME: is this necessary?

        # For QEMU/VM, this may be the first chance to retreive the filename.
        if not responder.nodename:
            responder.nodename = requester_name

        ret = handle_request(request, requester_name, responder)
예제 #8
0
    def __init__(self, args=None):
        '''Args must be an object with the following attributes:
           foreground, logfile, mailbox, nClients, silent, socketpath, verbose
           Suitable defaults will be supplied.'''

        # Pass command line args to ProtocolIVSHMSG, then open logging.
        if args is None:
            args = argparse.Namespace()
        for arg, default in self._required_arg_defaults.items():
            setattr(args, arg, getattr(args, arg, default))

        # Mailbox may be sized above the requested number of clients to
        # satisfy QEMU IVSHMEM restrictions.
        args.server_id = args.nClients + 1
        args.nEvents = args.nClients + 2
        FAMEZ_MailBox(args=args)  # singleton class, no need to keep instance

        self.cmdlineargs = args
        if args.foreground:
            TPlog.startLogging(sys.stdout, setStdout=False)
        else:
            PRINT('Logging to %s' % args.logfile)
            TPlog.startLogging(
                DailyLogFile.fromFullPath(args.logfile),
                setStdout=True)  # "Pass-through" explicit print() for debug
        args.logmsg = TPlog.msg
        args.logerr = TPlog.err

        # By Twisted version 18, "mode=" is deprecated and you should just
        # inherit the tacky bit from the parent directory.  wantPID creates
        # <path>.lock as a symlink to "PID".
        E = UNIXServerEndpoint(
            TIreactor,
            args.socketpath,
            mode=0o666,  # Deprecated at Twisted 18
            wantPID=True)
        E.listen(self)
        args.logmsg('FAME-Z server @%d ready for %d clients on %s' %
                    (args.server_id, args.nClients, args.socketpath))
예제 #9
0
 def get_nodenames(cls):
     cls.id2nodename = OrderedDict()
     for peer_id in sorted(cls.id2fd_list):  # keys() are integer IDs
         nodename, _ = FAMEZ_MailBox.retrieve(peer_id, clear=False)
         cls.id2nodename[peer_id] = nodename