Handle a single client.

        :param conn: The Connection instance.
        :param addr: The address of the client, for logging purposes.
        :param auth: A boolean specifying whether the connection
                     should be considered authenticated or not.
                     Provided for debugging.

def serve(self, conn, addr, auth=False):
        """
        Handle a single client.

        :param conn: The Connection instance.
        :param addr: The address of the client, for logging purposes.
        :param auth: A boolean specifying whether the connection
                     should be considered authenticated or not.
                     Provided for debugging.
        """

        try:
            # Handle data from the client
            while True:
                # Get the command
                try:
                    cmd, payload = conn.recv()
                except ValueError as exc:
                    # Tell the client about the error
                    conn.send('ERR', "Failed to parse command: %s" % str(exc))

                    # If they haven't successfully authenticated yet,
                    # disconnect them
                    if not auth:
                        return
                    continue  # Pragma: nocover

                # Log the command and payload, for debugging purposes
                LOG.debug("Received command %r from %s port %s; payload: %r" %
                          (cmd, addr[0], addr[1], payload))

                # Handle authentication
                if cmd == 'AUTH':
                    if auth:
                        conn.send('ERR', "Already authenticated")
                    elif payload[0] != self.authkey:
                        # Don't give them a second chance
                        conn.send('ERR', "Invalid authentication key")
                        return
                    else:
                        # Authentication successful
                        conn.send('OK')
                        auth = True

                # Handle unauthenticated connections
                elif not auth:
                    # No second chances
                    conn.send('ERR', "Not authenticated")
                    return

                # Handle aliveness test
                elif cmd == 'PING':
                    conn.send('PONG', *payload)

                # Handle a function call command
                elif cmd == 'CALL':
                    try:
                        # Get the call parameters
                        try:
                            funcname, args, kwargs = payload
                        except ValueError as exc:
                            conn.send('ERR', "Invalid payload for 'CALL' "
                                      "command: %s" % str(exc))
                            continue

                        # Look up the function
                        func = self._get_remote_method(funcname)

                        # Call the function
                        result = func(*args, **kwargs)
                    except Exception as exc:
                        exc_name = '%s:%s' % (exc.__class__.__module__,
                                              exc.__class__.__name__)
                        conn.send('EXC', exc_name, str(exc))
                    else:
                        # Return the result
                        conn.send('RES', result)

                # Handle all other commands by returning an ERR
                else:
                    conn.send('ERR', "Unrecognized command %r" % cmd)

        except ConnectionClosed:
            # Ignore the connection closed error
            pass
        except Exception as exc:
            # Log other exceptions
            LOG.exception("Error serving client at %s port %s: %s" %
                          (addr[0], addr[1], str(exc)))

        finally:
            LOG.info("Closing connection from %s port %s" %
                     (addr[0], addr[1]))

            # Make sure the socket gets closed
            conn.close()