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),)
def session_recv(locks, terminals, log, tap_events): """ 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, the number of seconds elapsed since lock was first held is consider stale after that period of time, and is acquire anyway. """ # No actual Lock instances are held or released, just a simple dictionary # state/time tracking system. from x84.terminal import kill_session from x84.db import DBHandler for sid, tty in terminals: while tty.master_read.poll(): try: event, data = tty.master_read.recv() except (EOFError, IOError) as err: # sub-process unexpectedly closed msg_err = 'master_read pipe: {err}'.format(err=err) log.exception(msg_err) kill_session(tty.client, msg_err) break except TypeError: msg_err = 'unpickling error' log.exception(msg_err) break # 'exit' event, unregisters client if event == 'exit': kill_session(tty.client, 'client exit') break # 'logger' event, prefix log message with handle and IP address elif event == 'logger': data.msg = ('{data.handle}[{tty.sid}] {data.msg}' .format(data=data, tty=tty)) log.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] reason = 'remote-disconnect by {sid.tty}'.format(sid=sid) for _sid, _tty in terminals: if send_to == _sid: kill_session(tty.client, reason) break # 'route': message passing directly from one session to another elif event == 'route': if tap_events: log.debug('route {0!r}'.format(data)) tgt_sid, send_event, send_val = data[0], data[1], data[2:] for _sid, _tty in terminals: if tgt_sid == _sid: _tty.master_write.send((send_event, send_val)) break # 'global': message broadcasting to all sessions elif event == 'global': if tap_events: log.debug('broadcast: {data!r}'.format(data=data)) for _sid, _tty in terminals: if sid != _sid: _tty.master_write.send((event, data,)) # 'set-timeout': set user-preferred timeout elif event == 'set-timeout': if tap_events: log.debug('[{tty.sid}] set-timeout {data}' .format(tty=tty, data=data)) tty.timeout = data # 'db*': access DBProxy API for shared sqlitedict elif event.startswith('db'): thread = DBHandler(tty.master_write, event, data) thread.start() # 'lock': access fine-grained bbs-global locking elif event.startswith('lock'): handle_lock(locks, tty, event, data, tap_events, log) else: log.error('[{tty.sid}] unhandled event, data: ' '({event}, {data})' .format(tty=tty, event=event, data=data))
def session_recv(locks, terminals, log, tap_events): """ Receive data waiting for terminal sessions. All data received from subprocess is handled here. """ for sid, tty in terminals: while tty.master_read.poll(): try: event, data = tty.master_read.recv() except (EOFError, IOError) as err: # sub-process unexpectedly closed log.exception('master_read pipe: {0}'.format(err)) kill_session(tty.client, 'master_read pipe: {0}'.format(err)) break except TypeError as err: log.exception('unpickling error: {0}'.format(err)) break # 'exit' event, unregisters client if event == 'exit': kill_session(tty.client, 'client exit') break # 'logger' event, prefix log message with handle and IP address elif event == 'logger': data.msg = ('{data.handle}[{tty.sid}] {data.msg}' .format(data=data, tty=tty)) log.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': for _sid, _tty in terminals: # data[0] is 'send-to' address. if data[0] == _sid: kill_session( tty.client, 'remote-disconnect by {0}'.format(sid)) break # 'route': message passing directly from one session to another elif event == 'route': if tap_events: log.debug('route {0!r}'.format(data)) tgt_sid, send_event, send_val = data[0], data[1], data[2:] for _sid, _tty in terminals: if tgt_sid == _sid: _tty.master_write.send((send_event, send_val)) break # 'global': message broadcasting to all sessions elif event == 'global': if tap_events: log.debug('broadcast: {data!r}'.format(data=data)) for _sid, _tty in terminals: if sid != _sid: _tty.master_write.send((event, data,)) # 'set-timeout': set user-preferred timeout elif event == 'set-timeout': if tap_events: log.debug('[{tty.sid}] set-timeout {data}' .format(tty=tty, data=data)) tty.timeout = data # 'db*': access DBProxy API for shared sqlitedict elif event.startswith('db'): DBHandler(tty.master_write, event, data).start() # 'lock': access fine-grained bbs-global locking elif event.startswith('lock'): handle_lock(locks, tty, event, data, tap_events, log) else: log.error('[{tty.sid}] unhandled event, data: ' '({event}, {data})' .format(tty=tty, event=event, data=data))