Projects : bitcoin : bitcoin_getblockindex_etc
1 | // Copyright (c) 2009-2010 Satoshi Nakamoto |
2 | // Copyright (c) 2009-2012 The Bitcoin developers |
3 | // Distributed under the MIT/X11 software license, see the accompanying |
4 | // file license.txt or http://www.opensource.org/licenses/mit-license.php. |
5 | #ifndef BITCOIN_NET_H |
6 | #define BITCOIN_NET_H |
7 | |
8 | #include <deque> |
9 | #include <boost/array.hpp> |
10 | #include <boost/foreach.hpp> |
11 | #include <openssl/rand.h> |
12 | |
13 | #include "protocol.h" |
14 | |
15 | class CAddrDB; |
16 | class CRequestTracker; |
17 | class CNode; |
18 | class CBlockIndex; |
19 | extern int nBestHeight; |
20 | extern int nConnectTimeout; |
21 | |
22 | |
23 | |
24 | inline unsigned int ReceiveBufferSize() { return 1000*GetArg("-maxreceivebuffer", 10*1000); } |
25 | inline unsigned int SendBufferSize() { return 1000*GetArg("-maxsendbuffer", 10*1000); } |
26 | static const unsigned int PUBLISH_HOPS = 5; |
27 | |
28 | bool ConnectSocket(const CAddress& addrConnect, SOCKET& hSocketRet, int nTimeout=nConnectTimeout); |
29 | bool Lookup(const char *pszName, std::vector<CAddress>& vaddr, int nServices, int nMaxSolutions, int portDefault = 0, bool fAllowPort = false); |
30 | bool Lookup(const char *pszName, CAddress& addr, int nServices, int portDefault = 0, bool fAllowPort = false); |
31 | bool AddAddress(CAddress addr, int64 nTimePenalty=0, CAddrDB *pAddrDB=NULL); |
32 | void AddressCurrentlyConnected(const CAddress& addr); |
33 | CNode* FindNode(unsigned int ip); |
34 | CNode* ConnectNode(CAddress addrConnect, int64 nTimeout=0); |
35 | void AbandonRequests(void (*fn)(void*, CDataStream&), void* param1); |
36 | bool AnySubscribed(unsigned int nChannel); |
37 | void MapPort(bool fMapPort); |
38 | bool BindListenPort(std::string& strError=REF(std::string())); |
39 | void StartNode(void* parg); |
40 | bool StopNode(); |
41 | |
42 | enum |
43 | { |
44 | MSG_TX = 1, |
45 | MSG_BLOCK, |
46 | }; |
47 | |
48 | class CRequestTracker |
49 | { |
50 | public: |
51 | void (*fn)(void*, CDataStream&); |
52 | void* param1; |
53 | |
54 | explicit CRequestTracker(void (*fnIn)(void*, CDataStream&)=NULL, void* param1In=NULL) |
55 | { |
56 | fn = fnIn; |
57 | param1 = param1In; |
58 | } |
59 | |
60 | bool IsNull() |
61 | { |
62 | return fn == NULL; |
63 | } |
64 | }; |
65 | |
66 | |
67 | |
68 | |
69 | |
70 | extern bool fClient; |
71 | extern bool fAllowDNS; |
72 | extern uint64 nLocalServices; |
73 | extern CAddress addrLocalHost; |
74 | extern uint64 nLocalHostNonce; |
75 | extern boost::array<int, 10> vnThreadsRunning; |
76 | |
77 | extern std::vector<CNode*> vNodes; |
78 | extern CCriticalSection cs_vNodes; |
79 | extern std::map<std::vector<unsigned char>, CAddress> mapAddresses; |
80 | extern CCriticalSection cs_mapAddresses; |
81 | extern std::map<CInv, CDataStream> mapRelay; |
82 | extern std::deque<std::pair<int64, CInv> > vRelayExpiration; |
83 | extern CCriticalSection cs_mapRelay; |
84 | extern std::map<CInv, int64> mapAlreadyAskedFor; |
85 | |
86 | // Settings |
87 | extern int fUseProxy; |
88 | extern CAddress addrProxy; |
89 | |
90 | |
91 | |
92 | |
93 | |
94 | |
95 | class CNode |
96 | { |
97 | public: |
98 | // socket |
99 | uint64 nServices; |
100 | SOCKET hSocket; |
101 | CDataStream vSend; |
102 | CDataStream vRecv; |
103 | CCriticalSection cs_vSend; |
104 | CCriticalSection cs_vRecv; |
105 | int64 nLastSend; |
106 | int64 nLastRecv; |
107 | int64 nLastSendEmpty; |
108 | int64 nTimeConnected; |
109 | unsigned int nHeaderStart; |
110 | unsigned int nMessageStart; |
111 | CAddress addr; |
112 | int nVersion; |
113 | std::string strSubVer; |
114 | bool fClient; |
115 | bool fInbound; |
116 | bool fNetworkNode; |
117 | bool fSuccessfullyConnected; |
118 | bool fDisconnect; |
119 | protected: |
120 | int nRefCount; |
121 | |
122 | // Denial-of-service detection/prevention |
123 | // Key is ip address, value is banned-until-time |
124 | static std::map<unsigned int, int64> setBanned; |
125 | static CCriticalSection cs_setBanned; |
126 | int nMisbehavior; |
127 | |
128 | public: |
129 | int64 nReleaseTime; |
130 | std::map<uint256, CRequestTracker> mapRequests; |
131 | CCriticalSection cs_mapRequests; |
132 | uint256 hashContinue; |
133 | int nStartingHeight; |
134 | |
135 | // flood relay |
136 | std::vector<CAddress> vAddrToSend; |
137 | std::set<CAddress> setAddrKnown; |
138 | bool fGetAddr; |
139 | std::set<uint256> setKnown; |
140 | |
141 | // inventory based relay |
142 | std::set<CInv> setInventoryKnown; |
143 | std::vector<CInv> vInventoryToSend; |
144 | CCriticalSection cs_inventory; |
145 | std::multimap<int64, CInv> mapAskFor; |
146 | |
147 | // publish and subscription |
148 | std::vector<char> vfSubscribe; |
149 | |
150 | CNode(SOCKET hSocketIn, CAddress addrIn, bool fInboundIn=false) |
151 | { |
152 | nServices = 0; |
153 | hSocket = hSocketIn; |
154 | vSend.SetType(SER_NETWORK); |
155 | vSend.SetVersion(0); |
156 | vRecv.SetType(SER_NETWORK); |
157 | vRecv.SetVersion(0); |
158 | // Version 0.2 obsoletes 20 Feb 2012 |
159 | if (GetTime() > 1329696000) |
160 | { |
161 | vSend.SetVersion(209); |
162 | vRecv.SetVersion(209); |
163 | } |
164 | nLastSend = 0; |
165 | nLastRecv = 0; |
166 | nLastSendEmpty = GetTime(); |
167 | nTimeConnected = GetTime(); |
168 | nHeaderStart = -1; |
169 | nMessageStart = -1; |
170 | addr = addrIn; |
171 | nVersion = 0; |
172 | strSubVer = ""; |
173 | fClient = false; // set by version message |
174 | fInbound = fInboundIn; |
175 | fNetworkNode = false; |
176 | fSuccessfullyConnected = false; |
177 | fDisconnect = false; |
178 | nRefCount = 0; |
179 | nReleaseTime = 0; |
180 | hashContinue = 0; |
181 | nStartingHeight = -1; |
182 | fGetAddr = false; |
183 | vfSubscribe.assign(256, false); |
184 | nMisbehavior = 0; |
185 | |
186 | // Be shy and don't send version until we hear |
187 | if (!fInbound) |
188 | PushVersion(); |
189 | } |
190 | |
191 | ~CNode() |
192 | { |
193 | if (hSocket != INVALID_SOCKET) |
194 | { |
195 | closesocket(hSocket); |
196 | hSocket = INVALID_SOCKET; |
197 | } |
198 | } |
199 | |
200 | private: |
201 | CNode(const CNode&); |
202 | void operator=(const CNode&); |
203 | public: |
204 | |
205 | |
206 | int GetRefCount() |
207 | { |
208 | return std::max(nRefCount, 0) + (GetTime() < nReleaseTime ? 1 : 0); |
209 | } |
210 | |
211 | CNode* AddRef(int64 nTimeout=0) |
212 | { |
213 | if (nTimeout != 0) |
214 | nReleaseTime = std::max(nReleaseTime, GetTime() + nTimeout); |
215 | else |
216 | nRefCount++; |
217 | return this; |
218 | } |
219 | |
220 | void Release() |
221 | { |
222 | nRefCount--; |
223 | } |
224 | |
225 | |
226 | |
227 | void AddAddressKnown(const CAddress& addr) |
228 | { |
229 | setAddrKnown.insert(addr); |
230 | } |
231 | |
232 | void PushAddress(const CAddress& addr) |
233 | { |
234 | // Known checking here is only to save space from duplicates. |
235 | // SendMessages will filter it again for knowns that were added |
236 | // after addresses were pushed. |
237 | if (addr.IsValid() && !setAddrKnown.count(addr)) |
238 | vAddrToSend.push_back(addr); |
239 | } |
240 | |
241 | |
242 | void AddInventoryKnown(const CInv& inv) |
243 | { |
244 | CRITICAL_BLOCK(cs_inventory) |
245 | setInventoryKnown.insert(inv); |
246 | } |
247 | |
248 | void PushInventory(const CInv& inv) |
249 | { |
250 | CRITICAL_BLOCK(cs_inventory) |
251 | if (!setInventoryKnown.count(inv)) |
252 | vInventoryToSend.push_back(inv); |
253 | } |
254 | |
255 | void AskFor(const CInv& inv) |
256 | { |
257 | // We're using mapAskFor as a priority queue, |
258 | // the key is the earliest time the request can be sent |
259 | int64& nRequestTime = mapAlreadyAskedFor[inv]; |
260 | printf("askfor %s %"PRI64d"\n", inv.ToString().c_str(), nRequestTime); |
261 | |
262 | // Make sure not to reuse time indexes to keep things in the same order |
263 | int64 nNow = (GetTime() - 1) * 1000000; |
264 | static int64 nLastTime; |
265 | ++nLastTime; |
266 | nNow = std::max(nNow, nLastTime); |
267 | nLastTime = nNow; |
268 | |
269 | // Each retry is 2 minutes after the last |
270 | nRequestTime = std::max(nRequestTime + 2 * 60 * 1000000, nNow); |
271 | mapAskFor.insert(std::make_pair(nRequestTime, inv)); |
272 | } |
273 | |
274 | |
275 | |
276 | void BeginMessage(const char* pszCommand) |
277 | { |
278 | ENTER_CRITICAL_SECTION(cs_vSend); |
279 | if (nHeaderStart != -1) |
280 | AbortMessage(); |
281 | nHeaderStart = vSend.size(); |
282 | vSend << CMessageHeader(pszCommand, 0); |
283 | nMessageStart = vSend.size(); |
284 | if (fDebug) { |
285 | printf("%s ", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str()); |
286 | printf("sending: %s ", pszCommand); |
287 | } |
288 | } |
289 | |
290 | void AbortMessage() |
291 | { |
292 | if (nHeaderStart == -1) |
293 | return; |
294 | vSend.resize(nHeaderStart); |
295 | nHeaderStart = -1; |
296 | nMessageStart = -1; |
297 | LEAVE_CRITICAL_SECTION(cs_vSend); |
298 | |
299 | if (fDebug) |
300 | printf("(aborted)\n"); |
301 | } |
302 | |
303 | void EndMessage() |
304 | { |
305 | if (mapArgs.count("-dropmessagestest") && GetRand(atoi(mapArgs["-dropmessagestest"])) == 0) |
306 | { |
307 | printf("dropmessages DROPPING SEND MESSAGE\n"); |
308 | AbortMessage(); |
309 | return; |
310 | } |
311 | |
312 | if (nHeaderStart == -1) |
313 | return; |
314 | |
315 | // Set the size |
316 | unsigned int nSize = vSend.size() - nMessageStart; |
317 | memcpy((char*)&vSend[nHeaderStart] + offsetof(CMessageHeader, nMessageSize), &nSize, sizeof(nSize)); |
318 | |
319 | // Set the checksum |
320 | if (vSend.GetVersion() >= 209) |
321 | { |
322 | uint256 hash = Hash(vSend.begin() + nMessageStart, vSend.end()); |
323 | unsigned int nChecksum = 0; |
324 | memcpy(&nChecksum, &hash, sizeof(nChecksum)); |
325 | assert(nMessageStart - nHeaderStart >= offsetof(CMessageHeader, nChecksum) + sizeof(nChecksum)); |
326 | memcpy((char*)&vSend[nHeaderStart] + offsetof(CMessageHeader, nChecksum), &nChecksum, sizeof(nChecksum)); |
327 | } |
328 | |
329 | if (fDebug) { |
330 | printf("(%d bytes)\n", nSize); |
331 | } |
332 | |
333 | nHeaderStart = -1; |
334 | nMessageStart = -1; |
335 | LEAVE_CRITICAL_SECTION(cs_vSend); |
336 | } |
337 | |
338 | void EndMessageAbortIfEmpty() |
339 | { |
340 | if (nHeaderStart == -1) |
341 | return; |
342 | int nSize = vSend.size() - nMessageStart; |
343 | if (nSize > 0) |
344 | EndMessage(); |
345 | else |
346 | AbortMessage(); |
347 | } |
348 | |
349 | |
350 | |
351 | void PushVersion() |
352 | { |
353 | /// when NTP implemented, change to just nTime = GetAdjustedTime() |
354 | int64 nTime = (fInbound ? GetAdjustedTime() : GetTime()); |
355 | CAddress addrYou = (fUseProxy ? CAddress("0.0.0.0") : addr); |
356 | CAddress addrMe = (fUseProxy || !addrLocalHost.IsRoutable() ? CAddress("0.0.0.0") : addrLocalHost); |
357 | RAND_bytes((unsigned char*)&nLocalHostNonce, sizeof(nLocalHostNonce)); |
358 | PushMessage("version", VERSION, nLocalServices, nTime, addrYou, addrMe, |
359 | nLocalHostNonce, FormatSubVersion(CLIENT_NAME, VERSION), nBestHeight); |
360 | } |
361 | |
362 | |
363 | |
364 | |
365 | void PushMessage(const char* pszCommand) |
366 | { |
367 | try |
368 | { |
369 | BeginMessage(pszCommand); |
370 | EndMessage(); |
371 | } |
372 | catch (...) |
373 | { |
374 | AbortMessage(); |
375 | throw; |
376 | } |
377 | } |
378 | |
379 | template<typename T1> |
380 | void PushMessage(const char* pszCommand, const T1& a1) |
381 | { |
382 | try |
383 | { |
384 | BeginMessage(pszCommand); |
385 | vSend << a1; |
386 | EndMessage(); |
387 | } |
388 | catch (...) |
389 | { |
390 | AbortMessage(); |
391 | throw; |
392 | } |
393 | } |
394 | |
395 | template<typename T1, typename T2> |
396 | void PushMessage(const char* pszCommand, const T1& a1, const T2& a2) |
397 | { |
398 | try |
399 | { |
400 | BeginMessage(pszCommand); |
401 | vSend << a1 << a2; |
402 | EndMessage(); |
403 | } |
404 | catch (...) |
405 | { |
406 | AbortMessage(); |
407 | throw; |
408 | } |
409 | } |
410 | |
411 | template<typename T1, typename T2, typename T3> |
412 | void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3) |
413 | { |
414 | try |
415 | { |
416 | BeginMessage(pszCommand); |
417 | vSend << a1 << a2 << a3; |
418 | EndMessage(); |
419 | } |
420 | catch (...) |
421 | { |
422 | AbortMessage(); |
423 | throw; |
424 | } |
425 | } |
426 | |
427 | template<typename T1, typename T2, typename T3, typename T4> |
428 | void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4) |
429 | { |
430 | try |
431 | { |
432 | BeginMessage(pszCommand); |
433 | vSend << a1 << a2 << a3 << a4; |
434 | EndMessage(); |
435 | } |
436 | catch (...) |
437 | { |
438 | AbortMessage(); |
439 | throw; |
440 | } |
441 | } |
442 | |
443 | template<typename T1, typename T2, typename T3, typename T4, typename T5> |
444 | void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4, const T5& a5) |
445 | { |
446 | try |
447 | { |
448 | BeginMessage(pszCommand); |
449 | vSend << a1 << a2 << a3 << a4 << a5; |
450 | EndMessage(); |
451 | } |
452 | catch (...) |
453 | { |
454 | AbortMessage(); |
455 | throw; |
456 | } |
457 | } |
458 | |
459 | template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6> |
460 | void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4, const T5& a5, const T6& a6) |
461 | { |
462 | try |
463 | { |
464 | BeginMessage(pszCommand); |
465 | vSend << a1 << a2 << a3 << a4 << a5 << a6; |
466 | EndMessage(); |
467 | } |
468 | catch (...) |
469 | { |
470 | AbortMessage(); |
471 | throw; |
472 | } |
473 | } |
474 | |
475 | template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7> |
476 | void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4, const T5& a5, const T6& a6, const T7& a7) |
477 | { |
478 | try |
479 | { |
480 | BeginMessage(pszCommand); |
481 | vSend << a1 << a2 << a3 << a4 << a5 << a6 << a7; |
482 | EndMessage(); |
483 | } |
484 | catch (...) |
485 | { |
486 | AbortMessage(); |
487 | throw; |
488 | } |
489 | } |
490 | |
491 | template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8> |
492 | void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4, const T5& a5, const T6& a6, const T7& a7, const T8& a8) |
493 | { |
494 | try |
495 | { |
496 | BeginMessage(pszCommand); |
497 | vSend << a1 << a2 << a3 << a4 << a5 << a6 << a7 << a8; |
498 | EndMessage(); |
499 | } |
500 | catch (...) |
501 | { |
502 | AbortMessage(); |
503 | throw; |
504 | } |
505 | } |
506 | |
507 | template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9> |
508 | void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4, const T5& a5, const T6& a6, const T7& a7, const T8& a8, const T9& a9) |
509 | { |
510 | try |
511 | { |
512 | BeginMessage(pszCommand); |
513 | vSend << a1 << a2 << a3 << a4 << a5 << a6 << a7 << a8 << a9; |
514 | EndMessage(); |
515 | } |
516 | catch (...) |
517 | { |
518 | AbortMessage(); |
519 | throw; |
520 | } |
521 | } |
522 | |
523 | |
524 | void PushRequest(const char* pszCommand, |
525 | void (*fn)(void*, CDataStream&), void* param1) |
526 | { |
527 | uint256 hashReply; |
528 | RAND_bytes((unsigned char*)&hashReply, sizeof(hashReply)); |
529 | |
530 | CRITICAL_BLOCK(cs_mapRequests) |
531 | mapRequests[hashReply] = CRequestTracker(fn, param1); |
532 | |
533 | PushMessage(pszCommand, hashReply); |
534 | } |
535 | |
536 | template<typename T1> |
537 | void PushRequest(const char* pszCommand, const T1& a1, |
538 | void (*fn)(void*, CDataStream&), void* param1) |
539 | { |
540 | uint256 hashReply; |
541 | RAND_bytes((unsigned char*)&hashReply, sizeof(hashReply)); |
542 | |
543 | CRITICAL_BLOCK(cs_mapRequests) |
544 | mapRequests[hashReply] = CRequestTracker(fn, param1); |
545 | |
546 | PushMessage(pszCommand, hashReply, a1); |
547 | } |
548 | |
549 | template<typename T1, typename T2> |
550 | void PushRequest(const char* pszCommand, const T1& a1, const T2& a2, |
551 | void (*fn)(void*, CDataStream&), void* param1) |
552 | { |
553 | uint256 hashReply; |
554 | RAND_bytes((unsigned char*)&hashReply, sizeof(hashReply)); |
555 | |
556 | CRITICAL_BLOCK(cs_mapRequests) |
557 | mapRequests[hashReply] = CRequestTracker(fn, param1); |
558 | |
559 | PushMessage(pszCommand, hashReply, a1, a2); |
560 | } |
561 | |
562 | |
563 | |
564 | void PushGetBlocks(CBlockIndex* pindexBegin, uint256 hashEnd); |
565 | bool IsSubscribed(unsigned int nChannel); |
566 | void Subscribe(unsigned int nChannel, unsigned int nHops=0); |
567 | void CancelSubscribe(unsigned int nChannel); |
568 | void CloseSocketDisconnect(); |
569 | void Cleanup(); |
570 | |
571 | |
572 | // Denial-of-service detection/prevention |
573 | // The idea is to detect peers that are behaving |
574 | // badly and disconnect/ban them, but do it in a |
575 | // one-coding-mistake-won't-shatter-the-entire-network |
576 | // way. |
577 | // IMPORTANT: There should be nothing I can give a |
578 | // node that it will forward on that will make that |
579 | // node's peers drop it. If there is, an attacker |
580 | // can isolate a node and/or try to split the network. |
581 | // Dropping a node for sending stuff that is invalid |
582 | // now but might be valid in a later version is also |
583 | // dangerous, because it can cause a network split |
584 | // between nodes running old code and nodes running |
585 | // new code. |
586 | static void ClearBanned(); // needed for unit testing |
587 | static bool IsBanned(unsigned int ip); |
588 | bool Misbehaving(int howmuch); // 1 == a little, 100 == a lot |
589 | }; |
590 | |
591 | |
592 | |
593 | |
594 | |
595 | |
596 | |
597 | |
598 | |
599 | |
600 | inline void RelayInventory(const CInv& inv) |
601 | { |
602 | // Put on lists to offer to the other nodes |
603 | CRITICAL_BLOCK(cs_vNodes) |
604 | BOOST_FOREACH(CNode* pnode, vNodes) |
605 | pnode->PushInventory(inv); |
606 | } |
607 | |
608 | template<typename T> |
609 | void RelayMessage(const CInv& inv, const T& a) |
610 | { |
611 | CDataStream ss(SER_NETWORK); |
612 | ss.reserve(10000); |
613 | ss << a; |
614 | RelayMessage(inv, ss); |
615 | } |
616 | |
617 | template<> |
618 | inline void RelayMessage<>(const CInv& inv, const CDataStream& ss) |
619 | { |
620 | CRITICAL_BLOCK(cs_mapRelay) |
621 | { |
622 | // Expire old relay messages |
623 | while (!vRelayExpiration.empty() && vRelayExpiration.front().first < GetTime()) |
624 | { |
625 | mapRelay.erase(vRelayExpiration.front().second); |
626 | vRelayExpiration.pop_front(); |
627 | } |
628 | |
629 | // Save original serialized message so newer versions are preserved |
630 | mapRelay[inv] = ss; |
631 | vRelayExpiration.push_back(std::make_pair(GetTime() + 15 * 60, inv)); |
632 | } |
633 | |
634 | RelayInventory(inv); |
635 | } |
636 | |
637 | |
638 | |
639 | |
640 | |
641 | |
642 | |
643 | |
644 | // |
645 | // Templates for the publish and subscription system. |
646 | // The object being published as T& obj needs to have: |
647 | // a set<unsigned int> setSources member |
648 | // specializations of AdvertInsert and AdvertErase |
649 | // Currently implemented for CTable and CProduct. |
650 | // |
651 | |
652 | template<typename T> |
653 | void AdvertStartPublish(CNode* pfrom, unsigned int nChannel, unsigned int nHops, T& obj) |
654 | { |
655 | // Add to sources |
656 | obj.setSources.insert(pfrom->addr.ip); |
657 | |
658 | if (!AdvertInsert(obj)) |
659 | return; |
660 | |
661 | // Relay |
662 | CRITICAL_BLOCK(cs_vNodes) |
663 | BOOST_FOREACH(CNode* pnode, vNodes) |
664 | if (pnode != pfrom && (nHops < PUBLISH_HOPS || pnode->IsSubscribed(nChannel))) |
665 | pnode->PushMessage("publish", nChannel, nHops, obj); |
666 | } |
667 | |
668 | template<typename T> |
669 | void AdvertStopPublish(CNode* pfrom, unsigned int nChannel, unsigned int nHops, T& obj) |
670 | { |
671 | uint256 hash = obj.GetHash(); |
672 | |
673 | CRITICAL_BLOCK(cs_vNodes) |
674 | BOOST_FOREACH(CNode* pnode, vNodes) |
675 | if (pnode != pfrom && (nHops < PUBLISH_HOPS || pnode->IsSubscribed(nChannel))) |
676 | pnode->PushMessage("pub-cancel", nChannel, nHops, hash); |
677 | |
678 | AdvertErase(obj); |
679 | } |
680 | |
681 | template<typename T> |
682 | void AdvertRemoveSource(CNode* pfrom, unsigned int nChannel, unsigned int nHops, T& obj) |
683 | { |
684 | // Remove a source |
685 | obj.setSources.erase(pfrom->addr.ip); |
686 | |
687 | // If no longer supported by any sources, cancel it |
688 | if (obj.setSources.empty()) |
689 | AdvertStopPublish(pfrom, nChannel, nHops, obj); |
690 | } |
691 | |
692 | #endif |