diff --git a/bin/release/redis-2.8.12.zip b/bin/release/redis-2.8.12.zip index d1a7c6d65d731c0f2e37946715ece9e9bb831854..a5dda0fd6c56efc4e658b47ac092c34390cd8e7a 100644 Binary files a/bin/release/redis-2.8.12.zip and b/bin/release/redis-2.8.12.zip differ diff --git a/deps/hiredis/async.c b/deps/hiredis/async.c index 9d39d46ef32402d6ad802a0c421a1cc552e10592..56ea9a38753e9a1ebc9b6c6aa811725f3addf753 100644 --- a/deps/hiredis/async.c +++ b/deps/hiredis/async.c @@ -167,12 +167,24 @@ static void __redisAsyncCopyError(redisAsyncContext *ac) { #ifdef WIN32_IOCP redisAsyncContext *redisAsyncConnect(const char *ip, int port) { - struct sockaddr_in sa; - redisContext *c = redisPreConnectNonBlock(ip, port, &sa); + SOCKADDR_STORAGE ss; + redisContext *c = redisPreConnectNonBlock(ip, port, &ss); redisAsyncContext *ac = redisAsyncInitialize(c); - if (aeWinSocketConnect(ac->c.fd, (struct sockaddr *)&sa, sizeof(sa)) != 0) { + if (aeWinSocketConnect(ac->c.fd, &ss) != 0) { + ac->c.err = errno; + strerror_r(errno, ac->c.errstr, sizeof(ac->c.errstr)); + } + __redisAsyncCopyError(ac); + return ac; +} + +redisAsyncContext *redisAsyncConnectBind(const char *ip, int port, const char *source_addr) { + SOCKADDR_STORAGE ss; + redisContext *c = redisPreConnectNonBlock(ip, port, &ss); + redisAsyncContext *ac = redisAsyncInitialize(c); + if (aeWinSocketConnectBind(ac->c.fd, &ss, source_addr) != 0) { ac->c.err = errno; - strerror_r(errno,ac->c.errstr,sizeof(ac->c.errstr)); + strerror_r(errno, ac->c.errstr, sizeof(ac->c.errstr)); } __redisAsyncCopyError(ac); return ac; @@ -195,7 +207,6 @@ redisAsyncContext *redisAsyncConnect(const char *ip, int port) { __redisAsyncCopyError(ac); return ac; } -#endif redisAsyncContext *redisAsyncConnectBind(const char *ip, int port, const char *source_addr) { @@ -204,6 +215,7 @@ redisAsyncContext *redisAsyncConnectBind(const char *ip, int port, __redisAsyncCopyError(ac); return ac; } +#endif redisAsyncContext *redisAsyncConnectUnix(const char *path) { redisContext *c; diff --git a/deps/hiredis/hiredis.c b/deps/hiredis/hiredis.c index bf78590689059b04cc838484d6fe85e415af2e84..3bcbea004a94d4087acdef71662eadb15b5a05d7 100644 --- a/deps/hiredis/hiredis.c +++ b/deps/hiredis/hiredis.c @@ -1135,11 +1135,11 @@ redisContext *redisConnectFd(int fd) { } #ifdef _WIN32 -redisContext *redisPreConnectNonBlock(const char *ip, int port, struct sockaddr_in *sa) { +redisContext *redisPreConnectNonBlock(const char *ip, int port, SOCKADDR_STORAGE *ss) { redisContext *c = redisContextInit(); c->fd = -1; c->flags &= ~REDIS_BLOCK; - redisContextPreConnectTcp(c, ip, port, NULL, sa); + redisContextPreConnectTcp(c, ip, port, NULL, ss); return c; } #endif diff --git a/deps/hiredis/hiredis.h b/deps/hiredis/hiredis.h index d7151df07a82bc070a510a37a5466fa392f3fc9f..96f4a40addca695165259fd48d91a7a641411541 100644 --- a/deps/hiredis/hiredis.h +++ b/deps/hiredis/hiredis.h @@ -197,7 +197,7 @@ int redisFreeKeepFd(redisContext *c); int redisBufferRead(redisContext *c); int redisBufferWrite(redisContext *c, int *done); #ifdef _WIN32 -redisContext *redisPreConnectNonBlock(const char *ip, int port, struct sockaddr_in *sa); +redisContext *redisPreConnectNonBlock(const char *ip, int port, SOCKADDR_STORAGE *sa); int redisBufferReadDone(redisContext *c, char *buf, int nread); int redisBufferWriteDone(redisContext *c, int nwritten, int *done); #endif diff --git a/deps/hiredis/net.c b/deps/hiredis/net.c index 5e2a0c92fbaf3ce12899cfab0a2499e37ad36154..0f77b3347d1064a3f50e8a86db534fae23734a07 100644 --- a/deps/hiredis/net.c +++ b/deps/hiredis/net.c @@ -287,32 +287,21 @@ int redisContextSetTimeout(redisContext *c, const struct timeval tv) { } #ifdef _WIN32 -int redisContextPreConnectTcp(redisContext *c, const char *addr, int port, -struct timeval *timeout, struct sockaddr_in *sa) { + +int redisContextPreConnectTcp( + redisContext *c, + const char *addr, + int port, + struct timeval *timeout, + SOCKADDR_STORAGE* ss) { int blocking = (c->flags & REDIS_BLOCK); - unsigned long inAddress; - if (REDIS_OK != redisCreateSocket(c, AF_INET)) { - return REDIS_ERR; + if (ParseStorageAddress(addr, port, ss) == FALSE) { + DebugBreak(); } - sa->sin_family = AF_INET; - sa->sin_port = htons(port); - - inAddress = inet_addr(addr); - if (inAddress == INADDR_NONE || inAddress == INADDR_ANY) { - struct hostent *he; - - he = gethostbyname(addr); - if (he == NULL) { - __redisSetError(c, REDIS_ERR_OTHER, - sdscatprintf(sdsempty(), "can't resolve: %s\n", addr)); - close(c->fd); - return REDIS_ERR; - } - memcpy(&sa->sin_addr, he->h_addr, sizeof(struct in_addr)); - } else { - sa->sin_addr.s_addr = inAddress; + if (REDIS_OK != redisCreateSocket(c, ss->ss_family)) { + return REDIS_ERR; } if (redisSetTcpNoDelay(c) != REDIS_OK) diff --git a/deps/hiredis/net.h b/deps/hiredis/net.h index 20b468b7f6a62c7fc860e089fbe098c74b99d7c3..c684ed2689bab718ffaff12e43e75a2fa6dadbe7 100644 --- a/deps/hiredis/net.h +++ b/deps/hiredis/net.h @@ -49,7 +49,7 @@ int redisContextConnectUnix(redisContext *c, const char *path, const struct time int redisKeepAlive(redisContext *c, int interval); #ifdef _WIN32 -int redisContextPreConnectTcp(redisContext *c, const char *addr, int port, struct timeval *timeout, struct sockaddr_in *sa); +int redisContextPreConnectTcp(redisContext *c, const char *addr, int port, struct timeval *timeout, SOCKADDR_STORAGE *ss); #endif #endif diff --git a/src/Win32_Interop/Win32_FDAPI.cpp b/src/Win32_Interop/Win32_FDAPI.cpp index 6bfffcc0e2823d9f6c2f764e919ad91dcc7da174..77a1e9aa9e4f52587dc7a2ca7588d0cddd28a904 100644 --- a/src/Win32_Interop/Win32_FDAPI.cpp +++ b/src/Win32_Interop/Win32_FDAPI.cpp @@ -1022,6 +1022,43 @@ const char* redis_inet_ntop_impl(int af, const void *src, char *dst, size_t size } } +BOOL ParseStorageAddress(const char *ip, int port, SOCKADDR_STORAGE* pSotrageAddr) { + struct addrinfo hints, *res; + int status; + char port_buffer[6]; + + sprintf(port_buffer, "%hu", port); + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + /* Setting AI_PASSIVE will give you a wildcard address if addr is NULL */ + hints.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV | AI_PASSIVE; + + if ((status = getaddrinfo(ip, port_buffer, &hints, &res) != 0)) { + fprintf(stderr, "getaddrinfo: %S\n", gai_strerror(status)); + return FALSE; + } + + /* Note, we're taking the first valid address, there may be more than one */ + memcpy(pSotrageAddr, res->ai_addr, res->ai_addrlen); + + freeaddrinfo(res); + return TRUE; +} + +int StorageSize(SOCKADDR_STORAGE *ss) { + switch (ss->ss_family) { + case AF_INET: + return sizeof(SOCKADDR_IN); + case AF_INET6: + return sizeof(SOCKADDR_IN6); + default: + return -1; + } +} + + class Win32_FDSockMap { public: static Win32_FDSockMap& getInstance() { diff --git a/src/Win32_Interop/Win32_FDAPI.h b/src/Win32_Interop/Win32_FDAPI.h index 3cf7a37749179ec4643875bf4e2d4477fc611222..f27c61bab6da293baf2ca477a8ee04b60c81ac1c 100644 --- a/src/Win32_Interop/Win32_FDAPI.h +++ b/src/Win32_Interop/Win32_FDAPI.h @@ -249,6 +249,10 @@ BOOL FDAPI_ConnectEx(int fd,const struct sockaddr *name,int namelen,PVOID lpSend void FDAPI_GetAcceptExSockaddrs(int fd, PVOID lpOutputBuffer,DWORD dwReceiveDataLength,DWORD dwLocalAddressLength,DWORD dwRemoteAddressLength,LPSOCKADDR *LocalSockaddr,LPINT LocalSockaddrLength,LPSOCKADDR *RemoteSockaddr,LPINT RemoteSockaddrLength); int FDAPI_UpdateAcceptContext( int fd ); +// other networking functions +BOOL ParseStorageAddress(const char *ip, int port, SOCKADDR_STORAGE* pSotrageAddr); +int StorageSize(SOCKADDR_STORAGE *ss); + // macroize CRT definitions to point to our own #ifndef FDAPI_NOCRTREDEFS #define close(fd) fdapi_close(fd) diff --git a/src/Win32_Interop/win32_wsiocp.c b/src/Win32_Interop/win32_wsiocp.c index 6a8e3c21fa15c2e9e347f081554655a16dd86750..21d6147e7e1c1e1c900b991c6a6110956243f26d 100644 --- a/src/Win32_Interop/win32_wsiocp.c +++ b/src/Win32_Interop/win32_wsiocp.c @@ -281,12 +281,14 @@ int aeWinSocketSend(int fd, char *buf, int len, return SOCKET_ERROR; } + + + /* for non-blocking connect with IOCP */ -int aeWinSocketConnect(int fd, const struct sockaddr *sa, int len) { +int aeWinSocketConnect(int fd, const SOCKADDR_STORAGE *ss) { const GUID wsaid_connectex = WSAID_CONNECTEX; DWORD result; aeSockState *sockstate; - struct sockaddr_in addr; if ((sockstate = aeGetSockState(iocpState, fd)) == NULL) { errno = WSAEINVAL; @@ -298,14 +300,97 @@ int aeWinSocketConnect(int fd, const struct sockaddr *sa, int len) { } memset(&sockstate->ov_read, 0, sizeof(sockstate->ov_read)); + /* need to bind sock before connectex */ - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = INADDR_ANY; - addr.sin_port = 0; - result = bind(fd, (struct sockaddr *)&addr, sizeof(addr)); + switch (ss->ss_family) { + case AF_INET: + { + SOCKADDR_IN addr; + memset(&addr, 0, sizeof(SOCKADDR_IN)); + addr.sin_family = ss->ss_family; + addr.sin_addr.S_un.S_addr = INADDR_ANY; + addr.sin_port = 0; + result = bind(fd, (SOCKADDR*)&addr, sizeof(addr)); + + result = FDAPI_ConnectEx(fd, (SOCKADDR*)ss, sizeof(SOCKADDR_IN), NULL, 0, NULL, &sockstate->ov_read); + break; + } + case AF_INET6: + { + SOCKADDR_IN6 addr; + memset(&addr, 0, sizeof(SOCKADDR_IN6)); + addr.sin6_family = ss->ss_family; + memset(&(addr.sin6_addr.u.Byte), 0, 16); + addr.sin6_port = 0; + result = bind(fd, (SOCKADDR*)&addr, sizeof(addr)); + + result = FDAPI_ConnectEx(fd, (SOCKADDR*)ss, sizeof(SOCKADDR_IN6), NULL, 0, NULL, &sockstate->ov_read); + break; + } + default: + { + DebugBreak(); + } + } + + if (result != TRUE) { + result = WSAGetLastError(); + if (result == ERROR_IO_PENDING) { + errno = WSA_IO_PENDING; + sockstate->masks |= CONNECT_PENDING; + } else { + errno = result; + return SOCKET_ERROR; + } + } + return 0; +} + +int aeWinSocketConnectBind(int fd, const SOCKADDR_STORAGE *ss, const char* source_addr) { + const GUID wsaid_connectex = WSAID_CONNECTEX; + DWORD result; + aeSockState *sockstate; + + if ((sockstate = aeGetSockState(iocpState, fd)) == NULL) { + errno = WSAEINVAL; + return SOCKET_ERROR; + } + + if (aeWinSocketAttach(fd) != 0) { + return SOCKET_ERROR; + } + + memset(&sockstate->ov_read, 0, sizeof(sockstate->ov_read)); + + /* need to bind sock before connectex */ + switch (ss->ss_family) { + case AF_INET: + { + SOCKADDR_IN addr; + memset(&addr, 0, sizeof(SOCKADDR_IN)); + addr.sin_family = ss->ss_family; + addr.sin_addr.S_un.S_addr = INADDR_ANY; + addr.sin_port = 0; + result = bind(fd, (SOCKADDR*)&addr, sizeof(addr)); + break; + } + case AF_INET6: + { + SOCKADDR_IN6 addr; + memset(&addr, 0, sizeof(SOCKADDR_IN6)); + addr.sin6_family = ss->ss_family; + memset(&(addr.sin6_addr.u.Byte), 0, 16); + addr.sin6_port = 0; + result = bind(fd, (SOCKADDR*)&addr, sizeof(addr)); + break; + } + default: + { + DebugBreak(); + } + } - result = FDAPI_ConnectEx(fd, sa, len, NULL, 0, NULL, &sockstate->ov_read); + result = FDAPI_ConnectEx(fd, (const LPSOCKADDR)ss, StorageSize(ss), NULL, 0, NULL, &sockstate->ov_read); if (result != TRUE) { result = WSAGetLastError(); if (result == ERROR_IO_PENDING) { diff --git a/src/Win32_Interop/win32fixes.h b/src/Win32_Interop/win32fixes.h index 2f75d55db8f1e3be17d9fe4bbd84d16860b25686..f07ddf96f9a03f71eea36a18a443e75bacd530f7 100644 --- a/src/Win32_Interop/win32fixes.h +++ b/src/Win32_Interop/win32fixes.h @@ -299,7 +299,8 @@ 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 aeWinSocketConnect(int fd, const struct sockaddr *sa, int len); +int aeWinSocketConnect(int fd, const SOCKADDR_STORAGE *ss); +int aeWinSocketConnectBind(int fd, const SOCKADDR_STORAGE *ss, const char* source_addr); int strerror_r(int err, char* buf, size_t buflen); char *wsa_strerror(int err); diff --git a/src/anet.c b/src/anet.c index 4160aa3519fdb0e78d71cb291bd81b00b9e4448f..5688bed50f9c2a8d2013fb7a261f23397e6d7864 100644 --- a/src/anet.c +++ b/src/anet.c @@ -260,31 +260,14 @@ static int anetCreateSocket(char *err, int domain) { #define ANET_CONNECT_NONBLOCK 1 static int anetTcpGenericConnect(char *err, char *addr, int port, int flags) { int rfd; - struct sockaddr_in sa; - unsigned long inAddress; + SOCKADDR_STORAGE ss; - if ((rfd = anetCreateSocket(err,AF_INET)) == ANET_ERR) { - return ANET_ERR; - } - sa.sin_family = AF_INET; - sa.sin_port = htons((u_short)port); - inAddress = inet_addr(addr); - if (inAddress == INADDR_NONE || inAddress == INADDR_ANY) { - struct hostent *he; + ParseStorageAddress(addr, port, &ss); - he = gethostbyname(addr); - if (he == NULL) { - anetSetError(err, "can't resolve: %s\n", addr); - close(rfd); - return ANET_ERR; - } - memcpy(&sa.sin_addr, he->h_addr, sizeof(struct in_addr)); - } - else { - sa.sin_addr.s_addr = inAddress; + if ((rfd = anetCreateSocket(err,ss.ss_family)) == ANET_ERR) { + return ANET_ERR; } - - if (aeWinSocketConnect(rfd, (struct sockaddr*)&sa, sizeof(sa)) == SOCKET_ERROR) { + if (aeWinSocketConnect(rfd, &ss ) == SOCKET_ERROR) { if ((errno == WSAEWOULDBLOCK || errno == WSA_IO_PENDING)) errno = EINPROGRESS; if (errno == EINPROGRESS && flags & ANET_CONNECT_NONBLOCK) { return rfd; diff --git a/src/redis-benchmark.c b/src/redis-benchmark.c index 34b77e016c480db76f2f37a8ca683ce3781cb02e..02e2e2857603beb3b4167965df90a1babf6d25d8 100644 --- a/src/redis-benchmark.c +++ b/src/redis-benchmark.c @@ -364,9 +364,9 @@ static client createClient(char *cmd, size_t len, client from) { if (config.hostsocket == NULL) { #ifdef WIN32_IOCP - struct sockaddr_in sa; - c->context = redisPreConnectNonBlock(config.hostip,config.hostport, &sa); - if (aeWinSocketConnect(c->context->fd, (struct sockaddr *)&sa, sizeof(sa)) != 0) { + SOCKADDR_STORAGE ss; + c->context = redisPreConnectNonBlock(config.hostip,config.hostport, &ss); + if (aeWinSocketConnect(c->context->fd, &ss) != 0) { c->context->err = errno; strerror_r(errno,c->context->errstr,sizeof(c->context->errstr)); } diff --git a/tests/instances.tcl b/tests/instances.tcl index c65bbf0bafad2c6794fdb74f2a7a2d094d530652..670b20241ec05236ae8b941f2317d89c537f4028 100644 --- a/tests/instances.tcl +++ b/tests/instances.tcl @@ -406,7 +406,7 @@ proc restart_instance {type id} { # Check that the instance is running if {[server_is_up 127.0.0.1 $port 100] == 0} { - abort_sentinel_test "Problems starting $type #$j: ping timeout" + abort_sentinel_test "Problems starting $type: ping timeout" } # Connect with it with a fresh link