diff --git a/FTPClient/.vs/FTPClient/v16/.suo b/FTPClient/.vs/FTPClient/v16/.suo index 333043fc55c3c93d0306c8bb762461de8e1df6ec..3e81d42b12a0398435db4ee212d2f06efdce020e 100644 Binary files a/FTPClient/.vs/FTPClient/v16/.suo and b/FTPClient/.vs/FTPClient/v16/.suo differ diff --git a/FTPClient/FTPClient/Client.cs b/FTPClient/FTPClient/Client.cs index 9fbf69059cc94f2ced57c1d49db9f32389886e5c..27d6c83a737ea7fcf472132f7820d8fa2d0b4dae 100644 --- a/FTPClient/FTPClient/Client.cs +++ b/FTPClient/FTPClient/Client.cs @@ -23,6 +23,7 @@ namespace FTPClient TftpClient client = new TftpClient("test", 69); client.InitializeAndRead("README"); client.SendWRQ("wrqFile"); + client.SendRRQ("SmallText"); } private static void FtpConversation() diff --git a/FTPClient/FTPClient/TftpClient.cs b/FTPClient/FTPClient/TftpClient.cs index 3586ff1df4a3846e9335922270b128b0e8b8ba86..09ebeec705ce9d450a610c5e4e6279efd2e48971 100644 --- a/FTPClient/FTPClient/TftpClient.cs +++ b/FTPClient/FTPClient/TftpClient.cs @@ -81,7 +81,8 @@ namespace FTPClient socket.SendTo(packet, endpoint); Console.WriteLine($"Sent Write Request for file: {writeFile}"); - HandleWriteRequest(); + if (!WaitAck()) return; + HandleWriteRequest(writeFile); } /// <summary> @@ -97,6 +98,16 @@ namespace FTPClient HandleReadRequest(); } + private bool WaitAck() + { + byte[] buffer = new byte[512]; + socket.ReceiveFrom(buffer, ref endpoint); + int opcode = buffer[0] | buffer[1] << 8; + if (opcode == (int)PACKET_TYPE.ACK) return true; + if (opcode == (int)PACKET_TYPE.ERROR) ReportError(buffer); + return false; + } + private byte[] MakeRequestPacket(PACKET_TYPE type) { byte[] packet = new byte[4 + filename.Length + MODE.Length]; @@ -131,9 +142,47 @@ namespace FTPClient endpoint = (EndPoint)ipEndp; } - private void HandleWriteRequest() + private void HandleWriteRequest(string filename) + { + string path = Path.Combine(FILE_PATH, filename + ".txt"); + using (FileStream fsSource = new FileStream(path, + FileMode.Open, FileAccess.Read)) + { + // Read the source file into a byte array. + int numBytesToRead = (int)fsSource.Length; + int numBytesRead = 0; + int packetNumber = 1; + + while (numBytesToRead > 0) + { + byte[] buffer = Create512Buffer((int)PACKET_TYPE.DATA); + buffer[2] = (byte)packetNumber; + buffer[3] = (byte)(packetNumber >> 8); + + // Read may return anything from 0 to numBytesToRead. + int n = fsSource.Read(buffer, 4, 508); + socket.SendTo(buffer, endpoint); + // Break when the end of the file is reached. + if (n == 0) + break; + + numBytesRead += n; + numBytesToRead -= n; + packetNumber += 1; + } + Console.WriteLine($"Sent {numBytesRead} bytes"); + } + } + + /// <summary> + /// Creates a data packet 512 bytes + /// </summary> + private static byte[] Create512Buffer(int opcode) { - // TODO: Create handler + byte[] buffer = new byte[512]; + buffer[0] = (byte)PACKET_TYPE.DATA; + buffer[1] = (byte)((int)PACKET_TYPE.DATA >> 8); + return buffer; } private void HandleReadRequest() @@ -167,29 +216,24 @@ namespace FTPClient // CheckPacketNumber(); string path = Path.Combine(FILE_PATH, filename + ".txt"); - if (!File.Exists(path)) + + // Create a file to write to. + using (StreamWriter sw = File.CreateText(path)) { - // Create a file to write to. - using (StreamWriter sw = File.CreateText(path)) + bool conversation = ReadData(packet, sw); + while (conversation) { - bool conversation = ReadData(packet, sw); - while (conversation) - { - byte[] buffer = new byte[512]; - socket.ReceiveFrom(buffer, ref endpoint); - conversation = ReadData(buffer, sw); - } - Console.WriteLine("File received"); + byte[] buffer = new byte[512]; + socket.ReceiveFrom(buffer, ref endpoint); + conversation = ReadData(buffer, sw); } + Console.WriteLine("File received"); } - else Console.WriteLine($"File: \"{path}\" already exists."); } /// <summary> /// Read data from packet and write it to file /// </summary> - /// <param name="packet">packet to read from</param> - /// <param name="sw">streamwriter to write with</param> /// <returns>true if wasn't last packet (not below 508 bytes)</returns> private bool ReadData(byte[] packet, StreamWriter sw) { diff --git a/FTPClient/FTPClient/bin/Debug/netcoreapp3.1/FTPClient.dll b/FTPClient/FTPClient/bin/Debug/netcoreapp3.1/FTPClient.dll index 5d45d24e1d1ba45efc207a2bc0abacb692db7b99..0ba8900f321ecc0a1921acf83544b67cb938c4f5 100644 Binary files a/FTPClient/FTPClient/bin/Debug/netcoreapp3.1/FTPClient.dll and b/FTPClient/FTPClient/bin/Debug/netcoreapp3.1/FTPClient.dll differ diff --git a/FTPClient/FTPClient/bin/Debug/netcoreapp3.1/FTPClient.pdb b/FTPClient/FTPClient/bin/Debug/netcoreapp3.1/FTPClient.pdb index 814b168d23af78a6b087a54e6ebe09c8e960ff13..77ac1f7cc1e40ef7b8452628ac939c8dd1f63012 100644 Binary files a/FTPClient/FTPClient/bin/Debug/netcoreapp3.1/FTPClient.pdb and b/FTPClient/FTPClient/bin/Debug/netcoreapp3.1/FTPClient.pdb differ diff --git a/FTPClient/FTPClient/obj/Debug/netcoreapp3.1/FTPClient.dll b/FTPClient/FTPClient/obj/Debug/netcoreapp3.1/FTPClient.dll index 5d45d24e1d1ba45efc207a2bc0abacb692db7b99..0ba8900f321ecc0a1921acf83544b67cb938c4f5 100644 Binary files a/FTPClient/FTPClient/obj/Debug/netcoreapp3.1/FTPClient.dll and b/FTPClient/FTPClient/obj/Debug/netcoreapp3.1/FTPClient.dll differ diff --git a/FTPClient/FTPClient/obj/Debug/netcoreapp3.1/FTPClient.pdb b/FTPClient/FTPClient/obj/Debug/netcoreapp3.1/FTPClient.pdb index 814b168d23af78a6b087a54e6ebe09c8e960ff13..77ac1f7cc1e40ef7b8452628ac939c8dd1f63012 100644 Binary files a/FTPClient/FTPClient/obj/Debug/netcoreapp3.1/FTPClient.pdb and b/FTPClient/FTPClient/obj/Debug/netcoreapp3.1/FTPClient.pdb differ diff --git a/TFTPServer/.vs/TFTPServer/v16/.suo b/TFTPServer/.vs/TFTPServer/v16/.suo index e7b4799492c9fbd4e348ff82277548131e12a6fe..4eb4a6a282f1ecc8bb0bc7eb1a347b0bfb12c260 100644 Binary files a/TFTPServer/.vs/TFTPServer/v16/.suo and b/TFTPServer/.vs/TFTPServer/v16/.suo differ diff --git a/TFTPServer/TFTPServer/Server.cs b/TFTPServer/TFTPServer/Server.cs index 05a8896ca657cf680298be22e5598354c8da51dc..9f5bda5c175704baec8fa5a30fc98c0f31d83237 100644 --- a/TFTPServer/TFTPServer/Server.cs +++ b/TFTPServer/TFTPServer/Server.cs @@ -40,27 +40,23 @@ namespace TFTPServer No_such_user } - private static void ReadRequest(byte[] buffer, EndPoint remote) + /// <summary> + /// Sends a acknowledgement packet + /// </summary> + private static void SendAck(EndPoint remote) { - string filename = string.Empty; - int index = 2; - do - { - filename += Convert.ToChar(buffer[index]); - index += 1; - } while (buffer[index] != 0); - Console.WriteLine($"Read request for file : {filename}"); + byte[] packet = new byte[4]; + packet[0] = (byte)PACKET_TYPE.ACK; + packet[1] = (byte)((int)PACKET_TYPE.ACK >> 8); + packet[2] = 0; + packet[3] = 0; - string file_path = Path.Combine(FILE_DIR, filename+".txt"); - if (!String.IsNullOrEmpty(filename) && File.Exists(file_path)) { - SendData(file_path, remote); - } else - { - string message = "File not found."; - SendError(remote, (int)ERROR_CODE.File_not_found, message); - } + socket.SendTo(packet, remote); } + /// <summary> + /// Sends the file data from path to client + /// </summary> private static void SendData(string path, EndPoint remote) { using (FileStream fsSource = new FileStream(path, @@ -69,11 +65,13 @@ namespace TFTPServer // Read the source file into a byte array. int numBytesToRead = (int)fsSource.Length; int numBytesRead = 0; + int packetNumber = 1; + while (numBytesToRead > 0) { byte[] buffer = Create512Buffer((int)PACKET_TYPE.DATA); - buffer[2] = (byte)blockNumber; - buffer[3] = (byte)(blockNumber >> 8); + buffer[2] = (byte)packetNumber; + buffer[3] = (byte)(packetNumber >> 8); // Read may return anything from 0 to numBytesToRead. int n = fsSource.Read(buffer, 4, 508); @@ -84,12 +82,15 @@ namespace TFTPServer numBytesRead += n; numBytesToRead -= n; - blockNumber += 1; + packetNumber += 1; } Console.WriteLine($"Sent {numBytesRead} bytes"); } } + /// <summary> + /// Creates a data packet 512 bytes + /// </summary> private static byte[] Create512Buffer(int opcode) { byte[] buffer = new byte[512]; @@ -98,14 +99,17 @@ namespace TFTPServer return buffer; } - private static void SendError(EndPoint remote, int error_code, string message) + /// <summary> + /// Sends a error with given error code and message + /// </summary> + private static void SendError(EndPoint remote, ERROR_CODE error_code, string message) { byte[] messageBytes = Encoding.ASCII.GetBytes(message); byte[] packet = new byte[4 + messageBytes.Length + 1]; packet[0] = (byte)PACKET_TYPE.ERROR; packet[1] = (byte)((int)PACKET_TYPE.ERROR >> 8); packet[2] = (byte)error_code; - packet[3] = (byte)(error_code >> 8); + packet[3] = (byte)((int)error_code >> 8); int index = 4; for(int i = 0; i < messageBytes.Length; i++) @@ -115,9 +119,103 @@ namespace TFTPServer socket.SendTo(packet, remote); } - private static void WriteRequest(byte[] buffer) + /// <summary> + /// Get filename from packet + /// </summary> + private static string FilenameFromPacket(byte[] packet) { - throw new NotImplementedException(); + string filename = String.Empty; + int index = 2; + do + { + filename += Convert.ToChar(packet[index]); + index += 1; + } while (packet[index] != 0); + return filename; + } + + /// <summary> + /// Handles a read request from client + /// </summary> + private static void ReadRequest(byte[] buffer, EndPoint remote) + { + string filename = FilenameFromPacket(buffer); + + Console.WriteLine($"Read request for file : {filename}"); + + string file_path = Path.Combine(FILE_DIR, filename + ".txt"); + if (!String.IsNullOrEmpty(filename) && File.Exists(file_path)) + { + SendData(file_path, remote); + } + else + { + string message = "File not found."; + SendError(remote, ERROR_CODE.File_not_found, message); + } + } + + /// <summary> + /// Handles a write request from client + /// </summary> + private static void WriteRequest(byte[] buffer, EndPoint remote) + { + string filename = FilenameFromPacket(buffer); + string path = Path.Combine(FILE_DIR, filename + ".txt"); + + if(File.Exists(path)) { + string message = "File already exists"; + SendError(remote, ERROR_CODE.File_already_exists, message); + return; + } + + SendAck(remote); + HandleWRQ(remote, filename); + } + + /// <summary> + /// Listens clients data packets + /// </summary> + private static void HandleWRQ(EndPoint remote, string filename) + { + string path = Path.Combine(FILE_DIR, filename + ".txt"); + byte[] packet = new byte[512]; + socket.ReceiveFrom(packet, ref remote); + int opcode = packet[0] | packet[1] << 8; + + if (opcode == (int)PACKET_TYPE.DATA) + { + // Create a file to write to. + using (StreamWriter sw = File.CreateText(path)) + { + bool conversation = ReadData(packet, sw); + while (conversation) + { + byte[] buffer = new byte[512]; + socket.ReceiveFrom(buffer, ref remote); + conversation = ReadData(buffer, sw); + } + Console.WriteLine("File received"); + } + } + } + + /// <summary> + /// Read data from packet and write it to file + /// </summary> + /// <returns>true if wasn't last packet (not below 508 bytes)</returns> + private static bool ReadData(byte[] packet, StreamWriter sw) + { + string data = String.Empty; + + for (int i = 4; i < packet.Length; i++) + { + if (packet[i] == 0) break; + data += Convert.ToChar(packet[i]); + } + sw.Write(data); + if (data.Length == 508) return true; + return false; } private static void ErrorResponse(byte[] buffer) @@ -146,12 +244,12 @@ namespace TFTPServer } catch (Exception ex) { - Console.WriteLine("Virhe... " + ex.Message); + Console.WriteLine("Error... " + ex.Message); Console.ReadKey(); return; } - Console.WriteLine("Odotetaan asiakasta..."); + Console.WriteLine("TFTP server up, listening for clients..."); while (!Console.KeyAvailable) { @@ -166,7 +264,7 @@ namespace TFTPServer ReadRequest(buffer, remote); break; case (int)PACKET_TYPE.WRQ: - WriteRequest(buffer); + WriteRequest(buffer, remote); break; case (int)PACKET_TYPE.DATA: DataRequest(buffer); diff --git a/TFTPServer/TFTPServer/bin/Debug/netcoreapp3.1/TFTPServer.dll b/TFTPServer/TFTPServer/bin/Debug/netcoreapp3.1/TFTPServer.dll index b058fc3c300dd99d861d7bbf67d5f824814836ff..084a1b12e9795a2b92ae5eee9d121406d90978ad 100644 Binary files a/TFTPServer/TFTPServer/bin/Debug/netcoreapp3.1/TFTPServer.dll and b/TFTPServer/TFTPServer/bin/Debug/netcoreapp3.1/TFTPServer.dll differ diff --git a/TFTPServer/TFTPServer/bin/Debug/netcoreapp3.1/TFTPServer.pdb b/TFTPServer/TFTPServer/bin/Debug/netcoreapp3.1/TFTPServer.pdb index 72cbb1aa296d1dfa3b542efeeaf3f917ecc8b666..cfe8abc3c584a0d3069531d2dab1bef3c8c25d3d 100644 Binary files a/TFTPServer/TFTPServer/bin/Debug/netcoreapp3.1/TFTPServer.pdb and b/TFTPServer/TFTPServer/bin/Debug/netcoreapp3.1/TFTPServer.pdb differ diff --git a/TFTPServer/TFTPServer/obj/Debug/netcoreapp3.1/TFTPServer.dll b/TFTPServer/TFTPServer/obj/Debug/netcoreapp3.1/TFTPServer.dll index b058fc3c300dd99d861d7bbf67d5f824814836ff..084a1b12e9795a2b92ae5eee9d121406d90978ad 100644 Binary files a/TFTPServer/TFTPServer/obj/Debug/netcoreapp3.1/TFTPServer.dll and b/TFTPServer/TFTPServer/obj/Debug/netcoreapp3.1/TFTPServer.dll differ diff --git a/TFTPServer/TFTPServer/obj/Debug/netcoreapp3.1/TFTPServer.pdb b/TFTPServer/TFTPServer/obj/Debug/netcoreapp3.1/TFTPServer.pdb index 72cbb1aa296d1dfa3b542efeeaf3f917ecc8b666..cfe8abc3c584a0d3069531d2dab1bef3c8c25d3d 100644 Binary files a/TFTPServer/TFTPServer/obj/Debug/netcoreapp3.1/TFTPServer.pdb and b/TFTPServer/TFTPServer/obj/Debug/netcoreapp3.1/TFTPServer.pdb differ