def telnet_recv(fds): """ test all telnet clients with file descriptors in list fds for recv(). If any are disconnected, signal exit to subprocess, unregister the session (if any). """ # read in any telnet input for client in (clt for (fno, clt) in telnetd.clients.iteritems() if fno in fds): try: client.socket_recv() except Disconnected as err: logger.info('%s Connection Closed: %s.', client.addrport(), err) tty = lookup(client) if tty is None: # no session found, just de-activate this client client.deactivate() else: # signal exit to sub-process and shutdown send_event, send_data = 'exception', Disconnected(err) tty.iqueue.send((send_event, send_data)) unregister(tty)
def telnet_send(recv_list): """ test all telnet clients for send(). If any are disconnected, signal exit to subprocess, unregister the session, and return recv_list pruned of their file descriptors. """ for sid, tty in terminals(): if tty.client.send_ready(): try: tty.client.socket_send() except Disconnected as err: logger.debug('%s Disconnected: %s.', sid, err) # client.sock.fileno() can raised 'bad file descriptor', # so, to remove it from the recv_list, reverse match by # instance saved with its FD as a key for telnetd.clients! for _fd, _client in telnetd.clients.items(): if tty.client == _client: if _fd in recv_list: recv_list.remove(_fd) break send_event, send_data = 'exception', Disconnected(err) tty.iqueue.send((send_event, send_data,)) unregister(tty) return recv_list
def session_recv(fds): """ receive data waiting for session; all data received from subprocess is in form (event, data), and is handled by ipc_recv. if stale is not None, elapsed time lock was held to consider stale and acquire anyway. no actual locks are held or released, just a simple dictionary state/time tracking system. """ disp_handle = lambda handle: ((handle + u' ') if handle is not None and 0 != len(handle) else u'') disp_origin = lambda client: client.addrport().split(':', 1)[0] for sid, tty in terminals(): while tty.oqueue.fileno() in fds and tty.oqueue.poll(): # receive data from pipe, unregister if any error, try: event, data = tty.oqueue.recv() except (EOFError, IOError) as err: # sub-process unexpectedly closed logger.exception(err) unregister(tty) return # 'exit' event, unregisters client if event == 'exit': unregister(tty) return # 'logger' event, propogated upward elif event == 'logger': # prefix message with 'ip:port/nick ' data.msg = '%s[%s] %s' % ( disp_handle(data.handle), disp_origin(tty.client), data.msg) logger.handle(data) # 'output' event, buffer for tcp socket elif event == 'output': tty.client.send_unicode(ucs=data[0], encoding=data[1]) # 'remote-disconnect' event, hunt and destroy elif event == 'remote-disconnect': send_to = data[0] for _sid, _tty in terminals(): if send_to == _sid: send_event = 'exception' send_val = Disconnected( 'remote-disconnect by %s' % (sid,)) tty.iqueue.send((send_event, send_val)) unregister(tty) break # 'route': message passing directly from one session to another elif event == 'route': logger.debug('route %r', (event, data)) tgt_sid, send_event, send_val = data[0], data[1], data[2:] for _sid, _tty in terminals(): if tgt_sid == _sid: _tty.iqueue.send((send_event, send_val)) break # 'global': message broadcasting to all sessions elif event == 'global': logger.debug('broadcast %r', (event, data)) for _sid, _tty in terminals(): if sid != _sid: _tty.iqueue.send((event, data,)) # 'set-timeout': set user-preferred timeout elif event == 'set-timeout': logger.debug('set-timeout %d', data) tty.timeout = data # 'db*': access DBProxy API for shared sqlitedict elif event.startswith('db'): thread = DBHandler(tty.iqueue, event, data) thread.start() # 'lock': access fine-grained bbs-global locking elif event.startswith('lock'): handle_lock(tty, event, data) else: assert False, 'unhandled %r' % ((event, data),)