From 0f79d723965a46e59dfbd239ad66c2d7c4bf5eeb Mon Sep 17 00:00:00 2001 From: Alexis Campailla Date: Tue, 24 Feb 2015 15:20:01 +0100 Subject: [PATCH] Workaround for getpeername() issue getpeername() is returning invalid addresses on ipv6 sockets accepted with AcceptEx, filling only 16 bytes of the address structure. Providing a workaround by saving the remote address returned by GetAcceptExSockaddrs, which is valid. --- src/Win32_Interop/win32_wsiocp.c | 32 ++++++++++++++++++++++++++++++-- src/Win32_Interop/win32_wsiocp.h | 3 ++- src/Win32_Interop/win32fixes.h | 1 + src/ae_wsiocp.c | 3 ++- src/anet.c | 4 ++++ 5 files changed, 39 insertions(+), 4 deletions(-) diff --git a/src/Win32_Interop/win32_wsiocp.c b/src/Win32_Interop/win32_wsiocp.c index c518469e..1704d8c5 100644 --- a/src/Win32_Interop/win32_wsiocp.c +++ b/src/Win32_Interop/win32_wsiocp.c @@ -29,11 +29,13 @@ #include "win32_wsiocp.h" #include "Win32_FDAPI.h" #include +#include static void *iocpState; static HANDLE iocph; static fnGetSockState * aeGetSockState; +static fnGetSockState * aeGetExistingSockState; static fnDelSockState * aeDelSockState; #define SUCCEEDED_WITH_IOCP(result) \ @@ -130,6 +132,7 @@ int aeWinAccept(int fd, struct sockaddr *sa, socklen_t *len) { SOCKADDR *premotesa; int locallen, remotelen; aacceptreq * areq; + aeSockState *acceptsockstate; if ((sockstate = aeGetSockState(iocpState, fd)) == NULL) { errno = WSAEINVAL; @@ -169,6 +172,13 @@ int aeWinAccept(int fd, struct sockaddr *sa, socklen_t *len) { aeWinSocketAttach(acceptsock); + // Save remote address to support aeWinGetPeerName() + if ((acceptsockstate = aeGetExistingSockState(iocpState, acceptsock)) == NULL) { + errno = WSAEINVAL; + return SOCKET_ERROR; + } + memcpy(&acceptsockstate->remoteAddress, premotesa, remotelen); + zfree(areq->buf); zfree(areq); @@ -180,6 +190,20 @@ int aeWinAccept(int fd, struct sockaddr *sa, socklen_t *len) { return acceptsock; } +int aeWinGetPeerName(int fd, struct sockaddr *addr, socklen_t * addrlen) { + aeSockState *sockState = aeGetExistingSockState(iocpState, fd); + if (sockState == NULL) { + errno = EBADF; + return -1; + } else { + if (sockState->remoteAddress.ss_family) { + memcpy(addr, &sockState->remoteAddress, *addrlen); + return 0; + } else { + return getpeername(fd, addr, addrlen); + } + } +} /* after doing read caller needs to call done * so that we can continue to check for read events. @@ -490,11 +514,15 @@ int aeWinCloseSocket(int fd) { return 0; } -void aeWinInit(void *state, HANDLE iocp, fnGetSockState *getSockState, - fnDelSockState *delSockState) { +void aeWinInit(void *state, + HANDLE iocp, + fnGetSockState *getSockState, + fnGetSockState *getExistingSockState, + fnDelSockState *delSockState) { iocpState = state; iocph = iocp; aeGetSockState = getSockState; + aeGetExistingSockState = getExistingSockState; aeDelSockState = delSockState; } diff --git a/src/Win32_Interop/win32_wsiocp.h b/src/Win32_Interop/win32_wsiocp.h index 4a7d9918..61d78e60 100644 --- a/src/Win32_Interop/win32_wsiocp.h +++ b/src/Win32_Interop/win32_wsiocp.h @@ -56,6 +56,7 @@ typedef struct aeSockState { int wreqs; OVERLAPPED ov_read; list wreqlist; + SOCKADDR_STORAGE remoteAddress; } aeSockState; typedef aeSockState * fnGetSockState(void *apistate, int fd); @@ -68,7 +69,7 @@ typedef void fnDelSockState(void *apistate, aeSockState *sockState); #define CONNECT_PENDING 0x002000 #define CLOSE_PENDING 0x004000 -void aeWinInit(void *state, HANDLE iocp, fnGetSockState *getSockState, fnDelSockState *delSockState); +void aeWinInit(void *state, HANDLE iocp, fnGetSockState *getSockState, fnGetSockState *getExistingSockState, fnDelSockState *delSockState); void aeWinCleanup(); #endif diff --git a/src/Win32_Interop/win32fixes.h b/src/Win32_Interop/win32fixes.h index 4dcfa230..855b4e81 100644 --- a/src/Win32_Interop/win32fixes.h +++ b/src/Win32_Interop/win32fixes.h @@ -301,6 +301,7 @@ int aeWinSocketSend(int fd, char *buf, int len, void *eventLoop, void *client, void *data, void *proc); int aeWinListen(int rfd, int backlog); int aeWinAccept(int fd, struct sockaddr *sa, socklen_t *len); +int aeWinGetPeerName(int fd, struct sockaddr *addr, socklen_t * addrlen); int aeWinSocketConnect(int fd, const SOCKADDR_STORAGE *ss); int aeWinSocketConnectBind(int fd, const SOCKADDR_STORAGE *ss, const char* source_addr); diff --git a/src/ae_wsiocp.c b/src/ae_wsiocp.c index f38a6de1..33e97e20 100644 --- a/src/ae_wsiocp.c +++ b/src/ae_wsiocp.c @@ -90,6 +90,7 @@ aeSockState *aeGetSockState(void *apistate, int fd) { sockState->wreqs = 0; sockState->reqs = NULL; memset(&sockState->wreqlist, 0, sizeof(sockState->wreqlist)); + memset(&sockState->remoteAddress, 0, sizeof(sockState->remoteAddress)); if (listAddNodeHead(socklist, sockState) != NULL) { return sockState; @@ -202,7 +203,7 @@ static int aeApiCreate(aeEventLoop *eventLoop) { state->setsize = eventLoop->setsize; eventLoop->apidata = state; /* initialize the IOCP socket code with state reference */ - aeWinInit(state, state->iocp, aeGetSockState, aeDelSockState); + aeWinInit(state, state->iocp, aeGetSockState, aeGetExistingSockState, aeDelSockState); return 0; } diff --git a/src/anet.c b/src/anet.c index d6a84c43..33ea2285 100644 --- a/src/anet.c +++ b/src/anet.c @@ -646,7 +646,11 @@ int anetPeerToString(int fd, char *ip, size_t ip_len, int *port) { struct sockaddr_storage sa; socklen_t salen = sizeof(sa); +#ifdef WIN32_IOCP + if (aeWinGetPeerName(fd,(struct sockaddr*)&sa,&salen) == -1) { +#else if (getpeername(fd,(struct sockaddr*)&sa,&salen) == -1) { +#endif if (port) *port = 0; ip[0] = '?'; ip[1] = '\0'; -- GitLab