# 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. Promoting an already-connected simulator is a controlled handoff. The manager first sends a reliable `UseCircuitCode` followed by the agent/session/circuit identified `CompleteAgentMovement`, installs the new seed capability, swaps `CurrentSim`, and finally raises `SimChanged` with the previous simulator. The old simulator remains tracked until an explicit disconnect so multi-simulator traffic can continue. A completed shutdown leaves the manager reusable: a later connection creates fresh workers and transports rather than retaining canceled ones. Connection attempts made while logout or teardown is still active fail with `InvalidOperation`, preventing a reentrant reconnect from racing resource cleanup. `RequestLogout`, blocking `Logout`, runtime-neutral `LogoutAsync`, and nonblocking `BeginLogout` all send the native `LogoutRequest` packet at most once per active handshake. A matching `LogoutReply` is accepted only for the current agent and session, raises `LoggedOut` with the returned inventory IDs, and then performs a client-initiated shutdown. Blocking calls wait for that ordered teardown; asynchronous calls additionally observe caller cancellation. `BeginLogout` raises an empty `LoggedOut` only after a bounded network-timeout teardown when no reply arrives, matching the reference ordering. Teardown is idempotent and ordered. It cancels active login and logout waits, disconnects non-current simulators before the current simulator, stops manager workers, clears connection/circuit/session/seed state and parsed login secrets, then raises one `Disconnected` event and marks shutdown complete. Reentrant and repeated shutdown calls do not repeat events. Nonblocking logout waiters observe the lifecycle cancellation and terminate rather than retaining the manager or client; their last detached error remains available through `NetworkManager::last_logout_error` for diagnostics. ## 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. ## Statistics and milestone gate `SimulatorSimStats` is the native thread-safe counterpart of the reference `Simulator.SimStats`. Atomic counters track received/sent packets and bytes, resends, drops, pings, pongs, lag, and bandwidth samples. Server `SimStats` blocks update the 25 defined simulator measurements with the reference ID and rounding rules; unknown IDs are ignored. Debug snapshots contain aggregate counters only—never packet bytes, endpoints, capability URLs, or credentials. The offline fake-grid gate composes the completed layers rather than replacing their focused tests. It authenticates through injected LLSD HTTP, establishes a real loopback UDP circuit, discovers seed capabilities, consumes an `EventQueueGet` message that enables a second region, downloads a capability asset, promotes that region, and completes the logout handshake. It then proves CAPS polling was canceled, download and network workers were joined, sockets were closed, state was cleared, and diagnostic formatting contains none of the fixture tokens. `tools/check_milestone_08.py` also audits owned source files for failure-only bodies and verifies the explicit queue, payload, event, retry, and concurrency policy markers remain present. 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, controlled region handoff, reconnect after teardown, all three logout wait modes, reply validation and event order, callback ordering and filtering, RAII unregistration, runtime-neutral async calls, concurrent registration/removal, reentrant/concurrent disconnect, and keepalive timeout reasons.