예제 #1
0
    def _handle_packet(self, packet):
        """ Find and call a handler for that packet.

        It is possible that we do not know the opcode, which is not a problem.

        If it is known, it should be legal (in a valid state) and we need to
        enforce a handler to it, even if it's just NopHandler. If I don't feel
        like adding the simplest handler for an opcode, it probably shouldn't be
        in the OpCode enum in the first place. If an opcode is not valid, we do
        not throw an error anymore because there are some cases where misc
        opcodes can be received just after changing states.
        """
        opcode, packet_data = self._parse_packet(packet)
        if opcode is None:
            return

        if ( self.state not in self.UNMANAGED_STATES
             and opcode not in self.UNMANAGED_OPS
             and not self.opcode_is_legal(opcode) ):
            LOG.debug("{}: received illegal opcode {} in state {}".format(
                type(self).__name__, opcode.name, self.state.name
            ))
            return

        handler_class = self.OP_HANDLERS.get(opcode, self.DEFAULT_HANDLER)
        self._call_handler(handler_class, packet_data)
예제 #2
0
파일: manager.py 프로젝트: Shgck/DuratorEmu
    def create_char(char_values):
        """ Try to create a new character and add it to the database. Return 0
        on success, 1 on unspecified failure, 2 on name already used, 3 if the
        race and class combination isn't supported.

        The arg char_values is a tuple containing the Character data in the
        order they're defined, from name to features. This last value has to be
        a tuple with CharacterFeatures fields values.

        This should check of other things like account char limit etc.
        """
        consts = _CharacterCreator._get_constants(char_values)
        if consts is None:
            return 3

        if CharacterManager.does_char_with_name_exist(char_values["name"]):
            return 2

        char_data = _CharacterCreator._try_create_char(char_values, consts)
        if char_data is None:
            return 1

        _CharacterCreator._add_default_skills(char_data, consts)
        _CharacterCreator._add_default_spells(char_data, consts)

        LOG.debug("Character " + char_data.name + " created.")
        return 0
예제 #3
0
    def process(self):
        self._parse_packet(self.packet)

        # We start by loading the session key because in any case the client
        # expects an encrypted response.
        self._load_session_key()
        if not self.session_key:
            LOG.warning("A client not logged in tried to join world server.")
            return self.conn.MAIN_ERROR_STATE, None

        self._setup_encryption()

        if self.build != int(CONFIG["general"]["build"]):
            LOG.warning("Wrong build tried to auth to world server: {}".format(
                str(self.build)
            ))
            error_code = AuthSessionResponseCode.AUTH_VERSION_MISMATCH
            response = self._get_failure_packet(error_code)
            return self.conn.MAIN_ERROR_STATE, response

        self._generate_server_hash()
        if self.server_hash != self.client_hash:
            LOG.warning("Wrong client hash in world server auth.")
            error_code = AuthSessionResponseCode.AUTH_REJECT
            response = self._get_failure_packet(error_code)
            return self.conn.MAIN_ERROR_STATE, response

        # Once the session cipher is up and the client is fully checked,
        # accept the authentication and move on.
        LOG.debug("World server auth OK.")
        response = self._get_success_packet()
        return WorldConnectionState.AUTH_OK, response
예제 #4
0
    def _get_response_packet(self, manager_code):
        response_code = {
            0: CharDeleteResponseCode.SUCCESS,
            1: CharDeleteResponseCode.FAILED
        }.get(manager_code, 1)
        LOG.debug("Character deletion status: " + str(response_code.name))

        response_data = self.RESPONSE_BIN.pack(response_code.value)
        return WorldPacket(OpCode.SMSG_CHAR_DELETE, response_data)
예제 #5
0
    def _actions_after_main_loop(self):
        LOG.debug("WorldConnection: session ended.")
        if self.account and self.session_cipher:
            AccountSessionManager.delete_session(self.account)
        if self.player:
            self.unset_player()

        with self.server.world_connections_lock:
            self.server.world_connections.remove(self)
예제 #6
0
 def process(self):
     if "worldport_ack_pending" in self.conn.shared_data:
         LOG.debug( "Received expected " +
                    str(OpCode.MSG_MOVE_WORLDPORT_ACK) )
         del self.conn.shared_data["worldport_ack_pending"]
         return None, None
     else:
         LOG.error( "Received unexpected " +
                    str(OpCode.MSG_MOVE_WORLDPORT_ACK) )
         return self.conn.MAIN_ERROR_STATE, None
예제 #7
0
    def _try_recv_packet(self):
        packet, has_timeout = None, False

        try:
            packet = self._recv_packet()
            if packet is None:
                LOG.debug("Client closed the connection.")
        except socket.timeout:
            has_timeout = True

        return packet, has_timeout
예제 #8
0
    def _get_response_packet(self, manager_code):
        response_code = {
            0: CharCreateResponseCode.SUCCESS,
            1: CharCreateResponseCode.FAILED,
            2: CharCreateResponseCode.NAME_IN_USE,
            3: CharCreateResponseCode.ERROR
        }.get(manager_code, 1)
        LOG.debug("Character creation status: " + str(response_code.name))

        response_data = self.RESPONSE_BIN.pack(response_code.value)
        return WorldPacket(OpCode.SMSG_CHAR_CREATE, response_data)
예제 #9
0
 def process(self):
     self._parse_packet(self.packet)
     self._generate_local_proof()
     if self.client_proof == self.local_proof:
         LOG.debug("Reconnection: correct proof")
         response = self._get_success_response()
         return LoginConnectionState.RECON_PROOF, response
     else:
         LOG.warning("Reconnection: wrong proof!")
         response = self._get_failure_response()
         return LoginConnectionState.CLOSED, response
예제 #10
0
 def _maintain_realm_list(self):
     """ Maintain realmlist by removing realms not updated for a while. """
     with self.locks["realms"]:
         to_remove = []
         for realm in self.realms:
             update_delay = time.time() - self.realms[realm]["last_update"]
             if update_delay > self.REALM_MAX_UPDATE_TIME:
                 to_remove.append(realm)
                 LOG.debug("Realm " + realm + " down, removed from list.")
         for realm_to_remove in to_remove:
             del self.realms[realm_to_remove]
예제 #11
0
 def _process_reconnection(self):
     session = AccountSessionManager.get_session(self.account_name)
     if session is not None:
         LOG.debug("Reconnection: account was logged in.")
         self.conn.account = ReconChallenge._get_session_account(session)
         self.conn.recon_challenge = os.urandom(16)
         response = self._get_success_response()
         return LoginConnectionState.RECON_CHALL, response
     else:
         LOG.warning("Reconnection: account wasn't logged in!")
         response = self._get_failure_response()
         return LoginConnectionState.CLOSED, response
예제 #12
0
 def close(self):
     """ Close the database connection, return True on success. """
     with self.num_connections_lock:
         self.num_connections -= 1
         if self.num_connections == 0:
             try:
                 self.database.close()
                 if DEBUG:
                     LOG.debug("[db] Database closed")
             except OperationalError as exc:
                 _DbConnector.log_error("close", exc)
                 return False
     return True
예제 #13
0
    def process(self):
        self._parse_packet(self.packet)
        LOG.debug("NameQuery: GUID {:X}".format(self.guid))

        object_manager = self.conn.server.object_manager
        unit = object_manager.get_player(self.guid)
        if unit is None:
            LOG.warning("NameQueryHandler: couldn't find player {:X}".format(
                self.guid
            ))
            return None, None

        response = self._get_response_packet(unit)
        return None, response
예제 #14
0
 def connect(self):
     """ Connect to the database, return True on success. """
     with self.num_connections_lock:
         assert self.num_connections >= 0
         self.num_connections += 1
         if self.num_connections == 1:
             try:
                 self.database.connect()
                 if DEBUG:
                     LOG.debug("[db] Database connected")
             except OperationalError as exc:
                 _DbConnector.log_error("connect", exc)
                 self.num_connections -= 1
                 return False
     return True
예제 #15
0
    def create_account(account_name, password):
        """ Create a valid account and add it to the database, or None if the
        arguments are invalid. """
        if not ACCOUNT_NAME_RE.match(account_name):
            LOG.debug("Invalid account name.")
            return None

        account = Account( name = account_name.upper()
                         , status = AccountStatus.NOT_READY.value )
        Srp.generate_account_srp_data(account, password)
        account.status = AccountStatus.VALID.value
        account.save()

        AccountDataManager.create_account_data(account)

        return account
예제 #16
0
파일: manager.py 프로젝트: Shgck/DuratorEmu
    def _delete_char(guid):
        character = CharacterData.get(CharacterData.guid == guid)

        _CharacterDestructor._delete_char_skills(character)
        _CharacterDestructor._delete_char_spells(character)

        features = character.features
        stats = character.stats
        position = character.position

        character.delete_instance()
        features.delete_instance()
        stats.delete_instance()
        position.delete_instance()

        LOG.debug("Character " + str(guid) + " deleted.")
        return 0
예제 #17
0
    def process(self):
        self._parse_packet(self.packet)

        account = self.conn.account
        verifier = account.srp_verifier_as_int
        self.conn.srp.generate_session_key(self.client_ephemeral, verifier)
        self.conn.srp.generate_client_proof(self.client_ephemeral, account)
        local_client_proof = self.conn.srp.client_proof

        if local_client_proof == self.client_proof:
            LOG.debug("Login: authenticated!")
            self.conn.accept_login()
            self.conn.srp.generate_server_proof(self.client_ephemeral)
            response = self._get_success_response()
            return LoginConnectionState.SENT_PROOF, response
        else:
            LOG.warning("Login: wrong proof!")
            response = self._get_failure_response()
            return LoginConnectionState.CLOSED, response
예제 #18
0
 def _actions_before_main_loop(self):
     LOG.debug("Sending auth challenge to setup session cipher.")
     self._send_auth_challenge()
예제 #19
0
 def _actions_after_main_loop(self):
     """ Close connection with client. """
     LOG.debug("LoginConnection: session ended.")
     self.socket.close()
예제 #20
0
 def process(self):
     """ Process the challenge packet: parse its data and check whether that
     account name can log. """
     self._parse_packet(self.packet)
     LOG.debug("Login: account " + self.account_name)
     return self._process_account()