aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPieter Wuille <pieter.wuille@gmail.com>2012-05-11 15:28:59 +0200
committerPieter Wuille <pieter.wuille@gmail.com>2012-05-11 15:29:20 +0200
commit8f10a2889089af1b2ac64802360494b54c8c7ff1 (patch)
tree06df6b9e6114b170fca7aaa7e205c26207a0ab2f
parent7fa4443f77a659031e277337770b506fcf954d69 (diff)
Separate listening sockets, -bind=<addr>
-rw-r--r--src/init.cpp36
-rw-r--r--src/net.cpp86
-rw-r--r--src/net.h3
-rw-r--r--src/netbase.cpp103
-rw-r--r--src/netbase.h4
5 files changed, 140 insertions, 92 deletions
diff --git a/src/init.cpp b/src/init.cpp
index 202d513677..877b1d471f 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -119,6 +119,18 @@ bool AppInit(int argc, char* argv[])
return fRet;
}
+bool static Bind(const CService &addr) {
+ if (IsLimited(addr))
+ return false;
+ std::string strError;
+ if (!BindListenPort(addr, strError))
+ {
+ ThreadSafeMessageBox(strError, _("Bitcoin"), wxOK | wxMODAL);
+ return false;
+ }
+ return true;
+}
+
bool AppInit2(int argc, char* argv[])
{
#ifdef _MSC_VER
@@ -193,6 +205,7 @@ bool AppInit2(int argc, char* argv[])
" -discover \t " + _("Try to discover public IP address (default: 1)") + "\n" +
" -irc \t " + _("Find peers using internet relay chat (default: 0)") + "\n" +
" -listen \t " + _("Accept connections from outside (default: 1)") + "\n" +
+ " -bind=<addr> \t " + _("Bind to given address. Use [host]:port notation for IPv6") + "\n" +
#ifdef QT_GUI
" -lang=<lang> \t\t " + _("Set language, for example \"de_DE\" (default: system locale)") + "\n" +
#endif
@@ -548,7 +561,11 @@ bool AppInit2(int argc, char* argv[])
if (mapArgs.count("-connect"))
SoftSetBoolArg("-dnsseed", false);
-
+
+ // even in Tor mode, if -bind is specified, you really want -listen
+ if (mapArgs.count("-bind"))
+ SoftSetBoolArg("-listen", true);
+
bool fTor = (fUseProxy && addrProxy.GetPort() == 9050);
if (fTor)
{
@@ -588,14 +605,23 @@ bool AppInit2(int argc, char* argv[])
const char* pszP2SH = "/P2SH/";
COINBASE_FLAGS << std::vector<unsigned char>(pszP2SH, pszP2SH+strlen(pszP2SH));
+ bool fBound = false;
if (!fNoListen)
{
std::string strError;
- if (!BindListenPort(strError))
- {
- ThreadSafeMessageBox(strError, _("Bitcoin"), wxOK | wxMODAL);
- return false;
+ if (mapArgs.count("-bind")) {
+ BOOST_FOREACH(std::string strBind, mapMultiArgs["-bind"]) {
+ fBound |= Bind(CService(strBind, GetDefaultPort(), false));
+ }
+ } else {
+ struct in_addr inaddr_any = {s_addr: INADDR_ANY};
+ fBound |= Bind(CService(inaddr_any, GetDefaultPort()));
+#ifdef USE_IPV6
+ fBound |= Bind(CService(in6addr_any, GetDefaultPort()));
+#endif
}
+ if (!fBound)
+ return false;
}
if (mapArgs.count("-externalip"))
diff --git a/src/net.cpp b/src/net.cpp
index a43b76d79c..28667166e6 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -52,7 +52,7 @@ static bool vfLimited[NET_MAX] = {};
static CNode* pnodeLocalHost = NULL;
uint64 nLocalHostNonce = 0;
array<int, THREAD_MAX> vnThreadsRunning;
-static SOCKET hListenSocket = INVALID_SOCKET;
+static std::vector<SOCKET> vhListenSocket;
CAddrMan addrman;
vector<CNode*> vNodes;
@@ -719,9 +719,10 @@ void ThreadSocketHandler2(void* parg)
FD_ZERO(&fdsetError);
SOCKET hSocketMax = 0;
- if(hListenSocket != INVALID_SOCKET)
+ BOOST_FOREACH(SOCKET hListenSocket, vhListenSocket) {
FD_SET(hListenSocket, &fdsetRecv);
- hSocketMax = max(hSocketMax, hListenSocket);
+ hSocketMax = max(hSocketMax, hListenSocket);
+ }
{
LOCK(cs_vNodes);
BOOST_FOREACH(CNode* pnode, vNodes)
@@ -762,12 +763,13 @@ void ThreadSocketHandler2(void* parg)
//
// Accept new connections
//
+ BOOST_FOREACH(SOCKET hListenSocket, vhListenSocket)
if (hListenSocket != INVALID_SOCKET && FD_ISSET(hListenSocket, &fdsetRecv))
{
#ifdef USE_IPV6
- struct sockaddr_in6 sockaddr;
+ struct sockaddr_storage sockaddr;
#else
- struct sockaddr_in sockaddr;
+ struct sockaddr sockaddr;
#endif
socklen_t len = sizeof(sockaddr);
SOCKET hSocket = accept(hListenSocket, (struct sockaddr*)&sockaddr, &len);
@@ -775,7 +777,8 @@ void ThreadSocketHandler2(void* parg)
int nInbound = 0;
if (hSocket != INVALID_SOCKET)
- addr = CAddress(sockaddr);
+ if (!addr.SetSockAddr((const struct sockaddr*)&sockaddr))
+ printf("warning: unknown socket family\n");
{
LOCK(cs_vNodes);
@@ -1656,9 +1659,8 @@ void ThreadMessageHandler2(void* parg)
-bool BindListenPort(string& strError)
+bool BindListenPort(const CService &addrBind, string& strError)
{
- unsigned short nPort = GetListenPort();
strError = "";
int nOne = 1;
@@ -1676,11 +1678,19 @@ bool BindListenPort(string& strError)
// Create socket for listening for incoming connections
#ifdef USE_IPV6
- int nFamily = AF_INET6;
+ struct sockaddr_storage sockaddr;
#else
- int nFamily = AF_INET;
+ struct sockaddr sockaddr;
#endif
- hListenSocket = socket(nFamily, SOCK_STREAM, IPPROTO_TCP);
+ socklen_t len = sizeof(sockaddr);
+ if (!addrBind.GetSockAddr((struct sockaddr*)&sockaddr, &len))
+ {
+ strError = strprintf("Error: bind address family for %s not supported", addrBind.ToString().c_str());
+ printf("%s\n", strError.c_str());
+ return false;
+ }
+
+ SOCKET hListenSocket = socket(((struct sockaddr*)&sockaddr)->sa_family, SOCK_STREAM, IPPROTO_TCP);
if (hListenSocket == INVALID_SOCKET)
{
strError = strprintf("Error: Couldn't open socket for incoming connections (socket returned error %d)", WSAGetLastError());
@@ -1699,6 +1709,7 @@ bool BindListenPort(string& strError)
setsockopt(hListenSocket, SOL_SOCKET, SO_REUSEADDR, (void*)&nOne, sizeof(int));
#endif
+
#ifdef WIN32
// Set to nonblocking, incoming connections will also inherit this
if (ioctlsocket(hListenSocket, FIONBIO, (u_long*)&nOne) == SOCKET_ERROR)
@@ -1711,38 +1722,33 @@ bool BindListenPort(string& strError)
return false;
}
- // The sockaddr_in structure specifies the address family,
- // IP address, and port for the socket that is being bound
#ifdef USE_IPV6
- struct sockaddr_in6 sockaddr = sockaddr_in6();
- memset(&sockaddr, 0, sizeof(sockaddr));
- sockaddr.sin6_family = AF_INET6;
- sockaddr.sin6_addr = in6addr_any; // bind to all IPs on this computer
- sockaddr.sin6_port = htons(nPort);
-# ifdef WIN32
- int nProtLevel = 10 /* PROTECTION_LEVEL_UNRESTRICTED */;
- int nParameterId = 23 /* IPV6_PROTECTION_LEVEl */;
- // this call is allowed to fail
- setsockopt(hListenSocket, IPPROTO_IPV6, nParameterId, (const char*)&nProtLevel, sizeof(int));
-# endif
-#else
- struct sockaddr_in sockaddr = sockaddr_in();
- memset(&sockaddr, 0, sizeof(sockaddr));
- sockaddr.sin_family = AF_INET;
- sockaddr.sin_addr.s_addr = INADDR_ANY; // bind to all IPs on this computer
- sockaddr.sin_port = htons(nPort);
+ // some systems don't have IPV6_V6ONLY but are always v6only; others do have the option
+ // and enable it by default or not. Try to enable it, if possible.
+ if (addrBind.IsIPv6()) {
+#ifdef IPV6_V6ONLY
+ setsockopt(hListenSocket, IPPROTO_IPV6, IPV6_V6ONLY, (void*)&nOne, sizeof(int));
#endif
- if (::bind(hListenSocket, (struct sockaddr*)&sockaddr, sizeof(sockaddr)) == SOCKET_ERROR)
+#ifdef WIN32
+ int nProtLevel = 10 /* PROTECTION_LEVEL_UNRESTRICTED */;
+ int nParameterId = 23 /* IPV6_PROTECTION_LEVEl */;
+ // this call is allowed to fail
+ setsockopt(hListenSocket, IPPROTO_IPV6, nParameterId, (const char*)&nProtLevel, sizeof(int));
+#endif
+ }
+#endif
+
+ if (::bind(hListenSocket, (struct sockaddr*)&sockaddr, len) == SOCKET_ERROR)
{
int nErr = WSAGetLastError();
if (nErr == WSAEADDRINUSE)
- strError = strprintf(_("Unable to bind to port %d on this computer. Bitcoin is probably already running."), nPort);
+ strError = strprintf(_("Unable to bind to %s on this computer. Bitcoin is probably already running."), addrBind.ToString().c_str());
else
- strError = strprintf("Error: Unable to bind to port %d on this computer (bind returned error %d, %s)", nPort, nErr, strerror(nErr));
+ strError = strprintf(_("Unable to bind to %s on this computer (bind returned error %d, %s)"), addrBind.ToString().c_str(), nErr, strerror(nErr));
printf("%s\n", strError.c_str());
return false;
}
- printf("Bound to port %d\n", (int)nPort);
+ printf("Bound to %s\n", addrBind.ToString().c_str());
// Listen for incoming connections
if (listen(hListenSocket, SOMAXCONN) == SOCKET_ERROR)
@@ -1752,6 +1758,11 @@ bool BindListenPort(string& strError)
return false;
}
+ vhListenSocket.push_back(hListenSocket);
+
+ if (addrBind.IsRoutable() && GetBoolArg("-discover", true))
+ AddLocal(addrBind, LOCAL_BIND);
+
return true;
}
@@ -1915,9 +1926,10 @@ public:
BOOST_FOREACH(CNode* pnode, vNodes)
if (pnode->hSocket != INVALID_SOCKET)
closesocket(pnode->hSocket);
- if (hListenSocket != INVALID_SOCKET)
- if (closesocket(hListenSocket) == SOCKET_ERROR)
- printf("closesocket(hListenSocket) failed with error %d\n", WSAGetLastError());
+ BOOST_FOREACH(SOCKET hListenSocket, vhListenSocket)
+ if (hListenSocket != INVALID_SOCKET)
+ if (closesocket(hListenSocket) == SOCKET_ERROR)
+ printf("closesocket(hListenSocket) failed with error %d\n", WSAGetLastError());
#ifdef WIN32
// Shutdown Windows Sockets
diff --git a/src/net.h b/src/net.h
index 398b89dcfc..d62f512716 100644
--- a/src/net.h
+++ b/src/net.h
@@ -38,7 +38,7 @@ CNode* FindNode(const CNetAddr& ip);
CNode* FindNode(const CService& ip);
CNode* ConnectNode(CAddress addrConnect, const char *strDest = NULL, int64 nTimeout=0);
void MapPort(bool fMapPort);
-bool BindListenPort(std::string& strError=REF(std::string()));
+bool BindListenPort(const CService &bindAddr, std::string& strError=REF(std::string()));
void StartNode(void* parg);
bool StopNode();
@@ -46,6 +46,7 @@ enum
{
LOCAL_NONE, // unknown
LOCAL_IF, // address a local interface listens on
+ LOCAL_BIND, // address explicit bound to
LOCAL_UPNP, // address reported by UPnP
LOCAL_IRC, // address reported by IRC (deprecated)
LOCAL_HTTP, // address reported by whatismyip.com and similars
diff --git a/src/netbase.cpp b/src/netbase.cpp
index 7e9620d9ff..ebf823e899 100644
--- a/src/netbase.cpp
+++ b/src/netbase.cpp
@@ -183,7 +183,12 @@ bool static Socks4(const CService &addrDest, SOCKET& hSocket)
}
char pszSocks4IP[] = "\4\1\0\0\0\0\0\0user";
struct sockaddr_in addr;
- addrDest.GetSockAddr(&addr);
+ socklen_t len = sizeof(addr);
+ if (!addrDest.GetSockAddr((struct sockaddr*)&addr, &len) || addr.sin_family != AF_INET)
+ {
+ closesocket(hSocket);
+ return error("Cannot get proxy destination address");
+ }
memcpy(pszSocks4IP + 2, &addr.sin_port, 2);
memcpy(pszSocks4IP + 4, &addr.sin_addr, 4);
char* pszSocks4 = pszSocks4IP;
@@ -319,37 +324,18 @@ bool static ConnectSocketDirectly(const CService &addrConnect, SOCKET& hSocketRe
{
hSocketRet = INVALID_SOCKET;
- struct sockaddr_storage sockaddr;
- int nFamily = 0;
- size_t nSockAddrLen = 0;
-
- if (addrConnect.IsIPv4())
- {
- // Use IPv4 stack to connect to IPv4 addresses
- struct sockaddr_in sockaddr4;
- if (!addrConnect.GetSockAddr(&sockaddr4))
- return false;
- memcpy(&sockaddr, &sockaddr4, sizeof(sockaddr4));
- nSockAddrLen = sizeof(sockaddr4);
- nFamily = AF_INET;
- }
#ifdef USE_IPV6
- else if (addrConnect.IsIPv6())
- {
- struct sockaddr_in6 sockaddr6;
- if (!addrConnect.GetSockAddr6(&sockaddr6))
- return false;
- memcpy(&sockaddr, &sockaddr6, sizeof(sockaddr6));
- nSockAddrLen = sizeof(sockaddr6);
- nFamily = AF_INET6;
- }
+ struct sockaddr_storage sockaddr;
+#else
+ struct sockaddr sockaddr;
#endif
- else {
+ socklen_t len = sizeof(sockaddr);
+ if (!addrConnect.GetSockAddr((struct sockaddr*)&sockaddr, &len)) {
printf("Cannot connect to %s: unsupported network\n", addrConnect.ToString().c_str());
return false;
}
- SOCKET hSocket = socket(nFamily, SOCK_STREAM, IPPROTO_TCP);
+ SOCKET hSocket = socket(((struct sockaddr*)&sockaddr)->sa_family, SOCK_STREAM, IPPROTO_TCP);
if (hSocket == INVALID_SOCKET)
return false;
#ifdef SO_NOSIGPIPE
@@ -369,7 +355,7 @@ bool static ConnectSocketDirectly(const CService &addrConnect, SOCKET& hSocketRe
return false;
}
- if (connect(hSocket, (struct sockaddr*)&sockaddr, nSockAddrLen) == SOCKET_ERROR)
+ if (connect(hSocket, (struct sockaddr*)&sockaddr, len) == SOCKET_ERROR)
{
// WSAEINVAL is here because some legacy version of winsock uses it
if (WSAGetLastError() == WSAEINPROGRESS || WSAGetLastError() == WSAEWOULDBLOCK || WSAGetLastError() == WSAEINVAL)
@@ -902,6 +888,22 @@ CService::CService(const struct sockaddr_in6 &addr) : CNetAddr(addr.sin6_addr),
}
#endif
+bool CService::SetSockAddr(const struct sockaddr *paddr)
+{
+ switch (paddr->sa_family) {
+ case AF_INET:
+ *this = CService(*(const struct sockaddr_in*)paddr);
+ return true;
+#ifdef USE_IPV6
+ case AF_INET6:
+ *this = CService(*(const struct sockaddr_in6*)paddr);
+ return true;
+#endif
+ default:
+ return false;
+ }
+}
+
CService::CService(const char *pszIpPort, bool fAllowLookup)
{
Init();
@@ -954,29 +956,36 @@ bool operator<(const CService& a, const CService& b)
return (CNetAddr)a < (CNetAddr)b || ((CNetAddr)a == (CNetAddr)b && a.port < b.port);
}
-bool CService::GetSockAddr(struct sockaddr_in* paddr) const
+bool CService::GetSockAddr(struct sockaddr* paddr, socklen_t *addrlen) const
{
- if (!IsIPv4())
- return false;
- memset(paddr, 0, sizeof(struct sockaddr_in));
- if (!GetInAddr(&paddr->sin_addr))
- return false;
- paddr->sin_family = AF_INET;
- paddr->sin_port = htons(port);
- return true;
-}
-
+ if (IsIPv4()) {
+ if (*addrlen < sizeof(struct sockaddr_in))
+ return false;
+ *addrlen = sizeof(struct sockaddr_in);
+ struct sockaddr_in *paddrin = (struct sockaddr_in*)paddr;
+ memset(paddrin, 0, *addrlen);
+ if (!GetInAddr(&paddrin->sin_addr))
+ return false;
+ paddrin->sin_family = AF_INET;
+ paddrin->sin_port = htons(port);
+ return true;
+ }
#ifdef USE_IPV6
-bool CService::GetSockAddr6(struct sockaddr_in6* paddr) const
-{
- memset(paddr, 0, sizeof(struct sockaddr_in6));
- if (!GetIn6Addr(&paddr->sin6_addr))
- return false;
- paddr->sin6_family = AF_INET6;
- paddr->sin6_port = htons(port);
- return true;
-}
+ if (IsIPv6()) {
+ if (*addrlen < sizeof(struct sockaddr_in6))
+ return false;
+ *addrlen = sizeof(struct sockaddr_in6);
+ struct sockaddr_in6 *paddrin6 = (struct sockaddr_in6*)paddr;
+ memset(paddrin6, 0, *addrlen);
+ if (!GetIn6Addr(&paddrin6->sin6_addr))
+ return false;
+ paddrin6->sin6_family = AF_INET6;
+ paddrin6->sin6_port = htons(port);
+ return true;
+ }
#endif
+ return false;
+}
std::vector<unsigned char> CService::GetKey() const
{
diff --git a/src/netbase.h b/src/netbase.h
index bd62c42e32..514a1ae950 100644
--- a/src/netbase.h
+++ b/src/netbase.h
@@ -105,7 +105,8 @@ class CService : public CNetAddr
void Init();
void SetPort(unsigned short portIn);
unsigned short GetPort() const;
- bool GetSockAddr(struct sockaddr_in* paddr) const;
+ bool GetSockAddr(struct sockaddr* paddr, socklen_t *addrlen) const;
+ bool SetSockAddr(const struct sockaddr* paddr);
friend bool operator==(const CService& a, const CService& b);
friend bool operator!=(const CService& a, const CService& b);
friend bool operator<(const CService& a, const CService& b);
@@ -117,7 +118,6 @@ class CService : public CNetAddr
#ifdef USE_IPV6
CService(const struct in6_addr& ipv6Addr, unsigned short port);
- bool GetSockAddr6(struct sockaddr_in6* paddr) const;
CService(const struct sockaddr_in6& addr);
#endif