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