diff options
author | Pieter Wuille <pieter.wuille@gmail.com> | 2012-01-03 23:33:31 +0100 |
---|---|---|
committer | Pieter Wuille <pieter.wuille@gmail.com> | 2012-01-06 18:55:37 +0100 |
commit | 67a42f929b1434f647c63922fd02dc2b93b28060 (patch) | |
tree | 9c4313e815bd77e817f2dc5b796347d343458d0e /src/net.cpp | |
parent | 7486c64dd8436febbe59e82dbb875e83ad6b5194 (diff) |
Network stack refactor
This introduces CNetAddr and CService, respectively wrapping an
(IPv6) IP address and an IP+port combination. This functionality used
to be part of CAddress, which also contains network flags and
connection attempt information. These extra fields are however not
always necessary.
These classes, along with logic for creating connections and doing
name lookups, are moved to netbase.{h,cpp}, which does not depend on
headers.h.
Furthermore, CNetAddr is mostly IPv6-ready, though IPv6
functionality is not yet enabled for the application itself.
Diffstat (limited to 'src/net.cpp')
-rw-r--r-- | src/net.cpp | 308 |
1 files changed, 50 insertions, 258 deletions
diff --git a/src/net.cpp b/src/net.cpp index 6dab7e8c11..72897687ef 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -45,7 +45,7 @@ bool OpenNetworkConnection(const CAddress& addrConnect); bool fClient = false; bool fAllowDNS = false; uint64 nLocalServices = (fClient ? 0 : NODE_NETWORK); -CAddress addrLocalHost("0.0.0.0", 0, false, nLocalServices); +CAddress addrLocalHost(CService("0.0.0.0", 0), nLocalServices); static CNode* pnodeLocalHost = NULL; uint64 nLocalHostNonce = 0; array<int, 10> vnThreadsRunning; @@ -60,10 +60,6 @@ deque<pair<int64, CInv> > vRelayExpiration; CCriticalSection cs_mapRelay; map<CInv, int64> mapAlreadyAskedFor; -// Settings -int fUseProxy = false; -int nConnectTimeout = 5000; -CAddress addrProxy("127.0.0.1",9050); @@ -88,213 +84,7 @@ void CNode::PushGetBlocks(CBlockIndex* pindexBegin, uint256 hashEnd) -bool ConnectSocket(const CAddress& addrConnect, SOCKET& hSocketRet, int nTimeout) -{ - hSocketRet = INVALID_SOCKET; - - SOCKET hSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - if (hSocket == INVALID_SOCKET) - return false; -#ifdef SO_NOSIGPIPE - int set = 1; - setsockopt(hSocket, SOL_SOCKET, SO_NOSIGPIPE, (void*)&set, sizeof(int)); -#endif - - bool fProxy = (fUseProxy && addrConnect.IsRoutable()); - struct sockaddr_in sockaddr = (fProxy ? addrProxy.GetSockAddr() : addrConnect.GetSockAddr()); - -#ifdef WIN32 - u_long fNonblock = 1; - if (ioctlsocket(hSocket, FIONBIO, &fNonblock) == SOCKET_ERROR) -#else - int fFlags = fcntl(hSocket, F_GETFL, 0); - if (fcntl(hSocket, F_SETFL, fFlags | O_NONBLOCK) == -1) -#endif - { - closesocket(hSocket); - return false; - } - - - if (connect(hSocket, (struct sockaddr*)&sockaddr, sizeof(sockaddr)) == SOCKET_ERROR) - { - // WSAEINVAL is here because some legacy version of winsock uses it - if (WSAGetLastError() == WSAEINPROGRESS || WSAGetLastError() == WSAEWOULDBLOCK || WSAGetLastError() == WSAEINVAL) - { - struct timeval timeout; - timeout.tv_sec = nTimeout / 1000; - timeout.tv_usec = (nTimeout % 1000) * 1000; - - fd_set fdset; - FD_ZERO(&fdset); - FD_SET(hSocket, &fdset); - int nRet = select(hSocket + 1, NULL, &fdset, NULL, &timeout); - if (nRet == 0) - { - printf("connection timeout\n"); - closesocket(hSocket); - return false; - } - if (nRet == SOCKET_ERROR) - { - printf("select() for connection failed: %i\n",WSAGetLastError()); - closesocket(hSocket); - return false; - } - socklen_t nRetSize = sizeof(nRet); -#ifdef WIN32 - if (getsockopt(hSocket, SOL_SOCKET, SO_ERROR, (char*)(&nRet), &nRetSize) == SOCKET_ERROR) -#else - if (getsockopt(hSocket, SOL_SOCKET, SO_ERROR, &nRet, &nRetSize) == SOCKET_ERROR) -#endif - { - printf("getsockopt() for connection failed: %i\n",WSAGetLastError()); - closesocket(hSocket); - return false; - } - if (nRet != 0) - { - printf("connect() failed after select(): %s\n",strerror(nRet)); - closesocket(hSocket); - return false; - } - } -#ifdef WIN32 - else if (WSAGetLastError() != WSAEISCONN) -#else - else -#endif - { - printf("connect() failed: %i\n",WSAGetLastError()); - closesocket(hSocket); - return false; - } - } - - /* - this isn't even strictly necessary - CNode::ConnectNode immediately turns the socket back to non-blocking - but we'll turn it back to blocking just in case - */ -#ifdef WIN32 - fNonblock = 0; - if (ioctlsocket(hSocket, FIONBIO, &fNonblock) == SOCKET_ERROR) -#else - fFlags = fcntl(hSocket, F_GETFL, 0); - if (fcntl(hSocket, F_SETFL, fFlags & !O_NONBLOCK) == SOCKET_ERROR) -#endif - { - closesocket(hSocket); - return false; - } - - if (fProxy) - { - printf("proxy connecting %s\n", addrConnect.ToString().c_str()); - char pszSocks4IP[] = "\4\1\0\0\0\0\0\0user"; - memcpy(pszSocks4IP + 2, &addrConnect.port, 2); - memcpy(pszSocks4IP + 4, &addrConnect.ip, 4); - char* pszSocks4 = pszSocks4IP; - int nSize = sizeof(pszSocks4IP); - - int ret = send(hSocket, pszSocks4, nSize, MSG_NOSIGNAL); - if (ret != nSize) - { - closesocket(hSocket); - return error("Error sending to proxy"); - } - char pchRet[8]; - if (recv(hSocket, pchRet, 8, 0) != 8) - { - closesocket(hSocket); - return error("Error reading proxy response"); - } - if (pchRet[1] != 0x5a) - { - closesocket(hSocket); - if (pchRet[1] != 0x5b) - printf("ERROR: Proxy returned error %d\n", pchRet[1]); - return false; - } - printf("proxy connected %s\n", addrConnect.ToString().c_str()); - } - - hSocketRet = hSocket; - return true; -} - -// portDefault is in host order -bool Lookup(const char *pszName, vector<CAddress>& vaddr, int nServices, int nMaxSolutions, bool fAllowLookup, int portDefault, bool fAllowPort) -{ - vaddr.clear(); - if (pszName[0] == 0) - return false; - int port = portDefault; - char psz[256]; - char *pszHost = psz; - strlcpy(psz, pszName, sizeof(psz)); - if (fAllowPort) - { - char* pszColon = strrchr(psz+1,':'); - char *pszPortEnd = NULL; - int portParsed = pszColon ? strtoul(pszColon+1, &pszPortEnd, 10) : 0; - if (pszColon && pszPortEnd && pszPortEnd[0] == 0) - { - if (psz[0] == '[' && pszColon[-1] == ']') - { - // Future: enable IPv6 colon-notation inside [] - pszHost = psz+1; - pszColon[-1] = 0; - } - else - pszColon[0] = 0; - port = portParsed; - if (port < 0 || port > std::numeric_limits<unsigned short>::max()) - port = std::numeric_limits<unsigned short>::max(); - } - } - - unsigned int addrIP = inet_addr(pszHost); - if (addrIP != INADDR_NONE) - { - // valid IP address passed - vaddr.push_back(CAddress(addrIP, port, nServices)); - return true; - } - - if (!fAllowLookup) - return false; - - struct hostent* phostent = gethostbyname(pszHost); - if (!phostent) - return false; - - if (phostent->h_addrtype != AF_INET) - return false; - - char** ppAddr = phostent->h_addr_list; - while (*ppAddr != NULL && vaddr.size() != nMaxSolutions) - { - CAddress addr(((struct in_addr*)ppAddr[0])->s_addr, port, nServices); - if (addr.IsValid()) - vaddr.push_back(addr); - ppAddr++; - } - - return (vaddr.size() > 0); -} - -// portDefault is in host order -bool Lookup(const char *pszName, CAddress& addr, int nServices, bool fAllowLookup, int portDefault, bool fAllowPort) -{ - vector<CAddress> vaddr; - bool fRet = Lookup(pszName, vaddr, nServices, 1, fAllowLookup, portDefault, fAllowPort); - if (fRet) - addr = vaddr[0]; - return fRet; -} - -bool GetMyExternalIP2(const CAddress& addrConnect, const char* pszGet, const char* pszKeyword, unsigned int& ipRet) +bool GetMyExternalIP2(const CService& addrConnect, const char* pszGet, const char* pszKeyword, CNetAddr& ipRet) { SOCKET hSocket; if (!ConnectSocket(addrConnect, hSocket)) @@ -328,11 +118,11 @@ bool GetMyExternalIP2(const CAddress& addrConnect, const char* pszGet, const cha strLine = strLine.substr(strspn(strLine.c_str(), " \t\n\r")); while (strLine.size() > 0 && isspace(strLine[strLine.size()-1])) strLine.resize(strLine.size()-1); - CAddress addr(strLine,0,true); + CService addr(strLine,0,true); printf("GetMyExternalIP() received [%s] %s\n", strLine.c_str(), addr.ToString().c_str()); - if (addr.ip == 0 || addr.ip == INADDR_NONE || !addr.IsRoutable()) + if (!addr.IsValid() || !addr.IsRoutable()) return false; - ipRet = addr.ip; + ipRet.SetIP(addr); return true; } } @@ -341,7 +131,7 @@ bool GetMyExternalIP2(const CAddress& addrConnect, const char* pszGet, const cha } // We now get our external IP from the IRC server first and only use this as a backup -bool GetMyExternalIP(unsigned int& ipRet) +bool GetMyExternalIP(CNetAddr& ipRet) { CAddress addrConnect; const char* pszGet; @@ -363,7 +153,7 @@ bool GetMyExternalIP(unsigned int& ipRet) if (nLookup == 1) { - CAddress addrIP("checkip.dyndns.org", 80, true); + CService addrIP("checkip.dyndns.org", 80, true); if (addrIP.IsValid()) addrConnect = addrIP; } @@ -382,7 +172,7 @@ bool GetMyExternalIP(unsigned int& ipRet) if (nLookup == 1) { - CAddress addrIP("www.showmyip.com", 80, true); + CService addrIP("www.showmyip.com", 80, true); if (addrIP.IsValid()) addrConnect = addrIP; } @@ -417,7 +207,7 @@ void ThreadGetMyExternalIP(void* parg) } // Fallback in case IRC fails to get it - if (GetMyExternalIP(addrLocalHost.ip)) + if (GetMyExternalIP(addrLocalHost)) { printf("GetMyExternalIP() returned %s\n", addrLocalHost.ToStringIP().c_str()); if (addrLocalHost.IsRoutable()) @@ -441,7 +231,7 @@ bool AddAddress(CAddress addr, int64 nTimePenalty, CAddrDB *pAddrDB) { if (!addr.IsRoutable()) return false; - if (addr.ip == addrLocalHost.ip) + if ((CService)addr == (CService)addrLocalHost) return false; addr.nTime = max((int64)0, (int64)addr.nTime - nTimePenalty); bool fUpdated = false; @@ -494,7 +284,7 @@ bool AddAddress(CAddress addr, int64 nTimePenalty, CAddrDB *pAddrDB) return fNew; } -void AddressCurrentlyConnected(const CAddress& addr) +void AddressCurrentlyConnected(const CService& addr) { CAddress *paddrFound = NULL; @@ -624,23 +414,23 @@ void CNode::CancelSubscribe(unsigned int nChannel) -CNode* FindNode(unsigned int ip) +CNode* FindNode(const CNetAddr& ip) { CRITICAL_BLOCK(cs_vNodes) { BOOST_FOREACH(CNode* pnode, vNodes) - if (pnode->addr.ip == ip) + if ((CNetAddr)pnode->addr == ip) return (pnode); } return NULL; } -CNode* FindNode(CAddress addr) +CNode* FindNode(const CService& addr) { CRITICAL_BLOCK(cs_vNodes) { BOOST_FOREACH(CNode* pnode, vNodes) - if (pnode->addr == addr) + if ((CService)pnode->addr == addr) return (pnode); } return NULL; @@ -648,11 +438,11 @@ CNode* FindNode(CAddress addr) CNode* ConnectNode(CAddress addrConnect, int64 nTimeout) { - if (addrConnect.ip == addrLocalHost.ip) + if ((CNetAddr)addrConnect == (CNetAddr)addrLocalHost) return NULL; // Look for an existing connection - CNode* pnode = FindNode(addrConnect.ip); + CNode* pnode = FindNode((CService)addrConnect); if (pnode) { if (nTimeout != 0) @@ -746,7 +536,7 @@ void CNode::PushVersion() -std::map<unsigned int, int64> CNode::setBanned; +std::map<CNetAddr, int64> CNode::setBanned; CCriticalSection CNode::cs_setBanned; void CNode::ClearBanned() @@ -754,12 +544,12 @@ void CNode::ClearBanned() setBanned.clear(); } -bool CNode::IsBanned(unsigned int ip) +bool CNode::IsBanned(CNetAddr ip) { bool fResult = false; CRITICAL_BLOCK(cs_setBanned) { - std::map<unsigned int, int64>::iterator i = setBanned.find(ip); + std::map<CNetAddr, int64>::iterator i = setBanned.find(ip); if (i != setBanned.end()) { int64 t = (*i).second; @@ -783,8 +573,8 @@ bool CNode::Misbehaving(int howmuch) { int64 banTime = GetTime()+GetArg("-bantime", 60*60*24); // Default 24-hour ban CRITICAL_BLOCK(cs_setBanned) - if (setBanned[addr.ip] < banTime) - setBanned[addr.ip] = banTime; + if (setBanned[addr] < banTime) + setBanned[addr] = banTime; CloseSocketDisconnect(); printf("Disconnected %s for misbehavior (score=%d)\n", addr.ToString().c_str(), nMisbehavior); return true; @@ -962,7 +752,7 @@ void ThreadSocketHandler2(void* parg) { closesocket(hSocket); } - else if (CNode::IsBanned(addr.ip)) + else if (CNode::IsBanned(addr)) { printf("connetion from %s dropped (banned)\n", addr.ToString().c_str()); closesocket(hSocket); @@ -1277,15 +1067,16 @@ void ThreadDNSAddressSeed2(void* parg) printf("Loading addresses from DNS seeds (could take a while)\n"); for (int seed_idx = 0; seed_idx < ARRAYLEN(strDNSSeed); seed_idx++) { - vector<CAddress> vaddr; - if (Lookup(strDNSSeed[seed_idx], vaddr, NODE_NETWORK, -1, true)) + vector<CNetAddr> vaddr; + if (LookupHost(strDNSSeed[seed_idx], vaddr)) { CAddrDB addrDB; addrDB.TxnBegin(); - BOOST_FOREACH (CAddress& addr, vaddr) + BOOST_FOREACH (CNetAddr& ip, vaddr) { - if (addr.GetByte(3) != 127) + if (ip.IsRoutable()) { + CAddress addr(CService(ip, GetDefaultPort()), NODE_NETWORK); addr.nTime = 0; AddAddress(addr, 0, &addrDB); found++; @@ -1470,8 +1261,8 @@ void ThreadOpenConnections2(void* parg) CRITICAL_BLOCK(cs_mapAddresses) { // Add seed nodes if IRC isn't working - bool fTOR = (fUseProxy && addrProxy.port == htons(9050)); - if (mapAddresses.empty() && (GetTime() - nStart > 60 || fUseProxy) && !fTestNet) + bool fTOR = (fUseProxy && addrProxy.GetPort() == 9050); + if (mapAddresses.empty() && (GetTime() - nStart > 60 || fTOR) && !fTestNet) fAddSeeds = true; } @@ -1484,8 +1275,9 @@ void ThreadOpenConnections2(void* parg) // Seed nodes are given a random 'last seen time' of between one and two // weeks ago. const int64 nOneWeek = 7*24*60*60; - CAddress addr; - addr.ip = pnSeed[i]; + struct in_addr ip; + memcpy(&ip, &pnSeed[i], sizeof(ip)); + CAddress addr(CService(ip, GetDefaultPort())); addr.nTime = GetTime()-GetRand(nOneWeek)-nOneWeek; AddAddress(addr); } @@ -1499,10 +1291,10 @@ void ThreadOpenConnections2(void* parg) // Only connect to one address per a.b.?.? range. // Do this here so we don't have to critsect vNodes inside mapAddresses critsect. - set<unsigned int> setConnected; + set<vector<unsigned char> > setConnected; CRITICAL_BLOCK(cs_vNodes) BOOST_FOREACH(CNode* pnode, vNodes) - setConnected.insert(pnode->addr.ip & 0x0000ffff); + setConnected.insert(pnode->addr.GetGroup()); int64 nANow = GetAdjustedTime(); @@ -1511,14 +1303,14 @@ void ThreadOpenConnections2(void* parg) BOOST_FOREACH(const PAIRTYPE(vector<unsigned char>, CAddress)& item, mapAddresses) { const CAddress& addr = item.second; - if (!addr.IsIPv4() || !addr.IsValid() || setConnected.count(addr.ip & 0x0000ffff)) + if (!addr.IsIPv4() || !addr.IsValid() || setConnected.count(addr.GetGroup())) continue; int64 nSinceLastSeen = nANow - addr.nTime; int64 nSinceLastTry = nANow - addr.nLastTry; // Randomize the order in a deterministic way, putting the standard port first - int64 nRandomizer = (uint64)(nStart * 4951 + addr.nLastTry * 9567851 + addr.ip * 7789) % (2 * 60 * 60); - if (addr.port != htons(GetDefaultPort())) + int64 nRandomizer = (uint64)(nStart * 4951 + addr.nLastTry * 9567851 + addr.GetHash()) % (2 * 60 * 60); + if (addr.GetPort() != GetDefaultPort()) nRandomizer += 2 * 60 * 60; // Last seen Base retry frequency @@ -1573,8 +1365,8 @@ bool OpenNetworkConnection(const CAddress& addrConnect) // if (fShutdown) return false; - if (addrConnect.ip == addrLocalHost.ip || !addrConnect.IsIPv4() || - FindNode(addrConnect.ip) || CNode::IsBanned(addrConnect.ip)) + if ((CNetAddr)addrConnect == (CNetAddr)addrLocalHost || !addrConnect.IsIPv4() || + FindNode((CNetAddr)addrConnect) || CNode::IsBanned(addrConnect)) return false; vnThreadsRunning[1]--; @@ -1676,7 +1468,7 @@ bool BindListenPort(string& strError) { strError = ""; int nOne = 1; - addrLocalHost.port = htons(GetListenPort()); + addrLocalHost.SetPort(GetListenPort()); #ifdef WIN32 // Initialize Windows Sockets @@ -1755,19 +1547,19 @@ bool BindListenPort(string& strError) void StartNode(void* parg) { if (pnodeLocalHost == NULL) - pnodeLocalHost = new CNode(INVALID_SOCKET, CAddress("127.0.0.1", 0, false, nLocalServices)); + pnodeLocalHost = new CNode(INVALID_SOCKET, CAddress(CService("127.0.0.1", 0), nLocalServices)); #ifdef WIN32 // Get local host ip char pszHostName[1000] = ""; if (gethostname(pszHostName, sizeof(pszHostName)) != SOCKET_ERROR) { - vector<CAddress> vaddr; - if (Lookup(pszHostName, vaddr, nLocalServices, -1, true)) - BOOST_FOREACH (const CAddress &addr, vaddr) - if (addr.GetByte(3) != 127) + vector<CNetAddr> vaddr; + if (LookupHost(pszHostName, vaddr)) + BOOST_FOREACH (const CNetAddr &addr, vaddr) + if (!addr.IsLocal()) { - addrLocalHost = addr; + addrLocalHost.SetIP(addr); break; } } @@ -1790,8 +1582,8 @@ void StartNode(void* parg) printf("ipv4 %s: %s\n", ifa->ifa_name, pszIP); // Take the first IP that isn't loopback 127.x.x.x - CAddress addr(*(unsigned int*)&s4->sin_addr, GetListenPort(), nLocalServices); - if (addr.IsValid() && addr.GetByte(3) != 127) + CAddress addr(CService(s4->sin_addr, GetListenPort()), nLocalServices); + if (addr.IsValid() && !addr.IsLocal()) { addrLocalHost = addr; break; @@ -1812,7 +1604,7 @@ void StartNode(void* parg) if (fUseProxy || mapArgs.count("-connect") || fNoListen) { // Proxies can't take incoming connections - addrLocalHost.ip = CAddress("0.0.0.0").ip; + addrLocalHost.SetIP(CNetAddr("0.0.0.0")); printf("addrLocalHost = %s\n", addrLocalHost.ToString().c_str()); } else |