Common Layer Overview
src/common/ is the shared library compiled into every binary. It holds the code that the client,
server, and commander must agree on (cryptography, the wire protocol, and the server <-> commander
IPC contract) plus cross-cutting utilities (atomic file IO and logging). It is the only module not
behind a feature gate: it always compiles, even with --no-default-features (individual items
inside it are gated per feature).
Layout
flowchart TD
mod["common/mod.rs<br/>re-exports + now_nanos + normalize_ip"]
subgraph crypto["crypto/"]
ch["handler.rs<br/>CryptoHandler (key lifecycle)"]
cho["handler_ops.rs<br/>encrypt / decrypt"]
cm["mod.rs<br/>blake2b_u64, verify_ed25519, get_random_range"]
end
subgraph protocol["protocol/"]
pc["constants.rs<br/>sizes"]
pcd["client_data.rs<br/>ClientData struct"]
pp["parser.rs<br/>DataParser encode/decode"]
ps["serialization.rs<br/>IP <-> 16 bytes"]
end
ipc["ipc.rs<br/>CommanderData + socket path (server/commander)"]
fs["fs.rs<br/>write_atomic, resolve_path, chown"]
log["logging.rs<br/>info / error"]
andr["android/<br/>JNI bridge (android only)"]
mod --> crypto
mod --> protocol
mod --> ipc
mod --> fs
mod --> log
mod -.cfg android.- andr
What mod.rs itself provides
src/common/mod.rs wires the submodules together and re-exports the items used elsewhere. It also
defines two small but important helpers.
now_nanos
#![allow(unused)]
fn main() {
pub(crate) fn now_nanos() -> anyhow::Result<u128>
}
Returns the current time as nanoseconds since the Unix epoch, as a u128. This single function is
the source of every counter value in the system: the client seeds and advances its replay counter
from it, and the server seeds its blocklist floor from it on startup. It returns an error (rather
than panicking) if the system clock is before the epoch.
normalize_ip (server / commander)
#![allow(unused)]
fn main() {
#[cfg(any(feature = "with-server", feature = "with-commander"))]
pub(crate) fn normalize_ip(ip: IpAddr) -> IpAddr
}
Collapses an IPv6-mapped IPv4 address (for example ::ffff:192.168.0.1) back to a plain IPv4
address, leaving genuine IPv6 and IPv4 addresses unchanged. Because every IP on the wire is stored
as 16 bytes (IPv6-mapped), this is how a clean IPv4 value is recovered for comparison and for
$RUROCO_IP. Both the server (validation) and the commander (decoding CommanderData) need it, so
it is gated for either role.
Re-exports
mod.rs curates the crate-internal surface so the rest of the code does not reach deep into
submodules:
| Re-export | From | Used by |
|---|---|---|
blake2b_u64 | crypto | client (build hash) and commander (command lookup) |
get_random_range | crypto | fs::write_atomic temp-name, UI |
crypto_handler (alias for crypto::handler) | crypto | parser |
change_file_ownership, resolve_path | fs | server, update, wizard |
info | logging | everywhere |
client_data, data_parser (alias for protocol::parser) | protocol | client, server |
Feature gating inside common
Even though common always compiles, individual functions inside it are feature-gated so that, for
example, the server build does not pull in client-only code:
encrypt,verify_ed25519,ClientData::create/serialize:with-client.decrypt,ClientData::deserialize,is_source_ip_invalid:with-server.- the
crypto::handler(CryptoHandler) andget_random_range, which pull in OpenSSL:with-clientorwith-server(never the commander). ipc(CommanderData, socket path),normalize_ip,deserialize_ip:with-serverorwith-commander(both roles need them; no OpenSSL involved). The config structs themselves are not incommon-ConfigServeris inserver::config,ConfigCommander/ConfigCommandsincommander::config.write_atomic:with-serverorwith-gui(the components that persist files).
The leaf chapters that follow document each file in full:
- crypto/:
CryptoHandler, AES-256-GCM-SIV encrypt/decrypt, Blake2b-64, Ed25519. - protocol/: the
ClientDatastruct, sizes, parser, and IP serialization. - fs.rs and logging.rs: atomic writes, path/ownership helpers, the logger.
- ipc.rs: the server <-> commander IPC contract (
CommanderData+ the socket path).
The Android JNI bridge under common/android/ is documented alongside the GUI it serves, in
Android integration, because it only exists to back the UI on Android.