Tighten multiplayer transport callback ownership
This commit is contained in:
parent
c1010458f8
commit
5c192b0fa4
5 changed files with 684 additions and 116 deletions
|
|
@ -33,5 +33,181 @@ What this note is for:
|
|||
|
||||
Highest-value open edge:
|
||||
|
||||
- The remaining owner-side callback roles behind the validated GameSpy packet branches and the
|
||||
exact user-facing meaning of the selector-view sample or companion fields.
|
||||
- The remaining multiplayer edge is narrower now:
|
||||
the status-route callback vector is bounded through selector-text or averaged-sample publication,
|
||||
control-id-list seeding, scalar-query forwarding, and the validated cookie or extended-payload
|
||||
callbacks. The selector-view sidecar is tighter too: `[entry+0x80]` now reads as the averaged
|
||||
millisecond probe sample and `[entry+0x54]` as the displayed version/build companion integer from
|
||||
the local `X...X|%d` marker family. Separately, the route-callback side now has its own compact
|
||||
GameSpy-style server or route descriptor family with primary and optional secondary endpoint
|
||||
tuples plus keyed fields like `hostname`, `gamever`, `numplayers`, and `numservers`, feeding the
|
||||
route-binding compatibility gate. The compact decode owners are tighter too: `0x5907d0` is now
|
||||
the allocate-and-append lane for self-consistent compact payloads, while `0x590d00` is the keyed
|
||||
upsert-by-primary-endpoint lane that reuses an existing descriptor when one already matches and
|
||||
then notifies the transport owner callback. The route-callback-table runtime above that decode
|
||||
path is tighter too: `0x5905e0` now constructs one transport-owned callback-table block,
|
||||
`0x5906f0` tears down the decoded schema dictionary rooted at `[this+0x08]`, `0x590540/0x5905a0`
|
||||
acquire and release refcounted shared schema strings through the global pool, and `0x5908c0`
|
||||
now reads as the live receive/decode state machine serviced by `0x591290` in table states `2/3`.
|
||||
The higher transport bring-up split is tighter too: `0x596090` now clearly constructs
|
||||
`[transport+0xba4]` through `0x5905e0` with owner callback `0x595a40`, then seeds the local
|
||||
field-cache family `[transport+0x1724]` through `0x5a08f0` with helper `0x595b60`, and then
|
||||
constructs `[transport+0x1164]` through the same `0x5905e0` path but with owner callback
|
||||
`0x595bc0`.
|
||||
The live-route lifecycle above it is tighter too: `0x590740` now cleanly resets one table's live
|
||||
route plus decode-side runtime without destroying the outer object, `0x5907a0` is the broader
|
||||
destroy path that also releases the active descriptor collection, `0x590ed0` opens the route
|
||||
handle into `[this+0x4a0]`, stages the initial outbound request, and seeds state `3` plus the
|
||||
receive buffer, `0x5911e0` is the state-`2/3` socket-service wrapper above `0x5908c0`,
|
||||
`0x5912c0` is the one-shot send-with-reopen-retry helper, and `0x590ea0` is the shared
|
||||
disconnect publication and reset tail. The recurring service helper `0x591290` is tighter too:
|
||||
it now first clears the staged intrusive descriptor list through `0x590490` before entering the
|
||||
state-driven seed-or-receive branch. The upstream openers are tighter now too: `0x5962e0` is the
|
||||
field-subscription route-table owner above `[transport+0xba4]`, while `0x596530` is the
|
||||
`gsi_am_rating` reopen path above `[transport+0x18bc]`. On that latter branch, `0x590dc0` is now
|
||||
bounded as the state-`0` raw-endpoint seed pass over the live route handle, repeatedly pulling
|
||||
endpoint tuples through `0x58bc7e` record type `0x1f3` before stamping descriptor flag byte
|
||||
`0x15` with `0x11`. That makes the remaining flag-bit question much narrower too: current
|
||||
evidence now supports reading byte-`0x15` bit `0x1` as a primary-endpoint-seed or endpoint-only
|
||||
source marker. In the `gsi_am_rating` dispatcher, clear-bit descriptors can take the richer
|
||||
direct transition lane, while set-bit descriptors are pushed through the queued enrichment path
|
||||
and later still suppress that direct transition even when the ready bit is present.
|
||||
The adjacent capacity-descriptor side is tighter too: `0x595bc0` no longer reads as a vague
|
||||
progress helper. Mode `0` is now clearly the live publish lane, and it lines up with the generic
|
||||
descriptor append-notify owner callback at `0x590370`: it samples `hostname`,
|
||||
`numwaiting`, `maxwaiting`, `numservers`, and `numplayers` from the current descriptor before
|
||||
publishing an opcode-`2` descriptor block, while still carrying three cached side scalars from
|
||||
the local capacity sidecar at `[transport+0x1778]`. That sidecar is tighter now too: current
|
||||
evidence says it behaves as one cached pointer into the transient work-record family at
|
||||
`[transport+0x1780]`, because every meaningful branch in `0x595bc0` reads the same
|
||||
`+0x0c/+0x10/+0x18` metadata triplet and the replay modes later consume the pointer through
|
||||
`0x5933a0`. The negative result is stronger too: local text-side xrefs still show no direct
|
||||
store to `[transport+0x1778]`, and a wider sweep also failed to show any obvious `lea`-based
|
||||
replay-band writer. So the sidecar writer remains upstream of this leaf capacity publisher. The
|
||||
payload split is tighter too:
|
||||
`0x592ae0` now grounds opcode `2` as a seven-dword descriptor payload with an owned string slot
|
||||
at `+0x08`, so live mode supplies a populated payload while modes `3` and `5` deliberately
|
||||
enqueue an all-zero payload and reuse only the sidecar metadata in the wrapper. Those two modes
|
||||
are tighter now too: they are not generic replay guesses, they are the live receive-state owner
|
||||
callbacks emitted by `0x5911e0 -> 0x5908c0`. So they are best read as delayed metadata replays
|
||||
over one cached work record, not over a standalone custom cache object. The producer side is
|
||||
tighter now too: callback-table attach,
|
||||
bound-route requests, selector-text route requests, and the type-`9` text fastpath all stage
|
||||
that same `+0x0c/+0x10/+0x18` triplet through `0x5934e0`, so the capacity replay sidecar is
|
||||
clearly reusing one broader transport work-record family. The generic owner-callback split above that family is tighter now
|
||||
too: `0x590370` is the shared append-notify lane in mode `0`, while `0x590430` is the distinct
|
||||
remove-notify-and-stage lane in mode `2`. So `0x595bc0` only owns the live append-style publish
|
||||
path plus delayed replay modes `3/5`, not the remove path. The neighboring transient work queue
|
||||
is tighter too:
|
||||
`0x593330/0x593370/0x593380` now bound `[transport+0x1780]` as a real construct/clear/destroy
|
||||
collection owner, while `0x5933a0`, `0x5934e0`, and `0x593570` now ground the remove, allocate,
|
||||
and completion side over that same family. The small sibling `0x593400` is tighter too: it is a
|
||||
pure uniqueness predicate over work-record field `+0x0c`. Its caller is tighter now too:
|
||||
`0x58d720` is an immediate-drain quiescence gate over one transport context id, using
|
||||
`0x593400` for the queued work family at `[transport+0x1780]` and `0x592970` for the active
|
||||
opcode-record collection at `[transport+0x17fc]`. The strongest current read is that
|
||||
`0x5934c0` seeds that shared drain context id first, then the transport copies it into queued
|
||||
work field `+0x0c` and active opcode-record field `+0x14` before the immediate-drain roots wait
|
||||
on one shared disappearance test rather than one vague “drain until something settles” loop. The
|
||||
currently grounded roots are `0x58df20`, the neighboring formatted selector-text publish path at
|
||||
`0x58dfb0`, and callback-table registration at `0x58e200`. The callback-table attach side now
|
||||
has a tighter active-opcode owner stack too: `0x5927b0` services and retires one active opcode
|
||||
record, `0x592800` performs the broader context-or-idle retirement sweep, `0x5929a0` removes
|
||||
active records by opcode type, and `0x5929f0` removes only opcode-`3` field-snapshot records
|
||||
keyed by the subscribed callback-pair payload. That also corrects `0x595b80`: its final cleanup
|
||||
is not a queued field-snapshot drain, but an active opcode-type-`3` purge beneath the field
|
||||
cache reset.
|
||||
The adjacent route-callback descriptor-table lifecycle is tighter too: `0x590410` now grounds
|
||||
`[table+0x5bc]` as a real staged intrusive descriptor-list head, `0x590430` is the generic
|
||||
remove-notify-and-stage path, `0x590490` releases that staged list, and `0x5904d0` releases the
|
||||
active descriptor collection before tearing the staged list down. That also tightens
|
||||
`0x5962e0`: its earlier “release active descriptors” step is now explicitly this same
|
||||
`0x5904d0` family, not a vague collection clear.
|
||||
The callback-table attach side now
|
||||
constrains the same work-record metadata family a little further too: `0x593650` deliberately
|
||||
duplicates one caller metadata dword into both work fields `+0x0c` and `+0x18`, while preserving
|
||||
the remaining caller callback function pointer in `+0x10`. The lower opcode wrappers are tighter
|
||||
now too: both `0x592a40` and `0x592a70` consume that staged triplet in the order `( callback fn
|
||||
+0x10, callback companion +0x18, drain context id +0x0c )`. So the replay-side triplet is
|
||||
clearly a broader transport callback-wrapper family, not one fixed route-only tuple. The type-`9`
|
||||
text fastpath confirms the same split from the other side too: `0x593d00` only emits the
|
||||
follow-on callback lane when work field `+0x10` is nonnull, and then forwards `(+0x10, +0x18,
|
||||
+0x0c)` into `0x593170` as callback function, callback companion, and trailing drain context.
|
||||
The nearby field-subscription side is tighter too: `0x592b50` now clearly uses
|
||||
`[transport+0x1774]` as a cached progress percentage under the `[transport+0xba4]` callback
|
||||
table, and `0x5962e0` seeds that percentage to `1` just before the first immediate mode-`3`
|
||||
snapshot. The nearby route-callback-table lifecycle is tighter now too: `0x596090` seeds
|
||||
`[transport+0xba0]` as the callback-plumbing enable latch, clears staged payload slot
|
||||
`[transport+0xb50]`, and constructs the three owner branches rooted at `[transport+0xba4]`,
|
||||
`[transport+0x1164]`, and `[transport+0x18bc]`. The matching local cleanup is tighter too:
|
||||
`0x5962c0` is the explicit staged route-callback payload clear on `[transport+0xb50]`, while
|
||||
`0x595ce0` now clearly resets only the capacity-descriptor route callback table at
|
||||
`[transport+0x1164]`, not the field-subscription table at `[transport+0xba4]`. The only
|
||||
meaningful gap left on the capacity side is the still-unrecovered writer that stages
|
||||
`[transport+0x1778]`. The carried sidecar fields are no longer anonymous: current evidence now
|
||||
says they are just the same cached callback-wrapper triplet reused by other work-record families,
|
||||
namely drain context id `+0x0c`, callback function `+0x10`, and callback companion `+0x18`.
|
||||
The negative result is stronger now too: the neighboring replay-band fields
|
||||
`[transport+0x176c]`, `[transport+0x1770]`, `[transport+0x1774]`, `[transport+0x177c]`,
|
||||
`[transport+0x1780]`, and `[transport+0x1784]` all have direct local lifecycle owners, but
|
||||
`[transport+0x1778]` still only appears as the single read in `0x595bc0`. So the remaining
|
||||
writer is upstream and indirect rather than one ordinary direct field store in the local text
|
||||
cluster. One adjacent staged-route callback is
|
||||
tighter now too: `0x595860` is the submit-result handler below
|
||||
`0x5958e0`, using the already-grounded third selector-generation counter at `[transport+0xac0]`
|
||||
plus the target at `[transport+0xb48]` to choose whether staged route-callback traffic can
|
||||
advance the route-mode state machine from mode `2` into `3` and later `4`. The counter beneath
|
||||
that decision is tighter too: `0x594e30` now reads as a selector-view entry counter for slot `2`
|
||||
flag bit `0x20`, optionally filtered by the current transport name buffer. The selector-view
|
||||
mutation side beneath that callback family is tighter too: `0x594a30` is now the direct keyed
|
||||
store remover, `0x594fb0` clears one selector-slot ownership pointer plus its slot-local flag
|
||||
dword and drops the whole entry when no slots remain, `0x595010` rekeys one selector-view entry
|
||||
under a new name while preserving the `0x40..` runtime band, and callback root `0x59f9c0` is now
|
||||
bounded as the lane that clears one named selector-view slot, publishes callback slot `18`, and
|
||||
can still re-enter the route-mode setter from the same slot-`2` state and generation gates. The
|
||||
next adjacent callback roots are tighter now too: `0x5950a0` clears one selector slot from every
|
||||
selector-view entry in the keyed store, `0x59fab0` is the rename or relabel sibling above
|
||||
`0x595010`, `0x59faf0` updates one selector slot's fixed sample-text buffer and refreshes the
|
||||
active selector object when present, and `0x59fb60` replaces one selector slot's name set,
|
||||
requests the default profile-key bundle for that slot, and publishes callback slot `20`. Slot
|
||||
`16` is tighter now too: current grounded caller `0x59f440` forwards the staged route-callback
|
||||
payload handle from `[transport+0xb50]` through `0x592ea0` just before route mode `5`. The last
|
||||
adjacent callback root in that block is tighter now too: `0x59fbd0` is the built-in
|
||||
per-slot profile-key query sibling. It resolves the caller selector name into one slot index,
|
||||
forwards the caller trio into `0x596b90`, and then publishes callback slot `28`; that lower
|
||||
helper indexes one slot-specific built-in string pair from `[transport+0x189c]` and
|
||||
`[transport+0x18ac]`, reuses the generic per-key handler `0x596970`, and only republishes slot
|
||||
`28` when that lower query path succeeds.
|
||||
The compact-header side is tighter too: `0x58fe20` and `0x58ff20` now show that compact payloads
|
||||
always carry the primary IPv4 dword and that header bit `0x10` only gates whether the primary
|
||||
port word is inline or inherited from the owner default port. The variable tails are tighter too:
|
||||
`0x58fe90` now validates the `0x40` inline keyed-property vector against the owner schema, and
|
||||
`0x58fe50` validates the signed-`0x80` trailing string-pair tail before decode. `0x58ff60` then
|
||||
grounds bit `0x02` as the inline secondary IPv4 dword branch, bit `0x20` as the paired
|
||||
secondary-port word branch with owner-port fallback, bit `0x08` as one still-unresolved
|
||||
auxiliary inline dword stored at `[descriptor+0x10]`, bit `0x40` as one inline keyed-property
|
||||
vector decoded through the property-store writers, and signed bit `0x80` as one trailing
|
||||
string-pair tail. The descriptor-state side is tighter too: queue insertion now cleanly splits
|
||||
pending tags `0x4/0x8` from serviced-ready bits `0x1/0x2`, and the `gsi_am_rating` lane now
|
||||
separates direct primary-endpoint handling from queued-descriptor handling. Current evidence now
|
||||
also says byte `[descriptor+0x14]` is not queue-only: `0x58ff60` can also OR in bit `0x1` after
|
||||
the inline keyed-property vector and bit `0x2` after the signed string-pair tail. Byte
|
||||
`[descriptor+0x15]` bit `0x1` is source-side too, not queue-generated: it is explicitly seeded
|
||||
by the primary-endpoint refresh path and preserved by the compact descriptor decode path before
|
||||
the transport later uses it in the `gsi_am_rating` lane both to choose direct-vs-queued handling
|
||||
and to suppress the direct `0x595dc0` transition even after ready bit `0x2` is present. The
|
||||
descriptor body is tighter too: `[descriptor+0x20]` is now the intrusive next-link used by the
|
||||
transport-owned primary-endpoint list, and `[descriptor+0x1c]` is now the special numeric scalar
|
||||
behind the current `queryid`/`ping` fallback pair. The compact-only auxiliary dword at
|
||||
`[descriptor+0x10]` is tighter in a different way: a local xref scan now shows it being preserved
|
||||
by later generic preservation helpers such as
|
||||
`generic_record_0x1c_deep_copy_with_owned_string_at_0x08` `0x591410` and the callback-marshaling
|
||||
wrappers `0x591480` and `0x591510`, but still no dedicated semantic reader has been recovered.
|
||||
So the main remaining uncertainty is the exact higher-level meaning of header bit
|
||||
`[descriptor+0x15] & 0x1`, plus whether `[descriptor+0x10]` ever matters outside that
|
||||
preservation path. The route-event dispatcher side is cleaner too:
|
||||
the mode-`5` tails in both callback families do not copy a descriptor-local field. They mirror the
|
||||
transport-staged companion dword at `[this+0x490]` into `[this+0x54]` and the local field-cache
|
||||
family instead. The `gsi_am_rating` maintenance lane is tighter now too: it sorts the
|
||||
primary-endpoint descriptor table through `0x590310` in mode `1` with key `gsi_am_rating`, then
|
||||
selects the new head through `0x590480` rather than treating the table as pure insertion order.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue