Exemplo n.º 1
0
 public static bool TryParse(byte[] bytes, out ITftpPacket packet)
 {
     try
     {
         packet = Parse(bytes);
         return(true);
     }
     catch
     {
         packet = null;
         return(false);
     }
 }
Exemplo n.º 2
0
 public ITftpPacket SendAndWaitForResponse(
     ITftpPacket sendPacket,
     IPEndPoint destinationEP,
     Func <ITftpPacket, bool> receiveFilter,
     out IPEndPoint receivedFromEP,
     CancellationToken cancellationToken)
 {
     return(SendAndWaitForResponse(
                sendPacket,
                destinationEP,
                DefaultResponseTimeout,
                DefaultRetryPeriod,
                receiveFilter,
                out receivedFromEP,
                cancellationToken));
 }
Exemplo n.º 3
0
        // Send to the default remote host
        public ITftpPacket SendAndWaitForResponse(
            ITftpPacket sendPacket,
            Func <ITftpPacket, bool> receiveFilter,
            CancellationToken cancellationToken)
        {
            if (_defaultRemoteEP == null)
            {
                throw new SocketException((int)SocketError.DestinationAddressRequired);
            }
            IPEndPoint receivedFromEP = new IPEndPoint(IPAddress.Any, 0);

            return(SendAndWaitForResponse(
                       sendPacket,
                       _defaultRemoteEP,
                       DefaultResponseTimeout,
                       DefaultRetryPeriod,
                       receiveFilter,
                       out receivedFromEP,
                       cancellationToken));
        }
Exemplo n.º 4
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());
        }
Exemplo n.º 5
0
        /*
         * This callback implements the main receive loop for UDP packets on this TftpConnection.
         * It is effectively a filtered producer thread of ITftpPackets.
         * All undesired datagrams are filtered out. Undesired means:
         * - non-TFTP datagrams
         * - datagrams from an incorrect source (ones that are not sent from the default remote endpoint if it is set)
         * - TFTP packets for which receiveFilter returns false
         * If a datagram is not filtered out, the resulting ITftpPacket is stored in _receivedPackets.
         * This callback is only to be passed to _udp.BeginReceive. It 'recurses' by calling BeginReceive again.
         */
        private void ReceiveCallback(IAsyncResult ar)
        {
            IPEndPoint receivedFromEP = new IPEndPoint(IPAddress.Any, 0);

            byte[] receivedBytes = null;
            try
            {
                receivedBytes = _udp.EndReceive(ar, ref receivedFromEP);
            }
            // TODO: _udp has been closed.
            catch (ObjectDisposedException)
            {
                return;
            }
            catch (SocketException e)
            {
                Console.WriteLine("Caught SocketException from EndReceive: {0}", e);
            }

            if (receivedBytes != null)
            {
                // Try to parse the received datagram as a TFTP packet.
                ITftpPacket receivedPacket = null;
                if (TftpPacketUtils.TryParse(receivedBytes, out receivedPacket))
                {
                    // Check whether the packet is the one we are looking for.
                    bool isResponseValid = false;
                    lock (_receiveFilterLock)
                    {
                        if (_receiveFilter != null)
                        {
                            isResponseValid = _receiveFilter(receivedPacket);
                        }
                    }
                    if (isResponseValid)
                    {
                        // If the default remote host is set, and the packet is not from that host, then ignore it and send an error back.
                        bool isRemoteEPCorrect = true;
                        lock (_defaultRemoteEPLock)
                        {
                            if (_defaultRemoteEP != null)
                            {
                                isRemoteEPCorrect = receivedFromEP.Equals(_defaultRemoteEP);
                            }
                        }
                        if (isRemoteEPCorrect)
                        {
                            if (!_receivedPackets.TryAdd(new ReceiveResult(receivedPacket, receivedFromEP)))
                            {
                                Console.WriteLine("Dropping valid packet since one has already been received.");
                            }
                        }
                        else
                        {
                            Console.WriteLine("Message received from incorrect endpoint.");
                            Send(new ErrorPacket(
                                     error: TftpError.UnknownTransferId, // TODO: is this the correct error to send?
                                     message: "Incorrect endpoint"));
                        }
                    }
                    else
                    {
                        Console.WriteLine("TFTP packet not valid.");
                    }
                }
                else
                {
                    Console.WriteLine("Failed to parse packet.");
                }
            }
            else
            {
                Console.WriteLine("EndReceive failed.");
            }

            // This method chains into itself until _udp is closed.
            try
            {
                _udp.BeginReceive(ReceiveCallback, null);
            }
            // TODO: _udp has been closed.
            catch (ObjectDisposedException)
            {
                return;
            }
        }
Exemplo n.º 6
0
 public ReceiveResult(ITftpPacket packet, IPEndPoint remoteEP)
 {
     _packet   = packet;
     _remoteEP = remoteEP;
 }
Exemplo n.º 7
0
 public int Send(ITftpPacket packet)
 {
     return(Send(packet.Serialize()));
 }
Exemplo n.º 8
0
        /*
         * This method performs the following steps:
         *   1) send sendPacket to destinationEP every retryPeriod
         *   2) All packets for which receiveFilter returns false are discarded
         * This will continue until:
         *   a) receiveFilter returns true for a received packet - receivedFromEP is set to the
         *      endpoint from which the packet was received and the packet is returned.
         *   b) timeout has elapsed - TimeoutException is thrown
         *   c) cancellationToken has been signalled - OperationCanceledException is thrown
         */
        public ITftpPacket SendAndWaitForResponse(
            ITftpPacket sendPacket,
            IPEndPoint destinationEP,
            TimeSpan timeout,
            TimeSpan retryPeriod,
            Func <ITftpPacket, bool> receiveFilter,
            out IPEndPoint receivedFromEP,
            CancellationToken cancellationToken)
        {
            ITftpPacket receivePacket = null;

            byte[] sendPacketBytes = sendPacket.Serialize();

            // Set up timeout cancellation token and link it with the cancellation token parameter.
            var timeoutCts = new CancellationTokenSource(timeout);
            var linkedCts  = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, timeoutCts.Token);

            // Spin up a task thread to re-send sendPacket every retryPeriod.
            Action sendAction = () =>
            {
                while (true)
                {
                    _udp.Send(sendPacketBytes, destinationEP);
                    linkedCts.Token.WaitHandle.WaitOne(retryPeriod);
                    linkedCts.Token.ThrowIfCancellationRequested();
                    Console.WriteLine("Re-sending packet");
                }
            };
            var sendTask = Task.Factory.StartNew(sendAction, linkedCts.Token);

            try
            {
                receivePacket = Receive(receiveFilter, out receivedFromEP, linkedCts.Token);
            }
            catch (OperationCanceledException)
            {
                // Here we need to disambiguate which cancellation token source caused the OperationCanceledException.
                // If the cancellation token passed into this method was signalled,
                // then we need to let the OperationCanceledException propagate up as-is.
                if (cancellationToken.IsCancellationRequested)
                {
                    Console.WriteLine("SendAndWaitForResponse was canceled.");
                    throw;
                }
                // Otherwise, the timeout cancellation token caused the OperationCanceledException.
                else
                {
                    Console.WriteLine("Receive timed out.");
                    throw new TimeoutException(string.Format("A response was not received after {0}.", timeout));
                }
            }

            // Cancel and clean up the send task.
            linkedCts.Cancel();
            try
            {
                sendTask.Wait();
            }
            catch (AggregateException ex)
            {
                ex.Handle(e => e is TaskCanceledException);
            }

            return(receivePacket);
        }