Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // 4-15-18
- // Client
- import java.net.*;
- import java.io.*;
- import java.util.*;
- import java.nio.charset.*;
- import java.time.LocalTime;
- import java.nio.file.*;
- import static java.nio.file.StandardOpenOption.CREATE;
- import static java.nio.file.StandardOpenOption.APPEND;
- public class Client
- {
- public static int serverPort = 69;
- public static int blockNumber = 0;
- public static String serverAddress;
- public static int timeouts = 0;
- public static int missedPackets = 0;
- public static int clientPort = 0;
- public static FileInputStream fileStream;
- public static String fileString;
- public static final int TIMEOUTS_MAX = 6;
- public static final int MISSED_PACKET_MAX = 6;
- public static final int BUFFER_SIZE = 516;
- public static final int TIMEOUT_INTERVAL = 2000;
- public static final boolean DEBUG = false;
- public static void main(String args[])
- {
- if(args.length != 3 && args.length != 4)
- {
- System.out.println("Improper argument length. Correct options are:\n\t <host> <PUT|GET> <file> [binary]");
- return;
- }
- serverAddress = args[0];
- String operation = args[1].toUpperCase();
- String fileName = args[2];
- String mode = "netascii";
- if(!"PUT".equals(operation) && !"GET".equals(operation))
- {
- System.out.println(String.format("Could not handle \'operation\' %s\nAccepted operations are:\n\tPUT\tGET\n",operation));
- return;
- }
- File file = new File(fileName);
- long fileSize = 0;
- if("PUT".equals(operation))
- {
- if(!file.exists() || file.isDirectory())
- {
- System.out.println(String.format("Could not handle request\n\t%s\ndoes not exist", fileName));
- return;
- }
- fileSize = file.length();
- if(fileSize > 65536 * 512)
- {
- System.out.println("\nFile over maximum per protocol. Consider packaging file into 32MB archives.");
- //return;
- }
- }
- if(args.length == 4)
- if("binary".equals(args[3]))
- {
- mode = "octet";
- try{fileStream = new FileInputStream(file);}
- catch(Exception e)
- {
- debug(e.toString());
- }
- }
- else
- {}
- else
- {
- try
- {
- String str = new String(Files.readAllBytes(Paths.get(fileName)));
- char[] fileChar = str.toCharArray();
- for(int index = 0; index<fileChar.length; index++)
- {
- if((int) fileChar[index] == 13 && (int) fileChar[index+1] != 10)
- fileString += (char) 13 + (char) 10;
- else
- fileString += fileChar[index];
- }
- fileString = fileString.substring(3,fileString.length());
- }
- catch(Exception e)
- {
- debug(e.toString());
- }
- }
- byte OPCode;
- if("GET".equals(operation))
- OPCode = 0x1;
- else
- {
- OPCode = 0x2;
- }
- // Communications
- byte[] receiveData = new byte[Client.BUFFER_SIZE];
- try
- {
- ByteArrayOutputStream sendStream = new ByteArrayOutputStream(Client.BUFFER_SIZE);
- ByteArrayOutputStream receiveStream = new ByteArrayOutputStream(Client.BUFFER_SIZE);
- int replyPort = 0;
- int randomPort = new Random().nextInt(65536-1023) + 1024;
- Client.clientPort = randomPort;
- sendStream.write(0x0);
- sendStream.write(OPCode);
- sendStream.write(fileName.getBytes("US-ASCII"));
- sendStream.write(0x0);
- sendStream.write(mode.getBytes("US-ASCII"));
- sendStream.write(0x0);
- DatagramSocket client = new DatagramSocket(randomPort);
- client.setSoTimeout(Client.TIMEOUT_INTERVAL);
- DatagramPacket receivedPacket = new DatagramPacket(receiveData, receiveData.length);
- while(true)
- {
- try
- {
- send(sendStream.toByteArray(), client, Client.serverPort);
- client.receive(receivedPacket);
- replyPort = receivedPacket.getPort();
- receiveData = receivedPacket.getData();
- break;
- }
- catch(SocketTimeoutException e)
- {
- Client.timeouts++;
- if(Client.timeouts>Client.TIMEOUTS_MAX)
- {
- System.out.println("Maximum number of attempts reached. No ACK received");
- return;
- }
- System.out.println("\nTimed out, retrying...\nNumber of attemps: " + Client.timeouts);
- send(sendStream.toByteArray(), client, replyPort);
- }
- }
- //debug("'" + new String(receiveData, "US-ASCII") + "'");
- int replyCode = receiveData[1];
- switch(replyCode)
- {
- case(5):
- System.out.println("Error:\n\t" + new String(Arrays.copyOfRange(receiveData, 4, receiveData.length), StandardCharsets.US_ASCII));
- return;
- case(4):
- if(0x2 == OPCode)
- {
- // State information
- debug("Acknowledged write request");
- int blockOne = 1;
- int blockTwo = 0;
- int sentData = 0;
- byte[] lastSentPacket = sendStream.toByteArray();
- byte[] lastReceivedPacket = receiveData;
- //Date date = new Date();
- long start = new Date().getTime();
- int dataInterval = 0;
- double rate = 0;
- while(sentData < fileSize)
- {
- Client.timeouts = 0;
- missedPackets = 0;
- debug("Creating packet");
- sendStream.reset();
- sendStream.write(0x0);
- sendStream.write(0x3);
- sendStream.write((byte) blockTwo);
- sendStream.write((byte) blockOne);
- read(sendStream, mode);
- debug(""+sendStream.size());
- sentData += sendStream.size() - 4; // Don't do buffer size because of last f
- dataInterval += sendStream.size() - 4;
- if(blockOne % 50 == 0)
- {
- start = new Date().getTime();
- dataInterval = 0;
- }
- if(blockOne % 50 == 49)
- rate = (double) dataInterval / (new Date().getTime() - start);
- if(blockOne % 100 == 0)
- {
- String status = String.format("\rStatus:\t%.2f%%", (double) sentData/fileSize*100);
- status += String.format("\t\tRate: \t%.0fkbps", rate);
- status += String.format("\t\tBlock: \t%h", (blockTwo * 128 + blockOne));
- System.out.print(status);
- }
- debug("Sending data now");
- send(sendStream.toByteArray(), client, replyPort);
- lastSentPacket = sendStream.toByteArray();
- while(true)
- {
- try
- {
- client.receive(receivedPacket);
- receiveData = receivedPacket.getData();
- lastReceivedPacket = receiveData;
- // TFTP resets at 128 to block 63 ???
- //if(block==128 && receiveData[3] == 63)
- // block = 62;
- replyPort = receivedPacket.getPort();
- break;
- }
- catch(SocketTimeoutException e)
- {
- Client.timeouts++;
- if(Client.timeouts>Client.TIMEOUTS_MAX)
- {
- System.out.println("Maximum number of attempts reached. Ending program.");
- return;
- }
- System.out.println("\nTimed out, retrying...\nNumber of attemps: " + Client.timeouts);
- send(lastSentPacket, client, replyPort);
- }
- }
- if(receiveData[3] != blockOne || receiveData[2] != blockTwo)
- {
- if(receiveData[1] == 5)
- {
- System.out.println("Error:\n\t" + new String(Arrays.copyOfRange(receiveData, 4, receiveData.length), StandardCharsets.US_ASCII));
- return;
- }
- if(receiveData[3] == blockOne - 1 && receiveData[2] == blockTwo)
- {
- while(true)
- {
- try
- {
- Client.missedPackets++;
- if(Client.missedPackets > Client.MISSED_PACKET_MAX)
- {
- System.out.println("Maximum number of missed packets reached. Ending program.");
- return;
- }
- System.out.println("\nMissed packet...\n"+ Client.missedPackets + " missed packets");
- send(lastSentPacket, client, replyPort);
- client.receive(receivedPacket);
- receiveData = receivedPacket.getData();
- lastReceivedPacket = receiveData;
- /*
- if(block==128 && receiveData[3] == 63)
- block = 62;
- */
- replyPort = receivedPacket.getPort();
- break;
- }
- catch(SocketTimeoutException e)
- {
- Client.timeouts++;
- if(Client.timeouts>Client.TIMEOUTS_MAX)
- {
- System.out.println("Maximum number of attempts reached. Ending program.");
- return;
- }
- System.out.println("Timed out, retrying...\nNumber of attemps: " + Client.timeouts);
- }
- }
- }
- }
- //System.out.println("\nBlock "+block+"\n");
- if(blockOne == Integer.MAX_VALUE)
- {
- blockOne = 0;
- if(blockTwo == Integer.MAX_VALUE)
- {
- blockTwo = 0;
- }
- else
- {
- blockTwo++;
- }
- }
- else
- {
- blockOne++;
- if((byte) blockOne == 0 && (blockOne > 0 || blockTwo>0))
- blockTwo++;
- if(blockTwo + blockOne == 0xffff && fileStream.available() > 0)
- {
- System.out.println("\n\nMaximum transfer size reached. \nConsider packaging file into 32MB archives if errors occur.\n");
- }
- }
- }
- System.out.println("\nFile transfer complete.");
- }
- break;
- case(3):
- if(OPCode == 1)
- {
- debug("Acknowledged write request");
- int blockOne = 1;
- int blockTwo = 0;
- int sentData = 0;
- byte[] lastSentPacket = sendStream.toByteArray();
- byte[] lastReceivedPacket = receiveData;
- //Date date = new Date();
- long start = new Date().getTime();
- int dataInterval = 0;
- double rate = 0;
- Client.timeouts = 0;
- missedPackets = 0;
- Files.deleteIfExists(Paths.get(fileName));
- while(true)
- {
- //Acknowledgment Packet
- sendStream.reset();
- sendStream.write(0x0);
- sendStream.write(0x4);
- sendStream.write((byte) blockTwo);
- sendStream.write((byte) blockOne);
- write(receivedPacket, fileName, mode);
- while(true)
- {
- try
- {
- send(sendStream.toByteArray(), client, replyPort);
- lastSentPacket = sendStream.toByteArray();
- client.receive(receivedPacket);
- receiveData = receivedPacket.getData();
- lastReceivedPacket = receiveData;
- // TFTP resets at 128 to block 63 ???
- //if(block==128 && receiveData[3] == 63)
- // block = 62;
- if(Client.timeouts > 0)
- System.out.println("\nPacket received, continuing normal program execution.\n");
- break;
- }
- catch(SocketTimeoutException e)
- {
- Client.timeouts++;
- if(Client.timeouts>Client.TIMEOUTS_MAX)
- {
- System.out.println("Maximum number of attempts reached. Ending program.");
- return;
- }
- if(receivedPacket.getLength() < Client.BUFFER_SIZE && Client.timeouts == 1)
- System.out.println("\nLikely last data packet was sent. Size: " + (receivedPacket.getLength() - 4) + "\nDallying...");
- if(receivedPacket.getLength() == Client.BUFFER_SIZE)
- System.out.println("\nTimed out, retrying...\nNumber of attemps: " + Client.timeouts);
- }
- catch(Exception e)
- {
- System.out.println("Unhandled exception: " + e.toString());
- }
- }
- replyPort = receivedPacket.getPort();
- debug("\nReply port: "+replyPort);
- if(blockOne == Integer.MAX_VALUE)
- {
- System.out.println("\nMax block value reached.\n");
- blockOne = 0;
- if(blockTwo == Integer.MAX_VALUE)
- {
- blockTwo = 0;
- }
- else
- {
- blockTwo++;
- }
- }
- else
- {
- blockOne++;
- if((byte) blockOne == 0 && (blockOne > 0 || blockTwo>0))
- blockTwo++;
- if(blockTwo + blockOne == 0xffff && fileStream.available() > 0)
- {
- System.out.println("\n\nMaximum transfer size reached. \nConsider packaging file into 32MB archives if errors occur.\n");
- }
- }
- sentData += receivedPacket.getLength() - 4; // Don't do buffer size because of last f
- dataInterval += receivedPacket.getLength();
- if(blockOne % 50 == 0)
- {
- start = new Date().getTime();
- dataInterval = 0;
- }
- if(blockOne % 50 == 49)
- rate = (double) dataInterval / (new Date().getTime() - start);
- if(blockOne % 100 == 0)
- {
- String status = String.format("\rStatus:\t%.2fkb", (double) sentData/1024);
- status += String.format("\t\tRate: \t%.0fkbps", rate);
- status += String.format("\t\tBlock: \t%h", (blockTwo * 128 + blockOne));
- System.out.print(status);
- }
- debug("Sending data now");
- debug("Creating packet");
- if(receiveData.length > Client.BUFFER_SIZE)
- {
- System.out.println("\nData over maximum packet size. Terminating program.");
- //Error Packet
- sendStream.reset();
- sendStream.write(0x0);
- sendStream.write(0x5);
- sendStream.write(0x0);
- sendStream.write(0x4);
- sendStream.write("Data sent over maximum size".getBytes());
- send(sendStream.toByteArray(), client, replyPort);
- return;
- }
- if(receiveData[3] != blockOne || receiveData[2] != blockTwo)
- {
- if(receiveData[1] == 5)
- {
- System.out.println("Error:\n\t" + new String(Arrays.copyOfRange(receiveData, 4, receiveData.length), StandardCharsets.US_ASCII));
- return;
- }
- if(receiveData[3] == blockOne - 1 && receiveData[2] == blockTwo)
- {
- while(true)
- {
- try
- {
- Client.missedPackets++;
- if(Client.missedPackets > Client.MISSED_PACKET_MAX)
- {
- System.out.println("Maximum number of missed packets reached. Ending program.");
- return;
- }
- System.out.println("\nMissed packet...\n"+ Client.missedPackets + " missed packets");
- send(lastSentPacket, client, replyPort);
- client.receive(receivedPacket);
- receiveData = receivedPacket.getData();
- lastReceivedPacket = receiveData;
- /*
- if(block==128 && receiveData[3] == 63)
- block = 62;
- */
- replyPort = receivedPacket.getPort();
- break;
- }
- catch(SocketTimeoutException e)
- {
- Client.timeouts++;
- if(Client.timeouts>Client.TIMEOUTS_MAX)
- {
- System.out.println("Maximum number of attempts reached. Ending program.");
- return;
- }
- System.out.println("Timed out, retrying...\nNumber of attemps: " + Client.timeouts);
- }
- }
- }
- }
- }
- }
- else
- {
- sendStream.reset();
- sendStream.write(0x0);
- sendStream.write(0x3);
- sendStream.write(0x0);
- sendStream.write(0x5);
- sendStream.write(0x0);
- sendStream.write(0x4);
- sendStream.write("Client does not support operation".getBytes("US-ASCII"));
- System.out.print("Data request denied");
- send(sendStream.toByteArray(), client, replyPort);
- }
- break;
- default:
- System.out.println("\nInvalid OPCode.");
- //Error Packet
- sendStream.reset();
- sendStream.write(0x0);
- sendStream.write(0x5);
- sendStream.write(0x0);
- sendStream.write(0x4);
- sendStream.write("Invalid OPCode".getBytes());
- send(sendStream.toByteArray(), client, replyPort);
- return;
- }
- }
- catch(Exception e)
- {
- debug(e.toString());
- }
- return;
- }
- public static void read(ByteArrayOutputStream sendStream, String mode)
- {
- switch(mode)
- {
- case "octet":
- try
- {
- int b = 0;
- while(sendStream.size() < Client.BUFFER_SIZE)
- {
- if((b = fileStream.read()) > -1)
- {
- sendStream.write(b);
- }
- else
- {
- break;
- }
- }
- }
- catch(Exception e)
- {
- debug(e.toString());
- }
- debug("Last bit read");
- break;
- case "netascii":
- try
- {
- int b = 0;
- while(sendStream.size() < Client.BUFFER_SIZE)
- {
- if(fileString.length() < 2)
- break;
- fileString = fileString.substring(1,fileString.length());
- sendStream.write(fileString.substring(0,1).getBytes("US-ASCII"));
- }
- }
- catch(Exception e)
- {
- debug(e.toString());
- }
- break;
- default:
- System.out.println("Invalid mode specified");
- return;
- }
- }
- public static void write(DatagramPacket packet, String fileName, String mode)
- {
- byte[] byteData = packet.getData();
- switch(mode)
- {
- case("octet"):
- try(FileOutputStream fos = new FileOutputStream(fileName, true);)
- {
- fos.write(Arrays.copyOfRange(byteData, 4, packet.getLength()));
- }
- catch(Exception e)
- {
- debug(e.toString());
- }
- break;
- case("netascii"):
- try(OutputStream out = new BufferedOutputStream(Files.newOutputStream(Paths.get(fileName), CREATE, APPEND));)
- {
- String data = new String(Arrays.copyOfRange(byteData, 4, packet.getLength()), "US-ASCII");
- data.replace(""+ (char) 13, ""+(char) 13 + (char) 10);
- debug(data);
- out.write(data.getBytes());
- }
- catch(Exception e)
- {
- debug(e.toString());
- }
- break;
- // Should never be reached, mode is handled by client
- default:
- System.out.println("\nUnspecified mode. Terminating Program.");
- /*
- sendStream.reset();
- sendStream.write(0x0);
- sendStream.write(0x5);
- sendStream.write(0x0);
- sendStream.write(0x4);
- sendStream.write("Unhandled transfer mode".getBytes());
- send(sendStream.toByteArray(), client, replyPort);
- */
- return;
- }
- }
- public static void send(byte[] response, DatagramSocket client, int port)
- {
- try
- {
- InetAddress IP = InetAddress.getByName(Client.serverAddress);
- DatagramPacket packetToSend = new DatagramPacket(
- response,
- response.length,
- IP,
- port
- );
- client.send(packetToSend);
- }
- catch(Exception e)
- {
- System.out.println(e.toString());
- }
- }
- public static void debug(String output)
- {
- if(Client.DEBUG)
- System.out.println(output);
- }
- public static void debug(byte[] array)
- {
- if(Client.DEBUG)
- {
- String debug = "";
- for(int x = 0; x < array.length; x++)
- {
- debug += " " + array[x];
- }
- System.out.println(debug);
- }
- }
- }
Add Comment
Please, Sign In to add comment