aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorGravatar Szymon Tomasz Stefanek2011-12-21 03:02:40 +0000
committerGravatar Szymon Tomasz Stefanek2011-12-21 03:02:40 +0000
commit7690f7d842c1025be16ae32fb60e81fa97d4f606 (patch)
tree7d5fd442acab701c964ef1e862a3427964aba3a0 /src
parentMore work on webkit (diff)
downloadKVIrc-7690f7d842c1025be16ae32fb60e81fa97d4f606.tar.gz
KVIrc-7690f7d842c1025be16ae32fb60e81fa97d4f606.tar.bz2
KVIrc-7690f7d842c1025be16ae32fb60e81fa97d4f606.zip
Better handling of ACKs in DCC transfers on asymmetric lines. Also a small bug fix.
git-svn-id: https://svn.kvirc.de/svn/trunk/kvirc@5995 17fca916-40b9-46aa-a4ea-0a15b648b75c
Diffstat (limited to 'src')
-rw-r--r--src/modules/dcc/DccFileTransfer.cpp81
1 files changed, 74 insertions, 7 deletions
diff --git a/src/modules/dcc/DccFileTransfer.cpp b/src/modules/dcc/DccFileTransfer.cpp
index 2d5c57398..251828fc2 100644
--- a/src/modules/dcc/DccFileTransfer.cpp
+++ b/src/modules/dcc/DccFileTransfer.cpp
@@ -122,16 +122,82 @@ bool DccRecvThread::sendAck(int filePos)
{
iRet = m_pSSL->write((char*)(&size),4);
} else {
-#endif
+#endif //COMPILE_SSL_SUPPORT
iRet = kvi_socket_send(m_fd,(void *)(&size),4);
#ifdef COMPILE_SSL_SUPPORT
}
-#endif
+#endif //COMPILE_SSL_SUPPORT
if(iRet != 4)
{
- postErrorEvent(KviError::AcknowledgeError);
- return false;
+ // When downloading from a fast server using send-ahead via an asymmetric link (such as the
+ // common ADSL lines) it may happen that the network output queue gets saturated with ACKs.
+ // In this case the network stack will refuse to send our packet and we get here.
+ //
+ // We should either retry to send the ACK in a while or avoid sending it at all (as with
+ // send-ahead acks aren't usually checked per-packet).
+
+ if(iRet == 0)
+ {
+ // We can live with this: no data has been sent at all
+ // Not sending the ack and hoping that the server will not stall is better than
+ // killing the connection from our side anyway.
+ return true;
+ }
+
+ if(iRet < 0)
+ {
+ // Reported error. If it's EAGAIN or EINTR then no data has been sent.
+
+#ifdef COMPILE_SSL_SUPPORT
+ if(m_pSSL)
+ {
+ // with ssl error handling is too complex here :/
+ postErrorEvent(KviError::AcknowledgeError);
+ return false;
+ }
+#endif //COMPILE_SSL_SUPPORT
+
+ int err = kvi_socket_error();
+#if defined(COMPILE_ON_WINDOWS) || defined(COMPILE_ON_MINGW)
+ if((err != EAGAIN) && (err != EINTR) && (err != WSAEWOULDBLOCK))
+#else //!(defined(COMPILE_ON_WINDOWS) || defined(COMPILE_ON_MINGW))
+ if((err != EAGAIN) && (err != EINTR))
+#endif //!(defined(COMPILE_ON_WINDOWS) || defined(COMPILE_ON_MINGW))
+ {
+ // some other kind of error
+ postErrorEvent(KviError::AcknowledgeError);
+ return false;
+ }
+
+ return true; // no data sent: same as iRet == 0 above.
+ }
+
+ // Sent something but not everything.
+
+ // Sleep for a short while and try to send the missing part.
+ // This will probably throttle the bandwidth usage a bit too.
+ msleep(10);
+
+ int iMissingPart = 4 - iRet;
+
+#ifdef COMPILE_SSL_SUPPORT
+ if(m_pSSL)
+ {
+ iRet = m_pSSL->write(((char*)(&size)) + iRet,iMissingPart);
+ } else {
+#endif //COMPILE_SSL_SUPPORT
+ iRet = kvi_socket_send(m_fd,(void *)(((char *)(&size)) + iRet),iMissingPart);
+#ifdef COMPILE_SSL_SUPPORT
+ }
+#endif //COMPILE_SSL_SUPPORT
+
+ if(iRet != iMissingPart)
+ {
+ // Crap.. couldn't send the missing part of the ack :/
+ postErrorEvent(KviError::AcknowledgeError);
+ return false;
+ }
}
return true;
}
@@ -895,14 +961,15 @@ void DccSendThread::run()
#endif
// error ?
- if(!handleInvalidSocketRead(written))break;
+ if(!handleInvalidSocketRead(written))
+ break;
handle_system_error:
int err = kvi_socket_error();
#if defined(COMPILE_ON_WINDOWS) || defined(COMPILE_ON_MINGW)
- if((err != EAGAIN) || (err != EINTR) || (err != WSAEWOULDBLOCK))
+ if((err != EAGAIN) && (err != EINTR) && (err != WSAEWOULDBLOCK))
#else
- if((err != EAGAIN)||(err != EINTR))
+ if((err != EAGAIN) && (err != EINTR))
#endif
{
postErrorEvent(KviError::translateSystemError(err));