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