/** * Try to put queued up data on the socket. * * Control packets have higher priority, and will be sent first, if possible. * Standard packets can be split up in several package containers. In that case * all the parts of a split package must be sent in a row, without any control packet * in between. * * @param maxNumberOfBytesToSend This is the maximum number of bytes that is allowed to be put on the socket * this call. The actual number of sent bytes will be returned from the method. * * @param onlyAllowedToSendControlPacket This call we only try to put control packets on the sockets. * If there's a standard packet "in the way", and we think that this socket * is no longer an upload slot, then it is ok to send the standard packet to * get it out of the way. But it is not allowed to pick a new standard packet * from the queue during this call. Several split packets are counted as one * standard packet though, so it is ok to finish them all off if necessary. * * @return the actual number of bytes that were put on the socket. */ SocketSentBytes CEMSocket::Send(uint32 maxNumberOfBytesToSend, uint32 minFragSize, bool onlyAllowedToSendControlPacket) { //EMTrace("CEMSocket::Send linked: %i, controlcount %i, standartcount %i, isbusy: %i",m_bLinkedPackets, controlpacket_queue.GetCount(), standartpacket_queue.GetCount(), IsBusy()); sendLocker.Lock(); if (byConnected == ES_DISCONNECTED) { sendLocker.Unlock(); SocketSentBytes returnVal = { false, 0, 0 }; return returnVal; } bool anErrorHasOccured = false; uint32 sentStandardPacketBytesThisCall = 0; uint32 sentControlPacketBytesThisCall = 0; if (byConnected == ES_CONNECTED && IsEncryptionLayerReady() && !(m_bBusy && onlyAllowedToSendControlPacket)) { if (minFragSize < 1) { minFragSize = 1; } maxNumberOfBytesToSend = GetNextFragSize(maxNumberOfBytesToSend, minFragSize); bool bWasLongTimeSinceSend = (::GetTickCount() - lastSent) > 1000; lastCalledSend = ::GetTickCount(); while (sentStandardPacketBytesThisCall + sentControlPacketBytesThisCall < maxNumberOfBytesToSend && anErrorHasOccured == false && // don't send more than allowed. Also, there should have been no error in earlier loop (sendbuffer != NULL || !controlpacket_queue.IsEmpty() || !standartpacket_queue.IsEmpty()) && // there must exist something to send (onlyAllowedToSendControlPacket == false || // this means we are allowed to send both types of packets, so proceed sendbuffer != NULL && m_currentPacket_is_controlpacket == true || // 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.IsEmpty() || // There's a control packet in queue, and we are not currently sending anything, so we will handle the control packet next sendbuffer != NULL && m_currentPacket_is_controlpacket == false && bWasLongTimeSinceSend && !controlpacket_queue.IsEmpty() && (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.IsEmpty()) { // There's a control packet to send m_currentPacket_is_controlpacket = true; curPacket = controlpacket_queue.RemoveHead(); } else if (!standartpacket_queue.IsEmpty()) { // There's a standard packet to send m_currentPacket_is_controlpacket = false; StandardPacketQueueEntry queueEntry = standartpacket_queue.RemoveHead(); curPacket = queueEntry.packet; m_actualPayloadSize = queueEntry.actualPayloadSize; // remember this for statistics purposes. m_currentPackageIsFromPartFile = curPacket->IsFromPF(); } else { // Just to be safe. Shouldn't happen? sendLocker.Unlock(); // if we reach this point, then there's something wrong with the while condition above! ASSERT(0); // Comment UI //theApp.QueueDebugLogLine(true,_T("EMSocket: Couldn't get a new packet! There's an error in the first while condition in EMSocket::Send()")); CGlobalVariable::QueueDebugLogLine(true,_T("EMSocket: Couldn't get a new packet! There's an error in the first while condition in EMSocket::Send()")); SocketSentBytes returnVal = { true, sentStandardPacketBytesThisCall, sentControlPacketBytesThisCall }; return returnVal; } // We found a package to send. Get the data to send from the // package container and dispose of the container. sendblen = curPacket->GetRealPacketSize(); sendbuffer = curPacket->DetachPacket(); sent = 0; delete curPacket; // encrypting which cannot be done transparent by base class CryptPrepareSendData((uchar*)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 == false || // this means we are allowed to send both types of packets, so proceed m_currentPacket_is_controlpacket || bWasLongTimeSinceSend && (sentStandardPacketBytesThisCall + sentControlPacketBytesThisCall) < minFragSize || (sentStandardPacketBytesThisCall + sentControlPacketBytesThisCall) % minFragSize != 0 ) && anErrorHasOccured == false) { uint32 tosend = sendblen-sent; if (!onlyAllowedToSendControlPacket || m_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 { uint32 nextFragMaxBytesToSent = GetNextFragSize(sentStandardPacketBytesThisCall + sentControlPacketBytesThisCall, minFragSize); if (nextFragMaxBytesToSent >= sentStandardPacketBytesThisCall + sentControlPacketBytesThisCall && tosend > nextFragMaxBytesToSent-(sentStandardPacketBytesThisCall + sentControlPacketBytesThisCall)) tosend = nextFragMaxBytesToSent-(sentStandardPacketBytesThisCall + sentControlPacketBytesThisCall); } ASSERT (tosend != 0 && tosend <= sendblen-sent); //DWORD tempStartSendTick = ::GetTickCount(); lastSent = ::GetTickCount(); uint32 result = CEncryptedStreamSocket::Send(sendbuffer+sent,tosend); // deadlake PROXYSUPPORT - changed to AsyncSocketEx if (result == (uint32)SOCKET_ERROR) { uint32 error = GetLastError(); if (error == WSAEWOULDBLOCK) { m_bBusy = true; //m_wasBlocked = true; sendLocker.Unlock(); SocketSentBytes returnVal = { true, sentStandardPacketBytesThisCall, sentControlPacketBytesThisCall }; return returnVal; // Send() blocked, onsend will be called when ready to send again } 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. m_bBusy = false; m_hasSent = true; sent += result; // Log send bytes in correct class if (m_currentPacket_is_controlpacket == false) { sentStandardPacketBytesThisCall += result; if (m_currentPackageIsFromPartFile == true) { m_numberOfSentBytesPartFile += result; } else { m_numberOfSentBytesCompleteFile += result; } } else { sentControlPacketBytesThisCall += result; m_numberOfSentBytesControlPacket += 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. delete[] sendbuffer; sendbuffer = NULL; sendblen = 0; if (!m_currentPacket_is_controlpacket) { m_actualPayloadSizeSent += m_actualPayloadSize; m_actualPayloadSize = 0; lastFinishedStandard = ::GetTickCount(); // reset timeout m_bAccelerateUpload = false; // Safe until told otherwise } sent = 0; } } } if (onlyAllowedToSendControlPacket && (!controlpacket_queue.IsEmpty() || sendbuffer != NULL && m_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. // Comment UI CGlobalVariable::uploadBandwidthThrottler->QueueForSendingControlPacket(this, HasSent()); } //CleanSendLatencyList(); sendLocker.Unlock(); SocketSentBytes returnVal = { !anErrorHasOccured, sentStandardPacketBytesThisCall, sentControlPacketBytesThisCall }; return returnVal; }
/** * Try to put queued up data on the socket. * * Control packets have higher priority, and will be sent first, if possible. * Standard packets can be split up in several package containers. In that case * all the parts of a split package must be sent in a row, without any control packet * in between. * * @param maxNumberOfBytesToSend This is the maximum number of bytes that is allowed to be put on the socket * this call. The actual number of sent bytes will be returned from the method. * * @param onlyAllowedToSendControlPacket This call we only try to put control packets on the sockets. * If there's a standard packet "in the way", and we think that this socket * is no longer an upload slot, then it is ok to send the standard packet to * get it out of the way. But it is not allowed to pick a new standard packet * from the queue during this call. Several split packets are counted as one * standard packet though, so it is ok to finish them all off if necessary. * * @return the actual number of bytes that were put on the socket. */ SocketSentBytes CEMSocket::Send(uint32 maxNumberOfBytesToSend, uint32 minFragSize, bool onlyAllowedToSendControlPacket) { wxMutexLocker lock(m_sendLocker); //printf("* Attempt to send a packet on socket %p\n", this); if (byConnected == ES_DISCONNECTED) { //printf("* Disconnected socket %p\n", this); SocketSentBytes returnVal = { false, 0, 0 }; return returnVal; } else if (m_bBusy && onlyAllowedToSendControlPacket) { //printf("* Busy socket %p\n", this); SocketSentBytes returnVal = { true, 0, 0 }; return returnVal; } bool anErrorHasOccured = false; uint32 sentStandardPacketBytesThisCall = 0; uint32 sentControlPacketBytesThisCall = 0; if (byConnected == ES_CONNECTED && IsEncryptionLayerReady() && (!m_bBusy || onlyAllowedToSendControlPacket)) { //printf("* Internal attemptto send on %p\n", this); if(minFragSize < 1) { minFragSize = 1; } maxNumberOfBytesToSend = GetNextFragSize(maxNumberOfBytesToSend, minFragSize); bool bWasLongTimeSinceSend = (::GetTickCount() - lastSent) > 1000; lastCalledSend = ::GetTickCount(); while(sentStandardPacketBytesThisCall + sentControlPacketBytesThisCall < maxNumberOfBytesToSend && anErrorHasOccured == false && // don't send more than allowed. Also, there should have been no error in earlier loop (!m_control_queue.empty() || !m_standard_queue.empty() || sendbuffer != NULL) && // there must exist something to send (onlyAllowedToSendControlPacket == false || // this means we are allowed to send both types of packets, so proceed (sentStandardPacketBytesThisCall + sentControlPacketBytesThisCall > 0 && (sentStandardPacketBytesThisCall + sentControlPacketBytesThisCall) % minFragSize != 0) || (sendbuffer == NULL && !m_control_queue.empty()) || // There's a control packet in queue, and we are not currently sending anything, so we will handle the control packet next (sendbuffer != NULL && m_currentPacket_is_controlpacket == true) || // We are in the progress of sending a control packet. We are always allowed to send those (sendbuffer != NULL && m_currentPacket_is_controlpacket == false && bWasLongTimeSinceSend && !m_control_queue.empty() && m_standard_queue.empty() && (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) { CPacket* curPacket = NULL; if(!m_control_queue.empty()) { // There's a control packet to send m_currentPacket_is_controlpacket = true; curPacket = m_control_queue.front(); m_control_queue.pop_front(); } else if(!m_standard_queue.empty() /*&& onlyAllowedToSendControlPacket == false*/) { // There's a standard packet to send m_currentPacket_is_controlpacket = false; StandardPacketQueueEntry queueEntry = m_standard_queue.front(); m_standard_queue.pop_front(); curPacket = queueEntry.packet; m_actualPayloadSize = queueEntry.actualPayloadSize; // remember this for statistics purposes. m_currentPackageIsFromPartFile = curPacket->IsFromPF(); } else { // Just to be safe. Shouldn't happen? // if we reach this point, then there's something wrong with the while condition above! wxFAIL; AddDebugLogLineC(logGeneral, wxT("EMSocket: Couldn't get a new packet! There's an error in the first while condition in EMSocket::Send()")); SocketSentBytes returnVal = { true, sentStandardPacketBytesThisCall, sentControlPacketBytesThisCall }; return returnVal; } // We found a packet to send. Get the data to send from the // package container and dispose of the container. sendblen = curPacket->GetRealPacketSize(); sendbuffer = curPacket->DetachPacket(); sent = 0; delete curPacket; CryptPrepareSendData((byte*)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 WOULDBLOCK), we will return from this method INSIDE this loop. while (sent < sendblen && sentStandardPacketBytesThisCall + sentControlPacketBytesThisCall < maxNumberOfBytesToSend && ( onlyAllowedToSendControlPacket == false || // this means we are allowed to send both types of packets, so proceed m_currentPacket_is_controlpacket || (bWasLongTimeSinceSend && (sentStandardPacketBytesThisCall + sentControlPacketBytesThisCall) < minFragSize) || (sentStandardPacketBytesThisCall + sentControlPacketBytesThisCall) % minFragSize != 0 ) && anErrorHasOccured == false) { uint32 tosend = sendblen-sent; if(!onlyAllowedToSendControlPacket || m_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 { uint32 nextFragMaxBytesToSent = GetNextFragSize(sentStandardPacketBytesThisCall + sentControlPacketBytesThisCall, minFragSize); if (nextFragMaxBytesToSent >= sentStandardPacketBytesThisCall + sentControlPacketBytesThisCall && tosend > nextFragMaxBytesToSent-(sentStandardPacketBytesThisCall + sentControlPacketBytesThisCall)) tosend = nextFragMaxBytesToSent-(sentStandardPacketBytesThisCall + sentControlPacketBytesThisCall); } wxASSERT(tosend != 0 && tosend <= sendblen-sent); //DWORD tempStartSendTick = ::GetTickCount(); lastSent = ::GetTickCount(); uint32 result = CEncryptedStreamSocket::Write(sendbuffer+sent,tosend); if (Error()){ uint32 error = LastError(); if (error == wxSOCKET_WOULDBLOCK){ m_bBusy = true; SocketSentBytes returnVal = { true, sentStandardPacketBytesThisCall, sentControlPacketBytesThisCall }; return returnVal; // Send() blocked, onsend will be called when ready to send again } else{ // Send() gave an error anErrorHasOccured = true; } } else { // we managed to send some bytes. Perform bookkeeping. m_bBusy = false; m_hasSent = true; sent += result; // Log send bytes in correct class if(m_currentPacket_is_controlpacket == false) { sentStandardPacketBytesThisCall += result; if(m_currentPackageIsFromPartFile == true) { m_numberOfSentBytesPartFile += result; } else { m_numberOfSentBytesCompleteFile += result; } } else { sentControlPacketBytesThisCall += result; m_numberOfSentBytesControlPacket += result; } } } if (sent == sendblen){ // we are done sending the current packet. Delete it and set // sendbuffer to NULL so a new packet can be fetched. delete[] sendbuffer; sendbuffer = NULL; sendblen = 0; if(!m_currentPacket_is_controlpacket) { m_actualPayloadSizeSent += m_actualPayloadSize; m_actualPayloadSize = 0; lastFinishedStandard = ::GetTickCount(); // reset timeout m_bAccelerateUpload = false; // Safe until told otherwise } sent = 0; } } } if(onlyAllowedToSendControlPacket && (!m_control_queue.empty() || (sendbuffer != NULL && m_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. //printf("* Requeueing control packet on %p\n", this); theApp->uploadBandwidthThrottler->QueueForSendingControlPacket(this, HasSent()); } //printf("* Finishing send debug on %p\n",this); SocketSentBytes returnVal = { !anErrorHasOccured, sentStandardPacketBytesThisCall, sentControlPacketBytesThisCall }; return returnVal; }