All Downloads are FREE. Search and download functionalities are using the official Maven repository.

ru.fix.stdlib.socket.proxy.ProxySocket Maven / Gradle / Ivy

There is a newer version: 3.1.4
Show newest version
package ru.fix.stdlib.socket.proxy;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

public class ProxySocket implements AutoCloseable {

    private static Logger log = LoggerFactory.getLogger(ProxySocket.class);

    private String destinationHost;
    private int destinationPort;
    private int sourcePort;
    private ExecutorService executorService;

    private ServerSocket sourceServerSocket;
    private AtomicBoolean isShutdown = new AtomicBoolean();

    /**
     * @param executorService provide thread pools for connections. Each connection to the socket
     *                        use separate thread from executorService's thread pool
     */
    public ProxySocket(String destinationHost, int destinationPort,
                       int sourcePort, ExecutorService executorService) throws IOException {
        this.destinationHost = destinationHost;
        this.destinationPort = destinationPort;
        this.sourcePort = sourcePort;
        this.executorService = executorService;

        start();
    }

    private void start() throws IOException {
        sourceServerSocket = new ServerSocket(sourcePort);
        executorService.submit(() -> {
                    final byte[] request = new byte[1024];
                    final byte[] reply = new byte[4096];

                    while (!isShutdown.get()) {
                        try (Socket sourceSocket = sourceServerSocket.accept();
                             final InputStream streamFromClient = sourceSocket.getInputStream();
                             final OutputStream streamToClient = sourceSocket.getOutputStream();
                             Socket destinationSocket = new Socket(destinationHost, destinationPort)) {
                            executorService.submit(() -> {
                                try (OutputStream streamToServer = destinationSocket.getOutputStream()) {
                                    int bytesRead;
                                    while (!isShutdown.get() && (bytesRead = streamFromClient.read(request)) != -1) {
                                        streamToServer.write(request, 0, bytesRead);
                                        streamToServer.flush();
                                    }
                                } catch (IOException e) {
                                    log.error("Failed to flush to dest", e);
                                }
                            });

                            try (InputStream streamFromServer = destinationSocket.getInputStream()) {
                                int bytesRead;
                                while (!isShutdown.get() && (bytesRead = streamFromServer.read(reply)) != -1) {
                                    streamToClient.write(reply, 0, bytesRead);
                                    streamToClient.flush();
                                }
                            } catch (IOException e) {
                                log.error("Failed to flush to client", e);
                            }
                        } catch (IOException e) {
                            log.error("Failed to open socket", e);
                        }
                    }
                }
        );
    }

    public int getPort() {
        return sourceServerSocket.getLocalPort();
    }

    @Override
    public void close() {
        isShutdown.set(true);

        try {
            sourceServerSocket.close();
        } catch (IOException e) {
            log.error("Error while trying to close socket: " + e);
        }

        shutdownExecutorService();
    }

    private void shutdownExecutorService() {
        executorService.shutdown();
        try {
            if (!executorService.awaitTermination(5, TimeUnit.SECONDS)) {
                executorService.shutdownNow();
            }
        } catch (InterruptedException e) {
            log.error("Error occurred when await termination", e);
            executorService.shutdownNow();
            Thread.currentThread().interrupt();
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy