DataServer em Rust: Por que reescrevemos o coracao do servidor WYD
O que é o DataServer?
No WYD2, o DataServer é o processo responsável por persistir e servir o estado das contas. Ele gerencia:
- Contas e personagens — arquivos binários
Account.bin(9364 bytes) eChars/0..3.bin(1892 bytes) - Guildas — criação, alianças e guerras
- Selos de alma — persistência em XML
- Loja de donate — compras, reload e disponibilidade
- Amigos e mensagens — lista de amigos e chat entre canais
- Imports em lote — criação de contas, itens e cash em massa
Nenhum cliente conecta diretamente no DataServer — ele se comunica exclusivamente com os GameServers através de um protocolo binário com cifra de stream proprietária.
Por que Rust?
Segurança de memória sem concessões
O código original em C++ (TMLinux) tem bugs latentes de corrupção de memória. Durante a auditoria linha a linha do port, encontramos um off-by-one em arrays de guildas: o código C++ indexava g_pGuildAlly[65535] — uma posição fora do array que causa corrupção silenciosa em C++ mas é impossível por construção em Rust.
Com Rust, índices fora dos limites são detectados em runtime e o compilador rejeita a maioria desses casos em tempo de compilação. Não existe uso-após-free, double-free ou race condition de dados entre threads. O estado global é protegido por Arc<Mutex<>> — sem variáveis globais mutáveis que são a raiz de tantos bugs em C.
Input de rede tratado como hostil
O C++ original confia cegamente em tamanhos de pacote e índices recebidos da rede. O port em Rust valida cada byte:
- Tamanho do pacote entre 12 e 20000 bytes (bounds check antes de alocar)
ClientIde índices validados antes de indexar arrays- Checksum de integridade verificado (o C++ original nem verificava!)
- Nenhum caminho de rede pode causar corrupção de estado — o processo sobrevive a pacotes malformados
Build determinístico e deployment trivial
cargo build --release produz um único binário estático com zero dependências de runtime além da libc do sistema. Nada de Wine, DLLs ou toolchain MSVC. O mesmo código compila para Windows e Linux. O binário atual é simplesmente copiado para a pasta Release/DataServer/ e executado.
4 bugs reais encontrados e corrigidos
A auditoria comparou o port Rust com três referências: o binário de produção (disassemblagem i686), a árvore MSVC original e o TMLinux (fonte do port). Cada bug tem teste de regressão automatizado.
1. "Servidor em Manutenção" para contas normais (crítico)
O port copiou um bloco de manutenção que estava ativo no TMLinux mas comentado na produção real. Resultado: qualquer conta normal recebia erro de manutenção e não conseguia logar. Corrigido com bloco comentado, mantendo o handler de protocolo inócuo.
2. Off-by-one em guildas (panic/DoS)
Arrays de guildas têm tamanho 65535, mas o código acessava o índice 65535 — out-of-bounds que em Rust derrubava o processo. Corrigido com guarda correta nos handlers de aliança e guerra de guilda.
3. Expiração de conta bloqueava para sempre
O port emitia erro de expiração incondicionalmente para qualquer conta com data de expiração preenchida, sem comparar com a data atual. Toda conta que já teve expiração ficava presa eternamente. Corrigido com localtime_r comparando ano e dia do ano.
4. Banimento expirava horas antes (UTC × local)
O cálculo de tempo restante de ban usava UTC civil; o C++ original usa mktime no fuso local. Em servidor UTC-3, um ban que expira à meia-noite local era encerrado 3 horas antes. Corrigido com libc::mktime local.
Qualidade e desempenho
44 testes de regressão
Cobrem cifra (round-trip, pacotes >256 bytes, invariante do checksum), framing de rede, XML round-trip byte-a-byte, selos, tamanhos binários, login (senha errada, Staff, expiração, ban) e todos os bugs corrigidos. cargo test roda em menos de 0,1 segundo.
Ferramentas de qualidade
cargo clippy(análise estática oficial do Rust) — zero warningscargo build --release— zero warnings- Tipagem forte (
u16,i32, tamanhos de array) pega erros que no C++ só aparecem em produção - Serialização wire explícita — sem
#pragma packnem padding implícito
Desempenho
opt-level 2 + LTO, sem GC e sem runtime pesado. Medido ao vivo: login real com p50 ≈ 2,3 ms por request. Para um daemon que faz I/O de arquivo e passa a maior parte do tempo esperando rede, a latência é dominada pelo socket e pelo disco — não pelo runtime.
Manutenibilidade
- Cada divergência do C++ original está comentada com referência exata (arquivo:linha)
- Ferramentas Python (
bench_login.py,dbg_staff.py) para validação ao vivo - ~7.400 linhas em 13 módulos bem definidos
- Novos desenvolvedores podem contribuir sem medo de quebrar algo — os testes pegam regressões instantaneamente
Como testar
cd dbsrv_rust
cargo build --release --offline
cargo test --offline
cargo clippy --offline --all-targets
cp target/release/dbsrv_rust ../Release/DataServer/dbsrv_rust
cd ../Release/DataServer
./dbsrv_rust
O código fonte completo está disponível na página de downloads.