diff options
| -rw-r--r-- | .travis.yml | 39 | ||||
| -rw-r--r-- | CHANGELOG.md | 15 | ||||
| -rw-r--r-- | CMakeLists.txt | 5 | ||||
| -rw-r--r-- | README.md | 3 | ||||
| -rw-r--r-- | async.c | 10 | ||||
| -rw-r--r-- | hiredis.c | 80 | ||||
| -rw-r--r-- | hiredis.h | 8 | ||||
| -rw-r--r-- | net.c | 19 | ||||
| -rw-r--r-- | read.c | 84 | ||||
| -rw-r--r-- | read.h | 12 | ||||
| -rw-r--r-- | sds.c | 2 | ||||
| -rw-r--r-- | sds.h | 30 | ||||
| -rw-r--r-- | sockcompat.c | 26 | ||||
| -rw-r--r-- | sockcompat.h | 2 | ||||
| -rw-r--r-- | sslio.c | 4 | ||||
| -rw-r--r-- | test.c | 5 | ||||
| -rw-r--r-- | win32.h | 10 | 
17 files changed, 301 insertions, 53 deletions
| diff --git a/.travis.yml b/.travis.yml index 51171c0..dd8e0e7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,6 +8,12 @@ os:    - linux    - osx +branches: +  only: +    - staging +    - trying +    - master +  before_script:      - if [ "$TRAVIS_OS_NAME" == "osx" ] ; then brew update; brew install redis; fi @@ -56,3 +62,36 @@ script:    - cmake .. ${EXTRA_CMAKE_OPTS}    - make VERBOSE=1    - ctest -V + +matrix: +  include: +    # Windows MinGW cross compile on Linux +    - os: linux +      dist: xenial +      compiler: mingw +      addons: +        apt: +          packages: +            - ninja-build +            - gcc-mingw-w64-x86-64 +            - g++-mingw-w64-x86-64 +      script: +        - mkdir build && cd build +        - CC=x86_64-w64-mingw32-gcc CXX=x86_64-w64-mingw32-g++ cmake .. -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_BUILD_WITH_INSTALL_RPATH=on +        - ninja -v + +    # Windows MSVC 2017 +    - os: windows +      compiler: msvc +      env: +        - MATRIX_EVAL="CC=cl.exe && CXX=cl.exe" +      before_install: +        - eval "${MATRIX_EVAL}" +      install: +        - choco install ninja +      script: +        - mkdir build && cd build +        - cmd.exe /C '"C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC\Auxiliary\Build\vcvarsall.bat" amd64 && +          cmake .. -G Ninja -DCMAKE_BUILD_TYPE=Release && +          ninja -v' +        - ctest -V diff --git a/CHANGELOG.md b/CHANGELOG.md index a7fe3ac..d1d37e5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,16 @@    compare to other values, casting might be necessary or can be removed, if    casting was applied before. +### 0.x.x (unreleased) +**BREAKING CHANGES**: + +* Change `redisReply.len` to `size_t`, as it denotes the the size of a string + +User code should compare this to `size_t` values as well. +If it was used to compare to other values, casting might be necessary or can be removed, if casting was applied before. + +* `redisReplyObjectFunctions.createArray` now takes `size_t` for its length parameter. +  ### 0.14.0 (2018-09-25)  * Make string2ll static to fix conflict with Redis (Tom Lee [c3188b]) @@ -50,8 +60,9 @@  * Import latest upstream sds. This breaks applications that are linked against the old hiredis v0.13  * Fix warnings, when compiled with -Wshadow  * Make hiredis compile in Cygwin on Windows, now CI-tested - -**BREAKING CHANGES**: +* Bulk and multi-bulk lengths less than -1 or greater than `LLONG_MAX` are now +  protocol errors. This is consistent with the RESP specification. On 32-bit +  platforms, the upper bound is lowered to `SIZE_MAX`.  * Remove backwards compatibility macro's diff --git a/CMakeLists.txt b/CMakeLists.txt index c8c8071..30140bf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -47,7 +47,10 @@ INSTALL(TARGETS hiredis  INSTALL(FILES hiredis.h read.h sds.h async.h      DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/hiredis) - +     +INSTALL(DIRECTORY adapters +    DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/hiredis) +      INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/hiredis.pc      DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) @@ -286,6 +286,7 @@ return `REDIS_ERR`. The function to set the disconnect callback has the followin  ```c  int redisAsyncSetDisconnectCallback(redisAsyncContext *ac, redisDisconnectCallback *fn);  ``` +`ac->data` may be used to pass user data to this callback, the same can be done for redisConnectCallback.  ### Sending commands and their callbacks  In an asynchronous context, commands are automatically pipelined due to the nature of an event loop. @@ -406,6 +407,6 @@ as soon as possible in order to prevent allocation of useless memory.  ## AUTHORS  Hiredis was written by Salvatore Sanfilippo (antirez at gmail) and -Pieter Noordhuis (pcnoordhuis at gmail) and is released under the BSD license.   +Pieter Noordhuis (pcnoordhuis at gmail) and is released under the BSD license.  Hiredis is currently maintained by Matt Stancliff (matt at genges dot com) and  Jan-Erik Rediger (janerik at fnordig dot com) @@ -32,11 +32,8 @@  #include "fmacros.h"  #include <stdlib.h>  #include <string.h> -#ifndef _WIN32 +#ifndef _MSC_VER  #include <strings.h> -#else
 -#define strcasecmp stricmp
 -#define strncasecmp  strnicmp  #endif  #include <assert.h>  #include <ctype.h> @@ -46,6 +43,7 @@  #include "dict.c"  #include "sds.h"  #include "sslio.h" +#include "win32.h"  #define _EL_ADD_READ(ctx)                                         \      do {                                                          \ @@ -438,7 +436,7 @@ static int __redisGetSubscribeCallback(redisAsyncContext *ac, redisReply *reply,                  assert(reply->element[2]->type == REDIS_REPLY_INTEGER);                  /* Unset subscribed flag only when no pipelined pending subscribe. */ -                if (reply->element[2]->integer == 0  +                if (reply->element[2]->integer == 0                      && dictSize(ac->sub.channels) == 0                      && dictSize(ac->sub.patterns) == 0)                      c->flags &= ~REDIS_SUBSCRIBED; @@ -557,7 +555,7 @@ static int __redisAsyncHandleConnect(redisAsyncContext *ac) {  /**   * Handle SSL when socket becomes available for reading. This also handles   * read-while-write and write-while-read. - *  + *   * These functions will not work properly unless `HIREDIS_SSL` is defined   * (however, they will compile)   */ @@ -46,9 +46,11 @@  static redisReply *createReplyObject(int type);  static void *createStringObject(const redisReadTask *task, char *str, size_t len); -static void *createArrayObject(const redisReadTask *task, int elements); +static void *createArrayObject(const redisReadTask *task, size_t elements);  static void *createIntegerObject(const redisReadTask *task, long long value); +static void *createDoubleObject(const redisReadTask *task, double value, char *str, size_t len);  static void *createNilObject(const redisReadTask *task); +static void *createBoolObject(const redisReadTask *task, int bval);  /* Default set of functions to build the reply. Keep in mind that such a   * function returning NULL is interpreted as OOM. */ @@ -56,7 +58,9 @@ static redisReplyObjectFunctions defaultFunctions = {      createStringObject,      createArrayObject,      createIntegerObject, +    createDoubleObject,      createNilObject, +    createBoolObject,      freeReplyObject  }; @@ -83,6 +87,8 @@ void freeReplyObject(void *reply) {      case REDIS_REPLY_INTEGER:          break; /* Nothing to free */      case REDIS_REPLY_ARRAY: +    case REDIS_REPLY_MAP: +    case REDIS_REPLY_SET:          if (r->element != NULL) {              for (j = 0; j < r->elements; j++)                  freeReplyObject(r->element[j]); @@ -92,6 +98,7 @@ void freeReplyObject(void *reply) {      case REDIS_REPLY_ERROR:      case REDIS_REPLY_STATUS:      case REDIS_REPLY_STRING: +    case REDIS_REPLY_DOUBLE:          free(r->str);          break;      } @@ -124,16 +131,18 @@ static void *createStringObject(const redisReadTask *task, char *str, size_t len      if (task->parent) {          parent = task->parent->obj; -        assert(parent->type == REDIS_REPLY_ARRAY); +        assert(parent->type == REDIS_REPLY_ARRAY || +               parent->type == REDIS_REPLY_MAP || +               parent->type == REDIS_REPLY_SET);          parent->element[task->idx] = r;      }      return r;  } -static void *createArrayObject(const redisReadTask *task, int elements) { +static void *createArrayObject(const redisReadTask *task, size_t elements) {      redisReply *r, *parent; -    r = createReplyObject(REDIS_REPLY_ARRAY); +    r = createReplyObject(task->type);      if (r == NULL)          return NULL; @@ -149,7 +158,9 @@ static void *createArrayObject(const redisReadTask *task, int elements) {      if (task->parent) {          parent = task->parent->obj; -        assert(parent->type == REDIS_REPLY_ARRAY); +        assert(parent->type == REDIS_REPLY_ARRAY || +               parent->type == REDIS_REPLY_MAP || +               parent->type == REDIS_REPLY_SET);          parent->element[task->idx] = r;      }      return r; @@ -166,7 +177,41 @@ static void *createIntegerObject(const redisReadTask *task, long long value) {      if (task->parent) {          parent = task->parent->obj; -        assert(parent->type == REDIS_REPLY_ARRAY); +        assert(parent->type == REDIS_REPLY_ARRAY || +               parent->type == REDIS_REPLY_MAP || +               parent->type == REDIS_REPLY_SET); +        parent->element[task->idx] = r; +    } +    return r; +} + +static void *createDoubleObject(const redisReadTask *task, double value, char *str, size_t len) { +    redisReply *r, *parent; + +    r = createReplyObject(REDIS_REPLY_DOUBLE); +    if (r == NULL) +        return NULL; + +    r->dval = value; +    r->str = malloc(len+1); +    if (r->str == NULL) { +        freeReplyObject(r); +        return NULL; +    } + +    /* The double reply also has the original protocol string representing a +     * double as a null terminated string. This way the caller does not need +     * to format back for string conversion, especially since Redis does efforts +     * to make the string more human readable avoiding the calssical double +     * decimal string conversion artifacts. */ +    memcpy(r->str, str, len); +    r->str[len] = '\0'; + +    if (task->parent) { +        parent = task->parent->obj; +        assert(parent->type == REDIS_REPLY_ARRAY || +               parent->type == REDIS_REPLY_MAP || +               parent->type == REDIS_REPLY_SET);          parent->element[task->idx] = r;      }      return r; @@ -181,7 +226,28 @@ static void *createNilObject(const redisReadTask *task) {      if (task->parent) {          parent = task->parent->obj; -        assert(parent->type == REDIS_REPLY_ARRAY); +        assert(parent->type == REDIS_REPLY_ARRAY || +               parent->type == REDIS_REPLY_MAP || +               parent->type == REDIS_REPLY_SET); +        parent->element[task->idx] = r; +    } +    return r; +} + +static void *createBoolObject(const redisReadTask *task, int bval) { +    redisReply *r, *parent; + +    r = createReplyObject(REDIS_REPLY_BOOL); +    if (r == NULL) +        return NULL; + +    r->integer = bval != 0; + +    if (task->parent) { +        parent = task->parent->obj; +        assert(parent->type == REDIS_REPLY_ARRAY || +               parent->type == REDIS_REPLY_MAP || +               parent->type == REDIS_REPLY_SET);          parent->element[task->idx] = r;      }      return r; @@ -35,10 +35,10 @@  #define __HIREDIS_H  #include "read.h"  #include <stdarg.h> /* for va_list */ -#ifndef _WIN32 +#ifndef _MSC_VER  #include <sys/time.h> /* for struct timeval */  #else -#include <winsock2.h> +struct timeval; /* forward declaration */  #endif  #include <stdint.h> /* uintXX_t, etc */  #include "sds.h" /* for sds */ @@ -101,8 +101,10 @@ extern "C" {  typedef struct redisReply {      int type; /* REDIS_REPLY_* */      long long integer; /* The integer when type is REDIS_REPLY_INTEGER */ +    double dval; /* The double when type is REDIS_REPLY_DOUBLE */      size_t len; /* Length of string */ -    char *str; /* Used for both REDIS_REPLY_ERROR and REDIS_REPLY_STRING */ +    char *str; /* Used for REDIS_REPLY_ERROR, REDIS_REPLY_STRING +                  and REDIS_REPLY_DOUBLE (in additionl to dval). */      size_t elements; /* number of elements, for REDIS_REPLY_ARRAY */      struct redisReply **element; /* elements vector for REDIS_REPLY_ARRAY */  } redisReply; @@ -63,6 +63,10 @@ int redisNetRead(redisContext *c, char *buf, size_t bufcap) {          if ((errno == EWOULDBLOCK && !(c->flags & REDIS_BLOCK)) || (errno == EINTR)) {              /* Try again later */              return 0; +        } else if(errno == ETIMEDOUT && (c->flags & REDIS_BLOCK)) { +            /* especially in windows */ +            __redisSetError(c, REDIS_ERR_TIMEOUT, "recv timeout"); +            return -1;          } else {              __redisSetError(c, REDIS_ERR_IO, NULL);              return -1; @@ -310,11 +314,18 @@ int redisCheckSocketError(redisContext *c) {  }  int redisContextSetTimeout(redisContext *c, const struct timeval tv) { -    if (setsockopt(c->fd,SOL_SOCKET,SO_RCVTIMEO,&tv,sizeof(tv)) == -1) { +    const void *to_ptr = &tv; +    size_t to_sz = sizeof(tv); +#ifdef _WIN32 +    DWORD timeout_msec = tv.tv_sec * 1000 + tv.tv_usec / 1000; +    to_ptr = &timeout_msec; +    to_sz = sizeof(timeout_msec); +#endif +    if (setsockopt(c->fd,SOL_SOCKET,SO_RCVTIMEO,to_ptr,to_sz) == -1) {          __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,to_ptr,to_sz) == -1) {          __redisSetErrorFromErrno(c,REDIS_ERR_IO,"setsockopt(SO_SNDTIMEO)");          return REDIS_ERR;      } @@ -435,9 +446,7 @@ addrretry:          }          /* For repeat connection */ -        if (c->saddr) { -            free(c->saddr); -        } +        free(c->saddr);          c->saddr = malloc(p->ai_addrlen);          memcpy(c->saddr, p->ai_addr, p->ai_addrlen);          c->addrlen = p->ai_addrlen; @@ -29,9 +29,9 @@   * POSSIBILITY OF SUCH DAMAGE.   */ -  #include "fmacros.h"  #include <string.h> +#include <strings.h>  #include <stdlib.h>  #ifndef _MSC_VER  #include <unistd.h> @@ -40,6 +40,7 @@  #include <errno.h>  #include <ctype.h>  #include <limits.h> +#include <math.h>  #include "read.h"  #include "sds.h" @@ -243,7 +244,9 @@ static void moveToNextTask(redisReader *r) {          cur = &(r->rstack[r->ridx]);          prv = &(r->rstack[r->ridx-1]); -        assert(prv->type == REDIS_REPLY_ARRAY); +        assert(prv->type == REDIS_REPLY_ARRAY || +               prv->type == REDIS_REPLY_MAP || +               prv->type == REDIS_REPLY_SET);          if (cur->idx == prv->elements-1) {              r->ridx--;          } else { @@ -276,6 +279,47 @@ static int processLineItem(redisReader *r) {              } else {                  obj = (void*)REDIS_REPLY_INTEGER;              } +        } else if (cur->type == REDIS_REPLY_DOUBLE) { +            if (r->fn && r->fn->createDouble) { +                char buf[326], *eptr; +                double d; + +                if ((size_t)len >= sizeof(buf)) { +                    __redisReaderSetError(r,REDIS_ERR_PROTOCOL, +                            "Double value is too large"); +                    return REDIS_ERR; +                } + +                memcpy(buf,p,len); +                buf[len] = '\0'; + +                if (strcasecmp(buf,",inf") == 0) { +                    d = 1.0/0.0; /* Positive infinite. */ +                } else if (strcasecmp(buf,",-inf") == 0) { +                    d = -1.0/0.0; /* Nevative infinite. */ +                } else { +                    d = strtod((char*)buf,&eptr); +                    if (buf[0] == '\0' || eptr[0] != '\0' || isnan(d)) { +                        __redisReaderSetError(r,REDIS_ERR_PROTOCOL, +                                "Bad double value"); +                        return REDIS_ERR; +                    } +                } +                obj = r->fn->createDouble(cur,d,buf,len); +            } else { +                obj = (void*)REDIS_REPLY_DOUBLE; +            } +        } else if (cur->type == REDIS_REPLY_NIL) { +            if (r->fn && r->fn->createNil) +                obj = r->fn->createNil(cur); +            else +                obj = (void*)REDIS_REPLY_NIL; +        } else if (cur->type == REDIS_REPLY_BOOL) { +            int bval = p[0] == 't' || p[0] == 'T'; +            if (r->fn && r->fn->createBool) +                obj = r->fn->createBool(cur,bval); +            else +                obj = (void*)REDIS_REPLY_BOOL;          } else {              /* Type will be error or status. */              if (r->fn && r->fn->createString) @@ -362,7 +406,8 @@ static int processBulkItem(redisReader *r) {      return REDIS_ERR;  } -static int processMultiBulkItem(redisReader *r) { +/* Process the array, map and set types. */ +static int processAggregateItem(redisReader *r) {      redisReadTask *cur = &(r->rstack[r->ridx]);      void *obj;      char *p; @@ -385,7 +430,7 @@ static int processMultiBulkItem(redisReader *r) {          root = (r->ridx == 0); -        if (elements < -1 || elements > INT_MAX) { +        if (elements < -1 || (LLONG_MAX > SIZE_MAX && elements > SIZE_MAX)) {              __redisReaderSetError(r,REDIS_ERR_PROTOCOL,                      "Multi-bulk length out of range");              return REDIS_ERR; @@ -404,10 +449,12 @@ static int processMultiBulkItem(redisReader *r) {              moveToNextTask(r);          } else { +            if (cur->type == REDIS_REPLY_MAP) elements *= 2; +              if (r->fn && r->fn->createArray)                  obj = r->fn->createArray(cur,elements);              else -                obj = (void*)REDIS_REPLY_ARRAY; +                obj = (void*)(long)cur->type;              if (obj == NULL) {                  __redisReaderSetErrorOOM(r); @@ -455,12 +502,27 @@ static int processItem(redisReader *r) {              case ':':                  cur->type = REDIS_REPLY_INTEGER;                  break; +            case ',': +                cur->type = REDIS_REPLY_DOUBLE; +                break; +            case '_': +                cur->type = REDIS_REPLY_NIL; +                break;              case '$':                  cur->type = REDIS_REPLY_STRING;                  break;              case '*':                  cur->type = REDIS_REPLY_ARRAY;                  break; +            case '%': +                cur->type = REDIS_REPLY_MAP; +                break; +            case '~': +                cur->type = REDIS_REPLY_SET; +                break; +            case '#': +                cur->type = REDIS_REPLY_BOOL; +                break;              default:                  __redisReaderSetErrorProtocolByte(r,*p);                  return REDIS_ERR; @@ -476,11 +538,16 @@ static int processItem(redisReader *r) {      case REDIS_REPLY_ERROR:      case REDIS_REPLY_STATUS:      case REDIS_REPLY_INTEGER: +    case REDIS_REPLY_DOUBLE: +    case REDIS_REPLY_NIL: +    case REDIS_REPLY_BOOL:          return processLineItem(r);      case REDIS_REPLY_STRING:          return processBulkItem(r);      case REDIS_REPLY_ARRAY: -        return processMultiBulkItem(r); +    case REDIS_REPLY_MAP: +    case REDIS_REPLY_SET: +        return processAggregateItem(r);      default:          assert(NULL);          return REDIS_ERR; /* Avoid warning. */ @@ -590,8 +657,11 @@ int redisReaderGetReply(redisReader *r, void **reply) {      /* Emit a reply when there is one. */      if (r->ridx == -1) { -        if (reply != NULL) +        if (reply != NULL) {              *reply = r->reply; +        } else if (r->reply != NULL && r->fn && r->fn->freeObject) { +            r->fn->freeObject(r->reply); +        }          r->reply = NULL;      }      return REDIS_OK; @@ -54,6 +54,14 @@  #define REDIS_REPLY_NIL 4  #define REDIS_REPLY_STATUS 5  #define REDIS_REPLY_ERROR 6 +#define REDIS_REPLY_DOUBLE 7 +#define REDIS_REPLY_BOOL 8 +#define REDIS_REPLY_VERB 9 +#define REDIS_REPLY_MAP 9 +#define REDIS_REPLY_SET 10 +#define REDIS_REPLY_ATTR 11 +#define REDIS_REPLY_PUSH 12 +#define REDIS_REPLY_BIGNUM 13  #define REDIS_READER_MAX_BUF (1024*16)  /* Default max unused reader buffer. */ @@ -72,9 +80,11 @@ typedef struct redisReadTask {  typedef struct redisReplyObjectFunctions {      void *(*createString)(const redisReadTask*, char*, size_t); -    void *(*createArray)(const redisReadTask*, int); +    void *(*createArray)(const redisReadTask*, size_t);      void *(*createInteger)(const redisReadTask*, long long); +    void *(*createDouble)(const redisReadTask*, double, char*, size_t);      void *(*createNil)(const redisReadTask*); +    void *(*createBool)(const redisReadTask*, int);      void (*freeObject)(void*);  } redisReplyObjectFunctions; @@ -1035,7 +1035,7 @@ sds *sdssplitargs(const char *line, int *argc) {                      s_free(vector);                      return NULL;                  } -                 +                  vector = new_vector;                  vector[*argc] = current;                  (*argc)++; @@ -34,7 +34,7 @@  #define __SDS_H  #define SDS_MAX_PREALLOC (1024*1024) -#ifdef _WIN32 +#ifdef _MSC_VER  #define __attribute__(x)  #endif @@ -135,20 +135,20 @@ static inline void sdssetlen(sds s, size_t newlen) {          case SDS_TYPE_5:              {                  unsigned char *fp = ((unsigned char*)s)-1; -                *fp = SDS_TYPE_5 | (newlen << SDS_TYPE_BITS); +                *fp = (unsigned char)(SDS_TYPE_5 | (newlen << SDS_TYPE_BITS));              }              break;          case SDS_TYPE_8: -            SDS_HDR(8,s)->len = newlen; +            SDS_HDR(8,s)->len = (uint8_t)newlen;              break;          case SDS_TYPE_16: -            SDS_HDR(16,s)->len = newlen; +            SDS_HDR(16,s)->len = (uint16_t)newlen;              break;          case SDS_TYPE_32: -            SDS_HDR(32,s)->len = newlen; +            SDS_HDR(32,s)->len = (uint32_t)newlen;              break;          case SDS_TYPE_64: -            SDS_HDR(64,s)->len = newlen; +            SDS_HDR(64,s)->len = (uint64_t)newlen;              break;      }  } @@ -159,21 +159,21 @@ static inline void sdsinclen(sds s, size_t inc) {          case SDS_TYPE_5:              {                  unsigned char *fp = ((unsigned char*)s)-1; -                unsigned char newlen = SDS_TYPE_5_LEN(flags)+inc; +                unsigned char newlen = SDS_TYPE_5_LEN(flags)+(unsigned char)inc;                  *fp = SDS_TYPE_5 | (newlen << SDS_TYPE_BITS);              }              break;          case SDS_TYPE_8: -            SDS_HDR(8,s)->len += inc; +            SDS_HDR(8,s)->len += (uint8_t)inc;              break;          case SDS_TYPE_16: -            SDS_HDR(16,s)->len += inc; +            SDS_HDR(16,s)->len += (uint16_t)inc;              break;          case SDS_TYPE_32: -            SDS_HDR(32,s)->len += inc; +            SDS_HDR(32,s)->len += (uint32_t)inc;              break;          case SDS_TYPE_64: -            SDS_HDR(64,s)->len += inc; +            SDS_HDR(64,s)->len += (uint64_t)inc;              break;      }  } @@ -203,16 +203,16 @@ static inline void sdssetalloc(sds s, size_t newlen) {              /* Nothing to do, this type has no total allocation info. */              break;          case SDS_TYPE_8: -            SDS_HDR(8,s)->alloc = newlen; +            SDS_HDR(8,s)->alloc = (uint8_t)newlen;              break;          case SDS_TYPE_16: -            SDS_HDR(16,s)->alloc = newlen; +            SDS_HDR(16,s)->alloc = (uint16_t)newlen;              break;          case SDS_TYPE_32: -            SDS_HDR(32,s)->alloc = newlen; +            SDS_HDR(32,s)->alloc = (uint32_t)newlen;              break;          case SDS_TYPE_64: -            SDS_HDR(64,s)->alloc = newlen; +            SDS_HDR(64,s)->alloc = (uint64_t)newlen;              break;      }  } diff --git a/sockcompat.c b/sockcompat.c index b52cbc6..4cc2f41 100644 --- a/sockcompat.c +++ b/sockcompat.c @@ -189,13 +189,35 @@ int win32_connect(SOCKET sockfd, const struct sockaddr *addr, socklen_t addrlen)  }  int win32_getsockopt(SOCKET sockfd, int level, int optname, void *optval, socklen_t *optlen) { -    int ret = getsockopt(sockfd, level, optname, (char*)optval, optlen); +    int ret = 0; +    if ((level == SOL_SOCKET) && ((optname == SO_RCVTIMEO) || (optname == SO_SNDTIMEO))) { +        if (*optlen >= sizeof (struct timeval)) { +            struct timeval *tv = optval; +            DWORD timeout = 0; +            socklen_t dwlen = 0; +            ret = getsockopt(sockfd, level, optname, (char *)&timeout, &dwlen); +            tv->tv_sec = timeout / 1000; +            tv->tv_usec = (timeout * 1000) % 1000000; +        } else { +            ret = WSAEFAULT; +        } +        *optlen = sizeof (struct timeval); +    } else { +        ret = getsockopt(sockfd, level, optname, (char*)optval, optlen); +    }      _updateErrno(ret != SOCKET_ERROR);      return ret != SOCKET_ERROR ? ret : -1;  }  int win32_setsockopt(SOCKET sockfd, int level, int optname, const void *optval, socklen_t optlen) { -    int ret = setsockopt(sockfd, level, optname, (const char*)optval, optlen); +    int ret = 0; +    if ((level == SOL_SOCKET) && ((optname == SO_RCVTIMEO) || (optname == SO_SNDTIMEO))) { +        struct timeval *tv = optval; +        DWORD timeout = tv->tv_sec * 1000 + tv->tv_usec / 1000; +        ret = setsockopt(sockfd, level, optname, (const char*)&timeout, sizeof(DWORD)); +    } else { +        ret = setsockopt(sockfd, level, optname, (const char*)optval, optlen); +    }      _updateErrno(ret != SOCKET_ERROR);      return ret != SOCKET_ERROR ? ret : -1;  } diff --git a/sockcompat.h b/sockcompat.h index e0b2e5e..56006c1 100644 --- a/sockcompat.h +++ b/sockcompat.h @@ -50,7 +50,9 @@  #include <ws2tcpip.h>  #include <stddef.h> +#ifdef _MSC_VER  typedef signed long ssize_t; +#endif  /* Emulate the parts of the BSD socket API that we need (override the winsock signatures). */  int win32_getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res); @@ -11,6 +11,7 @@  void __redisSetError(redisContext *c, int type, const char *str); +#ifdef HIREDIS_SSL_TRACE  /**   * Callback used for debugging   */ @@ -40,6 +41,7 @@ static void sslLogCallback(const SSL *ssl, int where, int ret) {          printf("Using SSL version %s. Cipher=%s\n", SSL_get_version(ssl), SSL_get_cipher_name(ssl));      }  } +#endif  typedef pthread_mutex_t sslLockType;  static void sslLockInit(sslLockType *l) { @@ -103,7 +105,9 @@ int redisSslCreate(redisContext *c, const char *capath, const char *certpath,      redisSsl *s = c->ssl;      s->ctx = SSL_CTX_new(SSLv23_client_method()); +#ifdef HIREDIS_SSL_TRACE      SSL_CTX_set_info_callback(s->ctx, sslLogCallback); +#endif      SSL_CTX_set_mode(s->ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);      SSL_CTX_set_options(s->ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);      SSL_CTX_set_verify(s->ctx, SSL_VERIFY_PEER, NULL); @@ -360,7 +360,8 @@ static void test_reply_reader(void) {      freeReplyObject(reply);      redisReaderFree(reader); -    test("Set error when array > INT_MAX: "); +#if LLONG_MAX > SIZE_MAX +    test("Set error when array > SIZE_MAX: ");      reader = redisReaderCreate();      redisReaderFeed(reader, "*9223372036854775807\r\n+asdf\r\n",29);      ret = redisReaderGetReply(reader,&reply); @@ -369,7 +370,6 @@ static void test_reply_reader(void) {      freeReplyObject(reply);      redisReaderFree(reader); -#if LLONG_MAX > SIZE_MAX      test("Set error when bulk > SIZE_MAX: ");      reader = redisReaderCreate();      redisReaderFeed(reader, "$9223372036854775807\r\nasdf\r\n",28); @@ -450,6 +450,7 @@ static void test_blocking_connection_errors(void) {              c->err == REDIS_ERR_OTHER &&              (strcmp(c->errstr, "Name or service not known") == 0 ||               strcmp(c->errstr, "Can't resolve: " HIREDIS_BAD_DOMAIN) == 0 || +             strcmp(c->errstr, "Name does not resolve") == 0 ||               strcmp(c->errstr,                      "nodename nor servname provided, or not known") == 0 ||               strcmp(c->errstr, "No address associated with hostname") == 0 || @@ -2,10 +2,20 @@  #define _WIN32_HELPER_INCLUDE  #ifdef _MSC_VER +#include <winsock2.h> /* for struct timeval */ +  #ifndef inline  #define inline __inline  #endif +#ifndef strcasecmp +#define strcasecmp stricmp +#endif + +#ifndef strncasecmp +#define strncasecmp strnicmp +#endif +  #ifndef va_copy  #define va_copy(d,s) ((d) = (s))  #endif | 
