Skip to content

Commit

Permalink
Fix on some versions of WINE, if you close the server while players a…
Browse files Browse the repository at this point in the history
…re still connected, you get EADDRINUSE for next few minutes if you try to start server again

This seems to happen because a socket is left in TIME_WAIT state, so workaround by this enabling SO_REUSEADDR. Except on Windows SO_REUSEADDR has different behaviour, so only apply the workaround when running on mono
  • Loading branch information
UnknownShadow200 committed Jul 4, 2021
1 parent 1d14560 commit 411f7f3
Show file tree
Hide file tree
Showing 4 changed files with 25 additions and 5 deletions.
3 changes: 1 addition & 2 deletions MCGalaxy/Commands/World/CmdOverseer.cs
Expand Up @@ -111,8 +111,7 @@ class SubCommand {
}

static string NextLevel(Player p) {
string level = p.name.ToLower();
int realms = p.group.OverseerMaps;
int realms = p.group.OverseerMaps;

for (int i = 1; realms > 0; i++) {
string map = GetLevelName(p, i);
Expand Down
18 changes: 18 additions & 0 deletions MCGalaxy/Network/Listeners.cs
Expand Up @@ -51,6 +51,23 @@ public sealed class TcpListen : INetListen {
}
}

void EnableAddressReuse() {
// This fixes when on certain environments, if the server is restarted while there are still some
// sockets in the TIME_WAIT state, the listener in the new server process will fail with EADDRINUSE
// https://stackoverflow.com/questions/3229860/what-is-the-meaning-of-so-reuseaddr-setsockopt-option-linux
// https://superuser.com/questions/173535/what-are-close-wait-and-time-wait-states
// https://stackoverflow.com/questions/14388706/how-do-so-reuseaddr-and-so-reuseport-differ
// SO_REUSEADDR behaves differently on Windows though, so don't enable it there
// (note that this code is required for WINE, therefore check if running in mono)
if (!Server.RunningOnMono()) return;

try {
socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, 1);
} catch {
// not really a critical issue if this fails to work
}
}

public override void Listen(IPAddress ip, int port) {
if (IP == ip && Port == port) return;
Close();
Expand All @@ -59,6 +76,7 @@ public sealed class TcpListen : INetListen {
try {
socket = new Socket(ip.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
DisableIPV6OnlyListener();
EnableAddressReuse();

socket.Bind(new IPEndPoint(ip, port));
socket.Listen((int)SocketOptionName.MaxConnections);
Expand Down
3 changes: 1 addition & 2 deletions MCGalaxy/Player/Player.Handlers.cs
Expand Up @@ -467,9 +467,8 @@ public partial class Player : IDisposable {
}

bool FilterChat(ref string text, byte continued) {
// handles the /womid client message, which displays the WoM vrersion
// Handle /womid [version] which informs the server of the WoM client version
if (text.StartsWith("/womid")) {
string version = (text.Length <= 21 ? text.Substring(text.IndexOf(' ') + 1) : text.Substring(7, 15));
UsingWom = true;
return true;
}
Expand Down
6 changes: 5 additions & 1 deletion MCGalaxy/Server/Server.cs
Expand Up @@ -277,7 +277,7 @@ public sealed partial class Server {

static bool HACK_TryExecvp() {
return CLIMode && Environment.OSVersion.Platform == PlatformID.Unix
&& Type.GetType("Mono.Runtime") != null;
&& RunningOnMono();
}

static void HACK_Execvp() {
Expand Down Expand Up @@ -307,6 +307,10 @@ public sealed partial class Server {
} catch {
}
}

public static bool RunningOnMono() {
return Type.GetType("Mono.Runtime") != null;
}

public static void UpdateUrl(string url) {
if (OnURLChange != null) OnURLChange(url);
Expand Down

0 comments on commit 411f7f3

Please sign in to comment.