Пример #1
0
        private void SendWorker()
        {
            byte[] block = new byte[512];
            while (true)
            {
                //
                // Send the file 512 bytes at a time to the channel, and then finish.
                //
                int read = _data.Read(block, 0, block.Length);
                _channel.Send(block, read, true);

                Log.Write(LogType.Verbose, LogComponent.EFTP, "Sent data, position is now {0}", _data.Position);

                if (read != block.Length)
                {
                    _channel.SendEnd();
                    break;
                }
            }
            _data.Close();
            _sendDone = true;

            EFTPManager.DestroyChannel(_channel);
        }
Пример #2
0
        /// <summary>
        /// Sends data to the channel (i.e. to the client).  Will block (waiting for an ACK) if an ACK is requested.
        /// </summary>
        /// <param name="data">The data to be sent</param>
        /// <param name="flush">Whether to flush data out immediately or to wait for enough for a full PUP first.</param>
        public void Send(byte[] data, int length, bool flush)
        {
            if (length > data.Length)
            {
                throw new InvalidOperationException("Length must be less than or equal to the size of data.");
            }

            // Add output data to output queue.
            // Again, this is really inefficient.
            for (int i = 0; i < length; i++)
            {
                _outputQueue.Enqueue(data[i]);
            }

            if (flush || _outputQueue.Count >= PUP.MAX_PUP_SIZE)
            {
                // Send data until all is used (for a flush) or until we have less than a full PUP (non-flush).
                while (_outputQueue.Count >= (flush ? 1 : PUP.MAX_PUP_SIZE))
                {
                    byte[] chunk = new byte[Math.Min(PUP.MAX_PUP_SIZE, _outputQueue.Count)];

                    // Ugh.
                    for (int i = 0; i < chunk.Length; i++)
                    {
                        chunk[i] = _outputQueue.Dequeue();
                    }

                    while (true)
                    {
                        // Send the data.
                        PUP dataPup = new PUP(PupType.EFTPData, _sendPos, _clientConnectionPort, _serverConnectionPort, chunk);

                        Router.Instance.SendPup(dataPup);

                        // Await an ACK.  We will retry several times and resend as necessary.
                        int retry = 0;
                        for (retry = 0; retry < EFTPRetryCount; retry++)
                        {
                            if (_outputAckEvent.WaitOne(EFTPAckTimeoutPeriod))
                            {
                                // done, we got our ACK.
                                break;
                            }
                            else
                            {
                                // timeout: resend the PUP and wait for an ACK again.
                                Router.Instance.SendPup(dataPup);
                            }
                        }

                        if (retry >= EFTPRetryCount)
                        {
                            Log.Write(LogType.Error, LogComponent.EFTP, "Timeout waiting for ACK, aborting connection.");
                            SendAbort("Client unresponsive.");
                            EFTPManager.DestroyChannel(this);
                        }

                        if (_lastRecvPos == _sendPos)
                        {
                            // The client is in sync with us, we are done with this packet.
                            break;
                        }
                        else if (_sendPos - _lastRecvPos > 1)
                        {
                            // We lost more than one packet, something is very broken.
                            Log.Write(LogType.Error, LogComponent.EFTP, "Client lost more than one packet, connection is broken.  Aborting.");
                            SendAbort("Client lost too much data.");
                            EFTPManager.DestroyChannel(this);
                        }
                        else
                        {
                            // We lost one packet, move back and send it again.
                            Log.Write(LogType.Warning, LogComponent.EFTP, "Client lost a packet, resending.");
                        }
                    }

                    // Move to next packet.
                    _sendPos++;
                }
            }
        }