Files
MetaCrate/docs/network-manager.md
Chili Palmer 3951bdb809
All checks were successful
Native code generation / deterministic (push) Successful in 11m53s
Imaging and meshing gate / native (push) Successful in 4m3s
JPEG 2000 feature / linux (push) Successful in 2m33s
Native Rust workspace compile / compile (push) Successful in 4m3s
Skia feature / linux (push) Successful in 31m24s
Implement native login and session initialization (#56)
2026-08-09 18:18:28 +00:00

98 lines
5.4 KiB
Markdown

# Native network manager and simulator lifecycle
`NetworkManager`, `Simulator`, `PacketEventDictionary`, and
`CapsEventDictionary` implement the native Rust boundary corresponding to the
LibreMetaverse connection and dispatch layer. They use the generated packet
codecs and the bounded `UDPBase` transport; they do not invoke .NET code or
start a helper process.
## Ownership and execution
A manager owns bounded incoming and outgoing channels plus one keepalive
worker. Each simulator owns a `UDPBase` transport running on a dedicated
current-thread Tokio executor so the mapped synchronous connection API does not
depend on the caller already having entered a runtime. Async connection methods
move blocking compatibility work to short-lived named standard threads and
return their result through a runtime-neutral one-shot future. Every worker
holds only a weak manager reference between operations. Dropping the last
manager and subscription guard therefore releases all manager-owned
`GridClient` handles, cancels the workers, joins their threads, and closes
simulator transports.
The public `SimulatorCollection` is a shared snapshot collection. Lookup,
addition, removal, current-simulator selection, and disconnect transitions are
synchronized. User callbacks receive cloned handles only after internal locks
have been released. `Subscription` is an RAII guard: dropping or closing it
removes exactly its registration through a weak registry reference.
## Dispatch semantics
Packet callbacks preserve registration order. `PacketType::Default` handlers
are selected before handlers for the concrete packet type. Once any callback
registered for a packet type requests asynchronous dispatch, that packet type
remains asynchronous after later removals, matching the conservative C#
delegate state. A bounded worker executes each asynchronous default/specific
batch in order. Callback panics are isolated and cannot terminate a processor
or poison a callback registry.
CAPS dispatch snapshots the default (`""`) and named callback chains, then
invokes them in that order without holding the registry lock. The built-in
`EnableSimulator` handler honors `Agent.MultipleSims`, ignores duplicate
endpoints, validates ports, and connects each newly advertised region with its
reported handle and dimensions. Incoming `DisableSimulator`, `KickUser`,
`RegionHandshake`, `StartPingCheck`, and generic-streaming UDP packets perform
their reference lifecycle actions before user dispatch. Ping replies preserve
the incoming ping identifier and immediately flush pending acknowledgements
when the simulator reports a nonzero `OldestUnacked` sequence.
## Connection and shutdown behavior
Connecting reuses an existing endpoint or inserts one simulator atomically,
starts the bounded manager workers, raises cancellable `SimConnecting`, sends a
reliable `UseCircuitCode`, and waits up to `Timing.LoginTimeout` for its actual
protocol ACK. Async compatibility methods use a runtime-neutral blocking
bridge, so they can be polled without an ambient Tokio runtime. Circuit-code
changes propagate to every tracked simulator. A default connection stores its
seed capability, updates `CurrentSim`, raises `SimChanged`, and then raises
`SimConnected`. A received region handshake is decoded and answered with the
reference `RegionHandshakeReply` flags before the simulator is marked complete.
The keepalive uses the same two-interval disconnect-candidate transition as the
C# timer: traffic clears the candidate, the first silent interval marks it and
sends a ping, and the second shuts the manager down with `NetworkTimeout`.
Concurrent disconnect attempts are serialized so one simulator and one global
transition are emitted. Per-simulator removal reports `NetworkTimeout`; losing
the last simulator reports `SimShutdown`. Explicit shutdown preserves the
caller-provided reason/message and sends `CloseCircuit` only for client or
network-timeout shutdowns.
## Login behavior
The native login path constructs the reference LLSD request, including the C#
MD5 password form, token/MFA fields, viewer identity, platform metadata,
requested options, and normalized home/last/region start locations. It uses the
client's injectable capability HTTP transport, limits redirects and server
delays, observes linked caller/client cancellation, and reports the mapped
`LoginStatus` transitions. Only a successful response invokes registered login
callbacks and proceeds to an ACK-gated initial simulator connection.
`LoginResponseData` parses the session and circuit identifiers, home and look-at
vectors, simulator endpoint and dimensions, seed capability, inventory roots and
skeletons, buddy rights, account benefits, service URLs, category/config arrays,
premium packages, and initial outfit. A rejected, malformed, timed-out, or
canceled login leaves no simulator installed. Passwords, login tokens, MFA
hashes, session identifiers, seed capabilities, and estate access tokens are
excluded from `Debug` output and diagnostic messages.
The deterministic tests use loopback fake simulators and require no live grid:
```sh
cargo test -p libremetaverse --test network_manager
```
They cover login hashing, redirects, cancellation and initial handoff alongside
ACK-gated circuit setup, typed handshake reply/state, ping response, CAPS enable,
UDP disable, current/seed selection, callback ordering and filtering, RAII
unregistration, runtime-neutral async calls, concurrent registration/removal,
reentrant/concurrent disconnect, and keepalive timeout reasons.