decomp DBCServer_Release and inspect/document database
This commit is contained in:
parent
4b267cbe05
commit
7834b98bf0
28222 changed files with 843300 additions and 144 deletions
|
|
@ -44,7 +44,7 @@ peer/session records. Names below are the wide strings the binary prints.
|
|||
|
||||
| Value | Name | Value | Name |
|
||||
|---|---|---|---|
|
||||
| 1 | Lobby | 0x0c | DBC_GAME |
|
||||
| 1 | Lobby (= GameServer EXE, D: `ServerFile`) | 0x0c | DBC_GAME |
|
||||
| 2 | Dungeon | 0x0d | Agent |
|
||||
| 3 | PVP | 0x11 | DBC_LOG |
|
||||
| 4 | WAR | 0x12 | DBC_CHAT |
|
||||
|
|
@ -54,7 +54,10 @@ peer/session records. Names below are the wide strings the binary prints.
|
|||
| 8 | Gate | 0x17 | `api` peer (no display name; `MS:0x14005dc20`) |
|
||||
| 9 | Manager | 0x0e–0x10, 0x14 | ? |
|
||||
| 0x0a | Auction | | |
|
||||
| 0x0b | Match | | |
|
||||
| 0x0b | Match | 0x18 (24) | PatchServer (D: `ServerFile` only; not shipped) |
|
||||
|
||||
The same numbers are stored in `RustyHearts_Auth.ServerOption.Type`, and
|
||||
`ServerFile` maps each one to an EXE (D; see `CONFIG.md` §5).
|
||||
|
||||
Separately, servers also have a numeric **code** (the instance ID). It appears
|
||||
in XML as `code="61"` and in file names such as `MSG_61.xml`. In the shipped
|
||||
|
|
@ -95,139 +98,27 @@ server code as its argument (`decomp/Agent_Release_x64/evidence.md` finding 3).
|
|||
|
||||
## 4. Configuration files
|
||||
|
||||
All of them are XML parsed with TinyXML 2.5.x (`third-party/tinyxml-2.5.3`).
|
||||
Paths are relative to the working directory, under `option\`. A sample
|
||||
deployment set ships in `binaries/Option/`.
|
||||
Moved to [`CONFIG.md`](CONFIG.md). It covers:
|
||||
- the per-server XML schema with field offsets;
|
||||
- `total_option.xml` and `customoption.xml`;
|
||||
- the database-backed server topology (`RustyHearts_Auth.ServerOption` /
|
||||
`ServerFile`).
|
||||
|
||||
That sample set contains placeholders such as `YOUR_WAN_IP`, `DB_USER` and
|
||||
`DB_SERVER`. It is probably a community deployment, not the original publisher
|
||||
files (I). It also contains **plaintext DB passwords** — never copy them into
|
||||
docs.
|
||||
|
||||
### 4.1 Per-server file — `MagiServerOption` (O, `MS:0x14005dc20`)
|
||||
|
||||
Default name per binary: `option\<kind>_serveroption.xml`. In MessageServer
|
||||
this is the global `L"option\\msg_serveroption.xml"` (`MS:0x14012e5c0`).
|
||||
Per-instance copies are `<KIND>_<code>.xml`, e.g. `MSG_61.xml`.
|
||||
|
||||
Top-level elements, the attributes read from each, and where the value is
|
||||
stored in the option object:
|
||||
|
||||
| Element | Attribute → field |
|
||||
|---|---|
|
||||
| `server` | `name` → +0x08 wstr · `code` → +0x154 · `private_ip` → +0x30 wstr · `private_port` → +0x80 · `public_ip` → +0x58 wstr · `public_port` → +0x84 · `public_udpport` → +0x88 · `udp_count` → +0x8c · `thread_num` → +0x15c (clamped ≥1; defaults to 1 if missing) · `agent` → +0x150 (bool, `=="1"`) · `debug` → +0x165 (bool) · `world` → +0x140 · `private_dns` / `public_dns` → override +0x30 / +0x58 (I: hostname form) |
|
||||
| `db_account`, `db_web`, `db_game`, `db_game_log` | `string` → +0x90 / +0xb8 / +0xe0 / +0x108 (std::string, ADO connection string) · `timeout` → +0x130 / +0x134 / +0x138 / +0x13c (`MS:0x14005fa80`) |
|
||||
| `dbc` | `write_thread_count` → +0x14c |
|
||||
| `db_cache` | `session_count` → +0x144 (also copied to +0x148) |
|
||||
| `db_log_cache` | `session_count` → +0x148 |
|
||||
| peer elements (table below) | `ip`, `port` → peer map at +0x1a8, keyed by kind (`MS:0x14005fb60`) |
|
||||
| `dns` | `dns` → +0x151 (bool) |
|
||||
| `setting` | `multi` → +0x166 (bool) · `lock` → +0x168 (double) |
|
||||
| `auto` | `id`/`value` → +0x158 (auto-start flag) |
|
||||
| `start_server` / `revive_server` / `open_channel` | → +0x178 (double) / +0x171 (bool) / +0x170 (bool). The element-to-field pairing is from the order of assignments: **I** |
|
||||
| `send` | `name`, `minlev`, `maxlev`, `group`, `type`, `id` → ? (not yet traced) |
|
||||
|
||||
Peer elements parsed by MessageServer, with the server kind each maps to:
|
||||
|
||||
| Element | Kind |
|
||||
|---|---|
|
||||
| `agentmanager` | 0x15 |
|
||||
| `db_cache` | 0x0c |
|
||||
| `db_log_cache` | 0x11 |
|
||||
| `msg_server` | 6 |
|
||||
| `gm_server` | 7 |
|
||||
| `manager_server` | 9 |
|
||||
| `auction_server` | 0x0a |
|
||||
| `match_server` | 0x0b |
|
||||
| `agent_server` | 0x0d |
|
||||
| `api` | 0x17 |
|
||||
|
||||
`gate_server`, `dungeon_server`, `pvp_server`, `guild_server` and
|
||||
`lobby_server` appear in the shipped `msg_serveroption.xml`, but
|
||||
**MessageServer's loader never reads them** (O: no string compare for them).
|
||||
Other binaries are expected to parse a different subset (I).
|
||||
|
||||
Mapping the `db_*` connection strings to schema files in `schema/`, by their
|
||||
`Initial Catalog` (S, sample config):
|
||||
|
||||
| Element | Database |
|
||||
|---|---|
|
||||
| `db_account`, `db_web` | `RustyHearts_Auth` (`server_info.ini` points Web at `RustyHearts_Account` instead) |
|
||||
| `db_game` | `RustyHearts` |
|
||||
| `db_game_log` | `RustyHearts_Log` |
|
||||
|
||||
### 4.2 `option\customoption.xml` — `MagiCustomOption` (O, ctor `MS:0x140062820`, parser `MS:0x140062910`)
|
||||
|
||||
The constructor initialises 16 boolean flags to 1 (`+0x08..+0x17`), then
|
||||
parses the file:
|
||||
- **`<log>` section:** `log_account`, `log_item`, `log_pet`, `log_loginout`,
|
||||
`agentmanagers`, `agent`, `api`, `pvp`, `serveroption` toggle per-category
|
||||
console logging. The parser prints `LOGVIEWER Option [%d] - … View.`.
|
||||
- **`<connect>` section:** `dbc_game`, `dbc_log`, `dbc_chat`, `dbc_emergency`,
|
||||
`auction`, `msg`, `manager`, `match`, `gm`, `gate`, `lobby`, `dungeon`,
|
||||
`guild`, `agentmanager`, `agent` select which peers this server connects to.
|
||||
The parser prints `Connect Option [%d] - …`.
|
||||
- **`print`:** **?**
|
||||
|
||||
The shipped `customoption.xml` has a different shape: flat `log_*`/`dbc_*`
|
||||
elements carrying `string` and `timeout`, which look like connection strings.
|
||||
It does **not** match the `<log>`/`<connect>` structure this parser expects.
|
||||
Either it was written for another binary, such as the DBCServer variants, or
|
||||
it isn't actually consumed (**?**). Resolve this when analysing DBCServer.
|
||||
|
||||
### 4.3 `option\total_option.xml` (O, `MS:0x14005ceb0` agent mode; `MS:0x14005c9f0` per-server apply)
|
||||
|
||||
This is a single combined file, used in agent mode.
|
||||
- **`MS:0x14005ceb0` (agent mode)** reads `agentmanager` (peer kind 0x15),
|
||||
`each_option`, `dns`, `code`, `guild`, `api`, `code_start`, `setting`
|
||||
(`multi`, `lock`), `start_server`, `revive_server` and `open_channel`. It
|
||||
also reads the debug keys `develop`, `preload`, `preload_char`,
|
||||
`enemy_debug`, `enemy_one`, `player_debug`, `lua_text` and `lua_send`.
|
||||
- **`MS:0x14005c9f0` (per-server apply)** reads, for DBC kinds, `db`, `game`,
|
||||
`log`, `chat` and `emergency` (each with `string`/`timeout`) plus `count`.
|
||||
The section chosen depends on the server kind: 0x0c→`game`, 0x11→`log`, ….
|
||||
For kind 5 (Guild) it sets the auto flag.
|
||||
|
||||
The shipped `total_option.xml` is empty apart from its XML declaration.
|
||||
|
||||
### 4.4 Other files referenced (S)
|
||||
|
||||
| File | Reference |
|
||||
|---|---|
|
||||
| `option\agent.xml` | `MS:0x14012e6d0`, parsed by `MS:0x1400602b0`: `<server …>` entries and the agent peer (kind 0x0d) |
|
||||
| `option\patch.xml` | `MS:0x14012e700`; no reader traced |
|
||||
| `option\service_control.xml` | per-country auth/billing URLs and feature flags; reader not traced in MessageServer |
|
||||
| `log_control.xml`, `content_control.xml` | in `binaries/Option/`; readers unknown |
|
||||
The `MagiServerOption` field layout matches between MessageServer and
|
||||
DBCServer (O).
|
||||
|
||||
## 5. Database access path
|
||||
|
||||
```
|
||||
Game/Guild/Msg/... server --ProudNet RMI (SERVERS2DBC)--> DBCServer[_LOG] --ADO/SQLOLEDB--> SQL Server
|
||||
MGDBCMsgSession pool <--ProudNet RMI (DBC2SERVERS)--
|
||||
```
|
||||
Moved to [`DATABASE.md`](DATABASE.md). It covers the RMI → command queue →
|
||||
`DBReq*` → stored procedure chain, the four connection types, the
|
||||
RMI → procedure map and the schema of the five databases.
|
||||
|
||||
- **Session pools (O, `MS:0x140004f00` startup step `DB_LOAD`):** MessageServer
|
||||
builds four pools of `MGDBCMsgSession`, one per DBC kind: 0x0c GAME, 0x11
|
||||
LOG, 0x12 CHAT and 0x13 EMERGENCY. Each pool has `db_cache session_count`
|
||||
sessions (`+0x144`; `MS:0x140009330`).
|
||||
- Each session embeds an `RNP::Servers2DbcProxy`, a subclass of the
|
||||
PIDL-generated `SERVERS2DBC_PROTOCOL::Proxy` (`MS:0x140008e20`).
|
||||
- The main loop pumps the pools (`DBCSessionManager->Process`) and retries
|
||||
failed connects (`RetryConnectSession`).
|
||||
- **Request protocol (O):** `SERVERS2DBC_PROTOCOL` contains **262 RMIs, IDs
|
||||
0x2ee1–0x2fe6**. The full name→ID table, extracted from the proxy marshal
|
||||
functions, is in `decomp/shared/rmi_from_MessageServer.tsv`.
|
||||
- The proxy code is generated, so every client binary is expected to contain
|
||||
the same table (I). Verify by diffing the table extracted from each binary.
|
||||
- Name groups include `UPDATE_*` (62), `READ_*`, `SAVE_*`, `INSERT_*`,
|
||||
`REQ_LOG_*`, `GUILD_*`, `MAIL_*`, `PET_*`, `CHARACTER_*` and
|
||||
`REQ_CHAT_LOG` (0x2fb2).
|
||||
- **Response protocol:** `RNP::Dbc2ServersStub` has 85 slots. Its dispatcher
|
||||
`MS:0x140039f20` **failed to decompile** (Ghidra headless timeout, and the
|
||||
REA call timed out too). Recover it from DBCServer's `Dbc2Servers` proxy
|
||||
instead.
|
||||
- **SQL side:** not analysed yet. Mapping RMI → stored procedure/table needs
|
||||
DBCServer, using `schema/*.mdf` to corroborate.
|
||||
Summary:
|
||||
- **Clients and connections:** client servers keep 4 `MGDBCMsgSession` pools
|
||||
(GAME/LOG/CHAT/EMERGENCY), sized by `db_cache session_count`. They send
|
||||
`SERVERS2DBC` RMIs (262, IDs 0x2ee1–0x2fe6); this table is **identical in
|
||||
MessageServer and DBCServer**, O. DBCServer runs stored procedures over ADO
|
||||
and answers with `DBC2SERVERS` (76 RMIs, 0x2af9–0x2b46).
|
||||
|
||||
## 6. Other shared protocols seen in MessageServer (O)
|
||||
|
||||
|
|
@ -239,13 +130,10 @@ The shipped `total_option.xml` is empty apart from its XML declaration.
|
|||
|
||||
## 7. Open questions (priority order)
|
||||
|
||||
1. Decompile DBCServer:
|
||||
- how it reads its DB connection strings;
|
||||
- how RMIs map to SQL (stored procedure names);
|
||||
- the `Dbc2Servers` response table.
|
||||
2. Extract the `SERVERS2DBC` table from a second client binary to confirm the
|
||||
protocol is identical across binaries.
|
||||
3. Explain the mismatch between the `customoption.xml` shape and its parser.
|
||||
4. Decode the semantics of the `send`, `auto`, `lock` and `each_option`
|
||||
elements, and of the `api` peer.
|
||||
1. AgentManager: confirm that it reads `ServerOption`/`ServerFile` and pushes
|
||||
the topology (`CONFIG.md` §5).
|
||||
2. DBCServer_LOG: the LOG RMIs and RustyHearts_Log (`DATABASE.md` §5).
|
||||
3. Diff the `SERVERS2DBC` table in the remaining client binaries.
|
||||
4. Semantics of `send`, `auto`, `lock`, `each_option`, `guildlobby`,
|
||||
`channel`, and of the `api` peer.
|
||||
5. Server kinds 0x0e–0x10 and 0x14.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue