/**
*
*/
package fr.cedrik.email.pop3;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLServerSocketFactory;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import fr.cedrik.email.spi.PropertiesFileSupplier;
import fr.cedrik.util.SSLSockets;
/**
* @author Cédrik LIME
*/
public class POP3Server implements fr.cedrik.email.MainRunner.Main {
private static final Logger logger = LoggerFactory.getLogger(POP3Server.class);
public static volatile boolean shutdown = false;
static LockOutFilter lockOutFilter;
public POP3Server() {
}
public static void shutdown() {
shutdown = true;
}
/**
* @param args
*/
@Override
public void _main(String[] args) throws IOException {
main(args);
}
/**
* @param args
*/
public static void main(String[] args) throws IOException {
POP3Properties pop3Properties = new POP3Properties(PropertiesFileSupplier.Util.get());
lockOutFilter = new LockOutFilter(pop3Properties);
Thread pop3Thread = null, pop3sThread = null;
if (pop3Properties.getPOP3ServerPort() >= 0) {
//ServerSocket serverSocket = ServerSocketFactory.getDefault().createServerSocket(pop3Properties.getPOP3ServerPort());
ServerSocket serverSocket = new ServerSocket(pop3Properties.getPOP3ServerPort());//FIXME allow to bind to a specific interface
pop3Thread = new ServerAcceptorThread(serverSocket, pop3Properties);
pop3Thread.start();
} else {
logger.info("No POP3 server port found in configuration!");
}
if (pop3Properties.getPOP3SServerPort() >= 0 && StringUtils.isNotBlank(pop3Properties.getPOP3SKeyStoreName())) {
SSLServerSocketFactory sslServerSocketFactory = SSLSockets.getSSLServerSocketFactory(
pop3Properties.getPOP3SKeyStoreName(), pop3Properties.getPOP3SKeyStorePassword(), pop3Properties.getPOP3SKeyStoreType(), pop3Properties.getPOP3SKeyPassword(),
pop3Properties.getPOP3STrustStoreName(), pop3Properties.getPOP3STrustStorePassword(), pop3Properties.getPOP3STrustStoreType());
SSLServerSocket serverSSLSocket = (SSLServerSocket) sslServerSocketFactory.createServerSocket(pop3Properties.getPOP3SServerPort());//FIXME allow to bind to a specific interface
serverSSLSocket.setNeedClientAuth(StringUtils.isNotBlank(pop3Properties.getPOP3STrustStoreName()));
pop3sThread = new ServerAcceptorThread(serverSSLSocket, pop3Properties);
pop3sThread.start();
} else {
logger.info("No POP3S server port or KeyStoreName found in configuration!");
}
try {
if (pop3Thread != null) {
pop3Thread.join();
}
if (pop3sThread != null) {
pop3sThread.join();
}
} catch (InterruptedException ignore) {
logger.trace("serverThread.join()", ignore);
}
}
private static class ServerAcceptorThread extends Thread {
private final ServerSocket serverSocket;
private final boolean secure;
private final POP3Properties pop3Properties;
public ServerAcceptorThread(ServerSocket serverSocket, POP3Properties pop3Properties) {
this.serverSocket = serverSocket;
this.secure = (serverSocket instanceof SSLServerSocket);
this.pop3Properties = pop3Properties;
}
@Override
public void run() {
logger.info("POP3{} server ready, listening on {}", (secure ? "S" : ""), serverSocket.toString());
try {
while (! shutdown) {
Socket clientSocket = serverSocket.accept();
if (lockOutFilter.isLocked(clientSocket.getInetAddress())) {
logger.warn("An attempt was made to authenticate the locked user \"{}\"", clientSocket.getRemoteSocketAddress());
IOUtils.closeQuietly(clientSocket);
continue;
}
logger.info("New POP3{} client: {}", (secure ? "S" : ""), clientSocket.getRemoteSocketAddress());
try {
clientSocket.setSoTimeout(pop3Properties.getPOP3soTimeout());
Thread clientThread = new Thread(new POP3Session(clientSocket),
"POP3"+ (secure ? "S" : "") + " client " + clientSocket.getRemoteSocketAddress());
clientThread.setDaemon(false);
clientThread.start();
} catch (IOException e) {
logger.error("Error while opening communication channels with client {}", clientSocket.getRemoteSocketAddress(), e);
IOUtils.closeQuietly(clientSocket);
}
}
} catch (IOException e) {
logger.error("Error while listening for client connection: ", e);
}
logger.info("POP3{} server ({}) shutting down...", (secure ? "S" : ""), serverSocket);
IOUtils.closeQuietly(serverSocket);
}
}
}