/* * Copyright (C) 2022 jimj316 * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ package moe.nekojimi.chords; import java.io.IOException; import java.net.*; import javax.net.SocketFactory; /** * * @author jimj316 */ public class LocalBindSocketFactory extends SocketFactory { private InetAddress localAddress; public InetAddress getLocalAddress() { return localAddress; } public void setLocalAddress(InetAddress localAddress) { this.localAddress = localAddress; } @Override public Socket createSocket() throws IOException { return new LocalBoundSocket(); // throw new RuntimeException("Trying to create an empty socket!"); } private InetSocketAddress findFreeSocketAddress() { return new InetSocketAddress(localAddress, findFreePort(localAddress)); } @Override public Socket createSocket(String remoteAddr, int remotePort) throws IOException, UnknownHostException { return createSocket(remoteAddr, remotePort, localAddress, findFreePort(localAddress)); } @Override public Socket createSocket(String remoteAddr, int remotePort, InetAddress x, int localPort) throws IOException, UnknownHostException { return createSocket(InetAddress.getByName(remoteAddr), remotePort, localAddress, localPort); } @Override public Socket createSocket(InetAddress remoteAddr, int remotePort) throws IOException { return createSocket(remoteAddr, remotePort, localAddress, findFreePort(localAddress)); } @Override public Socket createSocket(InetAddress remoteAddr, int remotePort, InetAddress x, int localPort) throws IOException { System.out.println("Requested socket; " + localAddress + ":" + localPort + " -> " + remoteAddr + ":" + remotePort); Socket socket = new Socket(remoteAddr, remotePort, localAddress, localPort); System.out.println("Returned socket; " + socket.getLocalSocketAddress() + ":" + socket.getLocalPort() + " -> " + socket.getRemoteSocketAddress() + ":" + socket.getPort()); return socket; } private static int findFreePort(InetAddress localAddr) { int port = 0; // For ServerSocket port number 0 means that the port number is automatically allocated. try (ServerSocket socket = new ServerSocket(0, 0, localAddr)) { // Disable timeout and reuse address after closing the socket. socket.setReuseAddress(true); port = socket.getLocalPort(); } catch (IOException ignored) { } if (port > 0) { return port; } throw new RuntimeException("Could not find a free port"); } private class LocalBoundSocket extends Socket { @Override public void bind(SocketAddress bindpoint) throws IOException { InetSocketAddress localAddress = findFreeSocketAddress(); System.err.println("LocalBoundSocket NOT binding to " + bindpoint + ", using " + localAddress + " instead!"); super.bind(localAddress); } } }