# 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. 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.