diff --git a/WorldServer/District/Listener.cs b/WorldServer/District/Listener.cs index b740271..c0eed30 100644 --- a/WorldServer/District/Listener.cs +++ b/WorldServer/District/Listener.cs @@ -121,25 +121,30 @@ private void handleDistrict(object client) } try { + // Issue #10: the old teardown iterated DistrictsTcp in insertion + // order, broke after the FIRST entry, and removed the code of + // whichever district registered first — not the dying one. With + // multiple districts the dead entry stayed listed and its + // re-registering replacement was rejected until a world restart. lock (DistrictsTcp) { - foreach (KeyValuePair dtcp in DistrictsTcp) + uint code; + if (DistrictsTcp.TryGetValue(tcpClient, out code)) { lock (Districts) { - foreach (KeyValuePair dis in Districts) + District dis; + if (Districts.TryGetValue(code, out dis)) { - if (dis.Key == dtcp.Value) - { - Log.Error("Listener", dis.Value.ToString() + " disconnected!"); - break; - } + Log.Error("Listener", dis.ToString() + " disconnected!"); } - Districts.Remove(dtcp.Value); - break; + // Remove exactly this connection's registration. + // Idempotent: harmless when a re-registration already + // replaced the entry after the old socket died. + Districts.Remove(code); } + DistrictsTcp.Remove(tcpClient); } - DistrictsTcp.Remove(tcpClient); } tcpClient.Close(); } diff --git a/WorldServer/District/RegisterDistrict.cs b/WorldServer/District/RegisterDistrict.cs index 43a0110..38bc7f8 100644 --- a/WorldServer/District/RegisterDistrict.cs +++ b/WorldServer/District/RegisterDistrict.cs @@ -64,7 +64,15 @@ public static void Register(District district, TcpClient tcpClient, int type, by { if (dist.Value.IP == ip && Program.districtsListener.Districts.ContainsKey(code)) { - district.tcp.Client.Send(new byte[] { 0x30, 0x31 }); + // Same-IP re-registration: replace the stale + // entry and reply with a SINGLE success byte-pair + // (0x33), identical to a fresh registration. The + // old 0x31 prelude made the reply TWO 2-byte + // messages for one registration; the + // DistrictServer's one-reply parser could not + // frame it (the trailing 0x33 leaked into its + // control-record stream and killed the + // connection loop). Program.districtsListener.Districts.Remove(code); break; } @@ -72,7 +80,12 @@ public static void Register(District district, TcpClient tcpClient, int type, by { Log.Error("RegisterDistrict", "Fail try of district registration that already exists!"); district.tcp.Client.Send(new byte[] { 0x30, 0x32 }); - break; + // Reject cleanly: do NOT fall through to the + // register+0x33 below. The old fall-through added + // the rejected district anyway and crashed on the + // duplicate key, leaving the socket open. + district.tcp.Client.Disconnect(true); + return; } } Program.districtsListener.Districts.Add(code, district);