Exemple #1
0
def __request(s,srv,r_type,args):
    '''Send request to server, receive response
    @param sock: UDP socket, used to send/receive
    @param src: tuple ( IP, port ), server socket address
    @param r_type: string, request type
    @param args: list, request parameters/data
    '''
    # Envelope request (prepare data unit)
    m = __SESS_FIELD_SEP.join([r_type]+map(str,args))
    # Send
    s.sendto(m,srv)
    source = None
    while source != srv:
        try:
            # Try receive a response
            r,source = s.recvfrom(__SESS_MAX_PDU)
        except KeyboardInterrupt:
            LOG.info('Ctrl+C issued, terminating ...')
            s.close()
            exit(0)
        # In case unexpected message was received
        if source != srv:
            LOG.debug('Unknown message origin %s:%d' % source)
            LOG.debug( 'Expected %s:%d' % srv)
    # Check error code
    r_data = r.split(__SESS_FIELD_SEP)
    err,r_args = r_data[0],r_data[1:] if len(r_data) > 1 else []
    if err != __SESS_RSP_OK:
        if err in __SESS_ERR_MSG.keys():
            LOG.error('Error: server response code [%s]' % err)
            LOG.error(__SESS_ERR_MSG[err])
        else:
            LOG.error('Malformed server response [%s]' % err)
    return err,r_args
Exemple #2
0
def process_session(block, source):
    '''Process the session block, assemble the message
    @param block: string, a piece of bigger message
    @param source: tuple ( ip, port ), client's socket address
    @returns string, response to send to client
    '''
    global __M
    LOG.debug('Received block length %d' % len(block))
    if len(block) < 2:
        LOG.debug('Not enough data received from %s ' % source)
        return __SESS_RSP_BADFORMAT
    # Declare new session
    if block.startswith(__SESS_REQ_NEW + __SESS_FIELD_SEP):
        sess_id = __new_session(source)
        LOG.debug('New session [%d] initiated with '\
                  ' %s:%d' % ((sess_id,)+source))
        return __SESS_FIELD_SEP.join(map(str, [__SESS_RSP_OK, sess_id]))
    # Receive a new block
    if block.startswith(__SESS_REQ_SEND_BLOCK + __SESS_FIELD_SEP):
        parts = block.split(__SESS_FIELD_SEP)
        if len(parts) < 6:
            LOG.degug('Malformed received from %s ' % source)
            return __SESS_RSP_BADFORMAT
        head, data = parts[1:5], __SESS_FIELD_SEP.join(parts[5:])
        LOG.debug('New block [head:%s] received '\
                  'from %s:%d' % ((str(head),)+source))
        # Parse header
        try:
            head = map(int, head)
            sess_id, i, count, l = head
        except ValueError:
            LOG.debug('No numeric data in block header [%s]' % (str(head)))
            return __SESS_RSP_BADFORMAT
        LOG.info('Session %d: Received block %d/%d '\
                 'size %d' % (sess_id,i,count,l))
        # Check block
        if len(data) != l:
            # Incomplete block
            LOG.info('Session %d: block %d/%d incomplete size '\
                     '%d of %d' % (sess_id,i,count,len(data),l))
            return __SESS_RSP_RETRANS
        # Store block
        n = __store_session_block(head, data, source)
        LOG.info('Session %d: %d/%d blocks received successfully'\
                 '' % (sess_id, n, count))
        return __SESS_FIELD_SEP.join(map(str, [__SESS_RSP_OK, n]))
    # Close session
    if block.startswith(__SESS_REQ_CLOSE + __SESS_FIELD_SEP):
        parts = block.split(__SESS_FIELD_SEP)
        if len(parts) < 2:
            LOG.degug('Malformed received from %s ' % source)
            return __SESS_RSP_BADFORMAT
        try:
            sess_id = int(parts[1])
        except ValueError:
            LOG.debug('No numeric data in control code [%s]' % parts[1])
            return __SESS_RSP_BADFORMAT
        # Retrieve full message, store it, clean session
        message = __retrieve_message(sess_id, source)
        if message == None:
            LOG.info('Session %d: interrupted by client %s:%d'\
                     '' % ((sess_id,)+source))
            return __SESS_FIELD_SEP.join(map(str, [__SESS_RSP_OK, 0]))
        LOG.debug('Received new message, size %d from %s:%d'\
                  '' % ((len(message),)+source))
        __M.append((source, message))
        return __SESS_FIELD_SEP.join(map(str, [__SESS_RSP_OK, 1]))
def server_process(board, message, source, oldprotocol=False):
    '''Process the client's message, modify the board if needed
        @param board: active message board (static lib.)
        @param message: string, protocol data unit received from client
        @param source: tuple ( ip, port ), client's socket address
        @param oldprotocol: backward compatibility flag (for 0.0.0.x clients)
        @returns string, response to send to client
    '''
    LOG.debug("###### RECEIVED REQUEST ######")
    LOG.debug('Received message length %d' % len(message))
    if len(message) < 2:
        LOG.debug('Not enough data received from %s ' % message)
        return __RSP_BADFORMAT
    LOG.debug('Message control code (%s) ' \
              '%s ' % (message[0], __CTR_MSGS[message[0]]))
    if message.startswith(__REQ_PUBLISH + __MSG_FIELD_SEP):
        msg = message[2:]
        LOG.debug('New message to publish from %s:%d, ' \
                  'msg: %s' % (source + ((msg[:60] + '...' if len(msg) > 60 else msg),)))
        m_id = board.publish(msg, source)
        LOG.info('Published new message, uuid: %d' % m_id)
        return __RSP_OK
    elif message.startswith(__REQ_LAST + __MSG_FIELD_SEP):
        s = message[2:]
        try:
            n = int(s)
            LOG.debug('New message listing request from %s:%d, ' \
                      'messages %d' % (source + (n,)))
        except ValueError:
            LOG.debug('Integer required, %s received' % s)
            return __RSP_BADFORMAT
        ids = board.last(n)
        LOG.debug('Last %d ids: %s ' % (n, ','.join(map(str, ids))))
        return __MSG_FIELD_SEP.join((__RSP_OK, ) + tuple(map(str, ids)))
    elif message.startswith(__REQ_GET + __MSG_FIELD_SEP):
        s = message[2:]
        try:
            m_id = int(s)
            LOG.debug('New message request by id from %s:%d, ' \
                      'id %d' % (source + (m_id,)))
        except ValueError:
            LOG.debug('Integer required, %s received' % s)
            return __RSP_BADFORMAT
        m = board.get(m_id)
        m = map(str, m)
        if oldprotocol:
            # too bad here will lose some of the message trail in
            # respect of the header, but this only affects long messages
            # client should be aware of it and not let publishing messages
            # which are close to maximal PDU size

            msg_info_size = sum(map(len, m[:3])) + len(m[:3])
            # +2 For control code
            if (len(m[3]) + msg_info_size + 2) > MAX_PDU_SIZE_OLD_PROTO:
                offset = MAX_PDU_SIZE_OLD_PROTO - (msg_info_size + 2)
                m = m[:3] + [m[3][:offset]]
                LOG.info('Big message was cut, %d trailing bytes removed' %
                         offset)
                LOG.info('Upgrade client code to protocol 0.0.1.x!')
        LOG.debug('Message id %d, msg size: [%d]' % (m_id, len(' '.join(m))))
        if m == None:
            LOG.debug('No messages by iD: %d' % m_id)
            return __RSP_MSGNOTFOUND
        return __MSG_FIELD_SEP.join((__RSP_OK, ) + tuple(m))

    elif message.startswith(__REQ_HAS_MESSAGES + __MSG_FIELD_SEP):
        n_msg = board.get_size()
        LOG.debug("Number of messages in server.protocol: %d" % n_msg)
        return __MSG_FIELD_SEP.join((__RSP_OK, ) + tuple(map(str, [n_msg])))

    elif message.startswith(__REQ_GET_MESSAGES + __MSG_FIELD_SEP):
        msg_board = board.get_all_unread()
        LOG.debug("All of the messages %s" % msg_board)
        msg_list = []
        for msg in msg_board:
            msg_list.append(msg_board[msg][4])
        return __MSG_FIELD_SEP.join((__RSP_OK, ) + tuple(map(str, msg_list)))

    elif message.startswith(__REQ_GET_BLOCK + __SESS_FIELD_SEP):
        LOG.debug("Message in server protocol get_block: %s" % str(message))
        parts = message.split(__SESS_FIELD_SEP)
        s_id = int(parts[1])
        block_n = int(parts[2])

        return_value = get_block(s_id, block_n)
        return __SESS_FIELD_SEP.join((__SESS_RSP_OK, ) +
                                     tuple(map(str, return_value)))

    elif message.startswith(__REQ_DOWNLOAD_FINISHED + __SESS_FIELD_SEP):
        parts = message.split(__SESS_FIELD_SEP)
        finish_download(int(parts[1]))

        return __SESS_RSP_OK + __SESS_FIELD_SEP

    else:
        LOG.debug('Unknown control message received: %s ' % message)
        return __RSP_UNKNCONTROL