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?
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))
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()
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
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
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)
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)
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))
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