public static byte[] Serialize(this ITftpPacket packet) { MemoryStream bytes = new MemoryStream(); bytes.Write(EndianBitConverter.Big.GetBytes((ushort)packet.Op), 0, sizeof(ushort)); switch (packet.Op) { case TftpOperation.ReadRequest: RrqPacket rrq = (RrqPacket)packet; StringToNetascii(rrq.FileName, bytes); StringToNetascii(rrq.Mode.ToString(), bytes); break; case TftpOperation.WriteRequest: WrqPacket wrq = (WrqPacket)packet; StringToNetascii(wrq.FileName, bytes); StringToNetascii(wrq.Mode.ToString(), bytes); break; case TftpOperation.Data: DataPacket data = (DataPacket)packet; bytes.Write(EndianBitConverter.Big.GetBytes((ushort)data.BlockNumber), 0, sizeof(ushort)); bytes.Write(data.Data, 0, data.Data.Length); break; case TftpOperation.Ack: AckPacket ack = (AckPacket)packet; bytes.Write(EndianBitConverter.Big.GetBytes((ushort)ack.BlockNumber), 0, sizeof(ushort)); break; case TftpOperation.Error: ErrorPacket error = (ErrorPacket)packet; bytes.Write(EndianBitConverter.Big.GetBytes((ushort)error.Error), 0, sizeof(ushort)); StringToNetascii(error.Message, bytes); break; default: throw new Exception("Operation not recognized."); } return(bytes.ToArray()); }
private void BeginWrite(byte[] byteRes, EndPoint ep) { DataPacket data = new DataPacket(byteRes); if (data.data.Length > 512) { Init(); Console.WriteLine("Receive Error.Data length beyond 512 bytes."); ErrorPacket error = new ErrorPacket(ErrorCode.IllegalOperation, "Data length beyond 512 bytes"); tftpSocket.SendTo(error.packet, SocketFlags.None, ep); return; } if (data.data.Length == 512) { Console.WriteLine("From: {3} --OpCode={0}, BlockNumber={1}\nData={2}", data.opCode, data.iblock, Encoding.Default.GetString(data.data), ((IPEndPoint)ep).Address.ToString()); foreach (byte x in data.data) { dataStream.WriteByte(x); } currentStatus = Status.WRITE; } else { Console.WriteLine("OpCode={0}, BlockNumber={1}\nData={2}", data.opCode, data.iblock, Encoding.Default.GetString(data.data)); Console.WriteLine("Receive Done."); foreach (byte x in data.data) { dataStream.WriteByte(x); } dataStream.Close(); currentStatus = Status.IDLE; } AckPacket ack = new AckPacket(data.iblock); tftpSocket.SendTo(ack.packet, SocketFlags.None, ep); Console.WriteLine("Send: ACK, BlockNumber={0}", data.iblock); }
private void OnWrite(byte[] byteRes, EndPoint ep) { ReqPacket wrq = new ReqPacket(byteRes); Console.WriteLine("From: {3} --OpCode={0}, FileName={1}, Mode={2}", wrq.opCode, wrq.fileName, wrq.mode, ((IPEndPoint)ep).Address.ToString()); currentStatus = Status.WRITE; string localPath = Path.Combine(Root, wrq.fileName); try { dataStream = new FileStream(localPath, FileMode.Create, FileAccess.Write); AckPacket ack = new AckPacket(0); tftpSocket.SendTo(ack.packet, 4, SocketFlags.None, ep); Console.WriteLine("Send: WRQ ACK"); } catch (Exception ex) { ErrorPacket error = new ErrorPacket(ErrorCode.AccessViolation, ex.ToString()); tftpSocket.SendTo(error.packet, 4, SocketFlags.None, ep); } }
public void Write(IPEndPoint server, string fileName, string inputPath, CancellationToken cancellationToken) { Console.WriteLine("Writing local file '{0}' to file '{1}' on server {2}", inputPath, fileName, server); // Read the file from the local file system. byte[] file = File.ReadAllBytes(inputPath); // Create a connection with the server. IPEndPoint receivedFromEP = new IPEndPoint(IPAddress.Any, 0); using (RemoteEndPointReservation clientReservation = new RemoteEndPointReservation(server)) using (TftpConnection connection = new TftpConnection()) { RemoteEndPointReservation remoteEPReservation = null; try { // Read the file contents to the remote endpoint in chunks. ushort currentBlockNumber = 0; int currentFileIndex = 0; bool done = false; while (!done) { Func <ITftpPacket, bool> receiveFilter = (ITftpPacket packet) => { if (packet.Op == TftpOperation.Ack) { AckPacket ack = (AckPacket)packet; if (ack.BlockNumber == currentBlockNumber) { Console.WriteLine("ACK received for block {0}", ack.BlockNumber); return(true); } else { Console.WriteLine("Incorrect ACK block number {0}", ack.BlockNumber); } } else { Console.WriteLine("Incorrect operation. Expected ACK."); } return(false); }; ITftpPacket sendPacket; // To initialize the transfer, send WRQ and wait for an ACK of block 0. if (currentBlockNumber == 0) { Console.WriteLine("Sending WRQ"); // NOTE: the server only supports octet mode by design. sendPacket = new WrqPacket(fileName, TftpMode.octet); IPEndPoint remoteEP; connection.SendAndWaitForResponse(sendPacket, server, receiveFilter, out remoteEP, cancellationToken); remoteEPReservation = new RemoteEndPointReservation(remoteEP); connection.Connect(remoteEP); } else { // Extract the current block from the file contents and put it in a DATA packet. Console.WriteLine("Sending block {0}", currentBlockNumber); int remainingBytes = file.Length - currentFileIndex; int blockSize; if (remainingBytes < DataPacket.MaxBlockSize) { blockSize = remainingBytes; done = true; } else { blockSize = DataPacket.MaxBlockSize; } byte[] block = new byte[blockSize]; Buffer.BlockCopy(file, currentFileIndex, block, 0, blockSize); currentFileIndex += block.Length; sendPacket = new DataPacket(blockNumber: currentBlockNumber, data: block); // Send the DATA packet and wait for the corresponding ACK. connection.SendAndWaitForResponse(sendPacket, receiveFilter, cancellationToken); } // Move to the next block. currentBlockNumber++; } } finally { if (remoteEPReservation != null) { remoteEPReservation.Dispose(); } } } }
public void Read(IPEndPoint server, string fileName, string outputPath, CancellationToken cancellationToken) { Console.WriteLine("Reading to local file '{0}' from file '{1}' on server {2}", outputPath, fileName, server); using (FileStream outputFileStream = new FileStream(outputPath, FileMode.CreateNew, FileAccess.Write, FileShare.Read)) using (TftpConnection connection = new TftpConnection()) { RemoteEndPointReservation remoteEPReservation = null; try { bool initialized = false; ushort currentBlockNumber = 1; DataPacket currentDataPacket; AckPacket ackPacket = null; while (true) { Func <ITftpPacket, bool> receiveFilter = (ITftpPacket packet) => { if (packet.Op == TftpOperation.Data) { DataPacket d = (DataPacket)packet; if (d.BlockNumber == currentBlockNumber) { return(true); } else { Console.WriteLine("Incorrect DATA block number."); } } else { Console.WriteLine("Incorrect operation. Expected DATA."); } return(false); }; // To initialize the transfer, send RRQ and wait for the first data block. if (!initialized) { Console.WriteLine("Sending RRQ"); // NOTE: the server only supports octet mode by design. RrqPacket requestPacket = new RrqPacket(fileName, TftpMode.octet); IPEndPoint remoteEP; currentDataPacket = (DataPacket)connection.SendAndWaitForResponse(requestPacket, server, receiveFilter, out remoteEP, cancellationToken); remoteEPReservation = new RemoteEndPointReservation(remoteEP); connection.Connect(remoteEP); initialized = true; } else { Console.WriteLine("Sending ack for block number {0}", ackPacket.BlockNumber); currentDataPacket = (DataPacket)connection.SendAndWaitForResponse(ackPacket, receiveFilter, cancellationToken); } Console.WriteLine("DATA packet containing block {0} received", currentDataPacket.BlockNumber); outputFileStream.Write(currentDataPacket.Data, 0, currentDataPacket.Data.Length); ackPacket = new AckPacket(currentBlockNumber); // When the received DATA packet is less than the maximum length, send a final ack and terminate. if (currentDataPacket.Data.Length < DataPacket.MaxBlockSize) { connection.Send(ackPacket); break; } ++currentBlockNumber; } } finally { if (remoteEPReservation != null) { remoteEPReservation.Dispose(); } } } }
// Send the file named fileName to remoteEP. private void ExecuteRead(string fileName, IPEndPoint clientEP, CancellationToken cancellationToken) { Console.WriteLine("RRQ for file '{0}' received from client '{1}'", fileName, clientEP); // Reserve a local port and create a connection with the client. IPEndPoint receivedFromEP = new IPEndPoint(IPAddress.Any, 0); using (RemoteEndPointReservation clientReservation = new RemoteEndPointReservation(clientEP)) using (TftpConnection connection = new TftpConnection()) { connection.Connect(clientEP); // Check if the file exists. If so, get the file contents. bool fileFound; byte[] file = null; lock (_files) { fileFound = _files.ContainsKey(fileName); if (fileFound) { // WARNING: files are read-only and do not support deletion in the protocol spec as of 6/9/14, so we do not need to make a copy of the file data. file = _files[fileName]; } } // If the file was not found, send an error to the client and terminate the connection. if (!fileFound) { string message = string.Format("Could not find file '{0}'", fileName); Console.WriteLine(message); connection.Send(new ErrorPacket( error: TftpError.FileNotFound, message: message)); return; } // Read the file contents to the remote endpoint in chunks. ushort currentBlockNumber = 1; int currentFileIndex = 0; bool done = false; while (!done) { // Extract the current block from the file contents and put it in a DATA packet. int remainingBytes = file.Length - currentFileIndex; int blockSize; if (remainingBytes < DataPacket.MaxBlockSize) { blockSize = remainingBytes; done = true; } else { blockSize = DataPacket.MaxBlockSize; } byte[] block = new byte[blockSize]; Buffer.BlockCopy(file, currentFileIndex, block, 0, blockSize); ITftpPacket sendPacket = new DataPacket(blockNumber: currentBlockNumber, data: block); // Send the DATA packet and wait for the corresponding ACK. Func <ITftpPacket, bool> receiveFilter = (ITftpPacket packet) => { if (packet.Op == TftpOperation.Ack) { AckPacket ack = (AckPacket)packet; if (ack.BlockNumber == currentBlockNumber) { Console.WriteLine("ACK received for block {0}", ack.BlockNumber); return(true); } else { Console.WriteLine("Incorrect ACK block number {0}", ack.BlockNumber); } } else { Console.WriteLine("Incorrect operation. Expected ACK."); } return(false); }; Console.WriteLine("Sending block {0}", currentBlockNumber); connection.SendAndWaitForResponse( sendPacket, receiveFilter, cancellationToken); // Move to the next block. currentBlockNumber++; currentFileIndex += block.Length; } } }
// Write the file named fileName using data from remoteEP. private void ExecuteWrite(string fileName, IPEndPoint clientEP, CancellationToken cancellationToken) { Console.WriteLine("WRQ for file '{0}' received from client {1}", fileName, clientEP); // Reserve a local port and create a connection with the client. using (MemoryStream fileInMemory = new MemoryStream()) using (RemoteEndPointReservation clientReservation = new RemoteEndPointReservation(clientEP)) using (TftpConnection connection = new TftpConnection()) { connection.Connect(clientEP); ushort currentBlockNumber = 1; DataPacket currentDataPacket; AckPacket ackPacket = new AckPacket(0); while (true) { Func <ITftpPacket, bool> receiveFilter = (ITftpPacket packet) => { if (packet.Op == TftpOperation.Data) { DataPacket d = (DataPacket)packet; if (d.BlockNumber == currentBlockNumber) { return(true); } else { Console.WriteLine("Incorrect DATA block number."); } } else { Console.WriteLine("Incorrect operation. Expected DATA."); } return(false); }; Console.WriteLine("Sending ack for block number {0}", ackPacket.BlockNumber); currentDataPacket = (DataPacket)connection.SendAndWaitForResponse(ackPacket, receiveFilter, cancellationToken); Console.WriteLine("DATA packet containing block {0} received", currentDataPacket.BlockNumber); fileInMemory.Write(currentDataPacket.Data, 0, currentDataPacket.Data.Length); ackPacket = new AckPacket(currentBlockNumber); // When the received DATA packet is less than the maximum length, that is the final DATA packet. if (currentDataPacket.Data.Length < DataPacket.MaxBlockSize) { lock (_files) { // If the file already exists, send an error. if (_files.ContainsKey(fileName)) { string message = string.Format("File {0} already exists.", fileName); Console.WriteLine(message); connection.Send(new ErrorPacket( error: TftpError.FileAlreadyExists, message: message)); } // Otherwise, commit the received bytes to the file dictionary and send the final ACK. else { _files[fileName] = fileInMemory.ToArray(); connection.Send(ackPacket); } } break; } ++currentBlockNumber; } } }