diff options
| -rw-r--r-- | src/net.h | 16 | ||||
| -rw-r--r-- | src/selftest.cpp | 37 |
2 files changed, 38 insertions, 15 deletions
| @@ -89,10 +89,9 @@ static const int BTF_HANDSHAKE_GRACE_SECS = 60; | |||
| 89 | 89 | ||
| 90 | // A serialized object cannot be larger than MAX_SIZE, so no valid network | 90 | // A serialized object cannot be larger than MAX_SIZE, so no valid network |
| 91 | // message needs the old 256 MB header allowance. Keep the wire cap aligned with | 91 | // message needs the old 256 MB header allowance. Keep the wire cap aligned with |
| 92 | // what the deserializer can accept and bound how long one peer may sit on a | 92 | // what the deserializer can accept. How long a peer may sit on a partial |
| 93 | // partial payload after a complete header has arrived. | 93 | // payload after a complete header has arrived is BTF_MSG_WAIT_MAX_SECS, below. |
| 94 | static const unsigned int MAX_PROTOCOL_MESSAGE_SIZE = MAX_SIZE; | 94 | static const unsigned int MAX_PROTOCOL_MESSAGE_SIZE = MAX_SIZE; |
| 95 | static const int BTF_INCOMPLETE_MESSAGE_TIMEOUT_SECS = 2 * 60; | ||
| 96 | 95 | ||
| 97 | // Ceiling on simultaneous connections. | 96 | // Ceiling on simultaneous connections. |
| 98 | // | 97 | // |
| @@ -656,9 +655,6 @@ public: | |||
| 656 | int64 nLastSend; | 655 | int64 nLastSend; |
| 657 | int64 nLastRecv; | 656 | int64 nLastRecv; |
| 658 | int64 nLastSendEmpty; | 657 | int64 nLastSendEmpty; |
| 659 | int64 nIncompleteMessageStart; | ||
| 660 | unsigned int nIncompleteMessageSize; | ||
| 661 | string strIncompleteMessageCommand; | ||
| 662 | string strBtfAddr; | 658 | string strBtfAddr; |
| 663 | string strBtfMeeting; | 659 | string strBtfMeeting; |
| 664 | 660 | ||
| @@ -699,11 +695,13 @@ public: | |||
| 699 | nLastSend = 0; | 695 | nLastSend = 0; |
| 700 | nLastRecv = 0; | 696 | nLastRecv = 0; |
| 701 | nLastSendEmpty = GetTime(); | 697 | nLastSendEmpty = GetTime(); |
| 702 | nIncompleteMessageStart = 0; | ||
| 703 | nIncompleteMessageSize = 0; | ||
| 704 | strIncompleteMessageCommand.clear(); | ||
| 705 | strBtfAddr.clear(); | 698 | strBtfAddr.clear(); |
| 706 | strBtfMeeting.clear(); | 699 | strBtfMeeting.clear(); |
| 700 | // Not waiting on anything yet. Left indeterminate, the first partial | ||
| 701 | // message this peer sends is measured against whatever was in this | ||
| 702 | // memory, and ProcessMessages drops it as unreadable on first contact. | ||
| 703 | nMsgWaitSince = 0; | ||
| 704 | nMsgWaitSize = 0; | ||
| 707 | nStartingHeight = -1; | 705 | nStartingHeight = -1; |
| 708 | 706 | ||
| 709 | // Push a version message | 707 | // Push a version message |
diff --git a/src/selftest.cpp b/src/selftest.cpp index ff0289b..d12c96b 100644 --- a/src/selftest.cpp +++ b/src/selftest.cpp | |||
| @@ -1105,6 +1105,13 @@ static int RunNetMessageSelfTest() | |||
| 1105 | int nFail = 0; | 1105 | int nFail = 0; |
| 1106 | try | 1106 | try |
| 1107 | { | 1107 | { |
| 1108 | // A peer that has not yet been kept waiting must not look like one that | ||
| 1109 | // has been waiting since the epoch. This is the whole bug: the stall | ||
| 1110 | // clock lives in CNode, so only the constructor can start it at zero. | ||
| 1111 | CNode opened(INVALID_SOCKET, CAddress("127.0.0.1")); | ||
| 1112 | nFail += Check(opened.nMsgWaitSince == 0 && opened.nMsgWaitSize == 0, | ||
| 1113 | "a new peer starts with its stall clock stopped") ? 0 : 1; | ||
| 1114 | |||
| 1108 | CNode complete(INVALID_SOCKET, CAddress("127.0.0.1")); | 1115 | CNode complete(INVALID_SOCKET, CAddress("127.0.0.1")); |
| 1109 | complete.nVersion = VERSION; | 1116 | complete.nVersion = VERSION; |
| 1110 | complete.vRecv << CMessageHeader("ping", 0); | 1117 | complete.vRecv << CMessageHeader("ping", 0); |
| @@ -1119,20 +1126,38 @@ static int RunNetMessageSelfTest() | |||
| 1119 | nFail += Check(ProcessMessages(&partial), "an incomplete message returns cleanly") ? 0 : 1; | 1126 | nFail += Check(ProcessMessages(&partial), "an incomplete message returns cleanly") ? 0 : 1; |
| 1120 | nFail += Check(partial.vRecv.size() == nPartialBefore, | 1127 | nFail += Check(partial.vRecv.size() == nPartialBefore, |
| 1121 | "an incomplete message keeps one header in the buffer") ? 0 : 1; | 1128 | "an incomplete message keeps one header in the buffer") ? 0 : 1; |
| 1122 | nFail += Check(partial.nIncompleteMessageStart != 0, | 1129 | nFail += Check(partial.nMsgWaitSince != 0, |
| 1123 | "an incomplete message starts a timeout clock") ? 0 : 1; | 1130 | "an incomplete message starts the stall clock") ? 0 : 1; |
| 1131 | nFail += Check(partial.nMsgWaitSize == 0, | ||
| 1132 | "the stall clock records how much payload had arrived") ? 0 : 1; | ||
| 1124 | nFail += Check(!partial.fDisconnect, | 1133 | nFail += Check(!partial.fDisconnect, |
| 1125 | "a fresh incomplete message does not disconnect immediately") ? 0 : 1; | 1134 | "a fresh incomplete message does not disconnect immediately") ? 0 : 1; |
| 1126 | 1135 | ||
| 1136 | // Still arriving, just slowly: more payload is here than when the clock | ||
| 1137 | // was started, so the clock restarts however old it was. Timing the | ||
| 1138 | // wait instead of the stall would drop this peer. | ||
| 1139 | CNode slow(INVALID_SOCKET, CAddress("127.0.0.1")); | ||
| 1140 | slow.nVersion = VERSION; | ||
| 1141 | slow.vRecv << CMessageHeader("block", 100); | ||
| 1142 | slow.vRecv.insert(slow.vRecv.end(), 50, '\0'); | ||
| 1143 | slow.nMsgWaitSince = GetTime() - BTF_MSG_WAIT_MAX_SECS - 1; | ||
| 1144 | slow.nMsgWaitSize = 10; | ||
| 1145 | ProcessMessages(&slow); | ||
| 1146 | nFail += Check(!slow.fDisconnect, | ||
| 1147 | "a peer still sending payload is not dropped") ? 0 : 1; | ||
| 1148 | nFail += Check(slow.nMsgWaitSize == 50, | ||
| 1149 | "progress restarts the stall clock") ? 0 : 1; | ||
| 1150 | |||
| 1151 | // Nothing more has arrived since the clock started, and the clock is | ||
| 1152 | // older than the limit. | ||
| 1127 | CNode stale(INVALID_SOCKET, CAddress("127.0.0.1")); | 1153 | CNode stale(INVALID_SOCKET, CAddress("127.0.0.1")); |
| 1128 | stale.nVersion = VERSION; | 1154 | stale.nVersion = VERSION; |
| 1129 | stale.vRecv << CMessageHeader("block", 100); | 1155 | stale.vRecv << CMessageHeader("block", 100); |
| 1130 | stale.nIncompleteMessageStart = GetTime() - BTF_INCOMPLETE_MESSAGE_TIMEOUT_SECS - 1; | 1156 | stale.nMsgWaitSince = GetTime() - BTF_MSG_WAIT_MAX_SECS - 1; |
| 1131 | stale.nIncompleteMessageSize = 100; | 1157 | stale.nMsgWaitSize = 0; |
| 1132 | stale.strIncompleteMessageCommand = "block"; | ||
| 1133 | ProcessMessages(&stale); | 1158 | ProcessMessages(&stale); |
| 1134 | nFail += Check(stale.fDisconnect, | 1159 | nFail += Check(stale.fDisconnect, |
| 1135 | "a stale incomplete message disconnects the peer") ? 0 : 1; | 1160 | "a stalled incomplete message disconnects the peer") ? 0 : 1; |
| 1136 | 1161 | ||
| 1137 | CNode oversized(INVALID_SOCKET, CAddress("127.0.0.1")); | 1162 | CNode oversized(INVALID_SOCKET, CAddress("127.0.0.1")); |
| 1138 | oversized.nVersion = VERSION; | 1163 | oversized.nVersion = VERSION; |