From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Andrew Steinborn <git@steinborn.me>
Date: Tue, 11 May 2021 17:39:22 -0400
Subject: [PATCH] Add Unix domain socket support

For Windows and ARM support, JEP-380 is required:
https://inside.java/2021/02/03/jep380-unix-domain-sockets-channels/
This will be possible as of the Minecraft 1.17 Java version bump.

Tested-by: Mariell Hoversholm <proximyst@proximyst.com>
Reviewed-by: Mariell Hoversholm <proximyst@proximyst.com>

diff --git a/src/main/java/net/minecraft/network/NetworkManager.java b/src/main/java/net/minecraft/network/NetworkManager.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/network/NetworkManager.java
+++ b/src/main/java/net/minecraft/network/NetworkManager.java
@@ -0,0 +0,0 @@ public class NetworkManager extends SimpleChannelInboundHandler<Packet<?>> {
     // Spigot Start
     public SocketAddress getRawAddress()
     {
+        // Paper start - this can be nullable in the case of a Unix domain socket, so if it is, fake something
+        if (this.channel.remoteAddress() == null) {
+            return new java.net.InetSocketAddress(java.net.InetAddress.getLoopbackAddress(), 0);
+        }
+        // Paper end
         return this.channel.remoteAddress();
     }
     // Spigot End
diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
@@ -0,0 +0,0 @@ public class DedicatedServer extends MinecraftServer implements IMinecraftServer
         this.i(dedicatedserverproperties.enforceWhitelist);
         // this.saveData.setGameType(dedicatedserverproperties.gamemode); // CraftBukkit - moved to world loading
         DedicatedServer.LOGGER.info("Default game type: {}", dedicatedserverproperties.gamemode);
+        // Paper start - Unix domain socket support
+        java.net.SocketAddress bindAddress;
+        if (this.getServerIp().startsWith("unix:")) {
+            if (!io.netty.channel.epoll.Epoll.isAvailable()) {
+                DedicatedServer.LOGGER.fatal("**** INVALID CONFIGURATION!");
+                DedicatedServer.LOGGER.fatal("You are trying to use a Unix domain socket but you're not on a supported OS.");
+                return false;
+            } else if (!com.destroystokyo.paper.PaperConfig.velocitySupport && !org.spigotmc.SpigotConfig.bungee) {
+                DedicatedServer.LOGGER.fatal("**** INVALID CONFIGURATION!");
+                DedicatedServer.LOGGER.fatal("Unix domain sockets require IPs to be forwarded from a proxy.");
+                return false;
+            }
+            bindAddress = new io.netty.channel.unix.DomainSocketAddress(this.getServerIp().substring("unix:".length()));
+        } else {
         InetAddress inetaddress = null;
 
         if (!this.getServerIp().isEmpty()) {
@@ -0,0 +0,0 @@ public class DedicatedServer extends MinecraftServer implements IMinecraftServer
         if (this.getPort() < 0) {
             this.setPort(dedicatedserverproperties.serverPort);
         }
+        bindAddress = new java.net.InetSocketAddress(inetaddress, this.getPort());
+        }
+        // Paper end
 
         this.P();
         DedicatedServer.LOGGER.info("Starting Minecraft server on {}:{}", this.getServerIp().isEmpty() ? "*" : this.getServerIp(), this.getPort());
 
         try {
-            this.getServerConnection().a(inetaddress, this.getPort());
+            this.getServerConnection().bind(bindAddress); // Paper - Unix domain socket support
         } catch (IOException ioexception) {
             DedicatedServer.LOGGER.warn("**** FAILED TO BIND TO PORT!");
             DedicatedServer.LOGGER.warn("The exception was: {}", ioexception.toString());
diff --git a/src/main/java/net/minecraft/server/network/HandshakeListener.java b/src/main/java/net/minecraft/server/network/HandshakeListener.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/server/network/HandshakeListener.java
+++ b/src/main/java/net/minecraft/server/network/HandshakeListener.java
@@ -0,0 +0,0 @@ public class HandshakeListener implements PacketHandshakingInListener {
                 this.c.setProtocol(EnumProtocol.LOGIN);
                 // CraftBukkit start - Connection throttle
                 try {
+                    if (!(this.c.channel.localAddress() instanceof io.netty.channel.unix.DomainSocketAddress)) { // Paper - the connection throttle is useless when you have a Unix domain socket
                     long currentTime = System.currentTimeMillis();
                     long connectionThrottle = this.b.server.getConnectionThrottle();
                     InetAddress address = ((java.net.InetSocketAddress) this.c.getSocketAddress()).getAddress();
@@ -0,0 +0,0 @@ public class HandshakeListener implements PacketHandshakingInListener {
                             }
                         }
                     }
+                    } // Paper - add closing bracket for if check above
                 } catch (Throwable t) {
                     org.apache.logging.log4j.LogManager.getLogger().debug("Failed to check connection throttle", t);
                 }
@@ -0,0 +0,0 @@ public class HandshakeListener implements PacketHandshakingInListener {
                 //if (org.spigotmc.SpigotConfig.bungee) { // Paper - comment out, we check above!
                         String[] split = packethandshakinginsetprotocol.hostname.split("\00");
                         if ( ( split.length == 3 || split.length == 4 ) && ( BYPASS_HOSTCHECK || HOST_PATTERN.matcher( split[1] ).matches() ) ) { // Paper
+                            // Paper start - Unix domain socket support
+                            java.net.SocketAddress socketAddress = c.getSocketAddress();
                             packethandshakinginsetprotocol.hostname = split[0];
-                            c.socketAddress = new java.net.InetSocketAddress(split[1], ((java.net.InetSocketAddress) c.getSocketAddress()).getPort());
+                            c.socketAddress = new java.net.InetSocketAddress(split[1], socketAddress instanceof java.net.InetSocketAddress ? ((java.net.InetSocketAddress) socketAddress).getPort() : 0);
+                            // Paper end
                             c.spoofedUUID = com.mojang.util.UUIDTypeAdapter.fromString( split[2] );
                         } else
                         {
diff --git a/src/main/java/net/minecraft/server/network/ServerConnection.java b/src/main/java/net/minecraft/server/network/ServerConnection.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/server/network/ServerConnection.java
+++ b/src/main/java/net/minecraft/server/network/ServerConnection.java
@@ -0,0 +0,0 @@ public class ServerConnection {
         this.c = true;
     }
 
+    // Paper start
     public void a(@Nullable InetAddress inetaddress, int i) throws IOException {
+        bind(new java.net.InetSocketAddress(inetaddress, i));
+    }
+    public void bind(java.net.SocketAddress address) throws IOException {
+    // Paper end
         List list = this.listeningChannels;
 
         synchronized (this.listeningChannels) {
@@ -0,0 +0,0 @@ public class ServerConnection {
             LazyInitVar lazyinitvar;
 
             if (Epoll.isAvailable() && this.e.l()) {
+                if (address instanceof io.netty.channel.unix.DomainSocketAddress) {
+                    oclass = io.netty.channel.epoll.EpollServerDomainSocketChannel.class;
+                } else {
                 oclass = EpollServerSocketChannel.class;
+                }
                 lazyinitvar = ServerConnection.b;
                 ServerConnection.LOGGER.info("Using epoll channel type");
             } else {
@@ -0,0 +0,0 @@ public class ServerConnection {
                     ((NetworkManager) object).setPacketListener(new HandshakeListener(ServerConnection.this.e, (NetworkManager) object));
                     io.papermc.paper.network.ChannelInitializeListenerHolder.callListeners(channel); // Paper
                 }
-            }).group((EventLoopGroup) lazyinitvar.a()).localAddress(inetaddress, i)).option(ChannelOption.AUTO_READ, false).bind().syncUninterruptibly()); // CraftBukkit
+            }).group((EventLoopGroup) lazyinitvar.a()).localAddress(address)).option(ChannelOption.AUTO_READ, false).bind().syncUninterruptibly()); // CraftBukkit // Paper
         }
     }