package net.sf.colossus.server;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import net.sf.colossus.common.Constants;
import net.sf.colossus.util.Split;
import net.sf.colossus.util.StaticResourceLoader;
/**
* Thread handling the distribution of files to clients.
*
* @author Romain Dolbeau
*/
final class FileServerThread extends Thread
{
private static final Logger LOGGER = Logger
.getLogger(FileServerThread.class.getName());
private ServerSocket fileServer;
private static final String separator = StaticResourceLoader.REQUEST_TOKEN_SEPARATOR;
private final Server server;
private final int port;
private boolean keepGoingOn = true;
FileServerThread(Server server, int port)
{
super();
setDaemon(true);
this.server = server;
this.port = port;
try
{
fileServer = new ServerSocket(port, Constants.MAX_MAX_PLAYERS);
}
catch (Exception e)
{
LOGGER.log(Level.SEVERE, "Can not open server socket", e);
// TODO don't do a System.exit in code outside main()
System.exit(1);
}
LOGGER.info("FileServerThread started on " + server + ":" + port);
}
/*
* Set the flag goingOn to false, and makes a dmumy connection to get
* the fileserverthread out of the accept() call.
*/
public void stopGoingOn()
{
keepGoingOn = false;
makeDummyConnection();
}
private void makeDummyConnection()
{
// make a dummy connection, to get the thread out of the
// accept().
try
{
Socket socket = new Socket("localhost", port);
socket.close();
}
// UnknownHostException, IOException, IllegalBlockingModeException
catch (Exception e)
{
LOGGER
.log(Level.SEVERE, "FileServerThread: " + e, (Throwable)null);
}
}
@Override
public void run()
{
net.sf.colossus.util.InstanceTracker.register(this, "only 1");
try
{
while (keepGoingOn)
{
try
{
Socket fileClient = fileServer.accept();
if (!keepGoingOn)
{
break;
}
InetAddress requester = fileClient.getInetAddress();
boolean knownIP = server.isKnownClient(requester);
if (knownIP)
{
InputStream is = fileClient.getInputStream();
BufferedReader in = new BufferedReader(
new InputStreamReader(is));
String request = in.readLine();
if (request == null)
{
LOGGER.log(Level.WARNING,
"Could not read request, got null");
fileClient.close();
continue;
}
OutputStream os = fileClient.getOutputStream();
LOGGER.log(Level.FINEST, "Serving request " + request
+ " from " + fileClient);
boolean ignoreFail = false;
List<String> li = Split.split(separator, request);
String filename = li.remove(0);
// TODO Remove this comment if nothing happened :)
// 2009-03 Now clients sends it. Let's see.
if (filename
.equals(StaticResourceLoader.FILESERVER_IGNOREFAIL_SIGNAL))
{
ignoreFail = true;
filename = li.remove(0);
}
// TODO Currently only commented out, remove whole
// stuff below at some point.
// Meanwhile, suppress the warnings at least for the
// README and the markersFile...
// we know that they usually print warnings for other
// than "Default" directory.
// @TODO: e.g. when the over-next public build is out
// (the one right now (20.4.2007) does not contain
// this yet), make the client one day submit the
// ignore-fail signal, and remove this
// markersFileName/README temporary hack.
/*
if (filename.startsWith(Constants.markersNameFile)
|| filename.startsWith("README"))
{
ignoreFail = true;
}
*/
byte[] data = StaticResourceLoader.getBytesFromFile(
filename, li, true, ignoreFail);
if (data != null)
{
os.write(data);
}
// else we just write nothing.
}
else
{
LOGGER.log(Level.WARNING, "SOMEBODY NOT A CLIENT "
+ "IS TRYING TO ACCESS A FILE !");
LOGGER.log(Level.WARNING, "Request was from "
+ fileClient);
}
fileClient.close();
}
catch (Exception e)
{
LOGGER.log(Level.WARNING,
"FileServerThread : " + e.toString());
}
}
LOGGER.log(Level.FINEST, "FileServerThread is done");
try
{
fileServer.close();
}
catch (IOException e)
{
LOGGER.log(Level.WARNING, "FileServerThread : " + e
+ " while closing socket");
}
}
// catch whatever it be, to make sure the unregister is done
catch (Exception e)
{
LOGGER.log(Level.WARNING, "FileServerThread : " + e
+ " outer try/catch block");
}
}
}