fix: on reconnect do not disconnect the new client

Currently when a client connects that is already there, the old socket is closed, and the code tries to reuse the existing client object be exchanging
its socket.

Reusing the same client object and just changing its socket does cause issues though with copies of the client in other threads. In the situations
that I could reproduce, it always disconnected both sockets, the old one and then the new one.

Instead I make a copy of the client object now, remove the old object and add the new object to the collection.
This commit is contained in:
Robin C. Ladiges 2022-09-03 23:04:01 +02:00
parent 391d020385
commit 9e6c312c8e
No known key found for this signature in database
GPG Key ID: B494D3DF92661B99
2 changed files with 22 additions and 23 deletions

View File

@ -28,6 +28,17 @@ public class Client : IDisposable {
Logger = new Logger("Unknown User");
}
// copy Client to use existing data for a new reconnected connection with a new socket
public Client(Client other, Socket socket) {
Metadata = other.Metadata;
Connected = other.Connected;
CurrentCostume = other.CurrentCostume;
Id = other.Id;
Socket = socket;
Server = other.Server;
Logger = other.Logger;
}
public void Dispose() {
if (Socket?.Connected is true)
Socket.Disconnect(false);
@ -83,4 +94,4 @@ public class Client : IDisposable {
public override int GetHashCode() {
return Id.GetHashCode(); //relies upon same info as == operator.
}
}
}

View File

@ -180,32 +180,21 @@ public class Server {
goto disconnect;
}
bool firstConn = false;
bool firstConn = true;
switch (connect.ConnectionType) {
case ConnectPacket.ConnectionTypes.FirstConnection: {
firstConn = true;
if (FindExistingClient(header.Id) is { } newClient) {
if (newClient.Connected) {
newClient.Logger.Info($"Disconnecting already connected client {newClient.Socket?.RemoteEndPoint} for {client.Socket?.RemoteEndPoint}");
newClient.Dispose();
}
newClient.Socket = client.Socket;
client = newClient;
}
break;
}
case ConnectPacket.ConnectionTypes.FirstConnection:
case ConnectPacket.ConnectionTypes.Reconnecting: {
client.Id = header.Id;
if (FindExistingClient(header.Id) is { } newClient) {
if (newClient.Connected) {
newClient.Logger.Info($"Disconnecting already connected client {newClient.Socket?.RemoteEndPoint} for {client.Socket?.RemoteEndPoint}");
newClient.Dispose();
if (FindExistingClient(header.Id) is { } oldClient) {
firstConn = false;
client = new Client(oldClient, socket);
Clients.Remove(oldClient);
Clients.Add(client);
if (oldClient.Connected) {
oldClient.Logger.Info($"Disconnecting already connected client {oldClient.Socket?.RemoteEndPoint} for {client.Socket?.RemoteEndPoint}");
oldClient.Dispose();
}
newClient.Socket = client.Socket;
client = newClient;
} else {
firstConn = true;
connect.ConnectionType = ConnectPacket.ConnectionTypes.FirstConnection;
}
@ -222,7 +211,6 @@ public class Server {
List<Client> toDisconnect = Clients.FindAll(c => c.Id == header.Id && c.Connected && c.Socket != null);
Clients.RemoveAll(c => c.Id == header.Id);
client.Id = header.Id;
Clients.Add(client);
Parallel.ForEachAsync(toDisconnect, (c, token) => c.Socket!.DisconnectAsync(false, token));