hiredis 0.6.1 → 0.6.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,126 +0,0 @@
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 */
@@ -1,21 +0,0 @@
1
- #ifndef __HIREDIS_FMACRO_H
2
- #define __HIREDIS_FMACRO_H
3
-
4
- #if defined(__linux__)
5
- #define _BSD_SOURCE
6
- #define _DEFAULT_SOURCE
7
- #endif
8
-
9
- #if defined(__sun__)
10
- #define _POSIX_C_SOURCE 200112L
11
- #elif defined(__linux__) || defined(__OpenBSD__) || defined(__NetBSD__)
12
- #define _XOPEN_SOURCE 600
13
- #else
14
- #define _XOPEN_SOURCE
15
- #endif
16
-
17
- #if __APPLE__ && __MACH__
18
- #define _OSX
19
- #endif
20
-
21
- #endif
@@ -1,979 +0,0 @@
1
- /*
2
- * Copyright (c) 2009-2011, Salvatore Sanfilippo <antirez at gmail dot com>
3
- * Copyright (c) 2010-2011, Pieter Noordhuis <pcnoordhuis at gmail dot com>
4
- *
5
- * All rights reserved.
6
- *
7
- * Redistribution and use in source and binary forms, with or without
8
- * modification, are permitted provided that the following conditions are met:
9
- *
10
- * * Redistributions of source code must retain the above copyright notice,
11
- * this list of conditions and the following disclaimer.
12
- * * Redistributions in binary form must reproduce the above copyright
13
- * notice, this list of conditions and the following disclaimer in the
14
- * documentation and/or other materials provided with the distribution.
15
- * * Neither the name of Redis nor the names of its contributors may be used
16
- * to endorse or promote products derived from this software without
17
- * specific prior written permission.
18
- *
19
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29
- * POSSIBILITY OF SUCH DAMAGE.
30
- */
31
-
32
- #include "fmacros.h"
33
- #include <string.h>
34
- #include <stdlib.h>
35
- #include <unistd.h>
36
- #include <assert.h>
37
- #include <errno.h>
38
- #include <ctype.h>
39
-
40
- #include "hiredis.h"
41
- #include "net.h"
42
- #include "sds.h"
43
-
44
- static redisReply *createReplyObject(int type);
45
- static void *createStringObject(const redisReadTask *task, char *str, size_t len);
46
- static void *createArrayObject(const redisReadTask *task, int elements);
47
- static void *createIntegerObject(const redisReadTask *task, long long value);
48
- static void *createNilObject(const redisReadTask *task);
49
-
50
- /* Default set of functions to build the reply. Keep in mind that such a
51
- * function returning NULL is interpreted as OOM. */
52
- static redisReplyObjectFunctions defaultFunctions = {
53
- createStringObject,
54
- createArrayObject,
55
- createIntegerObject,
56
- createNilObject,
57
- freeReplyObject
58
- };
59
-
60
- /* Create a reply object */
61
- static redisReply *createReplyObject(int type) {
62
- redisReply *r = calloc(1,sizeof(*r));
63
-
64
- if (r == NULL)
65
- return NULL;
66
-
67
- r->type = type;
68
- return r;
69
- }
70
-
71
- /* Free a reply object */
72
- void freeReplyObject(void *reply) {
73
- redisReply *r = reply;
74
- size_t j;
75
-
76
- if (r == NULL)
77
- return;
78
-
79
- switch(r->type) {
80
- case REDIS_REPLY_INTEGER:
81
- break; /* Nothing to free */
82
- case REDIS_REPLY_ARRAY:
83
- if (r->element != NULL) {
84
- for (j = 0; j < r->elements; j++)
85
- if (r->element[j] != NULL)
86
- freeReplyObject(r->element[j]);
87
- free(r->element);
88
- }
89
- break;
90
- case REDIS_REPLY_ERROR:
91
- case REDIS_REPLY_STATUS:
92
- case REDIS_REPLY_STRING:
93
- if (r->str != NULL)
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
-
434
- /* No need to check cmd since it is the last statement that can fail,
435
- * but do it anyway to be as defensive as possible. */
436
- if (cmd != NULL)
437
- free(cmd);
438
-
439
- return error_type;
440
- }
441
-
442
- /* Format a command according to the Redis protocol. This function
443
- * takes a format similar to printf:
444
- *
445
- * %s represents a C null terminated string you want to interpolate
446
- * %b represents a binary safe string
447
- *
448
- * When using %b you need to provide both the pointer to the string
449
- * and the length in bytes as a size_t. Examples:
450
- *
451
- * len = redisFormatCommand(target, "GET %s", mykey);
452
- * len = redisFormatCommand(target, "SET %s %b", mykey, myval, myvallen);
453
- */
454
- int redisFormatCommand(char **target, const char *format, ...) {
455
- va_list ap;
456
- int len;
457
- va_start(ap,format);
458
- len = redisvFormatCommand(target,format,ap);
459
- va_end(ap);
460
-
461
- /* The API says "-1" means bad result, but we now also return "-2" in some
462
- * cases. Force the return value to always be -1. */
463
- if (len < 0)
464
- len = -1;
465
-
466
- return len;
467
- }
468
-
469
- /* Format a command according to the Redis protocol using an sds string and
470
- * sdscatfmt for the processing of arguments. This function takes the
471
- * number of arguments, an array with arguments and an array with their
472
- * lengths. If the latter is set to NULL, strlen will be used to compute the
473
- * argument lengths.
474
- */
475
- int redisFormatSdsCommandArgv(sds *target, int argc, const char **argv,
476
- const size_t *argvlen)
477
- {
478
- sds cmd;
479
- unsigned long long totlen;
480
- int j;
481
- size_t len;
482
-
483
- /* Abort on a NULL target */
484
- if (target == NULL)
485
- return -1;
486
-
487
- /* Calculate our total size */
488
- totlen = 1+countDigits(argc)+2;
489
- for (j = 0; j < argc; j++) {
490
- len = argvlen ? argvlen[j] : strlen(argv[j]);
491
- totlen += bulklen(len);
492
- }
493
-
494
- /* Use an SDS string for command construction */
495
- cmd = sdsempty();
496
- if (cmd == NULL)
497
- return -1;
498
-
499
- /* We already know how much storage we need */
500
- cmd = sdsMakeRoomFor(cmd, totlen);
501
- if (cmd == NULL)
502
- return -1;
503
-
504
- /* Construct command */
505
- cmd = sdscatfmt(cmd, "*%i\r\n", argc);
506
- for (j=0; j < argc; j++) {
507
- len = argvlen ? argvlen[j] : strlen(argv[j]);
508
- cmd = sdscatfmt(cmd, "$%T\r\n", len);
509
- cmd = sdscatlen(cmd, argv[j], len);
510
- cmd = sdscatlen(cmd, "\r\n", sizeof("\r\n")-1);
511
- }
512
-
513
- assert(sdslen(cmd)==totlen);
514
-
515
- *target = cmd;
516
- return totlen;
517
- }
518
-
519
- void redisFreeSdsCommand(sds cmd) {
520
- sdsfree(cmd);
521
- }
522
-
523
- /* Format a command according to the Redis protocol. This function takes the
524
- * number of arguments, an array with arguments and an array with their
525
- * lengths. If the latter is set to NULL, strlen will be used to compute the
526
- * argument lengths.
527
- */
528
- int redisFormatCommandArgv(char **target, int argc, const char **argv, const size_t *argvlen) {
529
- char *cmd = NULL; /* final command */
530
- int pos; /* position in final command */
531
- size_t len;
532
- int totlen, j;
533
-
534
- /* Abort on a NULL target */
535
- if (target == NULL)
536
- return -1;
537
-
538
- /* Calculate number of bytes needed for the command */
539
- totlen = 1+countDigits(argc)+2;
540
- for (j = 0; j < argc; j++) {
541
- len = argvlen ? argvlen[j] : strlen(argv[j]);
542
- totlen += bulklen(len);
543
- }
544
-
545
- /* Build the command at protocol level */
546
- cmd = malloc(totlen+1);
547
- if (cmd == NULL)
548
- return -1;
549
-
550
- pos = sprintf(cmd,"*%d\r\n",argc);
551
- for (j = 0; j < argc; j++) {
552
- len = argvlen ? argvlen[j] : strlen(argv[j]);
553
- pos += sprintf(cmd+pos,"$%zu\r\n",len);
554
- memcpy(cmd+pos,argv[j],len);
555
- pos += len;
556
- cmd[pos++] = '\r';
557
- cmd[pos++] = '\n';
558
- }
559
- assert(pos == totlen);
560
- cmd[pos] = '\0';
561
-
562
- *target = cmd;
563
- return totlen;
564
- }
565
-
566
- void redisFreeCommand(char *cmd) {
567
- free(cmd);
568
- }
569
-
570
- void __redisSetError(redisContext *c, int type, const char *str) {
571
- size_t len;
572
-
573
- c->err = type;
574
- if (str != NULL) {
575
- len = strlen(str);
576
- len = len < (sizeof(c->errstr)-1) ? len : (sizeof(c->errstr)-1);
577
- memcpy(c->errstr,str,len);
578
- c->errstr[len] = '\0';
579
- } else {
580
- /* Only REDIS_ERR_IO may lack a description! */
581
- assert(type == REDIS_ERR_IO);
582
- __redis_strerror_r(errno, c->errstr, sizeof(c->errstr));
583
- }
584
- }
585
-
586
- redisReader *redisReaderCreate(void) {
587
- return redisReaderCreateWithFunctions(&defaultFunctions);
588
- }
589
-
590
- static redisContext *redisContextInit(void) {
591
- redisContext *c;
592
-
593
- c = calloc(1,sizeof(redisContext));
594
- if (c == NULL)
595
- return NULL;
596
-
597
- c->err = 0;
598
- c->errstr[0] = '\0';
599
- c->obuf = sdsempty();
600
- c->reader = redisReaderCreate();
601
-
602
- if (c->obuf == NULL || c->reader == NULL) {
603
- redisFree(c);
604
- return NULL;
605
- }
606
-
607
- return c;
608
- }
609
-
610
- void redisFree(redisContext *c) {
611
- if (c == NULL)
612
- return;
613
- if (c->fd > 0)
614
- close(c->fd);
615
- if (c->obuf != NULL)
616
- sdsfree(c->obuf);
617
- if (c->reader != NULL)
618
- redisReaderFree(c->reader);
619
- free(c);
620
- }
621
-
622
- int redisFreeKeepFd(redisContext *c) {
623
- int fd = c->fd;
624
- c->fd = -1;
625
- redisFree(c);
626
- return fd;
627
- }
628
-
629
- /* Connect to a Redis instance. On error the field error in the returned
630
- * context will be set to the return value of the error function.
631
- * When no set of reply functions is given, the default set will be used. */
632
- redisContext *redisConnect(const char *ip, int port) {
633
- redisContext *c;
634
-
635
- c = redisContextInit();
636
- if (c == NULL)
637
- return NULL;
638
-
639
- c->flags |= REDIS_BLOCK;
640
- redisContextConnectTcp(c,ip,port,NULL);
641
- return c;
642
- }
643
-
644
- redisContext *redisConnectWithTimeout(const char *ip, int port, const struct timeval tv) {
645
- redisContext *c;
646
-
647
- c = redisContextInit();
648
- if (c == NULL)
649
- return NULL;
650
-
651
- c->flags |= REDIS_BLOCK;
652
- redisContextConnectTcp(c,ip,port,&tv);
653
- return c;
654
- }
655
-
656
- redisContext *redisConnectNonBlock(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 *redisConnectBindNonBlock(const char *ip, int port,
669
- const char *source_addr) {
670
- redisContext *c = redisContextInit();
671
- c->flags &= ~REDIS_BLOCK;
672
- redisContextConnectBindTcp(c,ip,port,NULL,source_addr);
673
- return c;
674
- }
675
-
676
- redisContext *redisConnectBindNonBlockWithReuse(const char *ip, int port,
677
- const char *source_addr) {
678
- redisContext *c = redisContextInit();
679
- c->flags &= ~REDIS_BLOCK;
680
- c->flags |= REDIS_REUSEADDR;
681
- redisContextConnectBindTcp(c,ip,port,NULL,source_addr);
682
- return c;
683
- }
684
-
685
- redisContext *redisConnectUnix(const char *path) {
686
- redisContext *c;
687
-
688
- c = redisContextInit();
689
- if (c == NULL)
690
- return NULL;
691
-
692
- c->flags |= REDIS_BLOCK;
693
- redisContextConnectUnix(c,path,NULL);
694
- return c;
695
- }
696
-
697
- redisContext *redisConnectUnixWithTimeout(const char *path, const struct timeval tv) {
698
- redisContext *c;
699
-
700
- c = redisContextInit();
701
- if (c == NULL)
702
- return NULL;
703
-
704
- c->flags |= REDIS_BLOCK;
705
- redisContextConnectUnix(c,path,&tv);
706
- return c;
707
- }
708
-
709
- redisContext *redisConnectUnixNonBlock(const char *path) {
710
- redisContext *c;
711
-
712
- c = redisContextInit();
713
- if (c == NULL)
714
- return NULL;
715
-
716
- c->flags &= ~REDIS_BLOCK;
717
- redisContextConnectUnix(c,path,NULL);
718
- return c;
719
- }
720
-
721
- redisContext *redisConnectFd(int fd) {
722
- redisContext *c;
723
-
724
- c = redisContextInit();
725
- if (c == NULL)
726
- return NULL;
727
-
728
- c->fd = fd;
729
- c->flags |= REDIS_BLOCK | REDIS_CONNECTED;
730
- return c;
731
- }
732
-
733
- /* Set read/write timeout on a blocking socket. */
734
- int redisSetTimeout(redisContext *c, const struct timeval tv) {
735
- if (c->flags & REDIS_BLOCK)
736
- return redisContextSetTimeout(c,tv);
737
- return REDIS_ERR;
738
- }
739
-
740
- /* Enable connection KeepAlive. */
741
- int redisEnableKeepAlive(redisContext *c) {
742
- if (redisKeepAlive(c, REDIS_KEEPALIVE_INTERVAL) != REDIS_OK)
743
- return REDIS_ERR;
744
- return REDIS_OK;
745
- }
746
-
747
- /* Use this function to handle a read event on the descriptor. It will try
748
- * and read some bytes from the socket and feed them to the reply parser.
749
- *
750
- * After this function is called, you may use redisContextReadReply to
751
- * see if there is a reply available. */
752
- int redisBufferRead(redisContext *c) {
753
- char buf[1024*16];
754
- int nread;
755
-
756
- /* Return early when the context has seen an error. */
757
- if (c->err)
758
- return REDIS_ERR;
759
-
760
- nread = read(c->fd,buf,sizeof(buf));
761
- if (nread == -1) {
762
- if ((errno == EAGAIN && !(c->flags & REDIS_BLOCK)) || (errno == EINTR)) {
763
- /* Try again later */
764
- } else {
765
- __redisSetError(c,REDIS_ERR_IO,NULL);
766
- return REDIS_ERR;
767
- }
768
- } else if (nread == 0) {
769
- __redisSetError(c,REDIS_ERR_EOF,"Server closed the connection");
770
- return REDIS_ERR;
771
- } else {
772
- if (redisReaderFeed(c->reader,buf,nread) != REDIS_OK) {
773
- __redisSetError(c,c->reader->err,c->reader->errstr);
774
- return REDIS_ERR;
775
- }
776
- }
777
- return REDIS_OK;
778
- }
779
-
780
- /* Write the output buffer to the socket.
781
- *
782
- * Returns REDIS_OK when the buffer is empty, or (a part of) the buffer was
783
- * succesfully written to the socket. When the buffer is empty after the
784
- * write operation, "done" is set to 1 (if given).
785
- *
786
- * Returns REDIS_ERR if an error occured trying to write and sets
787
- * c->errstr to hold the appropriate error string.
788
- */
789
- int redisBufferWrite(redisContext *c, int *done) {
790
- int nwritten;
791
-
792
- /* Return early when the context has seen an error. */
793
- if (c->err)
794
- return REDIS_ERR;
795
-
796
- if (sdslen(c->obuf) > 0) {
797
- nwritten = write(c->fd,c->obuf,sdslen(c->obuf));
798
- if (nwritten == -1) {
799
- if ((errno == EAGAIN && !(c->flags & REDIS_BLOCK)) || (errno == EINTR)) {
800
- /* Try again later */
801
- } else {
802
- __redisSetError(c,REDIS_ERR_IO,NULL);
803
- return REDIS_ERR;
804
- }
805
- } else if (nwritten > 0) {
806
- if (nwritten == (signed)sdslen(c->obuf)) {
807
- sdsfree(c->obuf);
808
- c->obuf = sdsempty();
809
- } else {
810
- sdsrange(c->obuf,nwritten,-1);
811
- }
812
- }
813
- }
814
- if (done != NULL) *done = (sdslen(c->obuf) == 0);
815
- return REDIS_OK;
816
- }
817
-
818
- /* Internal helper function to try and get a reply from the reader,
819
- * or set an error in the context otherwise. */
820
- int redisGetReplyFromReader(redisContext *c, void **reply) {
821
- if (redisReaderGetReply(c->reader,reply) == REDIS_ERR) {
822
- __redisSetError(c,c->reader->err,c->reader->errstr);
823
- return REDIS_ERR;
824
- }
825
- return REDIS_OK;
826
- }
827
-
828
- int redisGetReply(redisContext *c, void **reply) {
829
- int wdone = 0;
830
- void *aux = NULL;
831
-
832
- /* Try to read pending replies */
833
- if (redisGetReplyFromReader(c,&aux) == REDIS_ERR)
834
- return REDIS_ERR;
835
-
836
- /* For the blocking context, flush output buffer and read reply */
837
- if (aux == NULL && c->flags & REDIS_BLOCK) {
838
- /* Write until done */
839
- do {
840
- if (redisBufferWrite(c,&wdone) == REDIS_ERR)
841
- return REDIS_ERR;
842
- } while (!wdone);
843
-
844
- /* Read until there is a reply */
845
- do {
846
- if (redisBufferRead(c) == REDIS_ERR)
847
- return REDIS_ERR;
848
- if (redisGetReplyFromReader(c,&aux) == REDIS_ERR)
849
- return REDIS_ERR;
850
- } while (aux == NULL);
851
- }
852
-
853
- /* Set reply object */
854
- if (reply != NULL) *reply = aux;
855
- return REDIS_OK;
856
- }
857
-
858
-
859
- /* Helper function for the redisAppendCommand* family of functions.
860
- *
861
- * Write a formatted command to the output buffer. When this family
862
- * is used, you need to call redisGetReply yourself to retrieve
863
- * the reply (or replies in pub/sub).
864
- */
865
- int __redisAppendCommand(redisContext *c, const char *cmd, size_t len) {
866
- sds newbuf;
867
-
868
- newbuf = sdscatlen(c->obuf,cmd,len);
869
- if (newbuf == NULL) {
870
- __redisSetError(c,REDIS_ERR_OOM,"Out of memory");
871
- return REDIS_ERR;
872
- }
873
-
874
- c->obuf = newbuf;
875
- return REDIS_OK;
876
- }
877
-
878
- int redisAppendFormattedCommand(redisContext *c, const char *cmd, size_t len) {
879
-
880
- if (__redisAppendCommand(c, cmd, len) != REDIS_OK) {
881
- return REDIS_ERR;
882
- }
883
-
884
- return REDIS_OK;
885
- }
886
-
887
- int redisvAppendCommand(redisContext *c, const char *format, va_list ap) {
888
- char *cmd;
889
- int len;
890
-
891
- len = redisvFormatCommand(&cmd,format,ap);
892
- if (len == -1) {
893
- __redisSetError(c,REDIS_ERR_OOM,"Out of memory");
894
- return REDIS_ERR;
895
- } else if (len == -2) {
896
- __redisSetError(c,REDIS_ERR_OTHER,"Invalid format string");
897
- return REDIS_ERR;
898
- }
899
-
900
- if (__redisAppendCommand(c,cmd,len) != REDIS_OK) {
901
- free(cmd);
902
- return REDIS_ERR;
903
- }
904
-
905
- free(cmd);
906
- return REDIS_OK;
907
- }
908
-
909
- int redisAppendCommand(redisContext *c, const char *format, ...) {
910
- va_list ap;
911
- int ret;
912
-
913
- va_start(ap,format);
914
- ret = redisvAppendCommand(c,format,ap);
915
- va_end(ap);
916
- return ret;
917
- }
918
-
919
- int redisAppendCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen) {
920
- sds cmd;
921
- int len;
922
-
923
- len = redisFormatSdsCommandArgv(&cmd,argc,argv,argvlen);
924
- if (len == -1) {
925
- __redisSetError(c,REDIS_ERR_OOM,"Out of memory");
926
- return REDIS_ERR;
927
- }
928
-
929
- if (__redisAppendCommand(c,cmd,len) != REDIS_OK) {
930
- sdsfree(cmd);
931
- return REDIS_ERR;
932
- }
933
-
934
- sdsfree(cmd);
935
- return REDIS_OK;
936
- }
937
-
938
- /* Helper function for the redisCommand* family of functions.
939
- *
940
- * Write a formatted command to the output buffer. If the given context is
941
- * blocking, immediately read the reply into the "reply" pointer. When the
942
- * context is non-blocking, the "reply" pointer will not be used and the
943
- * command is simply appended to the write buffer.
944
- *
945
- * Returns the reply when a reply was succesfully retrieved. Returns NULL
946
- * otherwise. When NULL is returned in a blocking context, the error field
947
- * in the context will be set.
948
- */
949
- static void *__redisBlockForReply(redisContext *c) {
950
- void *reply;
951
-
952
- if (c->flags & REDIS_BLOCK) {
953
- if (redisGetReply(c,&reply) != REDIS_OK)
954
- return NULL;
955
- return reply;
956
- }
957
- return NULL;
958
- }
959
-
960
- void *redisvCommand(redisContext *c, const char *format, va_list ap) {
961
- if (redisvAppendCommand(c,format,ap) != REDIS_OK)
962
- return NULL;
963
- return __redisBlockForReply(c);
964
- }
965
-
966
- void *redisCommand(redisContext *c, const char *format, ...) {
967
- va_list ap;
968
- void *reply = NULL;
969
- va_start(ap,format);
970
- reply = redisvCommand(c,format,ap);
971
- va_end(ap);
972
- return reply;
973
- }
974
-
975
- void *redisCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen) {
976
- if (redisAppendCommandArgv(c,argc,argv,argvlen) != REDIS_OK)
977
- return NULL;
978
- return __redisBlockForReply(c);
979
- }