Skip to content

Commit 6590f86

Browse files
Stop send worker after send failure (#660)
Add a volatile sendFailed flag to Session to record the first SendRaw failure and prevent the send queue from continuing to drain after a failed write. sendFailed is set on write timeout and on IO/Socket/other write exceptions. SendWorker now checks sendFailed (in addition to disposed) and breaks out of its loop when set. This avoids continuing to process/encrypt queued packets after the connection is known-bad and reduces wasted work or potential blocking.
1 parent 0d7c586 commit 6590f86

1 file changed

Lines changed: 6 additions & 2 deletions

File tree

Maple2.Server.Core/Network/Session.cs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ public abstract class Session : IDisposable {
3737

3838
private bool disposed;
3939
private int disconnecting; // 0 = not disconnecting, 1 = disconnect in progress/already triggered (reentrancy guard)
40+
private volatile bool sendFailed; // set on first SendRaw failure to stop send queue drain
4041
private readonly uint siv;
4142
private readonly uint riv;
4243

@@ -335,6 +336,7 @@ private void SendRaw(ByteWriter packet) {
335336
// Use async write with timeout to prevent indefinite blocking
336337
Task writeTask = networkStream.WriteAsync(packet.Buffer, 0, packet.Length);
337338
if (!writeTask.Wait(SEND_TIMEOUT_MS)) {
339+
sendFailed = true;
338340
Logger.Warning("SendRaw timeout after {Timeout}ms, disconnecting account={AccountId} char={CharacterId}",
339341
SEND_TIMEOUT_MS, AccountId, CharacterId);
340342

@@ -356,10 +358,12 @@ private void SendRaw(ByteWriter packet) {
356358
throw writeTask.Exception?.GetBaseException() ?? new Exception("Write task faulted");
357359
}
358360
} catch (Exception ex) when (ex.InnerException is IOException or SocketException || ex is IOException or SocketException) {
359-
// Expected when client closes the connection (e.g., during migration)
361+
// Connection was closed by the client or is no longer valid
362+
sendFailed = true;
360363
Logger.Debug("SendRaw connection closed account={AccountId} char={CharacterId}", AccountId, CharacterId);
361364
Disconnect();
362365
} catch (Exception ex) {
366+
sendFailed = true;
363367
Logger.Warning(ex, "[LIFECYCLE] SendRaw write failed account={AccountId} char={CharacterId}", AccountId, CharacterId);
364368
Disconnect();
365369
}
@@ -368,7 +372,7 @@ private void SendRaw(ByteWriter packet) {
368372
private void SendWorker() {
369373
try {
370374
foreach ((byte[] packet, int length) in sendQueue.GetConsumingEnumerable()) {
371-
if (disposed) break;
375+
if (disposed || sendFailed) break;
372376

373377
// Encrypt outside lock, then send with timeout
374378
PoolByteWriter encryptedPacket;

0 commit comments

Comments
 (0)