/*
* Copyright 2013-2014 Cel Skeggs
*
* This file is part of the CCRE, the Common Chicken Runtime Engine.
*
* The CCRE is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option) any
* later version.
*
* The CCRE 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 Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the CCRE. If not, see <http://www.gnu.org/licenses/>.
*/
package ccre.net;
import java.io.IOException;
import ccre.concurrency.ReporterThread;
import ccre.log.Logger;
/**
* A simple thread to allow easy writing of servers without creating a custom
* thread to receive new client connections.
*
* @author skeggsc
*/
public abstract class ConnectionReceiverThread extends ReporterThread {
/**
* The port that the server is started on.
*/
private final int port;
/**
* The name of this thread.
*/
private final String thrName;
/**
* Create a new ConnectionReceiverThread with the specified thread name and
* port.
*
* @param name The thread name. This is passed directly to ReporterThread.
* @param port This is the TCP port to host on.
*/
public ConnectionReceiverThread(String name, int port) {
super(name);
this.thrName = name;
this.port = port;
}
@Override
protected final void threadBody() throws IOException {
Logger.fine("About to listen on " + port);
ServerSocket sock;
try {
sock = Network.bind(port);
} catch (IOException e) {
if (e.getClass().getName().equals("java.net.BindException")) {
Logger.warning("Failed to bind to port " + port + ".");
return;
}
throw e;
}
while (true) {
final ClientSocket conn = sock.accept();
new ReporterThread(thrName + "-client") {
@Override
protected void threadBody() throws Throwable {
try {
handleClient(conn);
} finally {
conn.close();
}
}
}.start();
}
}
/**
* Handle a client. This is run in a new thread, so you don't need to worry
* about holding up other threads or accidentally terminating all
* connections if an error occurs. The connection will be closed
* automatically once this method returns or throws an error.
*
* @param conn The client connection.
* @throws Throwable If something bad happens.
*/
protected abstract void handleClient(ClientSocket conn) throws Throwable;
}