# DBCServer_Release_x64.exe — porting spec (Win32 → Linux) This was kept from the removed Linux reconstruction `src/dbc_server/` (removed 2026-10-15). It records the facts about the original binary that a re-implementation needs, and the nearest Linux equivalent for each Win32 call. Sources: `evidence.md`, `docs/DATABASE.md`, `docs/CONFIG.md`. Static analysis only. ## Structure to reproduce ``` peer ──SERVERS2DBC RMI {rmi_id, …}──▶ stub handler (e.g. 0x140050d20: ++per-RMI counter) │ push {size, cmd 1001–1317, args} ▼ write queue [idx < 1000] (0x140144730; else "Invalid Queue Index") │ critical section + semaphore, 1 worker per queue ▼ worker switch (cmd - 1001) (0x1400a8190, jump table 0x1400a9dd4) ▼ CDBLobbyWriteQuery::DBReq* (e.g. 0x1400acbb0) — ADODB.Command "dbo.up_xxx" ▼ reply via DBC2SERVERS proxy (76 RMIs, 0x2af9–0x2b46) ``` - **Data tables:** - The RMI → command → procedure mapping is in `rmi_to_proc.tsv`, and the command dispatch in `cmd_dispatch.tsv`. - Procedure parameters (names, SQL types, OUTPUT flags) are in `decomp/schema//routines.tsv`. - `decomp/scripts/gen_dbc_tables.py` joins them into `procs_used.tsv`. - **Queue array:** a 0x1f48-byte block holding 1000 pointers. How queue slots are created has not been decoded. - **Connections (`0x1400a7aa0`):** - Type 1 WEB = `db_web`, 2 AUTH = `db_account`, 3 GAME = `db_game`, 4 GAME LOG = `db_game_log`. - A timeout of 0 becomes 500. - A string longer than 255 characters gives `Error … String Max.!`. - **AUTH uses the WEB timeout** (+0x134); this is an original bug. - **Startup (`0x140042cf0`):** opens AUTH and GAME connections, then `up_read_world_server` reads the world list. - **Connect failure (`0x1400a80c0`):** `DB Connect failed\n Connection String = %s` is appended to `Error_ADO DB Connect.Log`. The original writes the password verbatim. - **Procedure error:** `ADO_ON_ERROR : [ %s ] Proc [ %s ]` with source file and line (catch funclets, `dbreq_methods.tsv`). - **Single instance:** mutex `Global\RustyHearts_DBC`. - **Startup modes:** a numeric `argv[1]` selects agent mode (`total_option.xml` ``); otherwise `argv[1]` is the path of the per-server XML (`docs/CONFIG.md`). ## Win32 → Linux substitutions | Original (address) | Win32 / library | Nearest Linux equivalent | Notes | |---|---|---|---| | Single instance | `CreateMutexW("Global\\RustyHearts_DBC")` | `flock(LOCK_EX\|LOCK_NB)` on `$TMPDIR/RustyHearts_DBC.lock` | Lock file instead of a kernel object | | DB access (`0x1400a7aa0`, `0x1400a80c0`, `DBReq*`) | ADO `_Connection` / `ADODB.Command` over `SQLOLEDB`, `CoInitialize`, `_com_issue_errorex` | ODBC: unixODBC + Microsoft ODBC Driver 18, or FreeTDS `libtdsodbc` | Call as `{? = call dbo.proc(?,…)}` with positional parameters (ADO uses named ones); GUIDs in SQL Server byte order. ODBC 18 needs `TrustServerCertificate=yes`, because SQLOLEDB never validated TLS. FreeTDS needs `Port=` (not `host,port`) and `TDS_Version=7.4` | | ADO connection string | `Provider=SQLOLEDB;Data Source;Initial Catalog;User ID;Password` | `Driver={…};Server;Database;UID;PWD` | Keys map 1:1. Treating the XML `timeout` as milliseconds (rounded to seconds) is an inference | | Transport | ProudNet `CNetServer` over Winsock2/MSWSOCK/IOCP | BSD sockets / epoll | ProudNet internal net version is **196978**; 1.8 is 197144, so the protocols are incompatible. Interop would need a reimplementation of the 2013 protocol (`third-party/README.md`) | | Write queue (`0x140144730`) | `CRITICAL_SECTION` + semaphore (`ReleaseSemaphore`) | `std::mutex` + `std::condition_variable` | — | | Threads | `_beginthreadex` | `std::thread` | — | | XML (`MagiServerOption`, `MagiCustomOption`) | TinyXML 2.5.x | pugixml with `parse_fragment` (the files have several top-level elements) | — | | Console / stop | `wprintf`, console menu | stdout, `SIGINT`/`SIGTERM`; ignore `SIGPIPE` | — | | `timeGetTime` | WINMM | `std::chrono::steady_clock` | — | | Crash reporting | BugTrap, `MiniDumpWriteDump` | core dumps | — | ## Prior validation of the DB mapping (2026-10-14) Run with the removed port against copies of the shipped `.mdf` files, on SQL Server 2022 through FreeTDS 1.5.19: - `up_read_world_server` returned 1 row. - `REQ_READ_ALL_GUILD(10101)` returned the guild row. - `REQ_UPDATE_CHARACTER_HEARTS(guid, n)` updated `CharacterTable.Hearts` (then reverted). - `REQ_INVEN_SLOT` failed with "Could not find stored procedure", confirming that procedure is missing from the shipped schema. This validates the mapping and the parameter types against the schema. It says nothing about the original binary's runtime behaviour. ## Unknown / not recovered - **RMI argument marshalling** (ProudNet) and the per-`DBReq` post-processing of recordsets (e.g. `FIRST_CHARACTER` in `0x1400acbb0`). - **52 RMIs without a procedure mapping**, mostly log, logout and auth. - **Some mappings may be wrong:** those found two call levels deep, e.g. `REQ_CHARACTER_READ_ALL_DATA` → `up_read_Inquiry_character`. - **Which connection each queue/`DBReq` uses:** inferred from the database that holds the procedure. - **Queue-slot creation; agent-mode address/port** (pushed by the Agent over RMI); the `guildlobby`, `channel` and `Option` elements.