Skip to content

Net10 upgrade and threading fixes#19

Open
wjlafrance wants to merge 10 commits intoBNETDocs:developfrom
wjlafrance:net10-upgrade-and-threading-fixes
Open

Net10 upgrade and threading fixes#19
wjlafrance wants to merge 10 commits intoBNETDocs:developfrom
wjlafrance:net10-upgrade-and-threading-fixes

Conversation

@wjlafrance
Copy link
Collaborator

No description provided.

wjlafrance and others added 10 commits March 16, 2026 20:16
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Socket.UseOnlyOverlappedIO was removed in .NET 5+. Overlapped I/O
is the default behavior for async socket operations on modern .NET.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Friend.Sync() locked source then target. If two users interacted
simultaneously with swapped source/target, ABBA deadlock occurred.
Fix by always locking the object with the lower identity hash first.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
ProcessReceive() locked on ReceiveBuffer (a byte[]) then reassigned
it inside the lock. Subsequent calls locked on a different object,
breaking mutual exclusion entirely. Replace with a dedicated
readonly _receiveLock object used consistently for all buffer access.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
ActiveGameAds was a List<GameAd> accessed from multiple threads with
inconsistent locking. Add a dedicated ActiveGameAdsLock object and
use it at all access sites. SID_STOPADV previously had no lock at all.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Designate() wrote to the dictionary without a lock while RemoveUser()
locked it, creating a data race. Add matching lock.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
ActiveChannel, ActiveClan, ActiveAccount, and GameAd could be set to
null by another thread between the null check and the method call.
Use local variable capture to prevent NullReferenceException.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The existing exception handling in SocketIOCompleted already catches
all exceptions from message handlers and disconnects the client, so
the server does not crash on malformed packets. However, the log
output was unhelpful (e.g. "ArgumentOutOfRangeException error
encountered!" with no packet context).

Add try/catch in Invoke() that logs the message ID, size, and hex
dump before disconnecting. Fix BinaryReader.ReadByteString() to throw
a descriptive GameProtocolViolationException on missing null
terminators instead of an opaque ArgumentOutOfRangeException. Fix
GetNextNull() to restore stream position on failure.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Local variable captures only prevented NullReferenceException but
not the logical race (double cleanup if two threads call Close
concurrently). Use lock(this) to make the entire teardown atomic.
This is safe because Channel.RemoveUser already locks on the
GameState (reentrant), and no other code path holds a different
lock before calling Close.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@carlbennett carlbennett self-assigned this Mar 17, 2026
@carlbennett carlbennett added the enhancement New feature or request label Mar 17, 2026
@carlbennett carlbennett linked an issue Mar 17, 2026 that may be closed by this pull request
@carlbennett carlbennett removed a link to an issue Mar 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants