Пример #1
0
 def printswitch(clients, delay=0.5):
     if int(delay) < 0 or int(delay) > 2:
         delay = 1.0
     time.sleep(delay)
     lfmt = '%s %s [%s,%s]'
     rfmt = '[%s,%s] %s %s'
     half = (MB.MAILBOX_MAX_SLOTS - 1) // 2
     NSP = 32
     lspaces = ' ' * NSP
     PRINT('\n%s  ____ ____' % lspaces)
     notch = 'U'
     for i in range(1, half + 1):
         left = i
         right = MB.server_id - left  # 74XX TTL
         try:
             ldesc = lspaces
             c = clients[left]
             pa = c.peerattrs
             pa['cclass'] = MB.cclass(left)
             ldesc += lfmt % (pa['cclass'], MB.nodename(left), pa['CID0'],
                              pa['SID0'])
         except KeyError as e:
             pass
         try:
             c = clients[right]
             pa = c.peerattrs
             pa['cclass'] = MB.cclass(right)
             rdesc = rfmt % (pa['CID0'], pa['SID0'], pa['cclass'],
                             MB.nodename(right))
         except KeyError as e:
             rdesc = ''
         PRINT('%-s -|%1d  %c %2d|- %s' %
               (ldesc[-NSP:], left, notch, right, rdesc))
         notch = ' '
     PRINT('%s  =========' % lspaces)
Пример #2
0
    def connectionLost(self, reason):
        '''Tell the other peers that this one has died.'''
        dirty = reason.check(TIError.ConnectionDone) is None
        status = 'Dirty' if dirty else 'Clean'
        verb = 'server shutdown' if self.SI.quitting else 'disconnect'
        self.SI.logmsg('%s %s of peer id %d' % (status, verb, self.id))
        # For QEMU crashes and shutdowns (not the OS guest but QEMU itself).
        MB.clear_mailslot(self.id)

        if self.id in self.SI.clients:  # Only if everything was completed
            del self.SI.clients[self.id]
        if self.SI.recycled and not self.SI.quitting:
            self.SI.recycled[self.id] = self
        else:
            try:
                for other_peer in self.SI.clients.values():
                    ivshmsg_send_one_msg(other_peer.transport.socket, self.id)
                for EN in self.EN_list:
                    EN.cleanup()
            except Exception as e:
                self.SI.logmsg('Closing peer transports failed: %s' % str(e))
        self.printswitch(self.SI.clients)
        if self.SI.quitting and not self.SI.clients:  # last one exited
            self.SI.logmsg('Final client disconnected after "quit"')
            TIreactor.stop()  # turn out the lights
Пример #3
0
 def connectionLost(self, reason):
     print(reason.value)
     if reason.check(TIError.ConnectionDone) is None:  # Dirty
         print('Client was probably interrupted or killed.')
     else:
         if self.quitting:
             print('Last interactive command was "quit".')
         else:
             print('The server was probably shut down.')
     MB.clear_mailslot(self.id)  # In particular, nodename
     if TIreactor.running:  # Stopped elsewhere on SIGINT
         TIreactor.stop()
Пример #4
0
    def ServerCallback(vectorobj):
        requester_id = vectorobj.num
        requester_name = MB.nodename(requester_id)
        request = MB.retrieve(requester_id)
        SI = vectorobj.cbdata

        # Recover the appropriate requester proxy object which can die between
        # its interrupt and this callback.
        try:
            requester_proxy = SI.clients[requester_id]
            assert requester_proxy.SI is SI, 'Say WHAT?'
            assert requester_proxy.id == requester_id, 'WTF MF?'
            requester_proxy.requester_id = requester_id  # Pedantic?
            # For QEMU/VM, this may be the first chance to grab this (if the
            # drivers hadn't come up before).  Just get it fresh each time.
            requester_proxy.nodename = requester_name
            requester_proxy.cclass = MB.cclass(requester_id)
            requester_proxy.peerattrs['cclass'] = requester_proxy.cclass
        except KeyError as e:
            SI.logmsg('Disappeering act by %d' % requester_id)
            return

        # The object passed has two sets of data:
        # 1. Id/target information on where to send the response
        # 2. Peer attributes used in two requests:
        #    readout to send them
        #    overwrite if they're being sent by a PFM
        # I'm "if blah blah" in handle_request() but I should just strip the
        # peer attribute here (the server in this case).  for the server,
        # requester_name and requester_proxy.nodename are the same
        # peer_attributes are from the server, not the proxy.
        # it's different for the client.

        ro = ResponseObject(
            this=SI,  # has "my" (server) CID0, SID0, and cclass
            proxy=requester_proxy,  # for certain server-only admin
            from_id=SI.id,
            to_doorbell=requester_proxy.EN_list[SI.id],
            logmsg=SI.logmsg,
            stdtrace=SI.stdtrace,
            verbose=SI.verbose)
        ret = handle_request(request, requester_name, ro)

        # ret is either True, False, or...

        if ret == 'dump':
            # Might be some other stuff, but finally
            ProtocolIVSHMSGServer.printswitch(SI.clients)
Пример #5
0
    def doCommand(self, cmd, args=None):

        if cmd in ('h', 'help') or '?' in cmd:
            print('h[elp]\n\tThis message')
            print('d[ump]\n\tPrint status of all ports')
            print('q[uit]\n\tShut it all down')
            return True

        if cmd in ('d', 'dump'):
            if self.verbose > 1:
                PRINT('')
                for id, peer in self.SI.clients.items():
                    PRINT('%10s: %s' % (MB.nodename(id), peer.peerattrs))
                    if self.verbose > 2:
                        PPRINT(vars(peer), stream=sys.stdout)
            self.printswitch(self.SI.clients, 0)
            return True

        if cmd in ('q', 'quit'):
            self.quitting = True  # self == SI, remember?
            self.logmsg('Interactive command to "quit"')
            if self.clients:  # Trigger lostConnection
                for c in self.clients.values():
                    c.transport.loseConnection()  # Final callback exits
            else:
                TIreactor.stop()
            return False

        PRINT('Unrecognized command "%s", try "help"' % cmd)
        return True
Пример #6
0
def send_payload(payload,
                 from_id,
                 to_doorbell,
                 reset_tracker=False,
                 tag=None,
                 tagCID=0,
                 tagSID=0):
    global _next_tag, _tracker

    # PRINT('Send "%s" from %d to %s' % (payload, from_id, vars(to_doorbell)))

    if tag is not None:  # zero-length string can trigger this
        payload += ',Tag=%d' % _next_tag
        _tagged[str(_next_tag)] = '%d.%d!%s|%s' % (tagCID, tagSID, payload,
                                                   tag)
        _next_tag += 1

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

    ret = MB.fill(from_id, payload)  # True == no timeout, no stomp
    to_doorbell.ring()
    return ret
Пример #7
0
    def ClientCallback(vectorobj):
        requester_id = vectorobj.num
        requester_name = MB.nodename(requester_id)
        request = MB.retrieve(requester_id)
        requester_obj = vectorobj.cbdata
        # print('Raw Req ID = %d\n%s' % (requester_id, vars(requester_obj)))

        # [dest][src]
        ro = ResponseObject(
            this=requester_obj,  # has CID0, SID0, and cclass
            proxy=None,  # I don't manage ever (for now)
            from_id=requester_obj.id,
            to_doorbell=requester_obj.id2EN_list[requester_id][
                requester_obj.id],
            logmsg=requester_obj.logmsg,
            stdtrace=requester_obj.stdtrace,
            verbose=requester_obj.verbose,
        )
        ret = handle_request(request, requester_name, ro)
Пример #8
0
 def parse_target(caller_id, instr):
     '''Return a list even for one item for consistency with keywords
        ALL and OTHERS.'''
     try:
         tmp = (int(instr), )
         if 1 <= tmp[0] <= MB.server_id:
             return tmp
     except TypeError as e:
         return None
     except ValueError as e:
         if instr.lower()[-6:] in ('server', 'switch'):
             return (MB.server_id, )
         active_ids = MB.active_ids()
         for id in active_ids:
             if MB.slots[id].nodename == instr:
                 return (id, )
         if instr.lower() == 'all':  # Includes caller_id
             return active_ids
         if instr.lower() == 'others':
             return active_ids.remove(caller_id)
     return None
Пример #9
0
    def __init__(self, factory, args=None):
        '''"self" is a new client connection, not "me" the server.  As such
            it is a proxy object for the other end of each switch "port".
            args is NOT passed on instantiation via connection.'''
        assert isinstance(factory, TIPServerFactory), 'arg0 not my Factory'
        shutdown_http_logging()
        self.isPFM = False

        # Am I one of many peer proxies?
        if self.SI is not None and args is None:
            self.create_new_peer_id()
            # Python client will quickly fix this.  QEMU VM will eventually
            # modprobe, etc.
            self.peerattrs = {
                'CID0': '0',
                'SID0': '0',
                'cclass': 'Driverless QEMU'
            }
            MB.slots[self.id].cclass = self.peerattrs['cclass']
            return

        # This instance is voodoo from the first manual kick.  Originally
        # the server had "other" tracking but now it's a "reserved instance"
        # which is used as the callback for events (ie, incoming mailslot
        # doorbell for each active peer proxy).

        cls = self.__class__
        cls.SI = self  # Reserve it and flesh it out.
        cls.verbose = args.verbose

        self.id = args.server_id
        assert self.id == MB.server_id, 'Server ID mismatch'
        self.quitting = False
        self.cclass = MB.cclass(self.id)
        self.logmsg = args.logmsg
        self.logerr = args.logerr
        self.stdtrace = sys.stderr
        self.smart = args.smart
        self.clients = OrderedDict()  # Order probably not necessary
        self.recycled = {} if args.recycle else None

        # For the ResponseObject/request().
        if self.smart:
            self.default_SID = 27
            self.SID0 = self.default_SID
            self.CID0 = self.id * 100
            self.isPFM = True
        else:
            self.default_SID = 0
            self.SID0 = 0
            self.CID0 = 0

        # Non-standard addition to IVSHMEM server role: this server can be
        # interrupted and messaged to particpate in client activity.
        # This variable will get looped even if it's empty (silent mode).
        # Usually create eventfds for receiving messages in IVSHMSG and
        # set up a callback.  This arming is not a race condition as any
        # peer for which this is destined has not yet been "listened/heard".

        self.EN_list = []
        if not args.silent:
            self.EN_list = ivshmsg_event_notifier_list(MB.nEvents)
            # The actual client doing the sending needs to be fished out
            # via its "num" vector.
            for i, EN in enumerate(self.EN_list):
                EN.num = i
                tmp = EventfdReader(EN, self.ServerCallback, cls.SI)
                if i:  # Skip mailslot 0, the globals "slot"
                    tmp.start()
Пример #10
0
        # Instead of this.app.run(), break it open and wait for
        # twister_server.py to finally invoke TIreactor.run() as all these
        # things use the default reactor.  Note that self.app was assigned
        # durng the class-level scan/eval of this source file.  See also
        # /usr/lib/python3/dist-packages/klein/app.py::run()
        s = TWserver.Site(self.app.resource())
        TIreactor.listenTCP(port, s)


if __name__ == '__main__':

    from twisted.python import log as TPlog  # Deprecated

    from ivshmsg_mailbox import IVSHMSG_MailBox

    # These things are done explicitly in twisted_server.py
    fname = '/dev/shm/ivshmsg_mailbox' if len(sys.argv) < 2 else sys.argv[1]
    if not fname or fname[0] == '-':
        raise SystemExit('usage: %s [ /path/to/mailbox ]' % sys.argv[0])
    print('Opening', fname)
    fd = os.open(fname, os.O_RDWR)
    mb = IVSHMSG_MailBox(fd=fd, client_id=99)
    tmp = MailBoxReSTAPI(mb)

    # This is done explicitly in twisted_server.py
    TPlog.startLogging(sys.stdout, setStdout=False)

    # This is done implicitly after protocol registration in full app.
    TIreactor.run()