Skip to content

Fix/channel reclamation to prevent 'already connected' - #721

Open
BradAF wants to merge 2 commits into
mbbsemu:masterfrom
BradAF:fix/channel-reclamation
Open

BradAF wants to merge 2 commits into
mbbsemu:masterfrom
BradAF:fix/channel-reclamation

Conversation

@BradAF

@BradAF BradAF commented Oct 19, 2026

Copy link
Copy Markdown
Contributor

When a client disconnects, its socket can be disposed while output is
still queued for the session. Send() caught the ObjectDisposedException,
logged a warning and returned, so the session never reached LoggedOff
and ProcessDisconnects() never freed its channel. Every later queued
write logged the same warning again, and the user saw "already logged
in" when reconnecting.

Call CloseSocket() instead, which moves the session to LoggedOff so the
channel is reclaimed on the next ProcessDisconnects() pass. It is
guarded by _socketClosed, so repeated calls are harmless.

Channels take the lowest free number and are freed in any order, so the
channel numbers in use can have gaps (for example 0 and 2, with nothing
on 1). RemoveSessions() looped i from 0 to Count - 1 and treated i as a
channel number, so a channel numbered Count or higher was never checked.
A logged-off session on channel 2 with only two sessions open was
skipped on every pass, leaving the channel occupied and causing "already
logged in" on reconnect.

Loop over the channel numbers actually in use instead, still removing
the highest first.

Brad Furst added 2 commits October 18, 2026 23:10
When a client disconnects, its socket can be disposed while output is
still queued for the session. Send() caught the ObjectDisposedException,
logged a warning and returned, so the session never reached LoggedOff
and ProcessDisconnects() never freed its channel. Every later queued
write logged the same warning again, and the user saw "already logged
in" when reconnecting.

Call CloseSocket() instead, which moves the session to LoggedOff so the
channel is reclaimed on the next ProcessDisconnects() pass. It is
guarded by _socketClosed, so repeated calls are harmless.
Channels take the lowest free number and are freed in any order, so the
channel numbers in use can have gaps (for example 0 and 2, with nothing
on 1). RemoveSessions() looped i from 0 to Count - 1 and treated i as a
channel number, so a channel numbered Count or higher was never checked.
A logged-off session on channel 2 with only two sessions open was
skipped on every pass, leaving the channel occupied and causing "already
logged in" on reconnect.

Loop over the channel numbers actually in use instead, still removing
the highest first.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant