package serverP2P; import java.util.Vector; import java.io.File; import java.io.IOException; import java.net.InetAddress; import java.net.SocketException; import java.nio.file.Paths; import java.nio.file.Files; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.net.ServerSocket; import java.net.Socket; import protocolP2P.ProtocolP2PPacketTCP; import protocolP2P.ProtocolP2PPacket; import protocolP2P.RequestResponseCode; import protocolP2P.Payload; import protocolP2P.LoadRequest; import protocolP2P.FileList; import protocolP2P.FilePart; import localException.InternalError; import localException.ProtocolError; import localException.SizeError; import localException.TransmissionError; import localException.VersionError; import localException.SocketClosed; import exception.LocalException; import java.util.Arrays; import tools.Logger; import tools.LogLevel; import tools.HostItem; import java.util.HashMap; import java.util.Map; import java.net.UnknownHostException; import protocolP2P.HashAlgorithm; import protocolP2P.HashRequest; import protocolP2P.HashResponse; import protocolP2P.Register; import protocolP2P.Unregister; import serverP2P.ServerManagement; import serverP2P.FileWatcherTCP; /** Implementation of P2P-JAVA-PROJECT VERSION 1.0 protocol for TCP. * @author Louis Royer * @author Flavien Haas * @author JS Auge * @version 1.0 */ public class ServerManagementTCP extends ServerManagement { private ServerSocket socket; /** Constructor for TCP implementation, with baseDirectory and TCPPort parameters. * @param baseDirectory the root directory where files are stored * @param hostName the server will bind on this address * @param TCPPort the server will listen on this port * @param logger Logger item * @param tracker Tracker */ public ServerManagementTCP(String baseDirectory, HostItem server, HostItem tracker, Logger logger) { super(baseDirectory, server, tracker, logger); assert baseDirectory != null : "baseDirectory is null"; assert server != null : "server is null"; assert tracker != null : "tracker is null"; assert logger != null : "logger is null"; try { socket = new ServerSocket(server.getPort(), 10, server.getInetAddress()); } catch (SocketException e) { writeLog("Error: cannot listen on " + server, LogLevel.Error); System.exit(-1); } catch (IOException e) { writeLog("Error: cannot openning socket", LogLevel.Error); System.exit(-2); } } /** Implementation of runnable. This methods allows to run the server. */ public void run() { writeLog("Server sucessfully started", LogLevel.Info); Runtime.getRuntime().addShutdownHook(new Thread() { public void run() { sendUnregisterRequest(); } }); fileListWatcher = (FileWatcher)new FileWatcherTCP(logger, 10000, server, tracker, baseDirectory); // checking every 10 seconds Thread flwt = new Thread(fileListWatcher); flwt.start(); fileListWatcher.setThread(flwt); ratioWatcher = (RatioWatcher)new RatioWatcherTCP(logger, 10000, tracker); Thread rwt = new Thread(ratioWatcher); rwt.start(); ratioWatcher.setThread(rwt); while(!stop) { try { Socket s = socket.accept(); ClientHandler c = new ClientHandler(s); (new Thread(c)).start(); } catch (IOException e) { writeLog("Socket has been closed", LogLevel.Info); } } writeLog("Server end of loop", LogLevel.Debug); } /** Private runnable class allowing to serve one client. */ private class ClientHandler implements Runnable { private HostItem addr; /** Constructor with a socket. * @param s Socket of this client */ public ClientHandler(Socket s) { addr = new HostItem(s); } /** Implementation of runnable. This method allow to serve one client. */ public void run() { boolean end = false; writeLog("[" + addr + "] New connection", LogLevel.Action); do { end = handleClientRequest(); } while(!end); writeLog("[" + addr + "] End of connection", LogLevel.Action); } /** Respond to next request incomming on socket s. * @param s Socket used to read request and send response * @return true if cannot expect another request (ie, socket is closed) */ private boolean handleClientRequest() { try { ProtocolP2PPacketTCP pd = new ProtocolP2PPacketTCP<>((Object)addr.getTCPSocket()); handleRequest(pd); } catch (IOException e) { return true; } catch (SocketClosed e) { return true; } catch (LocalException e) {} return false; } } /** Implementation of writeLog * @param text Text to log * @param logLevel level of logging */ protected void writeLog(String text, LogLevel logLevel) { logger.writeTCP(text, logLevel); } /** Implementation of writeLog * @param e exception to log * @param logLevel level of logging */ protected void writeLog(Exception e, LogLevel logLevel) { logger.writeTCP(e, logLevel); } /** Create packets * @param payload Payload */ protected < T extends Payload > ProtocolP2PPacket createProtocolP2PPacket(T payload) { return (ProtocolP2PPacket)new ProtocolP2PPacketTCP(payload); } /** Getter for tracker socket * @return Tracker's socket * @throws SocketException * @throws UnknownHostException * @throws IOException */ protected Object getTrackerSocket() throws SocketException, UnknownHostException, IOException { return (Object)tracker.tryGetTCPSocket(); } /** Closes socket */ protected void closeSocket() { try { socket.close(); } catch (IOException e) { writeLog("Could not close socket", LogLevel.Error); } } }