setPushNotificationToken() stores the token and returns early when the
proxy connection is not established yet, without ever scheduling the
subscriptions it skipped. Nothing retries them afterwards:
restartListeners() only resubscribes listeners whose opstate is not ok,
so listeners that are healthy keep the subscription they were created
with and the server is never told the session id of the current run.
Clients set the token while the account starts, before the first proxy
reply arrives, so this path is the common one rather than a corner case.
The server then keeps the listener registered under the session of a
previous run and stamps every notification with that stale id. The
client compares it with pushSessionId_, which is drawn once per
DhtProxyClient, and discards the notification:
if (sessionId != notification.end() and sessionId->second != pushSessionId_)
return PushNotificationResult::IgnoredWrongSession;
Observed on an Android device: every push received was rejected with
IgnoredWrongSession, 83 out of 83, including calls and the diagnostic
ping. Restarting the proxy instance cleared the stale listeners, after
which the device received no push at all, confirming it never subscribes
for push with its current session.
Remember the skipped subscriptions and send them from restartListeners()
once the connection comes up. searchLock_ is already held there, so the
loop is inlined rather than calling resubscribeAll(), and
lockCurrentProxyInfos_ is released before searchLock_ is taken in
setPushNotificationToken() to keep the lock order consistent.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Key partial messages by source and transaction ID, buffer bounded fragments received before their header, and avoid charging reordered requests twice against rate limits. Cover source collisions, early fragments, empty data and large values.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
RevocationList::sign() always overwrote the CRL Number extension: random
on the first signature, incremented afterwards. This leaves no way for a
certificate authority replicated over several devices to keep numbers
unique, since every device branching from the same list mints the same
number for a different content.
Add an optional `number` parameter, used verbatim when non-zero, so
callers can partition the number space (RFC 5280 5.2.3 requires
monotonicity for a given CRL scope and issuer, not globally).
Also fix the default increment path: the extension holds a DER integer
with leading zeros stripped, so reading it straight into an uint64_t only
worked for numbers wide enough to occupy all 8 bytes. Signing a list
numbered 5 produced 0x0500000000000001 instead of 6. Read and write the
number as a big-endian byte string instead, which makes the `endian()`
helper unnecessary.
Add tests covering the default numbering, explicit numbers (including
values with leading zero bytes and the largest positive 8-byte integer),
pack/unpack round-trips, and a device-partitioned numbering scheme.
This prevents ThreadPool::stop from hanging if it is called with `wait`
set to true (which is notably the case in ThreadPool::join) and the
pool's task queue is non-empty.
Make Hash default constructor, hex constructor, data(), const
operator[] and fromString constexpr. Change fromString to be
non-throwing: it now uses a validity flag and fills the hash with zeros
on parse error instead of throwing. Add a constexpr toHexArray helper
that returns a std::array<char, N*2> for compile-time hex conversion.
Update tests to include <string_view>, use std::string_view, add
constexpr InfoHash usage and a static_assert for the hex array.
Change the template unpackMsg to accept a const Blob& to avoid an
unnecessary copy of the Blob argument. Move the non-template unpackMsg
(returning msgpack::unpacked) into the header as an inline function and
remove its out-of-line definition from src/utils.cpp. Update
declarations accordingly.