Add -keepnode which attempts to -addnode and keep a connection open
[novacoin.git] / src / netbase.cpp
1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2011 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
6 #include "netbase.h"
7 #include "util.h"
8
9 #ifndef WIN32
10 #include <sys/fcntl.h>
11 #endif
12
13 #include "strlcpy.h"
14
15 using namespace std;
16
17 // Settings
18 int fUseProxy = false;
19 CService addrProxy("127.0.0.1",9050);
20 int nConnectTimeout = 5000;
21
22
23 static const unsigned char pchIPv4[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff };
24
25 bool static LookupIntern(const char *pszName, std::vector<CNetAddr>& vIP, int nMaxSolutions, bool fAllowLookup)
26 {
27     vIP.clear();
28     struct addrinfo aiHint = {};
29     aiHint.ai_socktype = SOCK_STREAM;
30     aiHint.ai_protocol = IPPROTO_TCP;
31 #ifdef WIN32
32 #  ifdef USE_IPV6
33     aiHint.ai_family = AF_UNSPEC;
34     aiHint.ai_flags = fAllowLookup ? 0 : AI_NUMERICHOST;
35 #  else
36     aiHint.ai_family = AF_INET;
37     aiHint.ai_flags = fAllowLookup ? 0 : AI_NUMERICHOST;
38 #  endif
39 #else
40 #  ifdef USE_IPV6
41     aiHint.ai_family = AF_UNSPEC;
42     aiHint.ai_flags = AI_ADDRCONFIG | (fAllowLookup ? 0 : AI_NUMERICHOST);
43 #  else
44     aiHint.ai_family = AF_INET;
45     aiHint.ai_flags = AI_ADDRCONFIG | (fAllowLookup ? 0 : AI_NUMERICHOST);
46 #  endif
47 #endif
48     struct addrinfo *aiRes = NULL;
49     int nErr = getaddrinfo(pszName, NULL, &aiHint, &aiRes);
50     if (nErr)
51         return false;
52
53     struct addrinfo *aiTrav = aiRes;
54     while (aiTrav != NULL && (nMaxSolutions == 0 || vIP.size() < nMaxSolutions))
55     {
56         if (aiTrav->ai_family == AF_INET)
57         {
58             assert(aiTrav->ai_addrlen >= sizeof(sockaddr_in));
59             vIP.push_back(CNetAddr(((struct sockaddr_in*)(aiTrav->ai_addr))->sin_addr));
60         }
61
62 #ifdef USE_IPV6
63         if (aiTrav->ai_family == AF_INET6)
64         {
65             assert(aiTrav->ai_addrlen >= sizeof(sockaddr_in6));
66             vIP.push_back(CNetAddr(((struct sockaddr_in6*)(aiTrav->ai_addr))->sin6_addr));
67         }
68 #endif
69
70         aiTrav = aiTrav->ai_next;
71     }
72
73     freeaddrinfo(aiRes);
74
75     return (vIP.size() > 0);
76 }
77
78 bool LookupHost(const char *pszName, std::vector<CNetAddr>& vIP, int nMaxSolutions, bool fAllowLookup)
79 {
80     if (pszName[0] == 0)
81         return false;
82     char psz[256];
83     char *pszHost = psz;
84     strlcpy(psz, pszName, sizeof(psz));
85     if (psz[0] == '[' && psz[strlen(psz)-1] == ']')
86     {
87         pszHost = psz+1;
88         psz[strlen(psz)-1] = 0;
89     }
90
91     return LookupIntern(pszHost, vIP, nMaxSolutions, fAllowLookup);
92 }
93
94 bool LookupHostNumeric(const char *pszName, std::vector<CNetAddr>& vIP, int nMaxSolutions)
95 {
96     return LookupHost(pszName, vIP, nMaxSolutions, false);
97 }
98
99 bool Lookup(const char *pszName, std::vector<CService>& vAddr, int portDefault, bool fAllowLookup, int nMaxSolutions)
100 {
101     if (pszName[0] == 0)
102         return false;
103     int port = portDefault;
104     char psz[256];
105     char *pszHost = psz;
106     strlcpy(psz, pszName, sizeof(psz));
107     char* pszColon = strrchr(psz+1,':');
108     char *pszPortEnd = NULL;
109     int portParsed = pszColon ? strtoul(pszColon+1, &pszPortEnd, 10) : 0;
110     if (pszColon && pszPortEnd && pszPortEnd[0] == 0)
111     {
112         if (psz[0] == '[' && pszColon[-1] == ']')
113         {
114             pszHost = psz+1;
115             pszColon[-1] = 0;
116         }
117         else
118             pszColon[0] = 0;
119         if (port >= 0 && port <= USHRT_MAX)
120             port = portParsed;
121     }
122     else
123     {
124         if (psz[0] == '[' && psz[strlen(psz)-1] == ']')
125         {
126             pszHost = psz+1;
127             psz[strlen(psz)-1] = 0;
128         }
129
130     }
131
132     std::vector<CNetAddr> vIP;
133     bool fRet = LookupIntern(pszHost, vIP, nMaxSolutions, fAllowLookup);
134     if (!fRet)
135         return false;
136     vAddr.resize(vIP.size());
137     for (int i = 0; i < vIP.size(); i++)
138         vAddr[i] = CService(vIP[i], port);
139     return true;
140 }
141
142 bool Lookup(const char *pszName, CService& addr, int portDefault, bool fAllowLookup)
143 {
144     std::vector<CService> vService;
145     bool fRet = Lookup(pszName, vService, portDefault, fAllowLookup, 1);
146     if (!fRet)
147         return false;
148     addr = vService[0];
149     return true;
150 }
151
152 bool LookupNumeric(const char *pszName, CService& addr, int portDefault)
153 {
154     return Lookup(pszName, addr, portDefault, false);
155 }
156
157 bool ConnectSocket(const CService &addrDest, SOCKET& hSocketRet, int nTimeout)
158 {
159     hSocketRet = INVALID_SOCKET;
160
161     SOCKET hSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
162     if (hSocket == INVALID_SOCKET)
163         return false;
164 #ifdef SO_NOSIGPIPE
165     int set = 1;
166     setsockopt(hSocket, SOL_SOCKET, SO_NOSIGPIPE, (void*)&set, sizeof(int));
167 #endif
168
169     bool fProxy = (fUseProxy && addrDest.IsRoutable());
170     struct sockaddr_in sockaddr;
171     if (fProxy)
172         addrProxy.GetSockAddr(&sockaddr);
173     else
174         addrDest.GetSockAddr(&sockaddr);
175
176 #ifdef WIN32
177     u_long fNonblock = 1;
178     if (ioctlsocket(hSocket, FIONBIO, &fNonblock) == SOCKET_ERROR)
179 #else
180     int fFlags = fcntl(hSocket, F_GETFL, 0);
181     if (fcntl(hSocket, F_SETFL, fFlags | O_NONBLOCK) == -1)
182 #endif
183     {
184         closesocket(hSocket);
185         return false;
186     }
187
188
189     if (connect(hSocket, (struct sockaddr*)&sockaddr, sizeof(sockaddr)) == SOCKET_ERROR)
190     {
191         // WSAEINVAL is here because some legacy version of winsock uses it
192         if (WSAGetLastError() == WSAEINPROGRESS || WSAGetLastError() == WSAEWOULDBLOCK || WSAGetLastError() == WSAEINVAL)
193         {
194             struct timeval timeout;
195             timeout.tv_sec  = nTimeout / 1000;
196             timeout.tv_usec = (nTimeout % 1000) * 1000;
197
198             fd_set fdset;
199             FD_ZERO(&fdset);
200             FD_SET(hSocket, &fdset);
201             int nRet = select(hSocket + 1, NULL, &fdset, NULL, &timeout);
202             if (nRet == 0)
203             {
204                 printf("connection timeout\n");
205                 closesocket(hSocket);
206                 return false;
207             }
208             if (nRet == SOCKET_ERROR)
209             {
210                 printf("select() for connection failed: %i\n",WSAGetLastError());
211                 closesocket(hSocket);
212                 return false;
213             }
214             socklen_t nRetSize = sizeof(nRet);
215 #ifdef WIN32
216             if (getsockopt(hSocket, SOL_SOCKET, SO_ERROR, (char*)(&nRet), &nRetSize) == SOCKET_ERROR)
217 #else
218             if (getsockopt(hSocket, SOL_SOCKET, SO_ERROR, &nRet, &nRetSize) == SOCKET_ERROR)
219 #endif
220             {
221                 printf("getsockopt() for connection failed: %i\n",WSAGetLastError());
222                 closesocket(hSocket);
223                 return false;
224             }
225             if (nRet != 0)
226             {
227                 printf("connect() failed after select(): %s\n",strerror(nRet));
228                 closesocket(hSocket);
229                 return false;
230             }
231         }
232 #ifdef WIN32
233         else if (WSAGetLastError() != WSAEISCONN)
234 #else
235         else
236 #endif
237         {
238             printf("connect() failed: %i\n",WSAGetLastError());
239             closesocket(hSocket);
240             return false;
241         }
242     }
243
244     // this isn't even strictly necessary
245     // CNode::ConnectNode immediately turns the socket back to non-blocking
246     // but we'll turn it back to blocking just in case
247 #ifdef WIN32
248     fNonblock = 0;
249     if (ioctlsocket(hSocket, FIONBIO, &fNonblock) == SOCKET_ERROR)
250 #else
251     fFlags = fcntl(hSocket, F_GETFL, 0);
252     if (fcntl(hSocket, F_SETFL, fFlags & !O_NONBLOCK) == SOCKET_ERROR)
253 #endif
254     {
255         closesocket(hSocket);
256         return false;
257     }
258
259     if (fProxy)
260     {
261         printf("proxy connecting %s\n", addrDest.ToString().c_str());
262         char pszSocks4IP[] = "\4\1\0\0\0\0\0\0user";
263         struct sockaddr_in addr;
264         addrDest.GetSockAddr(&addr);
265         memcpy(pszSocks4IP + 2, &addr.sin_port, 2);
266         memcpy(pszSocks4IP + 4, &addr.sin_addr, 4);
267         char* pszSocks4 = pszSocks4IP;
268         int nSize = sizeof(pszSocks4IP);
269
270         int ret = send(hSocket, pszSocks4, nSize, MSG_NOSIGNAL);
271         if (ret != nSize)
272         {
273             closesocket(hSocket);
274             return error("Error sending to proxy");
275         }
276         char pchRet[8];
277         if (recv(hSocket, pchRet, 8, 0) != 8)
278         {
279             closesocket(hSocket);
280             return error("Error reading proxy response");
281         }
282         if (pchRet[1] != 0x5a)
283         {
284             closesocket(hSocket);
285             if (pchRet[1] != 0x5b)
286                 printf("ERROR: Proxy returned error %d\n", pchRet[1]);
287             return false;
288         }
289         printf("proxy connected %s\n", addrDest.ToString().c_str());
290     }
291
292     hSocketRet = hSocket;
293     return true;
294 }
295
296 void CNetAddr::Init()
297 {
298     memset(ip, 0, 16);
299 }
300
301 void CNetAddr::SetIP(const CNetAddr& ipIn)
302 {
303     memcpy(ip, ipIn.ip, sizeof(ip));
304 }
305
306 CNetAddr::CNetAddr()
307 {
308     Init();
309 }
310
311 CNetAddr::CNetAddr(const struct in_addr& ipv4Addr)
312 {
313     memcpy(ip,    pchIPv4, 12);
314     memcpy(ip+12, &ipv4Addr, 4);
315 }
316
317 #ifdef USE_IPV6
318 CNetAddr::CNetAddr(const struct in6_addr& ipv6Addr)
319 {
320     memcpy(ip, &ipv6Addr, 16);
321 }
322 #endif
323
324 CNetAddr::CNetAddr(const char *pszIp, bool fAllowLookup)
325 {
326     Init();
327     std::vector<CNetAddr> vIP;
328     if (LookupHost(pszIp, vIP, 1, fAllowLookup))
329         *this = vIP[0];
330 }
331
332 CNetAddr::CNetAddr(const std::string &strIp, bool fAllowLookup)
333 {
334     Init();
335     std::vector<CNetAddr> vIP;
336     if (LookupHost(strIp.c_str(), vIP, 1, fAllowLookup))
337         *this = vIP[0];
338 }
339
340 int CNetAddr::GetByte(int n) const
341 {
342     return ip[15-n];
343 }
344
345 bool CNetAddr::IsIPv4() const
346 {
347     return (memcmp(ip, pchIPv4, sizeof(pchIPv4)) == 0);
348 }
349
350 bool CNetAddr::IsRFC1918() const
351 {
352     return IsIPv4() && (
353         GetByte(3) == 10 || 
354         (GetByte(3) == 192 && GetByte(2) == 168) || 
355         (GetByte(3) == 172 && (GetByte(2) >= 16 && GetByte(2) <= 31)));
356 }
357
358 bool CNetAddr::IsRFC3927() const
359 {
360     return IsIPv4() && (GetByte(3) == 169 && GetByte(2) == 254);
361 }
362
363 bool CNetAddr::IsRFC3849() const
364 {
365     return GetByte(15) == 0x20 && GetByte(14) == 0x01 && GetByte(13) == 0x0D && GetByte(12) == 0xB8;
366 }
367
368 bool CNetAddr::IsRFC3964() const
369 {
370     return (GetByte(15) == 0x20 && GetByte(14) == 0x02);
371 }
372
373 bool CNetAddr::IsRFC6052() const
374 {
375     static const unsigned char pchRFC6052[] = {0,0x64,0xFF,0x9B,0,0,0,0,0,0,0,0};
376     return (memcmp(ip, pchRFC6052, sizeof(pchRFC6052)) == 0);
377 }
378
379 bool CNetAddr::IsRFC4380() const
380 {
381     return (GetByte(15) == 0x20 && GetByte(14) == 0x01 && GetByte(13) == 0 && GetByte(12) == 0);
382 }
383
384 bool CNetAddr::IsRFC4862() const
385 {
386     static const unsigned char pchRFC4862[] = {0xFE,0x80,0,0,0,0,0,0};
387     return (memcmp(ip, pchRFC4862, sizeof(pchRFC4862)) == 0);
388 }
389
390 bool CNetAddr::IsRFC4193() const
391 {
392     return ((GetByte(15) & 0xFE) == 0xFC);
393 }
394
395 bool CNetAddr::IsRFC6145() const
396 {
397     static const unsigned char pchRFC6145[] = {0,0,0,0,0,0,0,0,0xFF,0xFF,0,0};
398     return (memcmp(ip, pchRFC6145, sizeof(pchRFC6145)) == 0);
399 }
400
401 bool CNetAddr::IsRFC4843() const
402 {
403     return (GetByte(15) == 0x20 && GetByte(14) == 0x01 && GetByte(13) == 0x00 && GetByte(12) & 0xF0 == 0x10);
404 }
405
406 bool CNetAddr::IsLocal() const
407 {
408     // IPv4 loopback
409    if (IsIPv4() && (GetByte(3) == 127 || GetByte(3) == 0))
410        return true;
411
412    // IPv6 loopback (::1/128)
413    static const unsigned char pchLocal[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1};
414    if (memcmp(ip, pchLocal, 16) == 0)
415        return true;
416
417    return false;
418 }
419
420 bool CNetAddr::IsMulticast() const
421 {
422     return    (IsIPv4() && (GetByte(3) & 0xF0) == 0xE0)
423            || (GetByte(15) == 0xFF);
424 }
425
426 bool CNetAddr::IsValid() const
427 {
428     // Clean up 3-byte shifted addresses caused by garbage in size field
429     // of addr messages from versions before 0.2.9 checksum.
430     // Two consecutive addr messages look like this:
431     // header20 vectorlen3 addr26 addr26 addr26 header20 vectorlen3 addr26 addr26 addr26...
432     // so if the first length field is garbled, it reads the second batch
433     // of addr misaligned by 3 bytes.
434     if (memcmp(ip, pchIPv4+3, sizeof(pchIPv4)-3) == 0)
435         return false;
436
437     // unspecified IPv6 address (::/128)
438     unsigned char ipNone[16] = {};
439     if (memcmp(ip, ipNone, 16) == 0)
440         return false;
441
442     // documentation IPv6 address
443     if (IsRFC3849())
444         return false;
445
446     if (IsIPv4())
447     {
448         // INADDR_NONE
449         uint32_t ipNone = INADDR_NONE;
450         if (memcmp(ip+12, &ipNone, 4) == 0)
451             return false;
452
453         // 0
454         ipNone = 0;
455         if (memcmp(ip+12, &ipNone, 4) == 0)
456             return false;
457     }
458
459     return true;
460 }
461
462 bool CNetAddr::IsRoutable() const
463 {
464     return IsValid() && !(IsRFC1918() || IsRFC3927() || IsRFC4862() || IsRFC4193() || IsRFC4843() || IsLocal());
465 }
466
467 std::string CNetAddr::ToStringIP() const
468 {
469     if (IsIPv4())
470         return strprintf("%u.%u.%u.%u", GetByte(3), GetByte(2), GetByte(1), GetByte(0));
471     else
472         return strprintf("%x:%x:%x:%x:%x:%x:%x:%x",
473                          GetByte(15) << 8 | GetByte(14), GetByte(13) << 8 | GetByte(12),
474                          GetByte(11) << 8 | GetByte(10), GetByte(9) << 8 | GetByte(8),
475                          GetByte(7) << 8 | GetByte(6), GetByte(5) << 8 | GetByte(4),
476                          GetByte(3) << 8 | GetByte(2), GetByte(1) << 8 | GetByte(0));
477 }
478
479 std::string CNetAddr::ToString() const
480 {
481     return ToStringIP();
482 }
483
484 bool operator==(const CNetAddr& a, const CNetAddr& b)
485 {
486     return (memcmp(a.ip, b.ip, 16) == 0);
487 }
488
489 bool operator!=(const CNetAddr& a, const CNetAddr& b)
490 {
491     return (memcmp(a.ip, b.ip, 16) != 0);
492 }
493
494 bool operator<(const CNetAddr& a, const CNetAddr& b)
495 {
496     return (memcmp(a.ip, b.ip, 16) < 0);
497 }
498
499 bool CNetAddr::GetInAddr(struct in_addr* pipv4Addr) const
500 {
501     if (!IsIPv4())
502         return false;
503     memcpy(pipv4Addr, ip+12, 4);
504     return true;
505 }
506
507 #ifdef USE_IPV6
508 bool CNetAddr::GetIn6Addr(struct in6_addr* pipv6Addr) const
509 {
510     memcpy(pipv6Addr, ip, 16);
511     return true;
512 }
513 #endif
514
515 // get canonical identifier of an address' group
516 // no two connections will be attempted to addresses with the same group
517 std::vector<unsigned char> CNetAddr::GetGroup() const
518 {
519     std::vector<unsigned char> vchRet;
520     int nClass = 0; // 0=IPv6, 1=IPv4, 255=unroutable
521     int nStartByte = 0;
522     int nBits = 16;
523
524     // for unroutable addresses, each address is considered different
525     if (!IsRoutable())
526     {
527         nClass = 255;
528         nBits = 128;
529     }
530     // for IPv4 addresses, '1' + the 16 higher-order bits of the IP
531     // includes mapped IPv4, SIIT translated IPv4, and the well-known prefix
532     else if (IsIPv4() || IsRFC6145() || IsRFC6052())
533     {
534         nClass = 1;
535         nStartByte = 12;
536     }
537     // for 6to4 tunneled addresses, use the encapsulated IPv4 address
538     else if (IsRFC3964())
539     {
540         nClass = 1;
541         nStartByte = 2;
542     }
543     // for Teredo-tunneled IPv6 addresses, use the encapsulated IPv4 address
544     else if (IsRFC4380())
545     {
546         vchRet.push_back(1);
547         vchRet.push_back(GetByte(3) ^ 0xFF);
548         vchRet.push_back(GetByte(2) ^ 0xFF);
549         return vchRet;
550     }
551     // for he.net, use /36 groups
552     else if (GetByte(15) == 0x20 && GetByte(14) == 0x11 && GetByte(13) == 0x04 && GetByte(12) == 0x70)
553         nBits = 36;
554     // for the rest of the IPv6 network, use /32 groups
555     else
556         nBits = 32;
557
558     vchRet.push_back(nClass);
559     while (nBits >= 8)
560     {
561         vchRet.push_back(GetByte(15 - nStartByte));
562         nStartByte++;
563         nBits -= 8;
564     }
565     if (nBits > 0)
566         vchRet.push_back(GetByte(15 - nStartByte) | ((1 << nBits) - 1));
567
568     return vchRet;
569 }
570
571 int64 CNetAddr::GetHash() const
572 {
573     uint256 hash = Hash(&ip[0], &ip[16]);
574     int64 nRet;
575     memcpy(&nRet, &hash, sizeof(nRet));
576     return nRet;
577 }
578
579 void CNetAddr::print() const
580 {
581     printf("CNetAddr(%s)\n", ToString().c_str());
582 }
583
584 void CService::Init()
585 {
586     port = 0;
587 }
588
589 CService::CService()
590 {
591     Init();
592 }
593
594 CService::CService(const CNetAddr& cip, unsigned short portIn) : CNetAddr(cip), port(portIn)
595 {
596 }
597
598 CService::CService(const struct in_addr& ipv4Addr, unsigned short portIn) : CNetAddr(ipv4Addr), port(portIn)
599 {
600 }
601
602 #ifdef USE_IPV6
603 CService::CService(const struct in6_addr& ipv6Addr, unsigned short portIn) : CNetAddr(ipv6Addr), port(portIn)
604 {
605 }
606 #endif
607
608 CService::CService(const struct sockaddr_in& addr) : CNetAddr(addr.sin_addr), port(ntohs(addr.sin_port))
609 {
610     assert(addr.sin_family == AF_INET);
611 }
612
613 #ifdef USE_IPV6
614 CService::CService(const struct sockaddr_in6 &addr) : CNetAddr(addr.sin6_addr), port(ntohs(addr.sin6_port))
615 {
616    assert(addr.sin6_family == AF_INET6);
617 }
618 #endif
619
620 CService::CService(const char *pszIpPort, bool fAllowLookup)
621 {
622     Init();
623     CService ip;
624     if (Lookup(pszIpPort, ip, 0, fAllowLookup))
625         *this = ip;
626 }
627
628 CService::CService(const char *pszIp, int portIn, bool fAllowLookup)
629 {
630     std::vector<CNetAddr> ip;
631     if (LookupHost(pszIp, ip, 1, fAllowLookup))
632         *this = CService(ip[0], portIn);
633 }
634
635 CService::CService(const std::string &strIpPort, bool fAllowLookup)
636 {
637     Init();
638     CService ip;
639     if (Lookup(strIpPort.c_str(), ip, 0, fAllowLookup))
640         *this = ip;
641 }
642
643 CService::CService(const std::string &strIp, int portIn, bool fAllowLookup)
644 {
645     std::vector<CNetAddr> ip;
646     if (LookupHost(strIp.c_str(), ip, 1, fAllowLookup))
647         *this = CService(ip[0], portIn);
648 }
649
650 unsigned short CService::GetPort() const
651 {
652     return port;
653 }
654
655 bool operator==(const CService& a, const CService& b)
656 {
657     return (CNetAddr)a == (CNetAddr)b && a.port == b.port;
658 }
659
660 bool operator!=(const CService& a, const CService& b)
661 {
662     return (CNetAddr)a != (CNetAddr)b || a.port != b.port;
663 }
664
665 bool operator<(const CService& a, const CService& b)
666 {
667     return (CNetAddr)a < (CNetAddr)b || ((CNetAddr)a == (CNetAddr)b && a.port < b.port);
668 }
669
670 bool CService::GetSockAddr(struct sockaddr_in* paddr) const
671 {
672     if (!IsIPv4())
673         return false;
674     memset(paddr, 0, sizeof(struct sockaddr_in));
675     if (!GetInAddr(&paddr->sin_addr))
676         return false;
677     paddr->sin_family = AF_INET;
678     paddr->sin_port = htons(port);
679     return true;
680 }
681
682 #ifdef USE_IPV6
683 bool CService::GetSockAddr6(struct sockaddr_in6* paddr) const
684 {
685     memset(paddr, 0, sizeof(struct sockaddr_in6));
686     if (!GetIn6Addr(&paddr->sin6_addr))
687         return false;
688     paddr->sin6_family = AF_INET6;
689     paddr->sin6_port = htons(port);
690     return true;
691 }
692 #endif
693
694 std::vector<unsigned char> CService::GetKey() const
695 {
696      std::vector<unsigned char> vKey;
697      vKey.resize(18);
698      memcpy(&vKey[0], ip, 16);
699      vKey[16] = port / 0x100;
700      vKey[17] = port & 0x0FF;
701      return vKey;
702 }
703
704 std::string CService::ToStringPort() const
705 {
706     return strprintf(":%i", port);
707 }
708
709 std::string CService::ToStringIPPort() const
710 {
711     return ToStringIP() + ToStringPort();
712 }
713
714 std::string CService::ToString() const
715 {
716     return ToStringIPPort();
717 }
718
719 void CService::print() const
720 {
721     printf("CService(%s)\n", ToString().c_str());
722 }
723
724 void CService::SetPort(unsigned short portIn)
725 {
726     port = portIn;
727 }