hiredis 0.6.2 → 0.6.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,126 @@
1
+ /* Hash table implementation.
2
+ *
3
+ * This file implements in memory hash tables with insert/del/replace/find/
4
+ * get-random-element operations. Hash tables will auto resize if needed
5
+ * tables of power of two in size are used, collisions are handled by
6
+ * chaining. See the source code for more information... :)
7
+ *
8
+ * Copyright (c) 2006-2010, Salvatore Sanfilippo <antirez at gmail dot com>
9
+ * All rights reserved.
10
+ *
11
+ * Redistribution and use in source and binary forms, with or without
12
+ * modification, are permitted provided that the following conditions are met:
13
+ *
14
+ * * Redistributions of source code must retain the above copyright notice,
15
+ * this list of conditions and the following disclaimer.
16
+ * * Redistributions in binary form must reproduce the above copyright
17
+ * notice, this list of conditions and the following disclaimer in the
18
+ * documentation and/or other materials provided with the distribution.
19
+ * * Neither the name of Redis nor the names of its contributors may be used
20
+ * to endorse or promote products derived from this software without
21
+ * specific prior written permission.
22
+ *
23
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
27
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33
+ * POSSIBILITY OF SUCH DAMAGE.
34
+ */
35
+
36
+ #ifndef __DICT_H
37
+ #define __DICT_H
38
+
39
+ #define DICT_OK 0
40
+ #define DICT_ERR 1
41
+
42
+ /* Unused arguments generate annoying warnings... */
43
+ #define DICT_NOTUSED(V) ((void) V)
44
+
45
+ typedef struct dictEntry {
46
+ void *key;
47
+ void *val;
48
+ struct dictEntry *next;
49
+ } dictEntry;
50
+
51
+ typedef struct dictType {
52
+ unsigned int (*hashFunction)(const void *key);
53
+ void *(*keyDup)(void *privdata, const void *key);
54
+ void *(*valDup)(void *privdata, const void *obj);
55
+ int (*keyCompare)(void *privdata, const void *key1, const void *key2);
56
+ void (*keyDestructor)(void *privdata, void *key);
57
+ void (*valDestructor)(void *privdata, void *obj);
58
+ } dictType;
59
+
60
+ typedef struct dict {
61
+ dictEntry **table;
62
+ dictType *type;
63
+ unsigned long size;
64
+ unsigned long sizemask;
65
+ unsigned long used;
66
+ void *privdata;
67
+ } dict;
68
+
69
+ typedef struct dictIterator {
70
+ dict *ht;
71
+ int index;
72
+ dictEntry *entry, *nextEntry;
73
+ } dictIterator;
74
+
75
+ /* This is the initial size of every hash table */
76
+ #define DICT_HT_INITIAL_SIZE 4
77
+
78
+ /* ------------------------------- Macros ------------------------------------*/
79
+ #define dictFreeEntryVal(ht, entry) \
80
+ if ((ht)->type->valDestructor) \
81
+ (ht)->type->valDestructor((ht)->privdata, (entry)->val)
82
+
83
+ #define dictSetHashVal(ht, entry, _val_) do { \
84
+ if ((ht)->type->valDup) \
85
+ entry->val = (ht)->type->valDup((ht)->privdata, _val_); \
86
+ else \
87
+ entry->val = (_val_); \
88
+ } while(0)
89
+
90
+ #define dictFreeEntryKey(ht, entry) \
91
+ if ((ht)->type->keyDestructor) \
92
+ (ht)->type->keyDestructor((ht)->privdata, (entry)->key)
93
+
94
+ #define dictSetHashKey(ht, entry, _key_) do { \
95
+ if ((ht)->type->keyDup) \
96
+ entry->key = (ht)->type->keyDup((ht)->privdata, _key_); \
97
+ else \
98
+ entry->key = (_key_); \
99
+ } while(0)
100
+
101
+ #define dictCompareHashKeys(ht, key1, key2) \
102
+ (((ht)->type->keyCompare) ? \
103
+ (ht)->type->keyCompare((ht)->privdata, key1, key2) : \
104
+ (key1) == (key2))
105
+
106
+ #define dictHashKey(ht, key) (ht)->type->hashFunction(key)
107
+
108
+ #define dictGetEntryKey(he) ((he)->key)
109
+ #define dictGetEntryVal(he) ((he)->val)
110
+ #define dictSlots(ht) ((ht)->size)
111
+ #define dictSize(ht) ((ht)->used)
112
+
113
+ /* API */
114
+ static unsigned int dictGenHashFunction(const unsigned char *buf, int len);
115
+ static dict *dictCreate(dictType *type, void *privDataPtr);
116
+ static int dictExpand(dict *ht, unsigned long size);
117
+ static int dictAdd(dict *ht, void *key, void *val);
118
+ static int dictReplace(dict *ht, void *key, void *val);
119
+ static int dictDelete(dict *ht, const void *key);
120
+ static void dictRelease(dict *ht);
121
+ static dictEntry * dictFind(dict *ht, const void *key);
122
+ static dictIterator *dictGetIterator(dict *ht);
123
+ static dictEntry *dictNext(dictIterator *iter);
124
+ static void dictReleaseIterator(dictIterator *iter);
125
+
126
+ #endif /* __DICT_H */
@@ -0,0 +1,12 @@
1
+ #ifndef __HIREDIS_FMACRO_H
2
+ #define __HIREDIS_FMACRO_H
3
+
4
+ #define _XOPEN_SOURCE 600
5
+ #define _POSIX_C_SOURCE 200112L
6
+
7
+ #if defined(__APPLE__) && defined(__MACH__)
8
+ /* Enable TCP_KEEPALIVE */
9
+ #define _DARWIN_C_SOURCE
10
+ #endif
11
+
12
+ #endif
@@ -0,0 +1,1006 @@
1
+ /*
2
+ * Copyright (c) 2009-2011, Salvatore Sanfilippo <antirez at gmail dot com>
3
+ * Copyright (c) 2010-2014, Pieter Noordhuis <pcnoordhuis at gmail dot com>
4
+ * Copyright (c) 2015, Matt Stancliff <matt at genges dot com>,
5
+ * Jan-Erik Rediger <janerik at fnordig dot com>
6
+ *
7
+ * All rights reserved.
8
+ *
9
+ * Redistribution and use in source and binary forms, with or without
10
+ * modification, are permitted provided that the following conditions are met:
11
+ *
12
+ * * Redistributions of source code must retain the above copyright notice,
13
+ * this list of conditions and the following disclaimer.
14
+ * * Redistributions in binary form must reproduce the above copyright
15
+ * notice, this list of conditions and the following disclaimer in the
16
+ * documentation and/or other materials provided with the distribution.
17
+ * * Neither the name of Redis nor the names of its contributors may be used
18
+ * to endorse or promote products derived from this software without
19
+ * specific prior written permission.
20
+ *
21
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
25
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31
+ * POSSIBILITY OF SUCH DAMAGE.
32
+ */
33
+
34
+ #include "fmacros.h"
35
+ #include <string.h>
36
+ #include <stdlib.h>
37
+ #include <unistd.h>
38
+ #include <assert.h>
39
+ #include <errno.h>
40
+ #include <ctype.h>
41
+
42
+ #include "hiredis.h"
43
+ #include "net.h"
44
+ #include "sds.h"
45
+
46
+ static redisReply *createReplyObject(int type);
47
+ static void *createStringObject(const redisReadTask *task, char *str, size_t len);
48
+ static void *createArrayObject(const redisReadTask *task, int elements);
49
+ static void *createIntegerObject(const redisReadTask *task, long long value);
50
+ static void *createNilObject(const redisReadTask *task);
51
+
52
+ /* Default set of functions to build the reply. Keep in mind that such a
53
+ * function returning NULL is interpreted as OOM. */
54
+ static redisReplyObjectFunctions defaultFunctions = {
55
+ createStringObject,
56
+ createArrayObject,
57
+ createIntegerObject,
58
+ createNilObject,
59
+ freeReplyObject
60
+ };
61
+
62
+ /* Create a reply object */
63
+ static redisReply *createReplyObject(int type) {
64
+ redisReply *r = calloc(1,sizeof(*r));
65
+
66
+ if (r == NULL)
67
+ return NULL;
68
+
69
+ r->type = type;
70
+ return r;
71
+ }
72
+
73
+ /* Free a reply object */
74
+ void freeReplyObject(void *reply) {
75
+ redisReply *r = reply;
76
+ size_t j;
77
+
78
+ if (r == NULL)
79
+ return;
80
+
81
+ switch(r->type) {
82
+ case REDIS_REPLY_INTEGER:
83
+ break; /* Nothing to free */
84
+ case REDIS_REPLY_ARRAY:
85
+ if (r->element != NULL) {
86
+ for (j = 0; j < r->elements; j++)
87
+ freeReplyObject(r->element[j]);
88
+ free(r->element);
89
+ }
90
+ break;
91
+ case REDIS_REPLY_ERROR:
92
+ case REDIS_REPLY_STATUS:
93
+ case REDIS_REPLY_STRING:
94
+ free(r->str);
95
+ break;
96
+ }
97
+ free(r);
98
+ }
99
+
100
+ static void *createStringObject(const redisReadTask *task, char *str, size_t len) {
101
+ redisReply *r, *parent;
102
+ char *buf;
103
+
104
+ r = createReplyObject(task->type);
105
+ if (r == NULL)
106
+ return NULL;
107
+
108
+ buf = malloc(len+1);
109
+ if (buf == NULL) {
110
+ freeReplyObject(r);
111
+ return NULL;
112
+ }
113
+
114
+ assert(task->type == REDIS_REPLY_ERROR ||
115
+ task->type == REDIS_REPLY_STATUS ||
116
+ task->type == REDIS_REPLY_STRING);
117
+
118
+ /* Copy string value */
119
+ memcpy(buf,str,len);
120
+ buf[len] = '\0';
121
+ r->str = buf;
122
+ r->len = len;
123
+
124
+ if (task->parent) {
125
+ parent = task->parent->obj;
126
+ assert(parent->type == REDIS_REPLY_ARRAY);
127
+ parent->element[task->idx] = r;
128
+ }
129
+ return r;
130
+ }
131
+
132
+ static void *createArrayObject(const redisReadTask *task, int elements) {
133
+ redisReply *r, *parent;
134
+
135
+ r = createReplyObject(REDIS_REPLY_ARRAY);
136
+ if (r == NULL)
137
+ return NULL;
138
+
139
+ if (elements > 0) {
140
+ r->element = calloc(elements,sizeof(redisReply*));
141
+ if (r->element == NULL) {
142
+ freeReplyObject(r);
143
+ return NULL;
144
+ }
145
+ }
146
+
147
+ r->elements = elements;
148
+
149
+ if (task->parent) {
150
+ parent = task->parent->obj;
151
+ assert(parent->type == REDIS_REPLY_ARRAY);
152
+ parent->element[task->idx] = r;
153
+ }
154
+ return r;
155
+ }
156
+
157
+ static void *createIntegerObject(const redisReadTask *task, long long value) {
158
+ redisReply *r, *parent;
159
+
160
+ r = createReplyObject(REDIS_REPLY_INTEGER);
161
+ if (r == NULL)
162
+ return NULL;
163
+
164
+ r->integer = value;
165
+
166
+ if (task->parent) {
167
+ parent = task->parent->obj;
168
+ assert(parent->type == REDIS_REPLY_ARRAY);
169
+ parent->element[task->idx] = r;
170
+ }
171
+ return r;
172
+ }
173
+
174
+ static void *createNilObject(const redisReadTask *task) {
175
+ redisReply *r, *parent;
176
+
177
+ r = createReplyObject(REDIS_REPLY_NIL);
178
+ if (r == NULL)
179
+ return NULL;
180
+
181
+ if (task->parent) {
182
+ parent = task->parent->obj;
183
+ assert(parent->type == REDIS_REPLY_ARRAY);
184
+ parent->element[task->idx] = r;
185
+ }
186
+ return r;
187
+ }
188
+
189
+ /* Return the number of digits of 'v' when converted to string in radix 10.
190
+ * Implementation borrowed from link in redis/src/util.c:string2ll(). */
191
+ static uint32_t countDigits(uint64_t v) {
192
+ uint32_t result = 1;
193
+ for (;;) {
194
+ if (v < 10) return result;
195
+ if (v < 100) return result + 1;
196
+ if (v < 1000) return result + 2;
197
+ if (v < 10000) return result + 3;
198
+ v /= 10000U;
199
+ result += 4;
200
+ }
201
+ }
202
+
203
+ /* Helper that calculates the bulk length given a certain string length. */
204
+ static size_t bulklen(size_t len) {
205
+ return 1+countDigits(len)+2+len+2;
206
+ }
207
+
208
+ int redisvFormatCommand(char **target, const char *format, va_list ap) {
209
+ const char *c = format;
210
+ char *cmd = NULL; /* final command */
211
+ int pos; /* position in final command */
212
+ sds curarg, newarg; /* current argument */
213
+ int touched = 0; /* was the current argument touched? */
214
+ char **curargv = NULL, **newargv = NULL;
215
+ int argc = 0;
216
+ int totlen = 0;
217
+ int error_type = 0; /* 0 = no error; -1 = memory error; -2 = format error */
218
+ int j;
219
+
220
+ /* Abort if there is not target to set */
221
+ if (target == NULL)
222
+ return -1;
223
+
224
+ /* Build the command string accordingly to protocol */
225
+ curarg = sdsempty();
226
+ if (curarg == NULL)
227
+ return -1;
228
+
229
+ while(*c != '\0') {
230
+ if (*c != '%' || c[1] == '\0') {
231
+ if (*c == ' ') {
232
+ if (touched) {
233
+ newargv = realloc(curargv,sizeof(char*)*(argc+1));
234
+ if (newargv == NULL) goto memory_err;
235
+ curargv = newargv;
236
+ curargv[argc++] = curarg;
237
+ totlen += bulklen(sdslen(curarg));
238
+
239
+ /* curarg is put in argv so it can be overwritten. */
240
+ curarg = sdsempty();
241
+ if (curarg == NULL) goto memory_err;
242
+ touched = 0;
243
+ }
244
+ } else {
245
+ newarg = sdscatlen(curarg,c,1);
246
+ if (newarg == NULL) goto memory_err;
247
+ curarg = newarg;
248
+ touched = 1;
249
+ }
250
+ } else {
251
+ char *arg;
252
+ size_t size;
253
+
254
+ /* Set newarg so it can be checked even if it is not touched. */
255
+ newarg = curarg;
256
+
257
+ switch(c[1]) {
258
+ case 's':
259
+ arg = va_arg(ap,char*);
260
+ size = strlen(arg);
261
+ if (size > 0)
262
+ newarg = sdscatlen(curarg,arg,size);
263
+ break;
264
+ case 'b':
265
+ arg = va_arg(ap,char*);
266
+ size = va_arg(ap,size_t);
267
+ if (size > 0)
268
+ newarg = sdscatlen(curarg,arg,size);
269
+ break;
270
+ case '%':
271
+ newarg = sdscat(curarg,"%");
272
+ break;
273
+ default:
274
+ /* Try to detect printf format */
275
+ {
276
+ static const char intfmts[] = "diouxX";
277
+ static const char flags[] = "#0-+ ";
278
+ char _format[16];
279
+ const char *_p = c+1;
280
+ size_t _l = 0;
281
+ va_list _cpy;
282
+
283
+ /* Flags */
284
+ while (*_p != '\0' && strchr(flags,*_p) != NULL) _p++;
285
+
286
+ /* Field width */
287
+ while (*_p != '\0' && isdigit(*_p)) _p++;
288
+
289
+ /* Precision */
290
+ if (*_p == '.') {
291
+ _p++;
292
+ while (*_p != '\0' && isdigit(*_p)) _p++;
293
+ }
294
+
295
+ /* Copy va_list before consuming with va_arg */
296
+ va_copy(_cpy,ap);
297
+
298
+ /* Integer conversion (without modifiers) */
299
+ if (strchr(intfmts,*_p) != NULL) {
300
+ va_arg(ap,int);
301
+ goto fmt_valid;
302
+ }
303
+
304
+ /* Double conversion (without modifiers) */
305
+ if (strchr("eEfFgGaA",*_p) != NULL) {
306
+ va_arg(ap,double);
307
+ goto fmt_valid;
308
+ }
309
+
310
+ /* Size: char */
311
+ if (_p[0] == 'h' && _p[1] == 'h') {
312
+ _p += 2;
313
+ if (*_p != '\0' && strchr(intfmts,*_p) != NULL) {
314
+ va_arg(ap,int); /* char gets promoted to int */
315
+ goto fmt_valid;
316
+ }
317
+ goto fmt_invalid;
318
+ }
319
+
320
+ /* Size: short */
321
+ if (_p[0] == 'h') {
322
+ _p += 1;
323
+ if (*_p != '\0' && strchr(intfmts,*_p) != NULL) {
324
+ va_arg(ap,int); /* short gets promoted to int */
325
+ goto fmt_valid;
326
+ }
327
+ goto fmt_invalid;
328
+ }
329
+
330
+ /* Size: long long */
331
+ if (_p[0] == 'l' && _p[1] == 'l') {
332
+ _p += 2;
333
+ if (*_p != '\0' && strchr(intfmts,*_p) != NULL) {
334
+ va_arg(ap,long long);
335
+ goto fmt_valid;
336
+ }
337
+ goto fmt_invalid;
338
+ }
339
+
340
+ /* Size: long */
341
+ if (_p[0] == 'l') {
342
+ _p += 1;
343
+ if (*_p != '\0' && strchr(intfmts,*_p) != NULL) {
344
+ va_arg(ap,long);
345
+ goto fmt_valid;
346
+ }
347
+ goto fmt_invalid;
348
+ }
349
+
350
+ fmt_invalid:
351
+ va_end(_cpy);
352
+ goto format_err;
353
+
354
+ fmt_valid:
355
+ _l = (_p+1)-c;
356
+ if (_l < sizeof(_format)-2) {
357
+ memcpy(_format,c,_l);
358
+ _format[_l] = '\0';
359
+ newarg = sdscatvprintf(curarg,_format,_cpy);
360
+
361
+ /* Update current position (note: outer blocks
362
+ * increment c twice so compensate here) */
363
+ c = _p-1;
364
+ }
365
+
366
+ va_end(_cpy);
367
+ break;
368
+ }
369
+ }
370
+
371
+ if (newarg == NULL) goto memory_err;
372
+ curarg = newarg;
373
+
374
+ touched = 1;
375
+ c++;
376
+ }
377
+ c++;
378
+ }
379
+
380
+ /* Add the last argument if needed */
381
+ if (touched) {
382
+ newargv = realloc(curargv,sizeof(char*)*(argc+1));
383
+ if (newargv == NULL) goto memory_err;
384
+ curargv = newargv;
385
+ curargv[argc++] = curarg;
386
+ totlen += bulklen(sdslen(curarg));
387
+ } else {
388
+ sdsfree(curarg);
389
+ }
390
+
391
+ /* Clear curarg because it was put in curargv or was free'd. */
392
+ curarg = NULL;
393
+
394
+ /* Add bytes needed to hold multi bulk count */
395
+ totlen += 1+countDigits(argc)+2;
396
+
397
+ /* Build the command at protocol level */
398
+ cmd = malloc(totlen+1);
399
+ if (cmd == NULL) goto memory_err;
400
+
401
+ pos = sprintf(cmd,"*%d\r\n",argc);
402
+ for (j = 0; j < argc; j++) {
403
+ pos += sprintf(cmd+pos,"$%zu\r\n",sdslen(curargv[j]));
404
+ memcpy(cmd+pos,curargv[j],sdslen(curargv[j]));
405
+ pos += sdslen(curargv[j]);
406
+ sdsfree(curargv[j]);
407
+ cmd[pos++] = '\r';
408
+ cmd[pos++] = '\n';
409
+ }
410
+ assert(pos == totlen);
411
+ cmd[pos] = '\0';
412
+
413
+ free(curargv);
414
+ *target = cmd;
415
+ return totlen;
416
+
417
+ format_err:
418
+ error_type = -2;
419
+ goto cleanup;
420
+
421
+ memory_err:
422
+ error_type = -1;
423
+ goto cleanup;
424
+
425
+ cleanup:
426
+ if (curargv) {
427
+ while(argc--)
428
+ sdsfree(curargv[argc]);
429
+ free(curargv);
430
+ }
431
+
432
+ sdsfree(curarg);
433
+ free(cmd);
434
+
435
+ return error_type;
436
+ }
437
+
438
+ /* Format a command according to the Redis protocol. This function
439
+ * takes a format similar to printf:
440
+ *
441
+ * %s represents a C null terminated string you want to interpolate
442
+ * %b represents a binary safe string
443
+ *
444
+ * When using %b you need to provide both the pointer to the string
445
+ * and the length in bytes as a size_t. Examples:
446
+ *
447
+ * len = redisFormatCommand(target, "GET %s", mykey);
448
+ * len = redisFormatCommand(target, "SET %s %b", mykey, myval, myvallen);
449
+ */
450
+ int redisFormatCommand(char **target, const char *format, ...) {
451
+ va_list ap;
452
+ int len;
453
+ va_start(ap,format);
454
+ len = redisvFormatCommand(target,format,ap);
455
+ va_end(ap);
456
+
457
+ /* The API says "-1" means bad result, but we now also return "-2" in some
458
+ * cases. Force the return value to always be -1. */
459
+ if (len < 0)
460
+ len = -1;
461
+
462
+ return len;
463
+ }
464
+
465
+ /* Format a command according to the Redis protocol using an sds string and
466
+ * sdscatfmt for the processing of arguments. This function takes the
467
+ * number of arguments, an array with arguments and an array with their
468
+ * lengths. If the latter is set to NULL, strlen will be used to compute the
469
+ * argument lengths.
470
+ */
471
+ int redisFormatSdsCommandArgv(sds *target, int argc, const char **argv,
472
+ const size_t *argvlen)
473
+ {
474
+ sds cmd;
475
+ unsigned long long totlen;
476
+ int j;
477
+ size_t len;
478
+
479
+ /* Abort on a NULL target */
480
+ if (target == NULL)
481
+ return -1;
482
+
483
+ /* Calculate our total size */
484
+ totlen = 1+countDigits(argc)+2;
485
+ for (j = 0; j < argc; j++) {
486
+ len = argvlen ? argvlen[j] : strlen(argv[j]);
487
+ totlen += bulklen(len);
488
+ }
489
+
490
+ /* Use an SDS string for command construction */
491
+ cmd = sdsempty();
492
+ if (cmd == NULL)
493
+ return -1;
494
+
495
+ /* We already know how much storage we need */
496
+ cmd = sdsMakeRoomFor(cmd, totlen);
497
+ if (cmd == NULL)
498
+ return -1;
499
+
500
+ /* Construct command */
501
+ cmd = sdscatfmt(cmd, "*%i\r\n", argc);
502
+ for (j=0; j < argc; j++) {
503
+ len = argvlen ? argvlen[j] : strlen(argv[j]);
504
+ cmd = sdscatfmt(cmd, "$%u\r\n", len);
505
+ cmd = sdscatlen(cmd, argv[j], len);
506
+ cmd = sdscatlen(cmd, "\r\n", sizeof("\r\n")-1);
507
+ }
508
+
509
+ assert(sdslen(cmd)==totlen);
510
+
511
+ *target = cmd;
512
+ return totlen;
513
+ }
514
+
515
+ void redisFreeSdsCommand(sds cmd) {
516
+ sdsfree(cmd);
517
+ }
518
+
519
+ /* Format a command according to the Redis protocol. This function takes the
520
+ * number of arguments, an array with arguments and an array with their
521
+ * lengths. If the latter is set to NULL, strlen will be used to compute the
522
+ * argument lengths.
523
+ */
524
+ int redisFormatCommandArgv(char **target, int argc, const char **argv, const size_t *argvlen) {
525
+ char *cmd = NULL; /* final command */
526
+ int pos; /* position in final command */
527
+ size_t len;
528
+ int totlen, j;
529
+
530
+ /* Abort on a NULL target */
531
+ if (target == NULL)
532
+ return -1;
533
+
534
+ /* Calculate number of bytes needed for the command */
535
+ totlen = 1+countDigits(argc)+2;
536
+ for (j = 0; j < argc; j++) {
537
+ len = argvlen ? argvlen[j] : strlen(argv[j]);
538
+ totlen += bulklen(len);
539
+ }
540
+
541
+ /* Build the command at protocol level */
542
+ cmd = malloc(totlen+1);
543
+ if (cmd == NULL)
544
+ return -1;
545
+
546
+ pos = sprintf(cmd,"*%d\r\n",argc);
547
+ for (j = 0; j < argc; j++) {
548
+ len = argvlen ? argvlen[j] : strlen(argv[j]);
549
+ pos += sprintf(cmd+pos,"$%zu\r\n",len);
550
+ memcpy(cmd+pos,argv[j],len);
551
+ pos += len;
552
+ cmd[pos++] = '\r';
553
+ cmd[pos++] = '\n';
554
+ }
555
+ assert(pos == totlen);
556
+ cmd[pos] = '\0';
557
+
558
+ *target = cmd;
559
+ return totlen;
560
+ }
561
+
562
+ void redisFreeCommand(char *cmd) {
563
+ free(cmd);
564
+ }
565
+
566
+ void __redisSetError(redisContext *c, int type, const char *str) {
567
+ size_t len;
568
+
569
+ c->err = type;
570
+ if (str != NULL) {
571
+ len = strlen(str);
572
+ len = len < (sizeof(c->errstr)-1) ? len : (sizeof(c->errstr)-1);
573
+ memcpy(c->errstr,str,len);
574
+ c->errstr[len] = '\0';
575
+ } else {
576
+ /* Only REDIS_ERR_IO may lack a description! */
577
+ assert(type == REDIS_ERR_IO);
578
+ strerror_r(errno, c->errstr, sizeof(c->errstr));
579
+ }
580
+ }
581
+
582
+ redisReader *redisReaderCreate(void) {
583
+ return redisReaderCreateWithFunctions(&defaultFunctions);
584
+ }
585
+
586
+ static redisContext *redisContextInit(void) {
587
+ redisContext *c;
588
+
589
+ c = calloc(1,sizeof(redisContext));
590
+ if (c == NULL)
591
+ return NULL;
592
+
593
+ c->obuf = sdsempty();
594
+ c->reader = redisReaderCreate();
595
+
596
+ if (c->obuf == NULL || c->reader == NULL) {
597
+ redisFree(c);
598
+ return NULL;
599
+ }
600
+
601
+ return c;
602
+ }
603
+
604
+ void redisFree(redisContext *c) {
605
+ if (c == NULL)
606
+ return;
607
+ if (c->fd > 0)
608
+ close(c->fd);
609
+ sdsfree(c->obuf);
610
+ redisReaderFree(c->reader);
611
+ free(c->tcp.host);
612
+ free(c->tcp.source_addr);
613
+ free(c->unix_sock.path);
614
+ free(c->timeout);
615
+ free(c);
616
+ }
617
+
618
+ int redisFreeKeepFd(redisContext *c) {
619
+ int fd = c->fd;
620
+ c->fd = -1;
621
+ redisFree(c);
622
+ return fd;
623
+ }
624
+
625
+ int redisReconnect(redisContext *c) {
626
+ c->err = 0;
627
+ memset(c->errstr, '\0', strlen(c->errstr));
628
+
629
+ if (c->fd > 0) {
630
+ close(c->fd);
631
+ }
632
+
633
+ sdsfree(c->obuf);
634
+ redisReaderFree(c->reader);
635
+
636
+ c->obuf = sdsempty();
637
+ c->reader = redisReaderCreate();
638
+
639
+ if (c->connection_type == REDIS_CONN_TCP) {
640
+ return redisContextConnectBindTcp(c, c->tcp.host, c->tcp.port,
641
+ c->timeout, c->tcp.source_addr);
642
+ } else if (c->connection_type == REDIS_CONN_UNIX) {
643
+ return redisContextConnectUnix(c, c->unix_sock.path, c->timeout);
644
+ } else {
645
+ /* Something bad happened here and shouldn't have. There isn't
646
+ enough information in the context to reconnect. */
647
+ __redisSetError(c,REDIS_ERR_OTHER,"Not enough information to reconnect");
648
+ }
649
+
650
+ return REDIS_ERR;
651
+ }
652
+
653
+ /* Connect to a Redis instance. On error the field error in the returned
654
+ * context will be set to the return value of the error function.
655
+ * When no set of reply functions is given, the default set will be used. */
656
+ redisContext *redisConnect(const char *ip, int port) {
657
+ redisContext *c;
658
+
659
+ c = redisContextInit();
660
+ if (c == NULL)
661
+ return NULL;
662
+
663
+ c->flags |= REDIS_BLOCK;
664
+ redisContextConnectTcp(c,ip,port,NULL);
665
+ return c;
666
+ }
667
+
668
+ redisContext *redisConnectWithTimeout(const char *ip, int port, const struct timeval tv) {
669
+ redisContext *c;
670
+
671
+ c = redisContextInit();
672
+ if (c == NULL)
673
+ return NULL;
674
+
675
+ c->flags |= REDIS_BLOCK;
676
+ redisContextConnectTcp(c,ip,port,&tv);
677
+ return c;
678
+ }
679
+
680
+ redisContext *redisConnectNonBlock(const char *ip, int port) {
681
+ redisContext *c;
682
+
683
+ c = redisContextInit();
684
+ if (c == NULL)
685
+ return NULL;
686
+
687
+ c->flags &= ~REDIS_BLOCK;
688
+ redisContextConnectTcp(c,ip,port,NULL);
689
+ return c;
690
+ }
691
+
692
+ redisContext *redisConnectBindNonBlock(const char *ip, int port,
693
+ const char *source_addr) {
694
+ redisContext *c = redisContextInit();
695
+ if (c == NULL)
696
+ return NULL;
697
+ c->flags &= ~REDIS_BLOCK;
698
+ redisContextConnectBindTcp(c,ip,port,NULL,source_addr);
699
+ return c;
700
+ }
701
+
702
+ redisContext *redisConnectBindNonBlockWithReuse(const char *ip, int port,
703
+ const char *source_addr) {
704
+ redisContext *c = redisContextInit();
705
+ if (c == NULL)
706
+ return NULL;
707
+ c->flags &= ~REDIS_BLOCK;
708
+ c->flags |= REDIS_REUSEADDR;
709
+ redisContextConnectBindTcp(c,ip,port,NULL,source_addr);
710
+ return c;
711
+ }
712
+
713
+ redisContext *redisConnectUnix(const char *path) {
714
+ redisContext *c;
715
+
716
+ c = redisContextInit();
717
+ if (c == NULL)
718
+ return NULL;
719
+
720
+ c->flags |= REDIS_BLOCK;
721
+ redisContextConnectUnix(c,path,NULL);
722
+ return c;
723
+ }
724
+
725
+ redisContext *redisConnectUnixWithTimeout(const char *path, const struct timeval tv) {
726
+ redisContext *c;
727
+
728
+ c = redisContextInit();
729
+ if (c == NULL)
730
+ return NULL;
731
+
732
+ c->flags |= REDIS_BLOCK;
733
+ redisContextConnectUnix(c,path,&tv);
734
+ return c;
735
+ }
736
+
737
+ redisContext *redisConnectUnixNonBlock(const char *path) {
738
+ redisContext *c;
739
+
740
+ c = redisContextInit();
741
+ if (c == NULL)
742
+ return NULL;
743
+
744
+ c->flags &= ~REDIS_BLOCK;
745
+ redisContextConnectUnix(c,path,NULL);
746
+ return c;
747
+ }
748
+
749
+ redisContext *redisConnectFd(int fd) {
750
+ redisContext *c;
751
+
752
+ c = redisContextInit();
753
+ if (c == NULL)
754
+ return NULL;
755
+
756
+ c->fd = fd;
757
+ c->flags |= REDIS_BLOCK | REDIS_CONNECTED;
758
+ return c;
759
+ }
760
+
761
+ /* Set read/write timeout on a blocking socket. */
762
+ int redisSetTimeout(redisContext *c, const struct timeval tv) {
763
+ if (c->flags & REDIS_BLOCK)
764
+ return redisContextSetTimeout(c,tv);
765
+ return REDIS_ERR;
766
+ }
767
+
768
+ /* Enable connection KeepAlive. */
769
+ int redisEnableKeepAlive(redisContext *c) {
770
+ if (redisKeepAlive(c, REDIS_KEEPALIVE_INTERVAL) != REDIS_OK)
771
+ return REDIS_ERR;
772
+ return REDIS_OK;
773
+ }
774
+
775
+ /* Use this function to handle a read event on the descriptor. It will try
776
+ * and read some bytes from the socket and feed them to the reply parser.
777
+ *
778
+ * After this function is called, you may use redisContextReadReply to
779
+ * see if there is a reply available. */
780
+ int redisBufferRead(redisContext *c) {
781
+ char buf[1024*16];
782
+ int nread;
783
+
784
+ /* Return early when the context has seen an error. */
785
+ if (c->err)
786
+ return REDIS_ERR;
787
+
788
+ nread = read(c->fd,buf,sizeof(buf));
789
+ if (nread == -1) {
790
+ if ((errno == EAGAIN && !(c->flags & REDIS_BLOCK)) || (errno == EINTR)) {
791
+ /* Try again later */
792
+ } else {
793
+ __redisSetError(c,REDIS_ERR_IO,NULL);
794
+ return REDIS_ERR;
795
+ }
796
+ } else if (nread == 0) {
797
+ __redisSetError(c,REDIS_ERR_EOF,"Server closed the connection");
798
+ return REDIS_ERR;
799
+ } else {
800
+ if (redisReaderFeed(c->reader,buf,nread) != REDIS_OK) {
801
+ __redisSetError(c,c->reader->err,c->reader->errstr);
802
+ return REDIS_ERR;
803
+ }
804
+ }
805
+ return REDIS_OK;
806
+ }
807
+
808
+ /* Write the output buffer to the socket.
809
+ *
810
+ * Returns REDIS_OK when the buffer is empty, or (a part of) the buffer was
811
+ * successfully written to the socket. When the buffer is empty after the
812
+ * write operation, "done" is set to 1 (if given).
813
+ *
814
+ * Returns REDIS_ERR if an error occurred trying to write and sets
815
+ * c->errstr to hold the appropriate error string.
816
+ */
817
+ int redisBufferWrite(redisContext *c, int *done) {
818
+ int nwritten;
819
+
820
+ /* Return early when the context has seen an error. */
821
+ if (c->err)
822
+ return REDIS_ERR;
823
+
824
+ if (sdslen(c->obuf) > 0) {
825
+ nwritten = write(c->fd,c->obuf,sdslen(c->obuf));
826
+ if (nwritten == -1) {
827
+ if ((errno == EAGAIN && !(c->flags & REDIS_BLOCK)) || (errno == EINTR)) {
828
+ /* Try again later */
829
+ } else {
830
+ __redisSetError(c,REDIS_ERR_IO,NULL);
831
+ return REDIS_ERR;
832
+ }
833
+ } else if (nwritten > 0) {
834
+ if (nwritten == (signed)sdslen(c->obuf)) {
835
+ sdsfree(c->obuf);
836
+ c->obuf = sdsempty();
837
+ } else {
838
+ sdsrange(c->obuf,nwritten,-1);
839
+ }
840
+ }
841
+ }
842
+ if (done != NULL) *done = (sdslen(c->obuf) == 0);
843
+ return REDIS_OK;
844
+ }
845
+
846
+ /* Internal helper function to try and get a reply from the reader,
847
+ * or set an error in the context otherwise. */
848
+ int redisGetReplyFromReader(redisContext *c, void **reply) {
849
+ if (redisReaderGetReply(c->reader,reply) == REDIS_ERR) {
850
+ __redisSetError(c,c->reader->err,c->reader->errstr);
851
+ return REDIS_ERR;
852
+ }
853
+ return REDIS_OK;
854
+ }
855
+
856
+ int redisGetReply(redisContext *c, void **reply) {
857
+ int wdone = 0;
858
+ void *aux = NULL;
859
+
860
+ /* Try to read pending replies */
861
+ if (redisGetReplyFromReader(c,&aux) == REDIS_ERR)
862
+ return REDIS_ERR;
863
+
864
+ /* For the blocking context, flush output buffer and read reply */
865
+ if (aux == NULL && c->flags & REDIS_BLOCK) {
866
+ /* Write until done */
867
+ do {
868
+ if (redisBufferWrite(c,&wdone) == REDIS_ERR)
869
+ return REDIS_ERR;
870
+ } while (!wdone);
871
+
872
+ /* Read until there is a reply */
873
+ do {
874
+ if (redisBufferRead(c) == REDIS_ERR)
875
+ return REDIS_ERR;
876
+ if (redisGetReplyFromReader(c,&aux) == REDIS_ERR)
877
+ return REDIS_ERR;
878
+ } while (aux == NULL);
879
+ }
880
+
881
+ /* Set reply object */
882
+ if (reply != NULL) *reply = aux;
883
+ return REDIS_OK;
884
+ }
885
+
886
+
887
+ /* Helper function for the redisAppendCommand* family of functions.
888
+ *
889
+ * Write a formatted command to the output buffer. When this family
890
+ * is used, you need to call redisGetReply yourself to retrieve
891
+ * the reply (or replies in pub/sub).
892
+ */
893
+ int __redisAppendCommand(redisContext *c, const char *cmd, size_t len) {
894
+ sds newbuf;
895
+
896
+ newbuf = sdscatlen(c->obuf,cmd,len);
897
+ if (newbuf == NULL) {
898
+ __redisSetError(c,REDIS_ERR_OOM,"Out of memory");
899
+ return REDIS_ERR;
900
+ }
901
+
902
+ c->obuf = newbuf;
903
+ return REDIS_OK;
904
+ }
905
+
906
+ int redisAppendFormattedCommand(redisContext *c, const char *cmd, size_t len) {
907
+
908
+ if (__redisAppendCommand(c, cmd, len) != REDIS_OK) {
909
+ return REDIS_ERR;
910
+ }
911
+
912
+ return REDIS_OK;
913
+ }
914
+
915
+ int redisvAppendCommand(redisContext *c, const char *format, va_list ap) {
916
+ char *cmd;
917
+ int len;
918
+
919
+ len = redisvFormatCommand(&cmd,format,ap);
920
+ if (len == -1) {
921
+ __redisSetError(c,REDIS_ERR_OOM,"Out of memory");
922
+ return REDIS_ERR;
923
+ } else if (len == -2) {
924
+ __redisSetError(c,REDIS_ERR_OTHER,"Invalid format string");
925
+ return REDIS_ERR;
926
+ }
927
+
928
+ if (__redisAppendCommand(c,cmd,len) != REDIS_OK) {
929
+ free(cmd);
930
+ return REDIS_ERR;
931
+ }
932
+
933
+ free(cmd);
934
+ return REDIS_OK;
935
+ }
936
+
937
+ int redisAppendCommand(redisContext *c, const char *format, ...) {
938
+ va_list ap;
939
+ int ret;
940
+
941
+ va_start(ap,format);
942
+ ret = redisvAppendCommand(c,format,ap);
943
+ va_end(ap);
944
+ return ret;
945
+ }
946
+
947
+ int redisAppendCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen) {
948
+ sds cmd;
949
+ int len;
950
+
951
+ len = redisFormatSdsCommandArgv(&cmd,argc,argv,argvlen);
952
+ if (len == -1) {
953
+ __redisSetError(c,REDIS_ERR_OOM,"Out of memory");
954
+ return REDIS_ERR;
955
+ }
956
+
957
+ if (__redisAppendCommand(c,cmd,len) != REDIS_OK) {
958
+ sdsfree(cmd);
959
+ return REDIS_ERR;
960
+ }
961
+
962
+ sdsfree(cmd);
963
+ return REDIS_OK;
964
+ }
965
+
966
+ /* Helper function for the redisCommand* family of functions.
967
+ *
968
+ * Write a formatted command to the output buffer. If the given context is
969
+ * blocking, immediately read the reply into the "reply" pointer. When the
970
+ * context is non-blocking, the "reply" pointer will not be used and the
971
+ * command is simply appended to the write buffer.
972
+ *
973
+ * Returns the reply when a reply was successfully retrieved. Returns NULL
974
+ * otherwise. When NULL is returned in a blocking context, the error field
975
+ * in the context will be set.
976
+ */
977
+ static void *__redisBlockForReply(redisContext *c) {
978
+ void *reply;
979
+
980
+ if (c->flags & REDIS_BLOCK) {
981
+ if (redisGetReply(c,&reply) != REDIS_OK)
982
+ return NULL;
983
+ return reply;
984
+ }
985
+ return NULL;
986
+ }
987
+
988
+ void *redisvCommand(redisContext *c, const char *format, va_list ap) {
989
+ if (redisvAppendCommand(c,format,ap) != REDIS_OK)
990
+ return NULL;
991
+ return __redisBlockForReply(c);
992
+ }
993
+
994
+ void *redisCommand(redisContext *c, const char *format, ...) {
995
+ va_list ap;
996
+ va_start(ap,format);
997
+ void *reply = redisvCommand(c,format,ap);
998
+ va_end(ap);
999
+ return reply;
1000
+ }
1001
+
1002
+ void *redisCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen) {
1003
+ if (redisAppendCommandArgv(c,argc,argv,argvlen) != REDIS_OK)
1004
+ return NULL;
1005
+ return __redisBlockForReply(c);
1006
+ }