summaryrefslogtreecommitdiff
path: root/src/modules/netlib/netlibbind.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/modules/netlib/netlibbind.cpp')
-rw-r--r--src/modules/netlib/netlibbind.cpp129
1 files changed, 93 insertions, 36 deletions
diff --git a/src/modules/netlib/netlibbind.cpp b/src/modules/netlib/netlibbind.cpp
index 6c0c4c19e9..5fb9c252cc 100644
--- a/src/modules/netlib/netlibbind.cpp
+++ b/src/modules/netlib/netlibbind.cpp
@@ -2,7 +2,7 @@
Miranda IM: the free IM client for Microsoft* Windows*
-Copyright 2000-2009 Miranda ICQ/IM project,
+Copyright 2000-2012 Miranda ICQ/IM project,
all portions of this codebase are copyrighted to the people
listed in contributors.txt.
@@ -23,17 +23,19 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "commonheaders.h"
#include "netlib.h"
-bool BindSocketToPort(const char *szPorts, SOCKET s, int* portn)
+bool BindSocketToPort(const char *szPorts, SOCKET s, SOCKET s6, int* portn)
{
SOCKADDR_IN sin = {0};
sin.sin_family = AF_INET;
- sin.sin_addr.s_addr = htonl(INADDR_ANY);
+
+ SOCKADDR_IN6 sin6 = {0};
+ sin6.sin6_family = AF_INET6;
EnterCriticalSection(&csNetlibUser);
- if (--*portn < 0 && s != INVALID_SOCKET)
+ if (--*portn < 0 && (s != INVALID_SOCKET || s6 != INVALID_SOCKET))
{
- BindSocketToPort(szPorts, INVALID_SOCKET, portn);
+ BindSocketToPort(szPorts, INVALID_SOCKET, INVALID_SOCKET, portn);
if (*portn == 0)
{
LeaveCriticalSection(&csNetlibUser);
@@ -88,7 +90,12 @@ bool BindSocketToPort(const char *szPorts, SOCKET s, int* portn)
}
sin.sin_port = htons((WORD)port);
- if (bind(s, (SOCKADDR*)&sin, sizeof(sin)) == 0)
+ bool bV4Mapped = s == INVALID_SOCKET || bind(s, (SOCKADDR*)&sin, sizeof(sin)) == 0;
+
+ sin6.sin6_port = htons((WORD)port);
+ bool bV6Mapped = s6 == INVALID_SOCKET || bind(s6, (PSOCKADDR)&sin6, sizeof(sin6)) == 0;
+
+ if (bV4Mapped && bV6Mapped)
{
LeaveCriticalSection(&csNetlibUser);
*portn = portnum + 1;
@@ -111,10 +118,10 @@ bool BindSocketToPort(const char *szPorts, SOCKET s, int* portn)
}
}
-
int NetlibFreeBoundPort(struct NetlibBoundPort *nlbp)
{
closesocket(nlbp->s);
+ closesocket(nlbp->s6);
WaitForSingleObject(nlbp->hThread,INFINITE);
CloseHandle(nlbp->hThread);
NetlibLogf(nlbp->nlu, "(%u) Port %u closed for incoming connections", nlbp->s, nlbp->wPort);
@@ -125,18 +132,39 @@ int NetlibFreeBoundPort(struct NetlibBoundPort *nlbp)
static unsigned __stdcall NetlibBindAcceptThread(void* param)
{
SOCKET s;
- SOCKADDR_IN sin;
+ SOCKADDR_INET_M sin;
int sinLen;
struct NetlibConnection *nlc;
struct NetlibBoundPort *nlbp = (NetlibBoundPort*)param;
NetlibLogf(nlbp->nlu, "(%u) Port %u opened for incoming connections", nlbp->s, nlbp->wPort);
- for(;;)
+ for (;;)
{
+ fd_set r;
+ FD_ZERO(&r);
+ FD_SET(nlbp->s, &r);
+ FD_SET(nlbp->s6, &r);
+
+ if (select(0, &r, NULL, NULL, NULL) == SOCKET_ERROR)
+ break;
+
sinLen = sizeof(sin);
- s = accept(nlbp->s, (struct sockaddr*)&sin, &sinLen);
- if (s == INVALID_SOCKET) break;
- NetlibLogf(nlbp->nlu, "New incoming connection on port %u from %s (%d)", nlbp->wPort, inet_ntoa(sin.sin_addr), s);
+ memset(&sin, 0, sizeof(sin));
+
+ if (FD_ISSET(nlbp->s, &r))
+ {
+ s = accept(nlbp->s, (struct sockaddr*)&sin, &sinLen);
+ if (s == INVALID_SOCKET) break;
+ }
+ else if (FD_ISSET(nlbp->s6, &r))
+ {
+ s = accept(nlbp->s6, (struct sockaddr*)&sin, &sinLen);
+ if (s == INVALID_SOCKET) break;
+ }
+
+ char *szHostA = NetlibAddressToString(&sin);
+ NetlibLogf(nlbp->nlu, "New incoming connection on port %u from %s (%p )", nlbp->wPort, szHostA, s);
+ mir_free(szHostA);
nlc = (NetlibConnection*)mir_calloc(sizeof(NetlibConnection));
nlc->handleType = NLH_CONNECTION;
nlc->nlu = nlbp->nlu;
@@ -144,21 +172,22 @@ static unsigned __stdcall NetlibBindAcceptThread(void* param)
nlc->s2 = INVALID_SOCKET;
InitializeCriticalSection(&nlc->csHttpSequenceNums);
nlc->hOkToCloseEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
- nlc->dontCloseNow = 0;
NetlibInitializeNestedCS(&nlc->ncsSend);
NetlibInitializeNestedCS(&nlc->ncsRecv);
- nlbp->pfnNewConnectionV2((HANDLE)nlc,ntohl(sin.sin_addr.S_un.S_addr), nlbp->pExtra);
+
+ if (nlbp->pfnNewConnectionV2) nlbp->pfnNewConnectionV2(nlc, ntohl(sin.Ipv4.sin_addr.S_un.S_addr), nlbp->pExtra);
}
NetlibUPnPDeletePortMapping(nlbp->wExPort, "TCP");
return 0;
}
-INT_PTR NetlibBindPort(WPARAM wParam,LPARAM lParam)
+INT_PTR NetlibBindPort(WPARAM wParam, LPARAM lParam)
{
NETLIBBIND *nlb = (NETLIBBIND*)lParam;
struct NetlibUser *nlu = (struct NetlibUser*)wParam;
struct NetlibBoundPort *nlbp;
- SOCKADDR_IN sin;
+ SOCKADDR_IN sin = {0};
+ SOCKADDR_IN6 sin6 = {0};
int foundPort = 0;
UINT dwThreadId;
@@ -178,23 +207,24 @@ INT_PTR NetlibBindPort(WPARAM wParam,LPARAM lParam)
nlbp->handleType = NLH_BOUNDPORT;
nlbp->nlu = nlu;
nlbp->pfnNewConnectionV2 = nlb->pfnNewConnectionV2;
- nlbp->s = socket(AF_INET, SOCK_STREAM, 0);
+
+ nlbp->s = socket(PF_INET, SOCK_STREAM, 0);
+ nlbp->s6 = socket(PF_INET6, SOCK_STREAM, 0);
nlbp->pExtra = (nlb->cbSize != NETLIBBIND_SIZEOF_V1) ? nlb->pExtra : NULL;
- if (nlbp->s == INVALID_SOCKET)
+ if (nlbp->s == INVALID_SOCKET && nlbp->s6 == INVALID_SOCKET)
{
NetlibLogf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"socket",WSAGetLastError());
mir_free(nlbp);
return 0;
}
sin.sin_family = AF_INET;
- sin.sin_addr.s_addr = htonl(INADDR_ANY);
- sin.sin_port = 0;
+ sin6.sin6_family = AF_INET6;
/* if the netlib user wanted a free port given in the range, then
they better have given wPort==0, let's hope so */
if (nlu->settings.specifyIncomingPorts && nlu->settings.szIncomingPorts && nlb->wPort == 0)
{
- if (!BindSocketToPort(nlu->settings.szIncomingPorts, nlbp->s, &nlu->outportnum))
+ if (!BindSocketToPort(nlu->settings.szIncomingPorts, nlbp->s, nlbp->s6, &nlu->outportnum))
{
NetlibLogf(nlu, "Netlib bind: Not enough ports for incoming connections specified");
SetLastError(WSAEADDRINUSE);
@@ -210,52 +240,78 @@ INT_PTR NetlibBindPort(WPARAM wParam,LPARAM lParam)
{
NetlibLogf(nlu,"%s %d: trying to bind port %d, this 'feature' can be abused, please be sure you want to allow it.",__FILE__,__LINE__,nlb->wPort);
sin.sin_port = htons(nlb->wPort);
+ sin6.sin6_port = htons(nlb->wPort);
}
if (bind(nlbp->s, (PSOCKADDR)&sin, sizeof(sin)) == 0)
+ {
+ SOCKADDR_IN sin = {0};
+ int len = sizeof(sin);
+ if (!getsockname(nlbp->s, (PSOCKADDR)&sin, &len))
+ sin6.sin6_port = sin.sin_port;
+ foundPort = 1;
+ }
+
+ if (bind(nlbp->s6, (PSOCKADDR)&sin6, sizeof(sin6)) == 0)
foundPort = 1;
}
if (!foundPort)
{
NetlibLogf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"bind",WSAGetLastError());
closesocket(nlbp->s);
+ closesocket(nlbp->s6);
mir_free(nlbp);
return 0;
}
- if (listen(nlbp->s, 5))
+ if (nlbp->s != INVALID_SOCKET && listen(nlbp->s, 5))
{
NetlibLogf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"listen",WSAGetLastError());
closesocket(nlbp->s);
+ closesocket(nlbp->s6);
mir_free(nlbp);
return 0;
}
- { int len;
- DWORD extIP;
+ if (nlbp->s6 != INVALID_SOCKET && listen(nlbp->s6, 5))
+ {
+ NetlibLogf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"listen",WSAGetLastError());
+ closesocket(nlbp->s);
+ closesocket(nlbp->s6);
+ mir_free(nlbp);
+ return 0;
+ }
- ZeroMemory(&sin,sizeof(sin));
- len = sizeof(sin);
- if (getsockname(nlbp->s,(SOCKADDR *)&sin,&len))
+ {
+ SOCKADDR_INET_M sin = {0};
+ int len = sizeof(sin);
+ if (!getsockname(nlbp->s, (PSOCKADDR)&sin, &len))
+ {
+ nlb->wPort = ntohs(sin.Ipv4.sin_port);
+ nlb->dwInternalIP = ntohl(sin.Ipv4.sin_addr.S_un.S_addr);
+ }
+ else if (!getsockname(nlbp->s6, (PSOCKADDR)&sin, &len))
+ nlb->wPort = ntohs(sin.Ipv6.sin6_port);
+ else
{
NetlibLogf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"getsockname",WSAGetLastError());
closesocket(nlbp->s);
+ closesocket(nlbp->s6);
mir_free(nlbp);
return 0;
}
- nlb->wPort = ntohs(sin.sin_port);
nlbp->wPort = nlb->wPort;
- nlb->dwInternalIP = ntohl(sin.sin_addr.S_un.S_addr);
if (nlb->dwInternalIP == 0)
{
- char hostname[64];
- struct hostent *he;
-
+ char hostname[64] = "";
gethostname(hostname, SIZEOF(hostname));
- he = gethostbyname(hostname);
- if (he && he->h_addr_list[0])
- nlb->dwInternalIP = ntohl(*(PDWORD)he->h_addr_list[0]);
- }
+
+ PHOSTENT he = gethostbyname(hostname);
+ if (he && he->h_addr)
+ nlb->dwInternalIP = ntohl(*(PDWORD)he->h_addr);
+ }
+
+ DWORD extIP;
if (nlu->settings.enableUPnP &&
NetlibUPnPAddPortMapping(nlb->wPort, "TCP", &nlbp->wExPort, &extIP, nlb->cbSize > NETLIBBIND_SIZEOF_V2))
{
@@ -282,6 +338,7 @@ INT_PTR NetlibBindPort(WPARAM wParam,LPARAM lParam)
}
}
}
+
nlbp->hThread = (HANDLE)forkthreadex(NULL, 0, NetlibBindAcceptThread, 0, nlbp, &dwThreadId);
return (INT_PTR)nlbp;
}