Beispiel #1
0
        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());
        }
Beispiel #2
0
        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);
        }
Beispiel #3
0
        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);
            }
        }
Beispiel #4
0
        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();
                        }
                    }
                }
        }
Beispiel #5
0
 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();
                 }
             }
         }
 }
Beispiel #6
0
        // 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;
                    }
                }
        }
Beispiel #7
0
        // 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;
                        }
                    }
        }