parent
b6351d30d3
commit
11fcaa25ea
224
src/clientP2P/ClientManagementTCP.java
Normal file
224
src/clientP2P/ClientManagementTCP.java
Normal file
@ -0,0 +1,224 @@
|
|||||||
|
package clientP2P;
|
||||||
|
import exception.InternalError;
|
||||||
|
import exception.ProtocolError;
|
||||||
|
import exception.SizeError;
|
||||||
|
import exception.TransmissionError;
|
||||||
|
import exception.VersionError;
|
||||||
|
import remoteException.EmptyFile;
|
||||||
|
import remoteException.EmptyDirectory;
|
||||||
|
import remoteException.InternalRemoteError;
|
||||||
|
import remoteException.NotFound;
|
||||||
|
import remoteException.ProtocolRemoteError;
|
||||||
|
import remoteException.VersionRemoteError;
|
||||||
|
import java.net.UnknownHostException;
|
||||||
|
import java.util.Scanner;
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.net.SocketException;
|
||||||
|
import java.net.Socket;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.io.File;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.nio.file.StandardOpenOption;
|
||||||
|
import protocolP2P.ProtocolP2PPacketTCP;
|
||||||
|
import protocolP2P.Payload;
|
||||||
|
import protocolP2P.RequestResponseCode;
|
||||||
|
import protocolP2P.FileList;
|
||||||
|
import protocolP2P.FilePart;
|
||||||
|
import protocolP2P.LoadRequest;
|
||||||
|
|
||||||
|
/** Implementation of P2P-JAVA-PROJECT CLIENT
|
||||||
|
* @author Louis Royer
|
||||||
|
* @author Flavien Haas
|
||||||
|
* @author JS Auge
|
||||||
|
* @version 1.0
|
||||||
|
*/
|
||||||
|
public class ClientManagementTCP implements Runnable {
|
||||||
|
private String baseDirectory;
|
||||||
|
private int TCPPort;
|
||||||
|
private String host;
|
||||||
|
private Socket socket;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** Constructor for TCP implementation, with baseDirectory and TCPPort parameters.
|
||||||
|
* @param baseDirectory the root directory where files are stored
|
||||||
|
* @param host hostname of the server
|
||||||
|
* @param TCPPort the server will listen on this port
|
||||||
|
*/
|
||||||
|
public ClientManagementTCP(String baseDirectory, String host, int TCPPort) {
|
||||||
|
this.baseDirectory = baseDirectory;
|
||||||
|
this.host = host;
|
||||||
|
this.TCPPort = TCPPort;
|
||||||
|
try {
|
||||||
|
socket = new Socket(InetAddress.getByName(host), TCPPort);
|
||||||
|
} catch (SocketException e) {
|
||||||
|
System.err.println("Error: No TCP socket available.");
|
||||||
|
System.exit(-1);
|
||||||
|
} catch (UnknownHostException e) {
|
||||||
|
System.err.println("Error: Unknown host.");
|
||||||
|
System.exit(-1);
|
||||||
|
} catch (IOException e) {
|
||||||
|
System.err.println("Error: Cannot create TCP socket");
|
||||||
|
System.exit(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Implementation of Runnable
|
||||||
|
*/
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
String[] list = listDirectory();
|
||||||
|
System.out.println("Files present on the server:");
|
||||||
|
for(String listItem: list) {
|
||||||
|
System.out.println(listItem);
|
||||||
|
}
|
||||||
|
System.out.println("Name of the file to download:");
|
||||||
|
Scanner scanner = new Scanner(System.in);
|
||||||
|
String f = scanner.nextLine();
|
||||||
|
download(f);
|
||||||
|
System.out.println("File sucessfully downloaded");
|
||||||
|
} catch (EmptyDirectory e) {
|
||||||
|
System.err.println("Error: Server has no file in directory");
|
||||||
|
} catch (InternalError e) {
|
||||||
|
System.err.println("Error: Client internal error");
|
||||||
|
} catch (UnknownHostException e) {
|
||||||
|
System.err.println("Error: Server host is unknown");
|
||||||
|
} catch (IOException e) {
|
||||||
|
System.err.println("Error: Request cannot be send or response cannot be received");
|
||||||
|
} catch (TransmissionError e) {
|
||||||
|
System.err.println("Error: Message received is too big");
|
||||||
|
} catch (ProtocolError e) {
|
||||||
|
System.err.println("Error: Cannot decode server’s response");
|
||||||
|
} catch (VersionError e) {
|
||||||
|
System.err.println("Error: Server’s response use bad version of the protocol");
|
||||||
|
} catch (SizeError e) {
|
||||||
|
System.err.println("Error: Cannot handle this packets because of internal representation limitations of numbers on the client");
|
||||||
|
} catch (InternalRemoteError e) {
|
||||||
|
System.err.println("Error: Server internal error");
|
||||||
|
} catch (ProtocolRemoteError e) {
|
||||||
|
System.err.println("Error: Server cannot decode client’s request");
|
||||||
|
} catch (VersionRemoteError e) {
|
||||||
|
System.err.println("Error: Server cannot decode this version of the protocol");
|
||||||
|
} catch (NotFound e) {
|
||||||
|
System.err.println("Error: Server has not this file in directory");
|
||||||
|
} catch (EmptyFile e) {
|
||||||
|
System.err.println("Error: File is empty");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Try to download a file
|
||||||
|
* @param filename name of the file to download
|
||||||
|
* @throws NotFound
|
||||||
|
* @throws InternalError
|
||||||
|
* @throws UnknownHostException
|
||||||
|
* @throws IOException
|
||||||
|
* @throws TransmissionError
|
||||||
|
* @throws ProtocolError
|
||||||
|
* @throws VersionError
|
||||||
|
* @throws SizeError
|
||||||
|
* @throws InternalRemoteError
|
||||||
|
* @throws ProtocolRemoteError
|
||||||
|
* @throws VersionRemoteError
|
||||||
|
* @throws EmptyFile
|
||||||
|
*/
|
||||||
|
private void download(String filename) throws EmptyFile, NotFound, InternalError, UnknownHostException, IOException, TransmissionError, ProtocolError, VersionError, SizeError, InternalRemoteError, ProtocolRemoteError, VersionRemoteError {
|
||||||
|
final long MAX_PARTIAL_SIZE = 1024;
|
||||||
|
ProtocolP2PPacketTCP d = new ProtocolP2PPacketTCP((Payload) new LoadRequest(filename, 0, MAX_PARTIAL_SIZE));
|
||||||
|
d.sendRequest((Object)socket);
|
||||||
|
boolean fileFullyWritten = false;
|
||||||
|
long offset = 0;
|
||||||
|
do {
|
||||||
|
try {
|
||||||
|
Payload p = d.receiveResponse().getPayload();
|
||||||
|
assert p instanceof FilePart : "This payload must be instance of FilePart";
|
||||||
|
if (!(p instanceof FilePart)) {
|
||||||
|
throw new InternalError();
|
||||||
|
} else {
|
||||||
|
FilePart fp = (FilePart)p;
|
||||||
|
if (!fp.getFilename().equals(filename)) {
|
||||||
|
System.err.println("Error: wrong file received: `" + fp.getFilename() + "`");
|
||||||
|
throw new ProtocolError();
|
||||||
|
}
|
||||||
|
if (fp.getOffset() == 0) {
|
||||||
|
System.err.println("Receiving first partialContent");
|
||||||
|
// first partialContent
|
||||||
|
// increment offset
|
||||||
|
offset = fp.getPartialContent().length;
|
||||||
|
/* write first partialContent */
|
||||||
|
try {
|
||||||
|
Files.write(new File(baseDirectory + filename).toPath(), fp.getPartialContent());
|
||||||
|
} catch (IOException e) {
|
||||||
|
System.err.println("Error: cannot write file (" + baseDirectory + filename + ")");
|
||||||
|
}
|
||||||
|
// next partialContentRequest
|
||||||
|
if (offset != fp.getTotalSize()) {
|
||||||
|
System.err.println("Sending following request with offset: " + offset + " maxpartialsize: " + MAX_PARTIAL_SIZE);
|
||||||
|
d = new ProtocolP2PPacketTCP((Payload) new LoadRequest(filename, offset, MAX_PARTIAL_SIZE));
|
||||||
|
d.sendRequest((Object)socket);
|
||||||
|
} else {
|
||||||
|
fileFullyWritten = true;
|
||||||
|
}
|
||||||
|
} else if (offset == fp.getOffset()){
|
||||||
|
System.err.println("Receiving following partialContent (offset: " + offset + ")");
|
||||||
|
// following
|
||||||
|
// increment offset
|
||||||
|
offset += fp.getPartialContent().length;
|
||||||
|
/* write following partialContent at end of file*/
|
||||||
|
try {
|
||||||
|
Files.write(Paths.get(baseDirectory + filename), fp.getPartialContent(), StandardOpenOption.APPEND);
|
||||||
|
} catch (IOException e) {
|
||||||
|
System.err.println("Error: cannot write file (" + baseDirectory + filename + ")");
|
||||||
|
}
|
||||||
|
if (offset >= fp.getTotalSize()) {
|
||||||
|
fileFullyWritten = true;
|
||||||
|
} else {
|
||||||
|
// next partialContentRequest
|
||||||
|
d = new ProtocolP2PPacketTCP((Payload) new LoadRequest(filename, offset, MAX_PARTIAL_SIZE));
|
||||||
|
d.sendRequest((Object)socket);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
System.err.println("offset: " + fp.getOffset() + " ; content.length: " + fp.getPartialContent().length + " ; totalSize: " + fp.getTotalSize());
|
||||||
|
System.err.println("Error: cannot handle non-consecutive partial files (not implemented)");
|
||||||
|
throw new InternalError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (EmptyDirectory e) {
|
||||||
|
throw new ProtocolError();
|
||||||
|
}
|
||||||
|
} while(!fileFullyWritten);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** list server’s directory content
|
||||||
|
* @return list of files
|
||||||
|
* @throws InternalError
|
||||||
|
* @throws UnknowHostException
|
||||||
|
* @throws IOException
|
||||||
|
* @throws TransmissionError
|
||||||
|
* @throws ProtocolError
|
||||||
|
* @throws VersionError
|
||||||
|
* @throws SizeError
|
||||||
|
* @throws EmptyDirectory
|
||||||
|
* @throws InternalRemoteError
|
||||||
|
* @throws ProtocolRemoteError
|
||||||
|
* @throws VersionRemoteError
|
||||||
|
*/
|
||||||
|
private String[] listDirectory() throws EmptyDirectory, InternalError, UnknownHostException, IOException, TransmissionError, ProtocolError, VersionError, SizeError, InternalRemoteError, ProtocolRemoteError, VersionRemoteError {
|
||||||
|
ProtocolP2PPacketTCP d = new ProtocolP2PPacketTCP(new Payload(RequestResponseCode.LIST_REQUEST));
|
||||||
|
d.sendRequest((Object)socket);
|
||||||
|
try {
|
||||||
|
Payload p = d.receiveResponse().getPayload();
|
||||||
|
assert p instanceof FileList : "This payload must be instance of Filelist";
|
||||||
|
if (!(p instanceof FileList)) {
|
||||||
|
throw new InternalError();
|
||||||
|
} else {
|
||||||
|
return ((FileList)p).getFileList();
|
||||||
|
}
|
||||||
|
} catch (NotFound e) {
|
||||||
|
throw new ProtocolError();
|
||||||
|
} catch (EmptyFile e) {
|
||||||
|
throw new ProtocolError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -54,7 +54,7 @@ public class ClientManagementUDP implements Runnable {
|
|||||||
socket = new DatagramSocket();
|
socket = new DatagramSocket();
|
||||||
socket.connect(InetAddress.getByName(host), UDPPort);
|
socket.connect(InetAddress.getByName(host), UDPPort);
|
||||||
} catch (SocketException e) {
|
} catch (SocketException e) {
|
||||||
System.err.println("Error: No socket available.");
|
System.err.println("Error: No UDP socket available.");
|
||||||
System.exit(-1);
|
System.exit(-1);
|
||||||
} catch (UnknownHostException e) {
|
} catch (UnknownHostException e) {
|
||||||
System.err.println("Error: Unknown host.");
|
System.err.println("Error: Unknown host.");
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package clientP2P;
|
package clientP2P;
|
||||||
import clientP2P.ClientManagementUDP;
|
import clientP2P.ClientManagementUDP;
|
||||||
//import clientP2P.ClientManagementTCP;
|
import clientP2P.ClientManagementTCP;
|
||||||
import tools.Directories;
|
import tools.Directories;
|
||||||
import java.util.Scanner;
|
import java.util.Scanner;
|
||||||
|
|
||||||
@ -26,6 +26,7 @@ public class ClientP2P {
|
|||||||
case "UDP":
|
case "UDP":
|
||||||
case "udp":
|
case "udp":
|
||||||
case "2" :
|
case "2" :
|
||||||
|
System.out.println("Starting with UDP");
|
||||||
ClientManagementUDP cmudp = new ClientManagementUDP(c.directories.getDataHomeDirectory(), c.host, c.port);
|
ClientManagementUDP cmudp = new ClientManagementUDP(c.directories.getDataHomeDirectory(), c.host, c.port);
|
||||||
t = new Thread(cmudp);
|
t = new Thread(cmudp);
|
||||||
break;
|
break;
|
||||||
@ -33,10 +34,10 @@ public class ClientP2P {
|
|||||||
case "tcp":
|
case "tcp":
|
||||||
case "1":
|
case "1":
|
||||||
default:
|
default:
|
||||||
//ClientManagementTCP cmtcp = new ClientManagementTCP(c.directories.getDataHomeDirectory(), c.host, c.port);
|
System.out.println("Starting with TCP");
|
||||||
//t = new Thread(cmtcp);
|
ClientManagementTCP cmtcp = new ClientManagementTCP(c.directories.getDataHomeDirectory(), c.host, c.port);
|
||||||
//break;
|
t = new Thread(cmtcp);
|
||||||
throw new java.lang.UnsupportedOperationException();
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
t.setName("client P2P-JAVA-PROJECT");
|
t.setName("client P2P-JAVA-PROJECT");
|
||||||
|
@ -64,7 +64,7 @@ public abstract class ProtocolP2PPacket {
|
|||||||
public abstract ProtocolP2PPacket receiveResponse() throws EmptyFile, NotFound, EmptyDirectory, InternalRemoteError, VersionRemoteError, ProtocolRemoteError, TransmissionError, ProtocolError, VersionError, InternalError, SizeError, IOException;
|
public abstract ProtocolP2PPacket receiveResponse() throws EmptyFile, NotFound, EmptyDirectory, InternalRemoteError, VersionRemoteError, ProtocolRemoteError, TransmissionError, ProtocolError, VersionError, InternalError, SizeError, IOException;
|
||||||
|
|
||||||
/** Receive a request, subclasses must overwrite this constructor.
|
/** Receive a request, subclasses must overwrite this constructor.
|
||||||
* @param serverSocket socket used to get the request
|
* @param socket socket used to get the request
|
||||||
* @throws TransmissionError
|
* @throws TransmissionError
|
||||||
* @throws ProtocolError
|
* @throws ProtocolError
|
||||||
* @throws VersionError
|
* @throws VersionError
|
||||||
@ -72,7 +72,7 @@ public abstract class ProtocolP2PPacket {
|
|||||||
* @throws SizeError
|
* @throws SizeError
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
protected ProtocolP2PPacket(Object serverSocket) throws TransmissionError, ProtocolError, VersionError, InternalError, SizeError, IOException {}
|
protected ProtocolP2PPacket(Object socket) throws TransmissionError, ProtocolError, VersionError, InternalError, SizeError, IOException {}
|
||||||
|
|
||||||
/** Construct a packet from byte[], subclasses must overwrite this constructor.
|
/** Construct a packet from byte[], subclasses must overwrite this constructor.
|
||||||
* @param packet Packet received
|
* @param packet Packet received
|
||||||
|
287
src/protocolP2P/ProtocolP2PPacketTCP.java
Normal file
287
src/protocolP2P/ProtocolP2PPacketTCP.java
Normal file
@ -0,0 +1,287 @@
|
|||||||
|
package protocolP2P;
|
||||||
|
import exception.InternalError;
|
||||||
|
import exception.ProtocolError;
|
||||||
|
import exception.SizeError;
|
||||||
|
import exception.TransmissionError;
|
||||||
|
import exception.VersionError;
|
||||||
|
import remoteException.EmptyDirectory;
|
||||||
|
import remoteException.InternalRemoteError;
|
||||||
|
import remoteException.NotFound;
|
||||||
|
import remoteException.ProtocolRemoteError;
|
||||||
|
import remoteException.VersionRemoteError;
|
||||||
|
import remoteException.EmptyFile;
|
||||||
|
import tools.BytesArrayTools;
|
||||||
|
import protocolP2P.Payload;
|
||||||
|
import protocolP2P.RequestResponseCode;
|
||||||
|
import protocolP2P.LoadRequest;
|
||||||
|
import protocolP2P.FileList;
|
||||||
|
import protocolP2P.FilePart;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.lang.Byte;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.net.Socket;
|
||||||
|
|
||||||
|
/** Representation of packet.
|
||||||
|
* @author Louis Royer
|
||||||
|
* @author Flavien Haas
|
||||||
|
* @author JS Auge
|
||||||
|
* @version 1.0
|
||||||
|
*/
|
||||||
|
public class ProtocolP2PPacketTCP extends ProtocolP2PPacket {
|
||||||
|
|
||||||
|
private Socket responseSocket; // socket used to recept request and send response
|
||||||
|
private Socket requestSocket; // socket used to send request and to reception response
|
||||||
|
|
||||||
|
/** Constructor with payload parameter (typically used when sending packet).
|
||||||
|
* @param payload the payload associated with the packet to send
|
||||||
|
*/
|
||||||
|
public ProtocolP2PPacketTCP(Payload payload) {
|
||||||
|
super(payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** Send a Packet. Socket must be set and connected.
|
||||||
|
* @param socket Socket used to send Packet.
|
||||||
|
* @throws InternalError
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
protected void send(Socket socket) throws InternalError, IOException {
|
||||||
|
assert socket != null : "Trying to send a Packet but no socket defined";
|
||||||
|
assert socket.isConnected() : "Trying to send a Packet but socket not connected";
|
||||||
|
if (socket == null || (!socket.isConnected())) {
|
||||||
|
throw new InternalError();
|
||||||
|
}
|
||||||
|
// generate Packet
|
||||||
|
byte[] packet = toPacket();
|
||||||
|
// send it
|
||||||
|
OutputStream outputStream = socket.getOutputStream();
|
||||||
|
outputStream.write(packet);
|
||||||
|
outputStream.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Send a Request throught socket. Socket must be connected (typically used from client).
|
||||||
|
* @param socket Socket. Must be connected.
|
||||||
|
* @throws InternalError
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public void sendRequest(Object socket) throws InternalError, IOException {
|
||||||
|
assert socket instanceof Socket: "Wrong socket type";
|
||||||
|
if (socket instanceof Socket) {
|
||||||
|
requestSocket = (Socket)socket;
|
||||||
|
send(requestSocket);
|
||||||
|
} else {
|
||||||
|
throw new InternalError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Receive Request (typically used from server).
|
||||||
|
* @param socket socket used to receive request
|
||||||
|
* @throws TransmissionError
|
||||||
|
* @throws ProtocolError
|
||||||
|
* @throws VersionError
|
||||||
|
* @throws InternalError
|
||||||
|
* @throws SizeError
|
||||||
|
* @throws IOException
|
||||||
|
* @return ProtocolP2PPacket received.
|
||||||
|
*/
|
||||||
|
public ProtocolP2PPacketTCP(Object socket) throws TransmissionError, ProtocolError, VersionError, InternalError, SizeError, IOException {
|
||||||
|
super(socket);
|
||||||
|
assert socket instanceof Socket : "Wrong socket type";
|
||||||
|
if (!(socket instanceof Socket)) {
|
||||||
|
throw new InternalError();
|
||||||
|
}
|
||||||
|
Socket ss = (Socket)socket;
|
||||||
|
byte[] packet = new byte[1024];
|
||||||
|
ss.getInputStream().read(packet);
|
||||||
|
// contruction
|
||||||
|
boolean protocolError = false;
|
||||||
|
try {
|
||||||
|
constructPacket(packet, ss);
|
||||||
|
Payload payload = getPayload();
|
||||||
|
switch (payload.getRequestResponseCode()) {
|
||||||
|
case PROTOCOL_ERROR :
|
||||||
|
// we do not want to create an infinite loop of protocolError message exchange.
|
||||||
|
protocolError = true;
|
||||||
|
break;
|
||||||
|
case VERSION_ERROR :
|
||||||
|
case INTERNAL_ERROR :
|
||||||
|
case EMPTY_DIRECTORY :
|
||||||
|
case NOT_FOUND :
|
||||||
|
case EMPTY_FILE:
|
||||||
|
case LOAD_RESPONSE:
|
||||||
|
case LIST_RESPONSE:
|
||||||
|
// we were expecting a request, but we are receiving a response
|
||||||
|
throw new ProtocolError();
|
||||||
|
default :
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} catch (TransmissionError e) {
|
||||||
|
(new ProtocolP2PPacketTCP(new Payload(RequestResponseCode.INTERNAL_ERROR))).send(ss);
|
||||||
|
throw e;
|
||||||
|
} catch (ProtocolError e) {
|
||||||
|
(new ProtocolP2PPacketTCP(new Payload(RequestResponseCode.PROTOCOL_ERROR))).send(ss);
|
||||||
|
throw e;
|
||||||
|
} catch (VersionError e) {
|
||||||
|
(new ProtocolP2PPacketTCP(new Payload(RequestResponseCode.VERSION_ERROR))).send(ss);
|
||||||
|
throw e;
|
||||||
|
} catch (InternalError e) {
|
||||||
|
(new ProtocolP2PPacketTCP(new Payload(RequestResponseCode.INTERNAL_ERROR))).send(ss);
|
||||||
|
throw e;
|
||||||
|
} catch (SizeError e) {
|
||||||
|
(new ProtocolP2PPacketTCP(new Payload(RequestResponseCode.INTERNAL_ERROR))).send(ss);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
if (protocolError) {
|
||||||
|
throw new ProtocolError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Send a Response to a Request (typically used from server).
|
||||||
|
* @param response Packet to send as a response.
|
||||||
|
* @throws InternalError
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public void sendResponse(ProtocolP2PPacket response) throws InternalError, IOException {
|
||||||
|
assert response instanceof ProtocolP2PPacketTCP: "Wrong Packet type";
|
||||||
|
if (response instanceof ProtocolP2PPacketTCP) {
|
||||||
|
ProtocolP2PPacketTCP r = (ProtocolP2PPacketTCP) response;
|
||||||
|
assert responseSocket != null : "Cannot send response to a packet not received";
|
||||||
|
if (responseSocket == null) {
|
||||||
|
throw new InternalError();
|
||||||
|
}
|
||||||
|
r.send(responseSocket);
|
||||||
|
} else {
|
||||||
|
throw new InternalError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Receive response (typically used by client).
|
||||||
|
* @return ProtocolP2PPacket received
|
||||||
|
* @throws EmptyFile
|
||||||
|
* @throws NotFound
|
||||||
|
* @throws EmptyDirectory
|
||||||
|
* @throws InternalRemoteError
|
||||||
|
* @throws VersionRemoteError
|
||||||
|
* @throws ProtocolRemoteError
|
||||||
|
* @throws TransmissionError
|
||||||
|
* @throws ProtocolError
|
||||||
|
* @throws VersionError
|
||||||
|
* @throws InternalError
|
||||||
|
* @throws SizeError
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public ProtocolP2PPacket receiveResponse() throws EmptyFile, NotFound, EmptyDirectory, InternalRemoteError, VersionRemoteError, ProtocolRemoteError, TransmissionError, ProtocolError, VersionError, InternalError, SizeError, IOException {
|
||||||
|
assert requestSocket != null : "Cannot receive response because request packet not sent.";
|
||||||
|
if (requestSocket == null) {
|
||||||
|
throw new InternalError();
|
||||||
|
}
|
||||||
|
// reception
|
||||||
|
byte[] packet = new byte[8192];
|
||||||
|
requestSocket.getInputStream().read(packet);
|
||||||
|
// contruction
|
||||||
|
try {
|
||||||
|
ProtocolP2PPacketTCP p = new ProtocolP2PPacketTCP(packet);
|
||||||
|
Payload payload = p.getPayload();
|
||||||
|
switch (payload.getRequestResponseCode()) {
|
||||||
|
case PROTOCOL_ERROR :
|
||||||
|
throw new ProtocolRemoteError();
|
||||||
|
case VERSION_ERROR :
|
||||||
|
throw new VersionRemoteError();
|
||||||
|
case INTERNAL_ERROR :
|
||||||
|
throw new InternalRemoteError();
|
||||||
|
case EMPTY_DIRECTORY :
|
||||||
|
throw new EmptyDirectory();
|
||||||
|
case NOT_FOUND :
|
||||||
|
throw new NotFound();
|
||||||
|
case EMPTY_FILE:
|
||||||
|
throw new EmptyFile();
|
||||||
|
default :
|
||||||
|
return (ProtocolP2PPacket)p;
|
||||||
|
}
|
||||||
|
} catch (TransmissionError e) {
|
||||||
|
(new ProtocolP2PPacketTCP(new Payload(RequestResponseCode.INTERNAL_ERROR))).send(requestSocket);
|
||||||
|
throw e;
|
||||||
|
} catch (ProtocolError e) {
|
||||||
|
(new ProtocolP2PPacketTCP(new Payload(RequestResponseCode.PROTOCOL_ERROR))).send(requestSocket);
|
||||||
|
throw e;
|
||||||
|
} catch (VersionError e) {
|
||||||
|
(new ProtocolP2PPacketTCP(new Payload(RequestResponseCode.VERSION_ERROR))).send(requestSocket);
|
||||||
|
throw e;
|
||||||
|
} catch (InternalError e) {
|
||||||
|
(new ProtocolP2PPacketTCP(new Payload(RequestResponseCode.INTERNAL_ERROR))).send(requestSocket);
|
||||||
|
throw e;
|
||||||
|
} catch (SizeError e) {
|
||||||
|
(new ProtocolP2PPacketTCP(new Payload(RequestResponseCode.INTERNAL_ERROR))).send(requestSocket);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Private constructor with packet as byte[] parameter (typically used when receiving Packet response).
|
||||||
|
* @param packet the full Packet received
|
||||||
|
* @throws TransmissionError
|
||||||
|
* @throws ProtocolError
|
||||||
|
* @throws VersionError
|
||||||
|
* @throws InternalError
|
||||||
|
* @throws SizeError
|
||||||
|
*/
|
||||||
|
private ProtocolP2PPacketTCP(byte[] packet) throws TransmissionError, ProtocolError, VersionError, InternalError, SizeError {
|
||||||
|
super(packet);
|
||||||
|
constructPacket(packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Private constructor helper with packet as byte[] parameter (typically used when receiving Packet response/request).
|
||||||
|
* @param packet the full Packet received
|
||||||
|
* @throws TransmissionError
|
||||||
|
* @throws ProtocolError
|
||||||
|
* @throws VersionError
|
||||||
|
* @throws InternalError
|
||||||
|
* @throws SizeError
|
||||||
|
*/
|
||||||
|
private void constructPacket(byte[] packet) throws TransmissionError, ProtocolError, VersionError, InternalError, SizeError {
|
||||||
|
// unwrap version
|
||||||
|
version = packet[VERSION_POSITION];
|
||||||
|
checkProtocolVersion(); // this can throw VersionError
|
||||||
|
RequestResponseCode r = RequestResponseCode.fromCode(packet[RequestResponseCode.RRCODE_POSITION]); // this can throw ProtocolError
|
||||||
|
switch (r) {
|
||||||
|
case LIST_RESPONSE:
|
||||||
|
payload = (Payload) new FileList(packet);
|
||||||
|
break;
|
||||||
|
case LOAD_RESPONSE:
|
||||||
|
payload = (Payload) new FilePart(packet);
|
||||||
|
break;
|
||||||
|
case LOAD_REQUEST:
|
||||||
|
payload = (Payload) new LoadRequest(packet);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
payload = new Payload(packet); // this can throw TransmissionError
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Private constructor helper with packet as byte[] parameter and (typically used when receiving Packet request).
|
||||||
|
* @param packet the full Packet received
|
||||||
|
* @param responseSocket socket address used to reception this request (use this one to respond)
|
||||||
|
* @throws TransmissionError
|
||||||
|
* @throws ProtocolError
|
||||||
|
* @throws VersionError
|
||||||
|
* @throws InternalError
|
||||||
|
* @throws SizeError
|
||||||
|
*/
|
||||||
|
private void constructPacket(byte[] packet, Socket responseSocket) throws TransmissionError, ProtocolError, VersionError, InternalError, SizeError {
|
||||||
|
constructPacket(packet);
|
||||||
|
this.responseSocket = responseSocket;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns a byte[] containing full packet (typically used when sending packet).
|
||||||
|
* This packet is complete and ready to be send.
|
||||||
|
* @return the full packet to send
|
||||||
|
* @throws InternalError
|
||||||
|
*/
|
||||||
|
protected byte[] toPacket() throws InternalError {
|
||||||
|
byte[] packet = payload.toPacket();
|
||||||
|
packet[VERSION_POSITION] = version;
|
||||||
|
return packet;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -90,7 +90,7 @@ public class ProtocolP2PPacketUDP extends ProtocolP2PPacket {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Receive Request (typically used from server).
|
/** Receive Request (typically used from server).
|
||||||
* @param serverSocket socket used to receive request
|
* @param socket socket used to receive request
|
||||||
* @throws TransmissionError
|
* @throws TransmissionError
|
||||||
* @throws ProtocolError
|
* @throws ProtocolError
|
||||||
* @throws VersionError
|
* @throws VersionError
|
||||||
@ -99,13 +99,13 @@ public class ProtocolP2PPacketUDP extends ProtocolP2PPacket {
|
|||||||
* @throws IOException
|
* @throws IOException
|
||||||
* @return ProtocolP2PPacket received.
|
* @return ProtocolP2PPacket received.
|
||||||
*/
|
*/
|
||||||
public ProtocolP2PPacketUDP(Object serverSocket) throws TransmissionError, ProtocolError, VersionError, InternalError, SizeError, IOException {
|
public ProtocolP2PPacketUDP(Object socket) throws TransmissionError, ProtocolError, VersionError, InternalError, SizeError, IOException {
|
||||||
super(serverSocket);
|
super(socket);
|
||||||
assert serverSocket instanceof DatagramSocket : "Wrong socket type";
|
assert socket instanceof DatagramSocket : "Wrong socket type";
|
||||||
if (!(serverSocket instanceof DatagramSocket)) {
|
if (!(socket instanceof DatagramSocket)) {
|
||||||
throw new InternalError();
|
throw new InternalError();
|
||||||
}
|
}
|
||||||
DatagramSocket ss = (DatagramSocket)serverSocket;
|
DatagramSocket ss = (DatagramSocket)socket;
|
||||||
byte[] packet = new byte[1024];
|
byte[] packet = new byte[1024];
|
||||||
DatagramPacket reception = new DatagramPacket(packet, packet.length);
|
DatagramPacket reception = new DatagramPacket(packet, packet.length);
|
||||||
ss.receive(reception);
|
ss.receive(reception);
|
||||||
|
185
src/serverP2P/ServerManagementTCP.java
Normal file
185
src/serverP2P/ServerManagementTCP.java
Normal file
@ -0,0 +1,185 @@
|
|||||||
|
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.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 exception.InternalError;
|
||||||
|
import exception.ProtocolError;
|
||||||
|
import exception.SizeError;
|
||||||
|
import exception.TransmissionError;
|
||||||
|
import exception.VersionError;
|
||||||
|
import remoteException.EmptyDirectory;
|
||||||
|
import remoteException.InternalRemoteError;
|
||||||
|
import remoteException.NotFound;
|
||||||
|
import remoteException.ProtocolRemoteError;
|
||||||
|
import remoteException.VersionRemoteError;
|
||||||
|
import remoteException.EmptyFile;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
|
||||||
|
/** 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 implements Runnable {
|
||||||
|
|
||||||
|
private String[] fileList;
|
||||||
|
private String baseDirectory;
|
||||||
|
private int TCPPort;
|
||||||
|
private ServerSocket socket;
|
||||||
|
|
||||||
|
/** Constructor for TCP implementation, with baseDirectory and TCPPort parameters.
|
||||||
|
* @param baseDirectory the root directory where files are stored
|
||||||
|
* @param TCPPort the server will listen on this port
|
||||||
|
*/
|
||||||
|
public ServerManagementTCP(String baseDirectory, int TCPPort) {
|
||||||
|
this.baseDirectory = baseDirectory;
|
||||||
|
this.TCPPort = TCPPort;
|
||||||
|
initFileList();
|
||||||
|
try {
|
||||||
|
socket = new ServerSocket(TCPPort);
|
||||||
|
} catch (SocketException e) {
|
||||||
|
System.err.println("Error: cannot listen on port " + TCPPort + " (TCP)");
|
||||||
|
System.exit(-1);
|
||||||
|
} catch (IOException e) {
|
||||||
|
System.err.println("Error: cannot openning TCP socket");
|
||||||
|
System.exit(-2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Implementation of runnable. This methods allows to run the server.
|
||||||
|
*/
|
||||||
|
public void run() {
|
||||||
|
// TODO: handling multiple clients
|
||||||
|
try {
|
||||||
|
Socket s = socket.accept();
|
||||||
|
System.err.println("Accepting new connection");
|
||||||
|
while(true) {
|
||||||
|
try {
|
||||||
|
ProtocolP2PPacketTCP pd = new ProtocolP2PPacketTCP((Object)s);
|
||||||
|
Payload p = pd.getPayload();
|
||||||
|
switch (p.getRequestResponseCode()) {
|
||||||
|
case LOAD_REQUEST:
|
||||||
|
System.out.println("Received LOAD_REQUEST");
|
||||||
|
assert p instanceof LoadRequest : "payload must be an instance of LoadRequest";
|
||||||
|
if (!(p instanceof LoadRequest)) {
|
||||||
|
sendInternalError(pd);
|
||||||
|
} else {
|
||||||
|
String filename = ((LoadRequest)p).getFilename();
|
||||||
|
long offset = ((LoadRequest)p).getOffset();
|
||||||
|
long maxSizePartialContent = ((LoadRequest)p).getMaxSizePartialContent();
|
||||||
|
try {
|
||||||
|
byte[] fullLoad = Files.readAllBytes(Paths.get(baseDirectory + filename));
|
||||||
|
long sizeToSend = 0;
|
||||||
|
if (fullLoad.length - offset < maxSizePartialContent) {
|
||||||
|
System.out.println("Sending last partialContent");
|
||||||
|
sizeToSend = fullLoad.length - offset;
|
||||||
|
} else {
|
||||||
|
sizeToSend = maxSizePartialContent;
|
||||||
|
}
|
||||||
|
System.out.println("maxSizePartialContent: " + maxSizePartialContent);
|
||||||
|
System.out.println("Sending " + filename + " from " + offset + " to " + (offset + sizeToSend));
|
||||||
|
byte[] load = Arrays.copyOfRange(fullLoad, (int)offset, (int)(offset + sizeToSend));
|
||||||
|
if (Arrays.binarySearch(fileList, filename) >= 0) {
|
||||||
|
try {
|
||||||
|
if (load.length == 0) {
|
||||||
|
pd.sendResponse((ProtocolP2PPacket)new ProtocolP2PPacketTCP(new Payload(RequestResponseCode.EMPTY_FILE)));
|
||||||
|
} else {
|
||||||
|
pd.sendResponse((ProtocolP2PPacket)new ProtocolP2PPacketTCP((Payload)(new FilePart(filename, fullLoad.length, offset, load))));
|
||||||
|
}
|
||||||
|
} catch (Exception e2) {
|
||||||
|
System.err.println(e2);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
System.err.println("File requested not found: `" + filename + "` " + Arrays.binarySearch(fileList, filename));
|
||||||
|
System.err.println("File list:");
|
||||||
|
for (String f: fileList) {
|
||||||
|
System.err.println("- " + f);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new IOException(); // to send a NOT_FOUND in the catch block
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
try {
|
||||||
|
pd.sendResponse((ProtocolP2PPacket)new ProtocolP2PPacketTCP(new Payload(RequestResponseCode.NOT_FOUND)));
|
||||||
|
} catch (Exception e2) {
|
||||||
|
System.err.println(e2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case LIST_REQUEST:
|
||||||
|
System.out.println("Received LIST_REQUEST");
|
||||||
|
try {
|
||||||
|
if (fileList.length == 0) {
|
||||||
|
System.err.println("Sending EMPTY_DIRECTORY");
|
||||||
|
pd.sendResponse((ProtocolP2PPacket)new ProtocolP2PPacketTCP(new Payload(RequestResponseCode.EMPTY_DIRECTORY)));
|
||||||
|
} else {
|
||||||
|
System.out.println("Sending LIST_RESPONSE");
|
||||||
|
pd.sendResponse((ProtocolP2PPacket)new ProtocolP2PPacketTCP((Payload)(new FileList(fileList))));
|
||||||
|
}
|
||||||
|
} catch (Exception e2) {
|
||||||
|
System.err.println(e2);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
sendInternalError(pd);
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
} catch (TransmissionError e) {
|
||||||
|
} catch (ProtocolError e) {
|
||||||
|
} catch (VersionError e) {
|
||||||
|
} catch (InternalError e) {
|
||||||
|
} catch (SizeError e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** Send an internal error message.
|
||||||
|
* @param pd ProtocolP2PPacketTCP to respond
|
||||||
|
*/
|
||||||
|
private void sendInternalError(ProtocolP2PPacketTCP pd) {
|
||||||
|
try {
|
||||||
|
pd.sendResponse((ProtocolP2PPacket)new ProtocolP2PPacketTCP(new Payload(RequestResponseCode.INTERNAL_ERROR)));
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.err.println(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -52,7 +52,7 @@ public class ServerManagementUDP implements Runnable {
|
|||||||
try {
|
try {
|
||||||
socket = new DatagramSocket(UDPPort);
|
socket = new DatagramSocket(UDPPort);
|
||||||
} catch (SocketException e) {
|
} catch (SocketException e) {
|
||||||
System.err.println("Error: cannot listen on port " + UDPPort);
|
System.err.println("Error: cannot listen on port " + UDPPort + " (UDP)");
|
||||||
System.exit(-1);
|
System.exit(-1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package serverP2P;
|
package serverP2P;
|
||||||
import serverP2P.ServerManagementUDP;
|
import serverP2P.ServerManagementUDP;
|
||||||
|
import serverP2P.ServerManagementTCP;
|
||||||
import tools.Directories;
|
import tools.Directories;
|
||||||
|
|
||||||
public class ServerP2P {
|
public class ServerP2P {
|
||||||
@ -14,10 +15,14 @@ public class ServerP2P {
|
|||||||
}
|
}
|
||||||
public static void main(String [] args) {
|
public static void main(String [] args) {
|
||||||
ServerP2P s = new ServerP2P();
|
ServerP2P s = new ServerP2P();
|
||||||
ServerManagementUDP sm = new ServerManagementUDP(s.directories.getDataHomeDirectory(), s.port);
|
ServerManagementUDP smudp = new ServerManagementUDP(s.directories.getDataHomeDirectory(), s.port);
|
||||||
Thread t = new Thread(sm);
|
ServerManagementTCP smtcp = new ServerManagementTCP(s.directories.getDataHomeDirectory(), s.port);
|
||||||
t.setName("server P2P-JAVA-PROJECT");
|
Thread tudp = new Thread(smudp);
|
||||||
t.start();
|
tudp.setName("server UDP P2P-JAVA-PROJECT");
|
||||||
|
tudp.start();
|
||||||
|
Thread ttcp = new Thread(smtcp);
|
||||||
|
ttcp.setName("server TCP P2P-JAVA-PROJECT");
|
||||||
|
ttcp.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user