コード例 #1
0
 def get_name(self):
     #do this until we have a name
     while self.name == '':
         #prompt user
         msg_name_prompt = message.Message()
         msg_name_prompt.clear()
         msg_name_prompt.set_text('Please input your name')
         self.send(message.pack(msg_name_prompt))
         #get name from socket
         msg_client_name = message.Message(data=message.unpack(self.conn.recv(DATA_SIZE)))
         while msg_client_name.get_type() == 'ping':
             self.handle_ping()
             msg_client_name = message.Message(data=message.unpack(self.conn.recv(DATA_SIZE)))
         name_from_client = msg_client_name.get_text()
         #check name length
         if len(name_from_client) > NAME_SIZE_LIMIT:
             msg_name_too_long = message.Message()
             msg_name_too_long.set_text('That name is too long')
             self.send(message.pack(msg_name_too_long))
         else:
             #check name isnt already taken
             name_taken = False
             for c in CLIENTS:
                 if name_from_client == c.name:
                     name_taken = True
             if name_taken:
                 msg_name_taken = message.Message()
                 msg_name_taken.set_text('That name is already taken')
                 self.send(message.pack(msg_name_taken))
             else:
                 #if we pass all the tests then set the clien name
                 self.name = name_from_client
コード例 #2
0
def handle_user_command(client, msg):
    cmds = msg.get_text().split()
    if cmds[0] == '/name':
        prev_name = client.name_color + client.name
        client.name = ''
        client.get_name()
        msg_name_change = message.Message()
        msg_name_change.set_time(get_time())
        msg_name_change.set_text('{} changed their name to {}'.format(prev_name, client.name))
        broadcast(message.pack(msg_name_change))
        return True
    elif cmds[0] == '/color':
        if cmds[1] in USER_COLORS:
            print('set {} color to red'.format(client))
            client.name_color = cmds[1]
        else:
            client.name_color = None
        return True
    elif cmds[0] == '/clan':
        if len(cmds) > 1:
            if cmds[1] == 'leave':
                client.clan = None
                return True
            elif len(cmds[1]) <= 4:
                client.clan = cmds[1]
                return True
        return False
    elif cmds[0] == '/help':
        msg_help = message.Message()
        msg_help.set_type('text')
        msg_help.set_text('\n\t/help - show help\n\t/name <new name> - change your name\n\t/color [red, green, yellow, blue, purple, cyan] - change name color WIP\n\t/clan leave/<4 characters> - leave or join a clan')
        client.send(message.pack(msg_help))
        return True
    return False
コード例 #3
0
def main():
    print('\033[1;37;40mType \'/quit\' to leave')

    global RUNNING

    #specify connection attempts loop
    for connection_attempts in range(0, 10):
        try:
            #create socket and connect to the server
            s = socket.socket()
            s.connect((IP_ADDR, PORT))
            s.settimeout(10)

            #if we havent failed yet then reset out connection_attempts counter
            connection_attempts = 0

            #start a thread to listen for messages from the server
            listen_thread = threading.Thread(target=listen_loop, args=(s, ))
            listen_thread.start()

            #start a thread to listen for pings from the server to verify connection
            ping_thread = threading.Thread(target=ping_loop, args=(s, ))
            ping_thread.start()

            #listen for CLI input
            while RUNNING:
                input_text = input()

                #if the user wants to quit, we should quit
                if input_text == '/quit':
                    msg_leave = message.Message()
                    msg_leave.set_type('leave')
                    s.sendall(message.pack(msg))
                    RUNNING = False
                    break

                #if it is a message to the server
                msg = message.Message()
                msg.set_type('text')
                msg.set_text(input_text)
                s.sendall(message.pack(msg))

            #cleanup
            listen_thread.join()
            ping_thread.join()
            s.shutdown()
        except:
            #handle exceptions
            print('No Connection.. Retrying')
            time.sleep(10)

    #say goodbye depending on how it shut down
    if RUNNING:
        print('Connection Failed!!!')
    else:
        print('Good bye!')
コード例 #4
0
    def run(self):
        try:
            #get the name from the client
            self.get_name()

            #tell everyone there is a new client
            msg_user_join = message.Message()
            msg_user_join.set_type('text')
            msg_user_join.set_text('{} has joined the chat!'.format(self.name))
            msg_user_join.set_time(get_time())
            print(message.pack(msg_user_join))
            broadcast(message.pack(msg_user_join))

            #add this client to the client list
            CLIENTS.append(self)

            msg_data = self.conn.recv(DATA_SIZE)
            while msg_data:
                msg = message.Message(data=message.unpack(msg_data))
                if msg.get_text() != None:
                    msg.set_time(time.strftime('%H:%M:%S', time.localtime()))
                    msg.set_sender(self.name, color=self.name_color, clan=self.clan)

                    if msg.get_type() == 'ping':
                        self.handle_ping()
                    elif msg.get_type() == 'leave':
                        self.leave()
                    elif msg.get_type() == 'text':
                        if msg.get_text().split()[0] in USER_COMMANDS:
                            if not handle_user_command(self, msg):
                                msg_invalid_command = message.Message()
                                msg_invalid_command.set_type('text')
                                msg_invalid_command.set_text('Invalid command. view /help')
                                self.send(message.pack(msg_invalid_command))
                            print('PASS')
                        else:
                            if len(msg.get_text()) > MSG_SIZE_MAX:
                                error_msg = message.Message()
                                error_msg.set_type('error')
                                error_msg.set_sender('[SERVER]')
                                error_msg.set_time(get_time())
                                error_msg.set_text('Your message was too long. Max is 200 characters.')
                                self.send(message.pack(error_msg))
                                print('{} attempted to send a LARGE message'.format(self.address))
                            else:
                                #the formatted message as it will be sent to all users
                                msg.print()
                                broadcast(message.pack(msg))
                    else:
                        print('Unknown message type: {}'.format(message.unpack(msg)))
                msg_data = self.conn.recv(DATA_SIZE)
        except Exception as e:
            print(e)
            print("Connection Lost to {}".format(self.address))
            self.leave()
コード例 #5
0
def ping_loop(socket):
    while RUNNING:
        time.sleep(3)
        ping_msg = message.Message()
        ping_msg.set_type('ping')
        bmsg = message.pack(ping_msg)
        socket.sendall(bmsg)
コード例 #6
0
    def get_name(self):
        #do this until we have a name
        while self.name == '':

            #prompt user
            msg_name_prompt = message.Message()
            msg_name_prompt.clear()
            msg_name_prompt.set_text('Please input your name')
            self.send(message.pack(msg_name_prompt))

            try:
                #get name from socket while the message received is not a ping
                msg_client_name = message.Message(data=message.unpack(self.conn.recv(DATA_SIZE)))
                while msg_client_name.get_type() == 'ping':
                    self.handle_ping()
                    msg_client_name = message.Message(data=message.unpack(self.conn.recv(DATA_SIZE)))
                name_from_client = msg_client_name.get_text()
            except:
                #if the data from the client is malformed then restart this process
                break

            #verify name length
            if len(name_from_client) > NAME_SIZE_LIMIT:
                # if the name is too long restart
                msg_name_too_long = message.Message()
                msg_name_too_long.set_type('text')
                msg_name_too_long.set_text('That name is too long. Max: {} characters'.format(NAME_SIZE_LIMIT))
                self.send(message.pack(msg_name_too_long))
            else:
                #verify name isnt already taken
                name_taken = False
                for c in CLIENTS:
                    if name_from_client == c.name:
                        name_taken = True

                # if the name is taken then restart
                if name_taken:
                    msg_name_taken = message.Message()
                    msg_name_taken.set_type('text')
                    msg_name_taken.set_text('That name is already taken')
                    self.send(message.pack(msg_name_taken))
                else:
                    #if we pass all the tests then set the clien name
                    self.name = name_from_client
コード例 #7
0
    def handle_loop_message(self, loop_payload, ttl):
        '''This function will process the loop message and will determine if the message should be passed to the next stage (the next process)
           or it should be discarted. (Returning True or False).
           '''
        type = struct.unpack(">B", loop_payload[0])[0]

        if type == passage.LOOP_SUBTYPE_BY_NAME['Leader']:
            syslog.syslog(syslog.LOG_DEBUG, "Leader Election received...")
            leader_name_len = struct.unpack('>B', loop_payload[1])[0]
            leader_name = struct.unpack('%is' % leader_name_len, loop_payload[2: leader_name_len+2])[0]

            if leader_name == self.localhost_name:
                syslog.syslog(syslog.LOG_DEBUG, "I'am the new leader %s (previous %s) of the group with %i members." % (str(self.localhost_name), str(self.leader_name), passage.TTL - ttl + 1))
                #Stop the leader algorithm. 
                #
                # The inbound process MUST start sending its localname as leadername to the outbound queue.
                # When that message come back to the outbound, then the algorithm finish and localname is the leadername
                self.leader_name = leader_name
                
                if self.leader_process and self.leader_process.poll() is None:
                   return False #iam the leader already

                self.clean()
                self.leader_process = Popen(["python", "leader.py", self.path, self.char_id_out, str(self.group_id), self.localhost_name, self.network_name])
               
                #XXX Who has the token?
                self.userland_inbound_queue.push(message.pack("\x00"*(4*3 + 256), passage.ID_BY_TYPE['USER']))
                return False 


            elif leader_name < self.localhost_name:
                syslog.syslog(syslog.LOG_DEBUG, "Minor leader proposal %s discarted by %s (actual leader %s)." % (str(leader_name), str(self.localhost_name), str(self.leader_name) ))
                return False
            else:
                syslog.syslog(syslog.LOG_DEBUG, "Mayor leader proposal %s exceeds me %s (previous leader %s)." % (str(leader_name), str(self.localhost_name), str(self.leader_name) ))
                self.clean()
                self.leader_name = leader_name
                return True

        elif type == passage.LOOP_SUBTYPE_BY_NAME['LinkBroken']:
            open_node_name_len = struct.unpack('>B', loop_payload[1])[0]
            open_node_name = struct.unpack('%is' % open_node_name_len, loop_payload[2: open_node_name_len+2])[0]

            if open_node_name == self.localhost_name:
               return False
            else:
               self.clean()
               return True
        else:
            #Tipo incorrecto, como llego aqui?!?
            raise Exception

        return False
コード例 #8
0
def handle_user_command(client, msg):
    # break the text into components of the command
    cmds = msg.get_text().split()

    ## NAME COMMAND
    if cmds[0] == '/name':
        prev_name = client.name_color + client.name
        client.name = ''
        client.get_name()
        # this code tells the chat room that a user changed their name
        # by popular demand this was removed
        # msg_name_change = message.Message()
        # msg_name_change.set_time(get_time())
        # msg_name_change.set_type('text')
        # msg_name_change.set_text('{} changed their name to {}'.format(prev_name, client.name))
        # broadcast(message.pack(msg_name_change))
        return True

    ## NAME COLOR COMMAND
    elif cmds[0] == '/color':
        if len(cmds) > 1:
            if cmds[1] in USER_COLORS:
                #print('set {} color to red'.format(client.name))
                client.name_color = cmds[1]
            else:
                client.name_color = None
        else:
            client.name_color = None
        return True

    ## CLAN COMMAND
    elif cmds[0] == '/clan':
        if len(cmds) > 1:
            if cmds[1] == 'leave':
                client.clan = None
                return True
            elif len(cmds[1]) <= 4:
                client.clan = cmds[1]
                return True
        return False

    ## HELP COMMAND
    elif cmds[0] == '/help':
        msg_help = message.Message()
        msg_help.set_type('text')
        msg_help.set_text('\n\t/help - show help\n\t/name <new name> - change your name\n\t/color [red, green, yellow, blue, purple, cyan] - change name color WIP\n\t/clan leave/<4 characters> - leave or join a clan')
        client.send(message.pack(msg_help))
        return True
    return False
コード例 #9
0
def main():
    #start the server
    server_socket = start_server()

    global RUNNING

    #start the client accept thread
    accept_thread = threading.Thread(target=accept_clients, args=(server_socket, ))
    accept_thread.start()

    #handle server command line input
    while RUNNING:
        user_input = input()
        if user_input.startswith('/stop'):
            RUNNING = False
            break
        elif user_input.startswith('/say'):
            msg_server_broadcast = message.Message()
            msg_server_broadcast.set_type('text')
            msg_server_broadcast.set_text(user_input[5:])
            msg_server_broadcast.set_sender('[SERVER]')
            broadcast(message.pack(msg_server_broadcast))

    accept_thread.stop()
コード例 #10
0
    def run(self):
        try:
            #get the name from the client
            self.get_name()

            #tell everyone there is a new client
            msg_user_join = message.Message()
            msg_user_join.set_type('text')
            msg_user_join.set_text('{} has joined the chat!'.format(self.name))
            msg_user_join.set_time(get_time())
            broadcast(message.pack(msg_user_join))

            #add this client to the client list
            CLIENTS.append(self)

            # main data listen loop
            msg_data = self.conn.recv(DATA_SIZE)
            while msg_data:
                # turn the data into a message
                msg = message.Message(data=message.unpack(msg_data))
                if msg.get_text() != None:
                    # set the values of the message such as the time and the sender
                    msg.set_time(get_time())
                    msg.set_sender(self.name, color=self.name_color, clan=self.clan)

                    #handle message types
                    if msg.get_type() == 'ping':
                        self.handle_ping()
                    elif msg.get_type() == 'leave':
                        self.leave()
                    elif msg.get_type() == 'text':
                        #check if the msg the user sent is a command
                        if msg.get_text().split()[0] in USER_COMMANDS:
                            #handle the user command
                            if not handle_user_command(self, msg):
                                #if the user command fails
                                #tell the user
                                msg_invalid_command = message.Message()
                                msg_invalid_command.set_type('text')
                                msg_invalid_command.set_text('Invalid command. view /help')
                                self.send(message.pack(msg_invalid_command))
                        else:
                            #check the text from the user is smaller than the max acceptable size
                            if len(msg.get_text()) > MSG_SIZE_MAX:
                                error_msg = message.Message()
                                error_msg.set_type('error')
                                error_msg.set_sender('[SERVER]')
                                error_msg.set_time(get_time())
                                error_msg.set_text('Your message was too long. Max is 200 characters.')
                                self.send(message.pack(error_msg))
                                print('{} attempted to send a LARGE message'.format(self.address))
                            else:
                                #broadcast the message to the clients
                                broadcast(message.pack(msg))
                                if SHOW_CLIENT_MESSAGES:
                                    print(msg)
                    else:
                        #handle unknown cases
                        print('Unknown message type: {}'.format(message.unpack(msg)))
                #continue to listen for data from the client
                msg_data = self.conn.recv(DATA_SIZE)
        except Exception as e:
            #handle exceptions
            #i am not the most familiar with the python exceptions
            #so im printing as much information to both learn and debug
            #this does lead to a messy server console
            exc_information = sys.exc_info()
            print(exc_information)
            print("Connection Lost to {}".format(self.address))
            self.leave()
コード例 #11
0
def passage_inbound_messages(inbound_socket, userland_inbound_queue, userland_outbound_queue, driver):
   try: 
      inbound_socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)

      inbound_socket.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
      inbound_socket.setsockopt(socket.SOL_TCP, socket.TCP_KEEPCNT, KEEPALIVE_PROBE_COUNT)
      inbound_socket.setsockopt(socket.SOL_TCP, socket.TCP_KEEPIDLE, KEEPALIVE_IDLE_TIMEOUT)
      inbound_socket.setsockopt(socket.SOL_TCP, socket.TCP_KEEPINTVL, KEEPALIVE_RETRY_SEND_PROBE)

      peer = inbound_socket.getpeername()

      while True:
         try:
            start_receiving = False
            syslog.syslog(syslog.LOG_INFO, "Receiving packet from remote node %s..." % str(peer))
            type = _recv(inbound_socket, 4, peer)
            start_receiving = True

            if type not in ID_BY_TYPE.keys():
               raise InvalidNetworkMessage("The message received from a member of the ring has a wrong type (corrupted message).", type, peer) 

            size = struct.unpack('>H', _recv(inbound_socket, 2, peer))[0]

            if size > MAX_PAYLOAD:
               raise InvalidNetworkMessage("The message received from a member of the ring has a wrong value in the 'size' field (corrupted message).", size, peer) 
            
            payload =  _recv(inbound_socket, size, peer)
            _send(inbound_socket, "A", peer)

            if type == 'LOOP':
               ttl = struct.unpack('>H', payload[:2])[0]
               
               syslog.syslog(syslog.LOG_DEBUG, "LOOP packet recieved (TTL %i): %s [%s]" % (ttl, " ".join(map(lambda c: hex(ord(c)), payload[2:])), "".join([(c if ord('0') <= ord(c) <= ord('Z') else '.') for c in payload[2:]])))
               if ttl <= 0:
                  syslog.syslog(syslog.LOG_INFO, "LOOP packet (TTL %i) discarted." % ttl)
                  continue 
               
               if driver.handle_loop_message(payload[2:], ttl):
                  syslog.syslog(syslog.LOG_INFO, "Moving LOOP packet to output queue.")
                  payload = struct.pack('>H', ttl - 1) + payload[2:]
                  userland_outbound_queue.push(message.pack(payload, ID_BY_TYPE[type]))
            elif type == 'USER':
               syslog.syslog(syslog.LOG_INFO, "Moving USER packet to the user (up): %s" % (" ".join(map(lambda c: hex(ord(c)), payload))))
               userland_inbound_queue.push(message.pack(payload, ID_BY_TYPE[type]))
            else:
               raise InvalidNetworkMessage("The message received from a member of the ring was corrupted.", payload, peer) 

         except socket.error, e:
            if start_receiving:
               syslog.syslog(syslog.LOG_INFO, "Packet received partially because some connection error.")
            else:
               syslog.syslog(syslog.LOG_INFO, "No packet received because some connection error.")

            raise UnstableChannel("The other side (other peer) is not responding to the probes or an internal error happen.", peer, e)

   finally:
      try:
         inbound_socket.shutdown(2)
      except socket.error:
         pass 
      inbound_socket.close()
コード例 #12
0
def create_leader_proposal_msj(localhost_name):
    s = struct.pack(">HBB%is" % (len(localhost_name)),
                    passage.TTL, passage.LOOP_SUBTYPE_BY_NAME['Leader'],
                    len(localhost_name), localhost_name)
    return message.pack(s, passage.ID_BY_TYPE['LOOP'])
コード例 #13
0
if __name__ == '__main__':
    print('\033[1;37;40mType \'quit\' to leave')

    s = socket.socket()
    s.connect((IP_ADDR, PORT))
    s.settimeout(10)

    listen_thread = threading.Thread(target=listen_loop, args=(s,))
    listen_thread.start()

    ping_thread = threading.Thread(target=ping_loop, args=(s,))
    ping_thread.start()

    while RUNNING:
        input_text = input()
        if input_text == 'quit':
            msg_leave = message.Message()
            msg_leave.set_type('leave')
            s.sendall(message.pack(msg))
            RUNNING = False
            break

        #if it is a message to the server
        msg = message.Message()
        msg.set_type('text')
        msg.set_text(input_text)
        s.sendall(message.pack(msg))

    listen_thread.join()
    s.shutdown()
コード例 #14
0
def create_leader_proposal_msj(localhost_name):
   s = struct.pack(">HBB%is" % (len(localhost_name)), passage.TTL, passage.LOOP_SUBTYPE_BY_NAME['Leader'], len(localhost_name), localhost_name)
   return message.pack(s, passage.ID_BY_TYPE['LOOP'])
コード例 #15
0
 def create_linkbroken_msj(self):
    s = struct.pack(">HBB%is" % (len(localhost_name)), passage.TTL, passage.LOOP_SUBTYPE_BY_NAME['LinkBroken'], len(localhost_name), localhost_name)
    return message.pack(s, passage.ID_BY_TYPE['LOOP'])
コード例 #16
0
def create_breaklink_msj():
   s = struct.pack(">HB", 0, passage.LOOP_SUBTYPE_BY_NAME['BreakLinkForced'])
   return message.pack(s, passage.ID_BY_TYPE['LOOP'])
コード例 #17
0
 def create_linkbroken_msj(self):
     s = struct.pack(">HBB%is" % (len(localhost_name)), passage.TTL,
                     passage.LOOP_SUBTYPE_BY_NAME['LinkBroken'],
                     len(localhost_name), localhost_name)
     return message.pack(s, passage.ID_BY_TYPE['LOOP'])
コード例 #18
0
 def handle_ping(self):
     #print('ping from {}'.format(self.address))
     msg_ping_resp = message.Message()
     msg_ping_resp.set_type('ping')
     self.send(message.pack(msg_ping_resp))
コード例 #19
0
    def handle_loop_message(self, loop_payload, ttl):
        '''This function will process the loop message and will determine if the message should be passed to the next stage (the next process)
           or it should be discarted. (Returning True or False).
           '''
        type = struct.unpack(">B", loop_payload[0])[0]

        if type == passage.LOOP_SUBTYPE_BY_NAME['Leader']:
            syslog.syslog(syslog.LOG_DEBUG, "Leader Election received...")
            leader_name_len = struct.unpack('>B', loop_payload[1])[0]
            leader_name = struct.unpack('%is' % leader_name_len,
                                        loop_payload[2:leader_name_len + 2])[0]

            if leader_name == self.localhost_name:
                syslog.syslog(
                    syslog.LOG_DEBUG,
                    "I'am the new leader %s (previous %s) of the group with %i members."
                    % (str(self.localhost_name), str(
                        self.leader_name), passage.TTL - ttl + 1))
                #Stop the leader algorithm.
                #
                # The inbound process MUST start sending its localname as leadername to the outbound queue.
                # When that message come back to the outbound, then the algorithm finish and localname is the leadername
                self.leader_name = leader_name

                if self.leader_process and self.leader_process.poll() is None:
                    return False  #iam the leader already

                self.clean()
                self.leader_process = Popen([
                    "python", "leader.py", self.path, self.char_id_out,
                    str(self.group_id), self.localhost_name, self.network_name
                ])

                #XXX Who has the token?
                self.userland_inbound_queue.push(
                    message.pack("\x00" * (4 * 3 + 256),
                                 passage.ID_BY_TYPE['USER']))
                return False

            elif leader_name < self.localhost_name:
                syslog.syslog(
                    syslog.LOG_DEBUG,
                    "Minor leader proposal %s discarted by %s (actual leader %s)."
                    % (str(leader_name), str(
                        self.localhost_name), str(self.leader_name)))
                return False
            else:
                syslog.syslog(
                    syslog.LOG_DEBUG,
                    "Mayor leader proposal %s exceeds me %s (previous leader %s)."
                    % (str(leader_name), str(
                        self.localhost_name), str(self.leader_name)))
                self.clean()
                self.leader_name = leader_name
                return True

        elif type == passage.LOOP_SUBTYPE_BY_NAME['LinkBroken']:
            open_node_name_len = struct.unpack('>B', loop_payload[1])[0]
            open_node_name = struct.unpack(
                '%is' % open_node_name_len,
                loop_payload[2:open_node_name_len + 2])[0]

            if open_node_name == self.localhost_name:
                return False
            else:
                self.clean()
                return True
        else:
            #Tipo incorrecto, como llego aqui?!?
            raise Exception

        return False
コード例 #20
0
 def leave(self):
     CLIENTS.remove(self)
     msg_user_left = message.Message()
     msg_user_left.set_time(get_time())
     msg_user_left.set_text('{} left the chat'.format(self.name))
     broadcast(message.pack(msg_user_left))
コード例 #21
0
def create_breaklink_msj():
    s = struct.pack(">HB", 0, passage.LOOP_SUBTYPE_BY_NAME['BreakLinkForced'])
    return message.pack(s, passage.ID_BY_TYPE['LOOP'])
コード例 #22
0
def passage_inbound_messages(inbound_socket, userland_inbound_queue,
                             userland_outbound_queue, driver):
    try:
        inbound_socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)

        inbound_socket.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
        inbound_socket.setsockopt(socket.SOL_TCP, socket.TCP_KEEPCNT,
                                  KEEPALIVE_PROBE_COUNT)
        inbound_socket.setsockopt(socket.SOL_TCP, socket.TCP_KEEPIDLE,
                                  KEEPALIVE_IDLE_TIMEOUT)
        inbound_socket.setsockopt(socket.SOL_TCP, socket.TCP_KEEPINTVL,
                                  KEEPALIVE_RETRY_SEND_PROBE)

        peer = inbound_socket.getpeername()

        while True:
            try:
                start_receiving = False
                syslog.syslog(
                    syslog.LOG_INFO,
                    "Receiving packet from remote node %s..." % str(peer))
                type = _recv(inbound_socket, 4, peer)
                start_receiving = True

                if type not in ID_BY_TYPE.keys():
                    raise InvalidNetworkMessage(
                        "The message received from a member of the ring has a wrong type (corrupted message).",
                        type, peer)

                size = struct.unpack('>H', _recv(inbound_socket, 2, peer))[0]

                if size > MAX_PAYLOAD:
                    raise InvalidNetworkMessage(
                        "The message received from a member of the ring has a wrong value in the 'size' field (corrupted message).",
                        size, peer)

                payload = _recv(inbound_socket, size, peer)
                _send(inbound_socket, "A", peer)

                if type == 'LOOP':
                    ttl = struct.unpack('>H', payload[:2])[0]

                    syslog.syslog(
                        syslog.LOG_DEBUG,
                        "LOOP packet recieved (TTL %i): %s [%s]" %
                        (ttl, " ".join(map(
                            lambda c: hex(ord(c)), payload[2:])), "".join(
                                [(c if ord('0') <= ord(c) <= ord('Z') else '.')
                                 for c in payload[2:]])))
                    if ttl <= 0:
                        syslog.syslog(syslog.LOG_INFO,
                                      "LOOP packet (TTL %i) discarted." % ttl)
                        continue

                    if driver.handle_loop_message(payload[2:], ttl):
                        syslog.syslog(syslog.LOG_INFO,
                                      "Moving LOOP packet to output queue.")
                        payload = struct.pack('>H', ttl - 1) + payload[2:]
                        userland_outbound_queue.push(
                            message.pack(payload, ID_BY_TYPE[type]))
                elif type == 'USER':
                    syslog.syslog(
                        syslog.LOG_INFO,
                        "Moving USER packet to the user (up): %s" %
                        (" ".join(map(lambda c: hex(ord(c)), payload))))
                    userland_inbound_queue.push(
                        message.pack(payload, ID_BY_TYPE[type]))
                else:
                    raise InvalidNetworkMessage(
                        "The message received from a member of the ring was corrupted.",
                        payload, peer)

            except socket.error, e:
                if start_receiving:
                    syslog.syslog(
                        syslog.LOG_INFO,
                        "Packet received partially because some connection error."
                    )
                else:
                    syslog.syslog(
                        syslog.LOG_INFO,
                        "No packet received because some connection error.")

                raise UnstableChannel(
                    "The other side (other peer) is not responding to the probes or an internal error happen.",
                    peer, e)

    finally:
        try:
            inbound_socket.shutdown(2)
        except socket.error:
            pass
        inbound_socket.close()