diff --git a/async.c b/async.c index cbbfb6d63..a721164c7 100644 --- a/async.c +++ b/async.c @@ -29,9 +29,12 @@ * POSSIBILITY OF SUCH DAMAGE. */ +#include "config.h" #include "fmacros.h" #include +#ifndef HIREDIS_WIN #include +#endif #include #include #include "async.h" @@ -47,8 +50,9 @@ static unsigned int callbackHash(const void *key) { } static void *callbackValDup(void *privdata, const void *src) { + redisCallback *dup; ((void) privdata); - redisCallback *dup = malloc(sizeof(*dup)); + dup = malloc(sizeof(*dup)); memcpy(dup,src,sizeof(*dup)); return dup; } @@ -129,12 +133,14 @@ redisAsyncContext *redisAsyncConnect(const char *ip, int port) { return ac; } +#ifndef HIREDIS_WIN redisAsyncContext *redisAsyncConnectUnix(const char *path) { redisContext *c = redisConnectUnixNonBlock(path); redisAsyncContext *ac = redisAsyncInitialize(c); __redisAsyncCopyError(ac); return ac; } +#endif int redisAsyncSetConnectCallback(redisAsyncContext *ac, redisConnectCallback *fn) { if (ac->onConnect == NULL) { diff --git a/config.h b/config.h new file mode 100644 index 000000000..dcee20400 --- /dev/null +++ b/config.h @@ -0,0 +1,28 @@ +/* +Special config for MSVC build of hiredis + +Does absolutely nothing for Unix! +*/ +#ifndef __CONFIG_H +#define __CONFIG_H + +#include "hiredis.h" +#ifdef HIREDIS_WIN + +#ifndef va_copy +/* WARNING - DANGER - ASSUMES TYPICAL STACK MACHINE */ +#define va_copy(dst, src) ((void)((dst) = (src))) +#endif + +#if defined( _MSC_VER ) && !defined( __cplusplus ) +#define inline __inline +#endif + +#define snprintf sprintf_s +#define strcasecmp strcmp +#define strncasecmp _strnicmp +#define strerror_r(errorno, buf, len) strerror_s(buf, len, errorno) + +#endif + +#endif \ No newline at end of file diff --git a/example.c b/example.c index 90ff9ed5e..a08eac8f8 100644 --- a/example.c +++ b/example.c @@ -4,6 +4,10 @@ #include "hiredis.h" +#ifdef HIREDIS_WIN +#define snprintf sprintf_s +#endif + int main(void) { unsigned int j; redisContext *c; diff --git a/hiredis.c b/hiredis.c index 9ea998ace..9d9221326 100644 --- a/hiredis.c +++ b/hiredis.c @@ -29,10 +29,13 @@ * POSSIBILITY OF SUCH DAMAGE. */ +#include "config.h" #include "fmacros.h" #include #include +#ifndef HIREDIS_WIN #include +#endif #include #include #include @@ -796,7 +799,7 @@ int redisvFormatCommand(char **target, const char *format, va_list ap) { } /* Consume and discard vararg */ - va_arg(ap,void); + va_arg(ap,char*); } } @@ -832,7 +835,12 @@ int redisvFormatCommand(char **target, const char *format, va_list ap) { pos = sprintf(cmd,"*%d\r\n",argc); for (j = 0; j < argc; j++) { +#ifdef HIREDIS_WIN + /* %zu not understood by VS2008 */ + pos += sprintf(cmd+pos,"$%lu\r\n",sdslen(curargv[j])); +#else pos += sprintf(cmd+pos,"$%zu\r\n",sdslen(curargv[j])); +#endif memcpy(cmd+pos,curargv[j],sdslen(curargv[j])); pos += sdslen(curargv[j]); sdsfree(curargv[j]); @@ -941,6 +949,19 @@ void __redisSetError(redisContext *c, int type, const char *str) { static redisContext *redisContextInit(void) { redisContext *c; +#ifdef HIREDIS_WIN + /* fireup Windows socket stuff */ + WORD wVersionRequested = MAKEWORD(2, 0); + WSADATA wsaData; + int ret; + + ret = WSAStartup(wVersionRequested, &wsaData); + if (ret != 0) { + fprintf(stderr, "error: WSAStartup() failed: %d\n", ret); + return NULL; + } +#endif + c = calloc(1,sizeof(redisContext)); if (c == NULL) return NULL; @@ -954,7 +975,11 @@ static redisContext *redisContextInit(void) { void redisFree(redisContext *c) { if (c->fd > 0) +#ifdef HIREDIS_WIN + closesocket(c->fd); +#else close(c->fd); +#endif if (c->obuf != NULL) sdsfree(c->obuf); if (c->reader != NULL) @@ -986,6 +1011,8 @@ redisContext *redisConnectNonBlock(const char *ip, int port) { return c; } +#ifndef HIREDIS_WIN +/* no Unix Domaind stuff */ redisContext *redisConnectUnix(const char *path) { redisContext *c = redisContextInit(); c->flags |= REDIS_BLOCK; @@ -1006,6 +1033,7 @@ redisContext *redisConnectUnixNonBlock(const char *path) { redisContextConnectUnix(c,path,NULL); return c; } +#endif /* Set read/write timeout on a blocking socket. */ int redisSetTimeout(redisContext *c, struct timeval tv) { @@ -1027,7 +1055,11 @@ int redisBufferRead(redisContext *c) { if (c->err) return REDIS_ERR; +#ifdef HIREDIS_WIN + nread = recv(c->fd,buf,sizeof(buf),0); +#else nread = read(c->fd,buf,sizeof(buf)); +#endif if (nread == -1) { if (errno == EAGAIN && !(c->flags & REDIS_BLOCK)) { /* Try again later */ @@ -1064,7 +1096,12 @@ int redisBufferWrite(redisContext *c, int *done) { return REDIS_ERR; if (sdslen(c->obuf) > 0) { +#ifdef HIREDIS_WIN + /* not treated as a file */ + nwritten = send(c->fd,c->obuf,sdslen(c->obuf),0); +#else nwritten = write(c->fd,c->obuf,sdslen(c->obuf)); +#endif if (nwritten == -1) { if (errno == EAGAIN && !(c->flags & REDIS_BLOCK)) { /* Try again later */ diff --git a/hiredis.h b/hiredis.h index 3c3491cac..9e2f9d626 100644 --- a/hiredis.h +++ b/hiredis.h @@ -31,9 +31,20 @@ #ifndef __HIREDIS_H #define __HIREDIS_H + +#if defined(_MSC_VER) +#define HIREDIS_WIN 1 +#endif + #include /* for size_t */ #include /* for va_list */ + +#ifndef HIREDIS_WIN #include /* for struct timeval */ +#else +#include +#include +#endif #define HIREDIS_MAJOR 0 #define HIREDIS_MINOR 10 diff --git a/net.c b/net.c index 98eee5d21..8bae42b22 100644 --- a/net.c +++ b/net.c @@ -30,8 +30,10 @@ * POSSIBILITY OF SUCH DAMAGE. */ +#include "config.h" #include "fmacros.h" #include +#ifndef HIREDIS_WIN #include #include #include @@ -39,16 +41,28 @@ #include #include #include -#include -#include #include +#include #include +#endif +#include #include #include #include "net.h" #include "sds.h" +#ifdef HIREDIS_WIN +#define close closesocket +#define SETERRNO errnox = WSAGetLastError() +#define EINPROGRESS WSAEINPROGRESS +#undef errno +int errnox = EINPROGRESS; +#define errno errnox +#else +#define SETERRNO +#endif + /* Defined in hiredis.c */ void __redisSetError(redisContext *c, int type, const char *str); @@ -65,11 +79,13 @@ static void __redisSetErrorFromErrno(redisContext *c, int type, const char *pref static int redisCreateSocket(redisContext *c, int type) { int s, on = 1; if ((s = socket(type, SOCK_STREAM, 0)) == -1) { + SETERRNO; __redisSetErrorFromErrno(c,REDIS_ERR_IO,NULL); return REDIS_ERR; } if (type == AF_INET) { - if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) { + if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char*)&on, sizeof(on)) == -1) { + SETERRNO; __redisSetErrorFromErrno(c,REDIS_ERR_IO,NULL); close(s); return REDIS_ERR; @@ -79,6 +95,24 @@ static int redisCreateSocket(redisContext *c, int type) { } static int redisSetBlocking(redisContext *c, int fd, int blocking) { +#ifdef HIREDIS_WIN + int iResult; + int flag; + + if (blocking) + flag = 0; + else + flag = 1; + + iResult = ioctlsocket(fd, FIONBIO, &flag); + if (iResult != NO_ERROR) + { + SETERRNO; + __redisSetErrorFromErrno(c,REDIS_ERR_IO,"fcntl(F_SETFL)"); + close(fd); + return REDIS_ERR; + } +#else int flags; /* Set the socket nonblocking. @@ -100,12 +134,14 @@ static int redisSetBlocking(redisContext *c, int fd, int blocking) { close(fd); return REDIS_ERR; } +#endif return REDIS_OK; } static int redisSetTcpNoDelay(redisContext *c, int fd) { int yes = 1; - if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &yes, sizeof(yes)) == -1) { + if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char*)&yes, sizeof(yes)) == -1) { + SETERRNO; __redisSetErrorFromErrno(c,REDIS_ERR_IO,"setsockopt(TCP_NODELAY)"); close(fd); return REDIS_ERR; @@ -126,18 +162,27 @@ static int redisContextWaitReady(redisContext *c, int fd, const struct timeval * toptr = &to; } +#ifdef HIREDIS_WIN + if (errno == EINPROGRESS || errno == WSAEWOULDBLOCK) { +#else if (errno == EINPROGRESS) { +#endif FD_ZERO(&wfd); FD_SET(fd, &wfd); if (select(FD_SETSIZE, NULL, &wfd, NULL, toptr) == -1) { + SETERRNO; __redisSetErrorFromErrno(c,REDIS_ERR_IO,"select(2)"); close(fd); return REDIS_ERR; } if (!FD_ISSET(fd, &wfd)) { +#ifdef HIREDIS_WIN + errno = WSAETIMEDOUT; +#else errno = ETIMEDOUT; +#endif __redisSetErrorFromErrno(c,REDIS_ERR_IO,NULL); close(fd); return REDIS_ERR; @@ -145,7 +190,8 @@ static int redisContextWaitReady(redisContext *c, int fd, const struct timeval * err = 0; errlen = sizeof(err); - if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &errlen) == -1) { + if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (char*)&err, &errlen) == -1) { + SETERRNO; __redisSetErrorFromErrno(c,REDIS_ERR_IO,"getsockopt(SO_ERROR)"); close(fd); return REDIS_ERR; @@ -161,17 +207,20 @@ static int redisContextWaitReady(redisContext *c, int fd, const struct timeval * return REDIS_OK; } + SETERRNO; __redisSetErrorFromErrno(c,REDIS_ERR_IO,NULL); close(fd); return REDIS_ERR; } int redisContextSetTimeout(redisContext *c, struct timeval tv) { - if (setsockopt(c->fd,SOL_SOCKET,SO_RCVTIMEO,&tv,sizeof(tv)) == -1) { + if (setsockopt(c->fd,SOL_SOCKET,SO_RCVTIMEO,(char*)&tv,sizeof(tv)) == -1) { + SETERRNO; __redisSetErrorFromErrno(c,REDIS_ERR_IO,"setsockopt(SO_RCVTIMEO)"); return REDIS_ERR; } - if (setsockopt(c->fd,SOL_SOCKET,SO_SNDTIMEO,&tv,sizeof(tv)) == -1) { + if (setsockopt(c->fd,SOL_SOCKET,SO_SNDTIMEO,(char*)&tv,sizeof(tv)) == -1) { + SETERRNO; __redisSetErrorFromErrno(c,REDIS_ERR_IO,"setsockopt(SO_SNDTIMEO)"); return REDIS_ERR; } @@ -190,7 +239,7 @@ int redisContextConnectTcp(redisContext *c, const char *addr, int port, struct t sa.sin_family = AF_INET; sa.sin_port = htons(port); - if (inet_aton(addr, &sa.sin_addr) == 0) { + if (inet_pton(AF_INET, addr, &sa.sin_addr) == 0) { struct hostent *he; he = gethostbyname(addr); @@ -205,6 +254,7 @@ int redisContextConnectTcp(redisContext *c, const char *addr, int port, struct t } if (connect(s, (struct sockaddr*)&sa, sizeof(sa)) == -1) { + SETERRNO; if (errno == EINPROGRESS && !blocking) { /* This is ok. */ } else { @@ -225,6 +275,7 @@ int redisContextConnectTcp(redisContext *c, const char *addr, int port, struct t return REDIS_OK; } +#ifndef HIREDIS_WIN int redisContextConnectUnix(redisContext *c, const char *path, struct timeval *timeout) { int s; int blocking = (c->flags & REDIS_BLOCK); @@ -254,3 +305,4 @@ int redisContextConnectUnix(redisContext *c, const char *path, struct timeval *t c->flags |= REDIS_CONNECTED; return REDIS_OK; } +#endif \ No newline at end of file diff --git a/net.h b/net.h index f9d3755b8..36aa9ac0c 100644 --- a/net.h +++ b/net.h @@ -41,6 +41,8 @@ int redisContextSetTimeout(redisContext *c, struct timeval tv); int redisContextConnectTcp(redisContext *c, const char *addr, int port, struct timeval *timeout); +#ifndef HIREDIS_WIN int redisContextConnectUnix(redisContext *c, const char *path, struct timeval *timeout); +#endif #endif diff --git a/sds.c b/sds.c index 0af9c6720..7e072a4aa 100644 --- a/sds.c +++ b/sds.c @@ -28,6 +28,7 @@ * POSSIBILITY OF SUCH DAMAGE. */ +#include "config.h" #include #include #include diff --git a/win32/example/example.vcproj b/win32/example/example.vcproj new file mode 100644 index 000000000..8d92acecc --- /dev/null +++ b/win32/example/example.vcproj @@ -0,0 +1,197 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/win32/hiredis.sln b/win32/hiredis.sln new file mode 100644 index 000000000..2f4bcd93b --- /dev/null +++ b/win32/hiredis.sln @@ -0,0 +1,29 @@ + +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual Studio 2008 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "hiredis", "hiredis.vcproj", "{62FE2454-AB35-4A57-9FA3-51892029221E}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "example", "example\example.vcproj", "{9715AC8D-EA96-4943-92D5-858F65D07EDB}" + ProjectSection(ProjectDependencies) = postProject + {62FE2454-AB35-4A57-9FA3-51892029221E} = {62FE2454-AB35-4A57-9FA3-51892029221E} + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {62FE2454-AB35-4A57-9FA3-51892029221E}.Debug|Win32.ActiveCfg = Debug|Win32 + {62FE2454-AB35-4A57-9FA3-51892029221E}.Debug|Win32.Build.0 = Debug|Win32 + {62FE2454-AB35-4A57-9FA3-51892029221E}.Release|Win32.ActiveCfg = Release|Win32 + {62FE2454-AB35-4A57-9FA3-51892029221E}.Release|Win32.Build.0 = Release|Win32 + {9715AC8D-EA96-4943-92D5-858F65D07EDB}.Debug|Win32.ActiveCfg = Debug|Win32 + {9715AC8D-EA96-4943-92D5-858F65D07EDB}.Debug|Win32.Build.0 = Debug|Win32 + {9715AC8D-EA96-4943-92D5-858F65D07EDB}.Release|Win32.ActiveCfg = Release|Win32 + {9715AC8D-EA96-4943-92D5-858F65D07EDB}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/win32/hiredis.vcproj b/win32/hiredis.vcproj new file mode 100644 index 000000000..36cc44c49 --- /dev/null +++ b/win32/hiredis.vcproj @@ -0,0 +1,205 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +