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 }