diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/main.cpp | 23 | ||||
| -rw-r--r-- | src/net.cpp | 43 | ||||
| -rw-r--r-- | src/net.h | 32 |
3 files changed, 97 insertions, 1 deletions
diff --git a/src/main.cpp b/src/main.cpp index d4fc6d0..f4e6ce2 100644 --- a/src/main.cpp +++ b/src/main.cpp | |||
| @@ -2190,6 +2190,18 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) | |||
| 2190 | } | 2190 | } |
| 2191 | 2191 | ||
| 2192 | 2192 | ||
| 2193 | else if (strCommand == "ping") | ||
| 2194 | { | ||
| 2195 | // Nothing to do and nothing to answer. Arriving at all is the entire | ||
| 2196 | // content of the message: the receive path has already stamped | ||
| 2197 | // nLastRecv, which is what the sender wanted us to notice. | ||
| 2198 | // | ||
| 2199 | // Deliberately no reply. A node old enough not to know "ping" ignores | ||
| 2200 | // it as an unknown command and would never answer one, so a scheme | ||
| 2201 | // that required an answer would read every such peer as dead. | ||
| 2202 | } | ||
| 2203 | |||
| 2204 | |||
| 2193 | else | 2205 | else |
| 2194 | { | 2206 | { |
| 2195 | // Ignore unknown commands for extensibility | 2207 | // Ignore unknown commands for extensibility |
| @@ -2222,6 +2234,17 @@ bool SendMessages(CNode* pto) | |||
| 2222 | 2234 | ||
| 2223 | 2235 | ||
| 2224 | // | 2236 | // |
| 2237 | // Message: keep-alive ping | ||
| 2238 | // | ||
| 2239 | // Only when we have nothing else queued -- any real message serves the | ||
| 2240 | // same purpose. A peer with nothing to relay is otherwise silent, and | ||
| 2241 | // silence is exactly what the inactivity check disconnects on. | ||
| 2242 | // | ||
| 2243 | if (pto->nLastSend && GetTime() - pto->nLastSend > BTF_PING_INTERVAL_SECS && pto->vSend.empty()) | ||
| 2244 | pto->PushMessage("ping"); | ||
| 2245 | |||
| 2246 | |||
| 2247 | // | ||
| 2225 | // Message: inventory | 2248 | // Message: inventory |
| 2226 | // | 2249 | // |
| 2227 | vector<CInv> vInventoryToSend; | 2250 | vector<CInv> vInventoryToSend; |
diff --git a/src/net.cpp b/src/net.cpp index 9ee056f..81932d7 100644 --- a/src/net.cpp +++ b/src/net.cpp | |||
| @@ -1092,7 +1092,11 @@ void ThreadSocketHandler2(void* parg) | |||
| 1092 | vRecv.resize(nPos + nBufSize); | 1092 | vRecv.resize(nPos + nBufSize); |
| 1093 | int nBytes = recv(hSocket, &vRecv[nPos], nBufSize, 0); | 1093 | int nBytes = recv(hSocket, &vRecv[nPos], nBufSize, 0); |
| 1094 | vRecv.resize(nPos + max(nBytes, 0)); | 1094 | vRecv.resize(nPos + max(nBytes, 0)); |
| 1095 | if (nBytes == 0) | 1095 | if (nBytes > 0) |
| 1096 | { | ||
| 1097 | pnode->nLastRecv = GetTime(); | ||
| 1098 | } | ||
| 1099 | else if (nBytes == 0) | ||
| 1096 | { | 1100 | { |
| 1097 | // socket closed gracefully | 1101 | // socket closed gracefully |
| 1098 | if (!pnode->fDisconnect) | 1102 | if (!pnode->fDisconnect) |
| @@ -1127,6 +1131,7 @@ void ThreadSocketHandler2(void* parg) | |||
| 1127 | if (nBytes > 0) | 1131 | if (nBytes > 0) |
| 1128 | { | 1132 | { |
| 1129 | vSend.erase(vSend.begin(), vSend.begin() + nBytes); | 1133 | vSend.erase(vSend.begin(), vSend.begin() + nBytes); |
| 1134 | pnode->nLastSend = GetTime(); | ||
| 1130 | } | 1135 | } |
| 1131 | else if (nBytes == 0) | 1136 | else if (nBytes == 0) |
| 1132 | { | 1137 | { |
| @@ -1140,6 +1145,42 @@ void ThreadSocketHandler2(void* parg) | |||
| 1140 | pnode->vSend.clear(); | 1145 | pnode->vSend.clear(); |
| 1141 | } | 1146 | } |
| 1142 | } | 1147 | } |
| 1148 | if (vSend.empty()) | ||
| 1149 | pnode->nLastSendEmpty = GetTime(); | ||
| 1150 | } | ||
| 1151 | } | ||
| 1152 | |||
| 1153 | // | ||
| 1154 | // Inactivity | ||
| 1155 | // | ||
| 1156 | // Dropping the connection is the whole cure: everything above this | ||
| 1157 | // layer already knows how to reconnect, and a peer we cannot hear | ||
| 1158 | // is worth exactly as much as no peer at all. Give a new | ||
| 1159 | // connection a grace period first, or we would cut off peers that | ||
| 1160 | // are still completing the rendezvous handshake. | ||
| 1161 | // | ||
| 1162 | if (GetTime() - pnode->nTimeConnected > BTF_HANDSHAKE_GRACE_SECS) | ||
| 1163 | { | ||
| 1164 | if (pnode->nLastRecv == 0 || pnode->nLastSend == 0) | ||
| 1165 | { | ||
| 1166 | LogPrint("net", "socket no message in first %d seconds, recv=%d send=%d\n", | ||
| 1167 | BTF_HANDSHAKE_GRACE_SECS, pnode->nLastRecv != 0, pnode->nLastSend != 0); | ||
| 1168 | pnode->fDisconnect = true; | ||
| 1169 | } | ||
| 1170 | else if (GetTime() - pnode->nLastSend > BTF_SEND_STALL_SECS && | ||
| 1171 | GetTime() - pnode->nLastSendEmpty > BTF_SEND_STALL_SECS) | ||
| 1172 | { | ||
| 1173 | // We have had something queued to send for this long and | ||
| 1174 | // none of it has gone out: the socket accepts no more. | ||
| 1175 | LogPrint("net", "socket not sending\n"); | ||
| 1176 | pnode->fDisconnect = true; | ||
| 1177 | } | ||
| 1178 | else if (GetTime() - pnode->nLastRecv > BTF_RECV_TIMEOUT_SECS) | ||
| 1179 | { | ||
| 1180 | // The deaf case. Nothing has arrived for many block | ||
| 1181 | // intervals while the socket still looks perfectly fine. | ||
| 1182 | LogPrint("net", "socket inactivity timeout\n"); | ||
| 1183 | pnode->fDisconnect = true; | ||
| 1143 | } | 1184 | } |
| 1144 | } | 1185 | } |
| 1145 | } | 1186 | } |
| @@ -51,6 +51,24 @@ static const int64 PEX_MIN_INTERVAL = 60; | |||
| 51 | // traffic is nothing: one per relay per five minutes. | 51 | // traffic is nothing: one per relay per five minutes. |
| 52 | static const int BTF_RENDEZVOUS_WAIT_SECS = 300; | 52 | static const int BTF_RENDEZVOUS_WAIT_SECS = 300; |
| 53 | 53 | ||
| 54 | // Liveness of an established peer connection. BTF_RENDEZVOUS_WAIT_SECS bounds | ||
| 55 | // the wait for a dial to arrive; these bound the connection that comes out of | ||
| 56 | // it, which has the same failure mode once it goes quiet. | ||
| 57 | // | ||
| 58 | // A healthy peer relays a block inventory roughly every nTargetSpacing (two | ||
| 59 | // minutes), so silence measured in block intervals is the honest signal. | ||
| 60 | // Bitcoin used ninety minutes against ten-minute blocks -- nine intervals -- | ||
| 61 | // and the same nine intervals here is eighteen minutes; thirty leaves margin | ||
| 62 | // for a slow stretch without letting a dead path last an hour. | ||
| 63 | static const int BTF_RECV_TIMEOUT_SECS = 30 * 60; | ||
| 64 | static const int BTF_SEND_STALL_SECS = 10 * 60; | ||
| 65 | static const int BTF_HANDSHAKE_GRACE_SECS = 60; | ||
| 66 | |||
| 67 | // Send a ping after this long with nothing to say, so a peer running the | ||
| 68 | // inactivity check above does not mistake a quiet node for a dead one. Must | ||
| 69 | // stay well under BTF_RECV_TIMEOUT_SECS. | ||
| 70 | static const int BTF_PING_INTERVAL_SECS = 10 * 60; | ||
| 71 | |||
| 54 | // Descriptors to hand a peer: ours first, then peers that answered us. | 72 | // Descriptors to hand a peer: ours first, then peers that answered us. |
| 55 | void BtfPexCollect(std::vector<std::string>& vDescOut); | 73 | void BtfPexCollect(std::vector<std::string>& vDescOut); |
| 56 | // Verify descriptors a peer sent and remember the good ones. Returns how many. | 74 | // Verify descriptors a peer sent and remember the good ones. Returns how many. |
| @@ -500,6 +518,16 @@ public: | |||
| 500 | // Last "btfpeers" we accepted from this node, to rate-limit the exchange. | 518 | // Last "btfpeers" we accepted from this node, to rate-limit the exchange. |
| 501 | int64 nLastPexRecv; | 519 | int64 nLastPexRecv; |
| 502 | 520 | ||
| 521 | // Liveness. A peer whose network path dies silently -- NAT drops an idle | ||
| 522 | // mapping, a relay restarts, a route changes -- never sends FIN, so the | ||
| 523 | // socket stays readable-never and the node simply stops hearing from it | ||
| 524 | // with no error anywhere. These stamps are the only way to tell that | ||
| 525 | // apart from a peer that merely has nothing to say. | ||
| 526 | int64 nTimeConnected; | ||
| 527 | int64 nLastSend; | ||
| 528 | int64 nLastRecv; | ||
| 529 | int64 nLastSendEmpty; | ||
| 530 | |||
| 503 | 531 | ||
| 504 | CNode(SOCKET hSocketIn, CAddress addrIn, bool fInboundIn=false) | 532 | CNode(SOCKET hSocketIn, CAddress addrIn, bool fInboundIn=false) |
| 505 | { | 533 | { |
| @@ -517,6 +545,10 @@ public: | |||
| 517 | nRefCount = 0; | 545 | nRefCount = 0; |
| 518 | nReleaseTime = 0; | 546 | nReleaseTime = 0; |
| 519 | nLastPexRecv = 0; | 547 | nLastPexRecv = 0; |
| 548 | nTimeConnected = GetTime(); | ||
| 549 | nLastSend = 0; | ||
| 550 | nLastRecv = 0; | ||
| 551 | nLastSendEmpty = GetTime(); | ||
| 520 | vfSubscribe.assign(256, false); | 552 | vfSubscribe.assign(256, false); |
| 521 | 553 | ||
| 522 | // Push a version message | 554 | // Push a version message |