Exemple #1
0
    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),)
Exemple #2
0
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))
Exemple #3
0
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))