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