@ -51,6 +51,8 @@ public class ServerManagementTCP implements Runnable {
private Logger logger ;
private Logger logger ;
private HostItem tracker ;
private HostItem tracker ;
private HostItem server ;
private HostItem server ;
private FileListWatcher fileListWatcher ;
private volatile boolean stop ;
/ * * Constructor for TCP implementation , with baseDirectory and TCPPort parameters .
/ * * Constructor for TCP implementation , with baseDirectory and TCPPort parameters .
* @param baseDirectory the root directory where files are stored
* @param baseDirectory the root directory where files are stored
@ -60,12 +62,12 @@ public class ServerManagementTCP implements Runnable {
* @param tracker Tracker
* @param tracker Tracker
* /
* /
public ServerManagementTCP ( String baseDirectory , String hostName , int port , Logger logger , HostItem tracker ) {
public ServerManagementTCP ( String baseDirectory , String hostName , int port , Logger logger , HostItem tracker ) {
stop = false ;
server = new HostItem ( hostName , port ) ;
server = new HostItem ( hostName , port ) ;
fileList = new String [ 0 ] ;
this . tracker = tracker ;
this . tracker = tracker ;
this . logger = logger ;
this . logger = logger ;
this . baseDirectory = baseDirectory ;
this . baseDirectory = baseDirectory ;
initFileList ( ) ;
initSha512 ( ) ;
try {
try {
socket = new ServerSocket ( server . getPort ( ) , 10 , server . getInetAddress ( ) ) ;
socket = new ServerSocket ( server . getPort ( ) , 10 , server . getInetAddress ( ) ) ;
} catch ( SocketException e ) {
} catch ( SocketException e ) {
@ -77,12 +79,26 @@ public class ServerManagementTCP implements Runnable {
}
}
}
}
/** Stop the thread */
public void setStop ( ) {
stop = true ;
}
/ * * Trigger a manual check of the file list
* /
public void updateFileList ( ) {
if ( fileListWatcher ! = null ) {
fileListWatcher . trigger ( ) ;
}
}
/ * * Implementation of runnable . This methods allows to run the server .
/ * * Implementation of runnable . This methods allows to run the server .
* /
* /
public void run ( ) {
public void run ( ) {
logger . writeTCP ( "Server sucessfully started" , LogLevel . Info ) ;
logger . writeTCP ( "Server sucessfully started" , LogLevel . Info ) ;
( new Thread ( new TrackerRegisterer ( ) ) ) . start ( ) ;
fileListWatcher = new FileListWatcher ( 10000 ) ; // checking every 10 seconds
do {
( new Thread ( fileListWatcher ) ) . start ( ) ;
while ( ! stop ) {
try {
try {
Socket s = socket . accept ( ) ;
Socket s = socket . accept ( ) ;
ClientHandler c = new ClientHandler ( s ) ;
ClientHandler c = new ClientHandler ( s ) ;
@ -90,7 +106,17 @@ public class ServerManagementTCP implements Runnable {
} catch ( IOException e ) {
} catch ( IOException e ) {
logger . writeTCP ( "Error while accepting new connection" , LogLevel . Warning ) ;
logger . writeTCP ( "Error while accepting new connection" , LogLevel . Warning ) ;
}
}
} while ( true ) ;
}
fileListWatcher . setStop ( ) ;
// unregistering from tracker
try {
logger . writeTCP ( "Unregistering from tracker" , LogLevel . Info ) ;
ProtocolP2PPacket p = ( ProtocolP2PPacket ) new ProtocolP2PPacketTCP ( ( Payload ) new Unregister ( server ) ) ;
p . sendRequest ( ( Object ) tracker . getTCPSocket ( ) ) ;
} catch ( Exception e ) {
logger . writeTCP ( "Cannot unregister from tracker" , LogLevel . Error ) ;
logger . writeTCP ( e , LogLevel . Error ) ;
}
}
}
/ * * Private runnable class allowing to serve one client .
/ * * Private runnable class allowing to serve one client .
@ -167,22 +193,6 @@ public class ServerManagementTCP implements Runnable {
}
}
}
}
/ * * Initialize local list of all files allowed to be shared .
* /
private void initFileList ( ) {
File folder = new File ( baseDirectory ) ;
Vector < String > v = new Vector < String > ( ) ;
File [ ] files = folder . listFiles ( ) ;
/* Add non-recursively files's names to fileList */
for ( File f : files ) {
if ( f . isFile ( ) ) {
v . add ( f . getName ( ) ) ;
}
}
fileList = new String [ v . size ( ) ] ;
v . toArray ( fileList ) ;
Arrays . sort ( fileList ) ;
}
/ * * Init sha512 map .
/ * * Init sha512 map .
* /
* /
@ -333,39 +343,89 @@ public class ServerManagementTCP implements Runnable {
}
}
}
}
/** Private runnable class allowing to initialize tracker while initializing server. */
/** Private runnable class allowing to keep the tracker informed about file list. */
private class TrackerRegisterer implements Runnable {
private class FileListWatcher implements Runnable {
private volatile boolean stop ;
private long time ;
private boolean force ;
/** Runnable implementation */
/ * * Register server on tracker
public void run ( ) {
* /
private void registerTracker ( ) {
try {
try {
registerTracker ( ) ;
logger . writeTCP ( "Trying to into tracker" , LogLevel . Info ) ;
ProtocolP2PPacket p = ( ProtocolP2PPacket ) new ProtocolP2PPacketTCP ( ( Payload ) new Register ( server ) ) ;
p . sendRequest ( ( Object ) tracker . tryGetTCPSocket ( ) ) ;
logger . writeTCP ( "Register request sent." , LogLevel . Debug ) ;
tracker . closeTCPSocket ( ) ;
} catch ( Exception e ) {
} catch ( Exception e ) {
logger . writeTCP ( e , LogLevel . Error ) ;
// error, trying again at next iteration
System . exit ( - 4 ) ;
force = true ;
logger . writeTCP ( "Cannot contact tracker, trying again at next iteration (" + time + " milliseconds)." , LogLevel . Error ) ;
}
}
}
}
/ * * Register server on tracker
* @throws InternalError
/ * * Update fileList and returns true if different than old list .
* @throws IOException
* @return true if changed
* @throws SocketClosed
* /
* /
private void registerTracker ( ) throws InternalError , IOException , SocketClosed {
private boolean updateFileList ( ) {
logger . writeTCP ( "Unregistering from tracker" , LogLevel . Info ) ;
File folder = new File ( baseDirectory ) ;
ProtocolP2PPacket p = ( ProtocolP2PPacket ) new ProtocolP2PPacketTCP ( ( Payload ) new Unregister ( server ) ) ;
Vector < String > v = new Vector < String > ( ) ;
p . sendRequest ( ( Object ) tracker . getTCPSocket ( ) ) ;
File [ ] files = folder . listFiles ( ) ;
// FIXME: this is a hack
/* Add non-recursively files's names to fileList */
// ProtocolP2PPacketTCP reads 1024 bytes but if 2 request comes at the same time InputStream is cleared fully
for ( File f : files ) {
// and we keep waiting forever on the other side
if ( f . isFile ( ) ) {
// a fix could be to read only the header first, and read the required size after
v . add ( f . getName ( ) ) ;
try {
}
Thread . sleep ( 100 ) ;
}
} catch ( InterruptedException e ) { }
String [ ] newFileList = new String [ v . size ( ) ] ;
logger . writeTCP ( "Registering into tracker" , LogLevel . Info ) ;
v . toArray ( newFileList ) ;
p = ( ProtocolP2PPacket ) new ProtocolP2PPacketTCP ( ( Payload ) new Register ( server ) ) ;
Arrays . sort ( newFileList ) ;
p . sendRequest ( ( Object ) tracker . getTCPSocket ( ) ) ;
if ( ! Arrays . equals ( newFileList , fileList ) ) {
logger . writeTCP ( "Registering completed" , LogLevel . Debug ) ;
fileList = newFileList ;
tracker . closeTCPSocket ( ) ;
initSha512 ( ) ;
return true ;
} else {
return false ;
}
}
/ * * Constructor with millis parameter
* @param millis interval of time between checks
* /
public FileListWatcher ( long millis ) {
this . stop = false ;
this . time = millis ;
}
/ * * Ask the thread to stop
* /
public void setStop ( ) {
stop = true ;
}
/ * * Allow a manual check
* /
public void trigger ( ) {
if ( updateFileList ( ) | | force ) {
force = false ;
logger . writeTCP ( "File list watcher detected changes. Informing tracker." , LogLevel . Info ) ;
registerTracker ( ) ;
}
}
/** Runnable implementation */
public void run ( ) {
logger . writeTCP ( "File list watcher started : delay " + time + " milliseconds." , LogLevel . Info ) ;
while ( ! stop ) {
trigger ( ) ;
try {
Thread . sleep ( time ) ;
} catch ( InterruptedException e ) {
logger . writeTCP ( "File list watcher interrupted" , LogLevel . Error ) ;
setStop ( ) ;
}
}
}
}
}
}