Revert "Use standard C99 (and Qt) types for 64-bit integers"
[novacoin.git] / src / protocol.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 "protocol.h"
7 #include "util.h"
8
9 #ifndef WIN32
10 # include <arpa/inet.h>
11 #endif
12
13 // Prototypes from net.h, but that header (currently) stinks, can't #include it without breaking things
14 bool Lookup(const char *pszName, std::vector<CAddress>& vaddr, int nServices, int nMaxSolutions, bool fAllowLookup = false, int portDefault = 0, bool fAllowPort = false);
15 bool Lookup(const char *pszName, CAddress& addr, int nServices, bool fAllowLookup = false, int portDefault = 0, bool fAllowPort = false);
16
17 static const unsigned char pchIPv4[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff };
18 static const char* ppszTypeName[] =
19 {
20     "ERROR",
21     "tx",
22     "block",
23 };
24
25 CMessageHeader::CMessageHeader()
26 {
27     memcpy(pchMessageStart, ::pchMessageStart, sizeof(pchMessageStart));
28     memset(pchCommand, 0, sizeof(pchCommand));
29     pchCommand[1] = 1;
30     nMessageSize = -1;
31     nChecksum = 0;
32 }
33
34 CMessageHeader::CMessageHeader(const char* pszCommand, unsigned int nMessageSizeIn)
35 {
36     memcpy(pchMessageStart, ::pchMessageStart, sizeof(pchMessageStart));
37     strncpy(pchCommand, pszCommand, COMMAND_SIZE);
38     nMessageSize = nMessageSizeIn;
39     nChecksum = 0;
40 }
41
42 std::string CMessageHeader::GetCommand() const
43 {
44     if (pchCommand[COMMAND_SIZE-1] == 0)
45         return std::string(pchCommand, pchCommand + strlen(pchCommand));
46     else
47         return std::string(pchCommand, pchCommand + COMMAND_SIZE);
48 }
49
50 bool CMessageHeader::IsValid() const
51 {
52     // Check start string
53     if (memcmp(pchMessageStart, ::pchMessageStart, sizeof(pchMessageStart)) != 0)
54         return false;
55
56     // Check the command string for errors
57     for (const char* p1 = pchCommand; p1 < pchCommand + COMMAND_SIZE; p1++)
58     {
59         if (*p1 == 0)
60         {
61             // Must be all zeros after the first zero
62             for (; p1 < pchCommand + COMMAND_SIZE; p1++)
63                 if (*p1 != 0)
64                     return false;
65         }
66         else if (*p1 < ' ' || *p1 > 0x7E)
67             return false;
68     }
69
70     // Message size
71     if (nMessageSize > MAX_SIZE)
72     {
73         printf("CMessageHeader::IsValid() : (%s, %u bytes) nMessageSize > MAX_SIZE\n", GetCommand().c_str(), nMessageSize);
74         return false;
75     }
76
77     return true;
78 }
79
80 CAddress::CAddress()
81 {
82     Init();
83 }
84
85 CAddress::CAddress(unsigned int ipIn, unsigned short portIn, uint64 nServicesIn)
86 {
87     Init();
88     ip = ipIn;
89     port = htons(portIn == 0 ? GetDefaultPort() : portIn);
90     nServices = nServicesIn;
91 }
92
93 CAddress::CAddress(const struct sockaddr_in& sockaddr, uint64 nServicesIn)
94 {
95     Init();
96     ip = sockaddr.sin_addr.s_addr;
97     port = sockaddr.sin_port;
98     nServices = nServicesIn;
99 }
100
101 CAddress::CAddress(const char* pszIn, int portIn, bool fNameLookup, uint64 nServicesIn)
102 {
103     Init();
104     Lookup(pszIn, *this, nServicesIn, fNameLookup, portIn);
105 }
106
107 CAddress::CAddress(const char* pszIn, bool fNameLookup, uint64 nServicesIn)
108 {
109     Init();
110     Lookup(pszIn, *this, nServicesIn, fNameLookup, 0, true);
111 }
112
113 CAddress::CAddress(std::string strIn, int portIn, bool fNameLookup, uint64 nServicesIn)
114 {
115     Init();
116     Lookup(strIn.c_str(), *this, nServicesIn, fNameLookup, portIn);
117 }
118
119 CAddress::CAddress(std::string strIn, bool fNameLookup, uint64 nServicesIn)
120 {
121     Init();
122     Lookup(strIn.c_str(), *this, nServicesIn, fNameLookup, 0, true);
123 }
124
125 void CAddress::Init()
126 {
127     nServices = NODE_NETWORK;
128     memcpy(pchReserved, pchIPv4, sizeof(pchReserved));
129     ip = INADDR_NONE;
130     port = htons(GetDefaultPort());
131     nTime = 100000000;
132     nLastTry = 0;
133 }
134
135 bool operator==(const CAddress& a, const CAddress& b)
136 {
137     return (memcmp(a.pchReserved, b.pchReserved, sizeof(a.pchReserved)) == 0 &&
138             a.ip   == b.ip &&
139             a.port == b.port);
140 }
141
142 bool operator!=(const CAddress& a, const CAddress& b)
143 {
144     return (!(a == b));
145 }
146
147 bool operator<(const CAddress& a, const CAddress& b)
148 {
149     int ret = memcmp(a.pchReserved, b.pchReserved, sizeof(a.pchReserved));
150     if (ret < 0)
151         return true;
152     else if (ret == 0)
153     {
154         if (ntohl(a.ip) < ntohl(b.ip))
155             return true;
156         else if (a.ip == b.ip)
157             return ntohs(a.port) < ntohs(b.port);
158     }
159     return false;
160 }
161
162 std::vector<unsigned char> CAddress::GetKey() const
163 {
164     CDataStream ss;
165     ss.reserve(18);
166     ss << FLATDATA(pchReserved) << ip << port;
167
168     #if defined(_MSC_VER) && _MSC_VER < 1300
169     return std::vector<unsigned char>((unsigned char*)&ss.begin()[0], (unsigned char*)&ss.end()[0]);
170     #else
171     return std::vector<unsigned char>(ss.begin(), ss.end());
172     #endif
173 }
174
175 struct sockaddr_in CAddress::GetSockAddr() const
176 {
177     struct sockaddr_in sockaddr;
178     memset(&sockaddr, 0, sizeof(sockaddr));
179     sockaddr.sin_family = AF_INET;
180     sockaddr.sin_addr.s_addr = ip;
181     sockaddr.sin_port = port;
182     return sockaddr;
183 }
184
185 bool CAddress::IsIPv4() const
186 {
187     return (memcmp(pchReserved, pchIPv4, sizeof(pchIPv4)) == 0);
188 }
189
190 bool CAddress::IsRFC1918() const
191 {
192   return IsIPv4() && (GetByte(3) == 10 ||
193     (GetByte(3) == 192 && GetByte(2) == 168) ||
194     (GetByte(3) == 172 &&
195       (GetByte(2) >= 16 && GetByte(2) <= 31)));
196 }
197
198 bool CAddress::IsRFC3927() const
199 {
200   return IsIPv4() && (GetByte(3) == 169 && GetByte(2) == 254);
201 }
202
203 bool CAddress::IsLocal() const
204 {
205   return IsIPv4() && (GetByte(3) == 127 ||
206       GetByte(3) == 0);
207 }
208
209 bool CAddress::IsRoutable() const
210 {
211     return IsValid() &&
212         !(IsRFC1918() || IsRFC3927() || IsLocal());
213 }
214
215 bool CAddress::IsValid() const
216 {
217     // Clean up 3-byte shifted addresses caused by garbage in size field
218     // of addr messages from versions before 0.2.9 checksum.
219     // Two consecutive addr messages look like this:
220     // header20 vectorlen3 addr26 addr26 addr26 header20 vectorlen3 addr26 addr26 addr26...
221     // so if the first length field is garbled, it reads the second batch
222     // of addr misaligned by 3 bytes.
223     if (memcmp(pchReserved, pchIPv4+3, sizeof(pchIPv4)-3) == 0)
224         return false;
225
226     return (ip != 0 && ip != INADDR_NONE && port != htons(std::numeric_limits<unsigned short>::max()));
227 }
228
229 unsigned char CAddress::GetByte(int n) const
230 {
231     return ((unsigned char*)&ip)[3-n];
232 }
233
234 std::string CAddress::ToStringIPPort() const
235 {
236     return strprintf("%u.%u.%u.%u:%u", GetByte(3), GetByte(2), GetByte(1), GetByte(0), ntohs(port));
237 }
238
239 std::string CAddress::ToStringIP() const
240 {
241     return strprintf("%u.%u.%u.%u", GetByte(3), GetByte(2), GetByte(1), GetByte(0));
242 }
243
244 std::string CAddress::ToStringPort() const
245 {
246     return strprintf("%u", ntohs(port));
247 }
248
249 std::string CAddress::ToString() const
250 {
251     return strprintf("%u.%u.%u.%u:%u", GetByte(3), GetByte(2), GetByte(1), GetByte(0), ntohs(port));
252 }
253
254 void CAddress::print() const
255 {
256     printf("CAddress(%s)\n", ToString().c_str());
257 }
258
259 CInv::CInv()
260 {
261     type = 0;
262     hash = 0;
263 }
264
265 CInv::CInv(int typeIn, const uint256& hashIn)
266 {
267     type = typeIn;
268     hash = hashIn;
269 }
270
271 CInv::CInv(const std::string& strType, const uint256& hashIn)
272 {
273     int i;
274     for (i = 1; i < ARRAYLEN(ppszTypeName); i++)
275     {
276         if (strType == ppszTypeName[i])
277         {
278             type = i;
279             break;
280         }
281     }
282     if (i == ARRAYLEN(ppszTypeName))
283         throw std::out_of_range(strprintf("CInv::CInv(string, uint256) : unknown type '%s'", strType.c_str()));
284     hash = hashIn;
285 }
286
287 bool operator<(const CInv& a, const CInv& b)
288 {
289     return (a.type < b.type || (a.type == b.type && a.hash < b.hash));
290 }
291
292 bool CInv::IsKnownType() const
293 {
294     return (type >= 1 && type < ARRAYLEN(ppszTypeName));
295 }
296
297 const char* CInv::GetCommand() const
298 {
299     if (!IsKnownType())
300         throw std::out_of_range(strprintf("CInv::GetCommand() : type=%d unknown type", type));
301     return ppszTypeName[type];
302 }
303
304 std::string CInv::ToString() const
305 {
306     return strprintf("%s %s", GetCommand(), hash.ToString().substr(0,20).c_str());
307 }
308
309 void CInv::print() const
310 {
311     printf("CInv(%s)\n", ToString().c_str());
312 }