package io.bitsquare.p2p.network;
import io.bitsquare.app.Log;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
// Runs in UserThread
class Server implements Runnable {
private static final Logger log = LoggerFactory.getLogger(Server.class);
private final MessageListener messageListener;
private final ConnectionListener connectionListener;
// accessed from different threads
private final ServerSocket serverSocket;
private final Set<Connection> connections = new CopyOnWriteArraySet<>();
private volatile boolean stopped;
public Server(ServerSocket serverSocket, MessageListener messageListener, ConnectionListener connectionListener) {
Log.traceCall();
this.serverSocket = serverSocket;
this.messageListener = messageListener;
this.connectionListener = connectionListener;
}
@Override
public void run() {
Log.traceCall();
try {
// Thread created by NetworkNode
Thread.currentThread().setName("Server-" + serverSocket.getLocalPort());
try {
while (!stopped && !Thread.currentThread().isInterrupted()) {
log.debug("Ready to accept new clients on port " + serverSocket.getLocalPort());
final Socket socket = serverSocket.accept();
if (!stopped && !Thread.currentThread().isInterrupted()) {
log.debug("Accepted new client on localPort/port " + socket.getLocalPort() + "/" + socket.getPort());
InboundConnection connection = new InboundConnection(socket, messageListener, connectionListener);
log.debug("\n\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n" +
"Server created new inbound connection:"
+ "\nlocalPort/port=" + serverSocket.getLocalPort()
+ "/" + socket.getPort()
+ "\nconnection.uid=" + connection.getUid()
+ "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n");
if (!stopped)
connections.add(connection);
else
connection.shutDown(CloseConnectionReason.APP_SHUT_DOWN);
}
}
} catch (IOException e) {
if (!stopped)
e.printStackTrace();
}
} catch (Throwable t) {
log.error("Executing task failed. " + t.getMessage());
t.printStackTrace();
}
}
public void shutDown() {
Log.traceCall();
if (!stopped) {
stopped = true;
connections.stream().forEach(c -> c.shutDown(CloseConnectionReason.APP_SHUT_DOWN));
try {
serverSocket.close();
} catch (SocketException e) {
log.debug("SocketException at shutdown might be expected " + e.getMessage());
} catch (IOException e) {
log.error("Exception at shutdown. " + e.getMessage());
e.printStackTrace();
} finally {
log.debug("Server shutdown complete");
}
} else {
log.warn("stopped already called ast shutdown");
}
}
}