Skip to content
Permalink
Browse files
Keep socket readable when EOF signal is needed
This is an important bugfix for some the slow bootstrapping problems
that have been plaguing our Tor experiments. A lot of communication with
the directory servers (and others?) depends on reading EOF from the
socket before taking the next step (like during consensus downloads).

There was a corner case where the socket had received a remote close
signal (FIN), and afterwords the user read all of the remaining data
out of the socket. In this case we were marking the socket as unreadable
because there was no data, when in fact it needed to be marked as
readable so the user could read the EOF and close the socket.

I'm not closing the issue yet in case I find other issues in the next
few days.

refs #62
  • Loading branch information
robgjansen committed Sep 6, 2012
1 parent d79ccd5 commit e2d30c9700a80d91b4ffb5b3b6dcfa03b4afaa91
Showing with 23 additions and 17 deletions.
  1. +23 −17 src/node/descriptor/shd-tcp.c
@@ -1233,27 +1233,33 @@ gssize tcp_receiveUserData(TCP* tcp, gpointer buffer, gsize nBytes, in_addr_t* i
packet_unref(packet);
}

/* return 0 to signal close if we have EOF and no more data */
if((tcp->unorderedInputLength == 0) && (tcp->super.inputBufferLength == 0) &&
(tcp->partialUserDataPacket == NULL) &&(tcp->error & TCPE_RECEIVE_EOF)
&& (totalCopied == 0))
{
if(tcp->flags & TCPF_EOF_SIGNALED) {
/* we already signaled close, now its an error */
return -2;
} else {
/* we have not signaled close, do that now */
_tcp_endOfFileSignalled(tcp);
return 0;
}
}

/* now we update readability of the socket */
if((tcp->super.inputBufferLength > 0) || (tcp->partialUserDataPacket != NULL)) {
/* we still have readable data */
descriptor_adjustStatus(&(tcp->super.super.super), DS_READABLE, TRUE);
} else {
/* all of our ordered user data is gone */
descriptor_adjustStatus(&(tcp->super.super.super), DS_READABLE, FALSE);
/* all of our ordered user data has been read */
if((tcp->unorderedInputLength == 0) && (tcp->error & TCPE_RECEIVE_EOF)) {
/* there is no more unordered data either, and we need to signal EOF */
if(totalCopied > 0) {
/* we just received bytes, so we can't EOF until the next call.
* make sure we stay readable so we DO actually EOF the socket */
descriptor_adjustStatus(&(tcp->super.super.super), DS_READABLE, TRUE);
} else {
/* OK, no more data and nothing just received. */
if(tcp->flags & TCPF_EOF_SIGNALED) {
/* we already signaled close, now its an error */
return -2;
} else {
/* we have not signaled close, do that now and close out the socket */
_tcp_endOfFileSignalled(tcp);
return 0;
}
}
} else {
/* our socket still has unordered data or is still open, but empty for now */
descriptor_adjustStatus(&(tcp->super.super.super), DS_READABLE, FALSE);
}
}

debug("%s <-> %s: receiving %lu user bytes", tcp->super.boundString, tcp->super.peerString, totalCopied);

0 comments on commit e2d30c9

Please sign in to comment.