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()); }
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(); } } } }