Skip to content

Commit 8f10a28

Browse files
committed
Separate listening sockets, -bind=<addr>
1 parent 7fa4443 commit 8f10a28

File tree

5 files changed

+140
-92
lines changed

5 files changed

+140
-92
lines changed

src/init.cpp

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,18 @@ bool AppInit(int argc, char* argv[])
119119
return fRet;
120120
}
121121

122+
bool static Bind(const CService &addr) {
123+
if (IsLimited(addr))
124+
return false;
125+
std::string strError;
126+
if (!BindListenPort(addr, strError))
127+
{
128+
ThreadSafeMessageBox(strError, _("Bitcoin"), wxOK | wxMODAL);
129+
return false;
130+
}
131+
return true;
132+
}
133+
122134
bool AppInit2(int argc, char* argv[])
123135
{
124136
#ifdef _MSC_VER
@@ -193,6 +205,7 @@ bool AppInit2(int argc, char* argv[])
193205
" -discover \t " + _("Try to discover public IP address (default: 1)") + "\n" +
194206
" -irc \t " + _("Find peers using internet relay chat (default: 0)") + "\n" +
195207
" -listen \t " + _("Accept connections from outside (default: 1)") + "\n" +
208+
" -bind=<addr> \t " + _("Bind to given address. Use [host]:port notation for IPv6") + "\n" +
196209
#ifdef QT_GUI
197210
" -lang=<lang> \t\t " + _("Set language, for example \"de_DE\" (default: system locale)") + "\n" +
198211
#endif
@@ -548,7 +561,11 @@ bool AppInit2(int argc, char* argv[])
548561

549562
if (mapArgs.count("-connect"))
550563
SoftSetBoolArg("-dnsseed", false);
551-
564+
565+
// even in Tor mode, if -bind is specified, you really want -listen
566+
if (mapArgs.count("-bind"))
567+
SoftSetBoolArg("-listen", true);
568+
552569
bool fTor = (fUseProxy && addrProxy.GetPort() == 9050);
553570
if (fTor)
554571
{
@@ -588,14 +605,23 @@ bool AppInit2(int argc, char* argv[])
588605
const char* pszP2SH = "/P2SH/";
589606
COINBASE_FLAGS << std::vector<unsigned char>(pszP2SH, pszP2SH+strlen(pszP2SH));
590607

608+
bool fBound = false;
591609
if (!fNoListen)
592610
{
593611
std::string strError;
594-
if (!BindListenPort(strError))
595-
{
596-
ThreadSafeMessageBox(strError, _("Bitcoin"), wxOK | wxMODAL);
597-
return false;
612+
if (mapArgs.count("-bind")) {
613+
BOOST_FOREACH(std::string strBind, mapMultiArgs["-bind"]) {
614+
fBound |= Bind(CService(strBind, GetDefaultPort(), false));
615+
}
616+
} else {
617+
struct in_addr inaddr_any = {s_addr: INADDR_ANY};
618+
fBound |= Bind(CService(inaddr_any, GetDefaultPort()));
619+
#ifdef USE_IPV6
620+
fBound |= Bind(CService(in6addr_any, GetDefaultPort()));
621+
#endif
598622
}
623+
if (!fBound)
624+
return false;
599625
}
600626

601627
if (mapArgs.count("-externalip"))

src/net.cpp

Lines changed: 49 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ static bool vfLimited[NET_MAX] = {};
5252
static CNode* pnodeLocalHost = NULL;
5353
uint64 nLocalHostNonce = 0;
5454
array<int, THREAD_MAX> vnThreadsRunning;
55-
static SOCKET hListenSocket = INVALID_SOCKET;
55+
static std::vector<SOCKET> vhListenSocket;
5656
CAddrMan addrman;
5757

5858
vector<CNode*> vNodes;
@@ -719,9 +719,10 @@ void ThreadSocketHandler2(void* parg)
719719
FD_ZERO(&fdsetError);
720720
SOCKET hSocketMax = 0;
721721

722-
if(hListenSocket != INVALID_SOCKET)
722+
BOOST_FOREACH(SOCKET hListenSocket, vhListenSocket) {
723723
FD_SET(hListenSocket, &fdsetRecv);
724-
hSocketMax = max(hSocketMax, hListenSocket);
724+
hSocketMax = max(hSocketMax, hListenSocket);
725+
}
725726
{
726727
LOCK(cs_vNodes);
727728
BOOST_FOREACH(CNode* pnode, vNodes)
@@ -762,20 +763,22 @@ void ThreadSocketHandler2(void* parg)
762763
//
763764
// Accept new connections
764765
//
766+
BOOST_FOREACH(SOCKET hListenSocket, vhListenSocket)
765767
if (hListenSocket != INVALID_SOCKET && FD_ISSET(hListenSocket, &fdsetRecv))
766768
{
767769
#ifdef USE_IPV6
768-
struct sockaddr_in6 sockaddr;
770+
struct sockaddr_storage sockaddr;
769771
#else
770-
struct sockaddr_in sockaddr;
772+
struct sockaddr sockaddr;
771773
#endif
772774
socklen_t len = sizeof(sockaddr);
773775
SOCKET hSocket = accept(hListenSocket, (struct sockaddr*)&sockaddr, &len);
774776
CAddress addr;
775777
int nInbound = 0;
776778

777779
if (hSocket != INVALID_SOCKET)
778-
addr = CAddress(sockaddr);
780+
if (!addr.SetSockAddr((const struct sockaddr*)&sockaddr))
781+
printf("warning: unknown socket family\n");
779782

780783
{
781784
LOCK(cs_vNodes);
@@ -1656,9 +1659,8 @@ void ThreadMessageHandler2(void* parg)
16561659

16571660

16581661

1659-
bool BindListenPort(string& strError)
1662+
bool BindListenPort(const CService &addrBind, string& strError)
16601663
{
1661-
unsigned short nPort = GetListenPort();
16621664
strError = "";
16631665
int nOne = 1;
16641666

@@ -1676,11 +1678,19 @@ bool BindListenPort(string& strError)
16761678

16771679
// Create socket for listening for incoming connections
16781680
#ifdef USE_IPV6
1679-
int nFamily = AF_INET6;
1681+
struct sockaddr_storage sockaddr;
16801682
#else
1681-
int nFamily = AF_INET;
1683+
struct sockaddr sockaddr;
16821684
#endif
1683-
hListenSocket = socket(nFamily, SOCK_STREAM, IPPROTO_TCP);
1685+
socklen_t len = sizeof(sockaddr);
1686+
if (!addrBind.GetSockAddr((struct sockaddr*)&sockaddr, &len))
1687+
{
1688+
strError = strprintf("Error: bind address family for %s not supported", addrBind.ToString().c_str());
1689+
printf("%s\n", strError.c_str());
1690+
return false;
1691+
}
1692+
1693+
SOCKET hListenSocket = socket(((struct sockaddr*)&sockaddr)->sa_family, SOCK_STREAM, IPPROTO_TCP);
16841694
if (hListenSocket == INVALID_SOCKET)
16851695
{
16861696
strError = strprintf("Error: Couldn't open socket for incoming connections (socket returned error %d)", WSAGetLastError());
@@ -1699,6 +1709,7 @@ bool BindListenPort(string& strError)
16991709
setsockopt(hListenSocket, SOL_SOCKET, SO_REUSEADDR, (void*)&nOne, sizeof(int));
17001710
#endif
17011711

1712+
17021713
#ifdef WIN32
17031714
// Set to nonblocking, incoming connections will also inherit this
17041715
if (ioctlsocket(hListenSocket, FIONBIO, (u_long*)&nOne) == SOCKET_ERROR)
@@ -1711,38 +1722,33 @@ bool BindListenPort(string& strError)
17111722
return false;
17121723
}
17131724

1714-
// The sockaddr_in structure specifies the address family,
1715-
// IP address, and port for the socket that is being bound
17161725
#ifdef USE_IPV6
1717-
struct sockaddr_in6 sockaddr = sockaddr_in6();
1718-
memset(&sockaddr, 0, sizeof(sockaddr));
1719-
sockaddr.sin6_family = AF_INET6;
1720-
sockaddr.sin6_addr = in6addr_any; // bind to all IPs on this computer
1721-
sockaddr.sin6_port = htons(nPort);
1722-
# ifdef WIN32
1723-
int nProtLevel = 10 /* PROTECTION_LEVEL_UNRESTRICTED */;
1724-
int nParameterId = 23 /* IPV6_PROTECTION_LEVEl */;
1725-
// this call is allowed to fail
1726-
setsockopt(hListenSocket, IPPROTO_IPV6, nParameterId, (const char*)&nProtLevel, sizeof(int));
1727-
# endif
1728-
#else
1729-
struct sockaddr_in sockaddr = sockaddr_in();
1730-
memset(&sockaddr, 0, sizeof(sockaddr));
1731-
sockaddr.sin_family = AF_INET;
1732-
sockaddr.sin_addr.s_addr = INADDR_ANY; // bind to all IPs on this computer
1733-
sockaddr.sin_port = htons(nPort);
1726+
// some systems don't have IPV6_V6ONLY but are always v6only; others do have the option
1727+
// and enable it by default or not. Try to enable it, if possible.
1728+
if (addrBind.IsIPv6()) {
1729+
#ifdef IPV6_V6ONLY
1730+
setsockopt(hListenSocket, IPPROTO_IPV6, IPV6_V6ONLY, (void*)&nOne, sizeof(int));
17341731
#endif
1735-
if (::bind(hListenSocket, (struct sockaddr*)&sockaddr, sizeof(sockaddr)) == SOCKET_ERROR)
1732+
#ifdef WIN32
1733+
int nProtLevel = 10 /* PROTECTION_LEVEL_UNRESTRICTED */;
1734+
int nParameterId = 23 /* IPV6_PROTECTION_LEVEl */;
1735+
// this call is allowed to fail
1736+
setsockopt(hListenSocket, IPPROTO_IPV6, nParameterId, (const char*)&nProtLevel, sizeof(int));
1737+
#endif
1738+
}
1739+
#endif
1740+
1741+
if (::bind(hListenSocket, (struct sockaddr*)&sockaddr, len) == SOCKET_ERROR)
17361742
{
17371743
int nErr = WSAGetLastError();
17381744
if (nErr == WSAEADDRINUSE)
1739-
strError = strprintf(_("Unable to bind to port %d on this computer. Bitcoin is probably already running."), nPort);
1745+
strError = strprintf(_("Unable to bind to %s on this computer. Bitcoin is probably already running."), addrBind.ToString().c_str());
17401746
else
1741-
strError = strprintf("Error: Unable to bind to port %d on this computer (bind returned error %d, %s)", nPort, nErr, strerror(nErr));
1747+
strError = strprintf(_("Unable to bind to %s on this computer (bind returned error %d, %s)"), addrBind.ToString().c_str(), nErr, strerror(nErr));
17421748
printf("%s\n", strError.c_str());
17431749
return false;
17441750
}
1745-
printf("Bound to port %d\n", (int)nPort);
1751+
printf("Bound to %s\n", addrBind.ToString().c_str());
17461752

17471753
// Listen for incoming connections
17481754
if (listen(hListenSocket, SOMAXCONN) == SOCKET_ERROR)
@@ -1752,6 +1758,11 @@ bool BindListenPort(string& strError)
17521758
return false;
17531759
}
17541760

1761+
vhListenSocket.push_back(hListenSocket);
1762+
1763+
if (addrBind.IsRoutable() && GetBoolArg("-discover", true))
1764+
AddLocal(addrBind, LOCAL_BIND);
1765+
17551766
return true;
17561767
}
17571768

@@ -1915,9 +1926,10 @@ class CNetCleanup
19151926
BOOST_FOREACH(CNode* pnode, vNodes)
19161927
if (pnode->hSocket != INVALID_SOCKET)
19171928
closesocket(pnode->hSocket);
1918-
if (hListenSocket != INVALID_SOCKET)
1919-
if (closesocket(hListenSocket) == SOCKET_ERROR)
1920-
printf("closesocket(hListenSocket) failed with error %d\n", WSAGetLastError());
1929+
BOOST_FOREACH(SOCKET hListenSocket, vhListenSocket)
1930+
if (hListenSocket != INVALID_SOCKET)
1931+
if (closesocket(hListenSocket) == SOCKET_ERROR)
1932+
printf("closesocket(hListenSocket) failed with error %d\n", WSAGetLastError());
19211933

19221934
#ifdef WIN32
19231935
// Shutdown Windows Sockets

src/net.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,15 @@ CNode* FindNode(const CNetAddr& ip);
3838
CNode* FindNode(const CService& ip);
3939
CNode* ConnectNode(CAddress addrConnect, const char *strDest = NULL, int64 nTimeout=0);
4040
void MapPort(bool fMapPort);
41-
bool BindListenPort(std::string& strError=REF(std::string()));
41+
bool BindListenPort(const CService &bindAddr, std::string& strError=REF(std::string()));
4242
void StartNode(void* parg);
4343
bool StopNode();
4444

4545
enum
4646
{
4747
LOCAL_NONE, // unknown
4848
LOCAL_IF, // address a local interface listens on
49+
LOCAL_BIND, // address explicit bound to
4950
LOCAL_UPNP, // address reported by UPnP
5051
LOCAL_IRC, // address reported by IRC (deprecated)
5152
LOCAL_HTTP, // address reported by whatismyip.com and similars

0 commit comments

Comments
 (0)