Exemplo n.º 1
0
        protected virtual SocketSentBytes Send(uint maxNumberOfBytesToSend, uint minFragSize, bool onlyAllowedToSendControlPacket)
        {
            lock (sendLocker_)
            {
                if (connState_ == ConnectionStateEnum.CS_DISCONNECTED)
                {
                    return(new SocketSentBytes(false, 0, 0));
                }

                bool anErrorHasOccured = false;
                uint sentStandardPacketBytesThisCall = 0;
                uint sentControlPacketBytesThisCall  = 0;

                if (connState_ == ConnectionStateEnum.CS_CONNECTED &&
                    IsEncryptionLayerReady &&
                    !(IsBusy && onlyAllowedToSendControlPacket))
                {
                    if (minFragSize < 1)
                    {
                        minFragSize = 1;
                    }

                    maxNumberOfBytesToSend = GetNextFragSize(maxNumberOfBytesToSend, minFragSize);

                    bool bWasLongTimeSinceSend = (MpdUtilities.GetTickCount() - lastSent_) > 1000;

                    lastCalledSend_ = MpdUtilities.GetTickCount();

                    while (sentStandardPacketBytesThisCall + sentControlPacketBytesThisCall < maxNumberOfBytesToSend &&
                           !anErrorHasOccured &&                                                                           // don't send more than allowed. Also, there should have been no error in earlier loop
                           (sendbuffer_ != null || controlpacket_queue_.Count != 0 || standartpacket_queue_.Count != 0) && // there must exist something to send
                           (!onlyAllowedToSendControlPacket ||                                                             // this means we are allowed to send both types of packets, so proceed
                            sendbuffer_ != null && currentPacket_is_controlpacket_ ||                                      // We are in the progress of sending a control packet. We are always allowed to send those
                            sentStandardPacketBytesThisCall + sentControlPacketBytesThisCall > 0 &&
                            (sentStandardPacketBytesThisCall + sentControlPacketBytesThisCall) % minFragSize != 0 ||       // Once we've started, continue to send until an even minFragsize to minimize packet overhead
                            sendbuffer_ == null && controlpacket_queue_.Count != 0 ||                                      // There's a control packet in queue, and we are not currently sending anything, so we will handle the control packet next
                            sendbuffer_ != null && !currentPacket_is_controlpacket_ &&
                            bWasLongTimeSinceSend && controlpacket_queue_.Count != 0 &&
                            (sentStandardPacketBytesThisCall + sentControlPacketBytesThisCall) < minFragSize // We have waited to long to clean the current packet (which may be a standard packet that is in the way). Proceed no matter what the value of onlyAllowedToSendControlPacket.
                           )
                           )
                    {
                        // If we are currently not in the progress of sending a packet, we will need to find the next one to send
                        if (sendbuffer_ == null)
                        {
                            Packet curPacket = null;
                            if (controlpacket_queue_.Count != 0)
                            {
                                // There's a control packet to send
                                currentPacket_is_controlpacket_ = true;
                                curPacket = controlpacket_queue_.Dequeue();
                            }
                            else if (standartpacket_queue_.Count > 0)
                            {
                                // There's a standard packet to send
                                currentPacket_is_controlpacket_ = false;
                                StandardPacketQueueEntry queueEntry = standartpacket_queue_.Dequeue();
                                curPacket          = queueEntry.Packet;
                                actualPayloadSize_ = queueEntry.ActualPayloadSize;

                                // remember this for statistics purposes.
                                currentPackageIsFromPartFile_ = curPacket.IsFromPartFile;
                            }
                            else
                            {
                                // if we reach this point, then there's something wrong with the while condition above!
                                Debug.Assert(false);
                                MpdUtilities.QueueDebugLogLine(true, ("EMSocket: Couldn't get a new packet! There's an error in the first while condition in EMSocket::Send()"));

                                return(new SocketSentBytes(true, sentStandardPacketBytesThisCall, sentControlPacketBytesThisCall));
                            }

                            // We found a package to send. Get the data to send from the
                            // package container and dispose of the container.
                            sendblen_   = curPacket.RealPacketSize;
                            sendbuffer_ = curPacket.DetachPacket();
                            sent_       = 0;
                            curPacket   = null;

                            // encrypting which cannot be done transparent by base class
                            CryptPrepareSendData(sendbuffer_, sendblen_);
                        }

                        // At this point we've got a packet to send in sendbuffer_. Try to send it. Loop until entire packet
                        // is sent, or until we reach maximum bytes to send for this call, or until we get an error.
                        // NOTE! If send would block (returns WSAEWOULDBLOCK), we will return from this method INSIDE this loop.
                        while (sent_ < sendblen_ &&
                               sentStandardPacketBytesThisCall + sentControlPacketBytesThisCall < maxNumberOfBytesToSend &&
                               (
                                   !onlyAllowedToSendControlPacket || // this means we are allowed to send both types of packets, so proceed
                                   currentPacket_is_controlpacket_ ||
                                   bWasLongTimeSinceSend &&
                                   (sentStandardPacketBytesThisCall + sentControlPacketBytesThisCall) < minFragSize ||
                                   (sentStandardPacketBytesThisCall + sentControlPacketBytesThisCall) % minFragSize != 0
                               ) &&
                               !anErrorHasOccured)
                        {
                            uint tosend = sendblen_ - sent_;
                            if (!onlyAllowedToSendControlPacket || currentPacket_is_controlpacket_)
                            {
                                if (maxNumberOfBytesToSend >= sentStandardPacketBytesThisCall + sentControlPacketBytesThisCall &&
                                    tosend > maxNumberOfBytesToSend - (sentStandardPacketBytesThisCall + sentControlPacketBytesThisCall))
                                {
                                    tosend = maxNumberOfBytesToSend - (sentStandardPacketBytesThisCall + sentControlPacketBytesThisCall);
                                }
                            }
                            else if (bWasLongTimeSinceSend && (sentStandardPacketBytesThisCall + sentControlPacketBytesThisCall) < minFragSize)
                            {
                                if (minFragSize >= sentStandardPacketBytesThisCall + sentControlPacketBytesThisCall &&
                                    tosend > minFragSize - (sentStandardPacketBytesThisCall + sentControlPacketBytesThisCall))
                                {
                                    tosend = minFragSize - (sentStandardPacketBytesThisCall + sentControlPacketBytesThisCall);
                                }
                            }
                            else
                            {
                                uint nextFragMaxBytesToSent =
                                    GetNextFragSize(sentStandardPacketBytesThisCall + sentControlPacketBytesThisCall,
                                                    minFragSize);
                                if (nextFragMaxBytesToSent >= sentStandardPacketBytesThisCall + sentControlPacketBytesThisCall &&
                                    tosend > nextFragMaxBytesToSent - (sentStandardPacketBytesThisCall + sentControlPacketBytesThisCall))
                                {
                                    tosend = nextFragMaxBytesToSent - (sentStandardPacketBytesThisCall + sentControlPacketBytesThisCall);
                                }
                            }
                            Debug.Assert(tosend != 0 && tosend <= sendblen_ - sent_);

                            //DWORD tempStartSendTick = ::GetTickCount();

                            lastSent_ = MpdUtilities.GetTickCount();

                            int result = base.Send(sendbuffer_, Convert.ToInt32(sent_), Convert.ToInt32(tosend)); // deadlake PROXYSUPPORT - changed to AsyncSocketEx
                            if (result == SOCKET_ERROR)
                            {
                                if (SocketErrorCode == SocketError.WouldBlock)
                                {
                                    IsBusy = true;

                                    // Send() blocked, onsend will be called when ready to send again
                                    return(new SocketSentBytes(true, sentStandardPacketBytesThisCall, sentControlPacketBytesThisCall));
                                }
                                else
                                {
                                    // Send() gave an error
                                    anErrorHasOccured = true;
                                    //DEBUG_ONLY( AddDebugLogLine(true,"EMSocket: An error has occured: %i", error) );
                                }
                            }
                            else
                            {
                                // we managed to send some bytes. Perform bookkeeping.
                                IsBusy   = false;
                                hasSent_ = true;

                                sent_ += Convert.ToUInt32(result);

                                // Log send bytes in correct class
                                if (!currentPacket_is_controlpacket_)
                                {
                                    sentStandardPacketBytesThisCall += Convert.ToUInt32(result);

                                    if (currentPackageIsFromPartFile_)
                                    {
                                        numberOfSentBytesPartFile_ += Convert.ToUInt32(result);
                                    }
                                    else
                                    {
                                        numberOfSentBytesCompleteFile_ += Convert.ToUInt32(result);
                                    }
                                }
                                else
                                {
                                    sentControlPacketBytesThisCall  += Convert.ToUInt32(result);
                                    numberOfSentBytesControlPacket_ += Convert.ToUInt32(result);
                                }
                            }
                        }

                        if (sent_ == sendblen_)
                        {
                            // we are done sending the current package. Delete it and set
                            // sendbuffer_ to null so a new packet can be fetched.
                            sendbuffer_ = null;
                            sendblen_   = 0;

                            if (!currentPacket_is_controlpacket_)
                            {
                                actualPayloadSizeSent_ += actualPayloadSize_;
                                actualPayloadSize_      = 0;

                                lastFinishedStandard_ = MpdUtilities.GetTickCount(); // reset timeout
                                accelerateUpload_     = false;                       // Safe until told otherwise
                            }

                            sent_ = 0;
                        }
                    }
                }

                if (onlyAllowedToSendControlPacket &&
                    (controlpacket_queue_.Count > 0 ||
                     sendbuffer_ != null && currentPacket_is_controlpacket_))
                {
                    // enter control packet send queue
                    // we might enter control packet queue several times for the same package,
                    // but that costs very little overhead. Less overhead than trying to make sure
                    // that we only enter the queue once.
                    MuleApplication.Instance.UploadBandwidthThrottler.QueueForSendingControlPacket(this, HasSent);
                }

                //CleanSendLatencyList();

                return(new SocketSentBytes(!anErrorHasOccured, sentStandardPacketBytesThisCall, sentControlPacketBytesThisCall));
            }//lock
        }