durable_rules 0.33.13 → 0.34.01
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/deps/hiredis/Makefile +110 -41
- data/deps/hiredis/async.c +87 -22
- data/deps/hiredis/async.h +4 -0
- data/deps/hiredis/fmacros.h +6 -1
- data/deps/hiredis/hiredis.c +270 -534
- data/deps/hiredis/hiredis.h +89 -76
- data/deps/hiredis/net.c +206 -47
- data/deps/hiredis/net.h +12 -6
- data/deps/hiredis/read.c +525 -0
- data/deps/hiredis/read.h +116 -0
- data/deps/hiredis/sds.c +260 -47
- data/deps/hiredis/sds.h +11 -6
- data/deps/hiredis/test.c +171 -18
- data/deps/hiredis/win32.h +42 -0
- data/librb/durable.rb +35 -6
- data/librb/engine.rb +173 -40
- data/src/rules/events.c +42 -4
- data/src/rules/net.c +184 -96
- data/src/rules/net.h +10 -0
- data/src/rules/rules.h +13 -0
- data/src/rulesrb/rules.c +55 -0
- metadata +5 -3
- data/deps/hiredis/zmalloc.h +0 -13
data/deps/hiredis/async.h
CHANGED
|
@@ -102,6 +102,9 @@ typedef struct redisAsyncContext {
|
|
|
102
102
|
|
|
103
103
|
/* Functions that proxy to hiredis */
|
|
104
104
|
redisAsyncContext *redisAsyncConnect(const char *ip, int port);
|
|
105
|
+
redisAsyncContext *redisAsyncConnectBind(const char *ip, int port, const char *source_addr);
|
|
106
|
+
redisAsyncContext *redisAsyncConnectBindWithReuse(const char *ip, int port,
|
|
107
|
+
const char *source_addr);
|
|
105
108
|
redisAsyncContext *redisAsyncConnectUnix(const char *path);
|
|
106
109
|
int redisAsyncSetConnectCallback(redisAsyncContext *ac, redisConnectCallback *fn);
|
|
107
110
|
int redisAsyncSetDisconnectCallback(redisAsyncContext *ac, redisDisconnectCallback *fn);
|
|
@@ -117,6 +120,7 @@ void redisAsyncHandleWrite(redisAsyncContext *ac);
|
|
|
117
120
|
int redisvAsyncCommand(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, const char *format, va_list ap);
|
|
118
121
|
int redisAsyncCommand(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, const char *format, ...);
|
|
119
122
|
int redisAsyncCommandArgv(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, int argc, const char **argv, const size_t *argvlen);
|
|
123
|
+
int redisAsyncFormattedCommand(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, const char *cmd, size_t len);
|
|
120
124
|
|
|
121
125
|
#ifdef __cplusplus
|
|
122
126
|
}
|
data/deps/hiredis/fmacros.h
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
#ifndef __HIREDIS_FMACRO_H
|
|
2
2
|
#define __HIREDIS_FMACRO_H
|
|
3
3
|
|
|
4
|
-
#if
|
|
4
|
+
#if defined(__linux__)
|
|
5
5
|
#define _BSD_SOURCE
|
|
6
|
+
#define _DEFAULT_SOURCE
|
|
6
7
|
#endif
|
|
7
8
|
|
|
8
9
|
#if defined(__sun__)
|
|
@@ -13,4 +14,8 @@
|
|
|
13
14
|
#define _XOPEN_SOURCE
|
|
14
15
|
#endif
|
|
15
16
|
|
|
17
|
+
#if __APPLE__ && __MACH__
|
|
18
|
+
#define _OSX
|
|
19
|
+
#endif
|
|
20
|
+
|
|
16
21
|
#endif
|
data/deps/hiredis/hiredis.c
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
/*
|
|
2
2
|
* Copyright (c) 2009-2011, Salvatore Sanfilippo <antirez at gmail dot com>
|
|
3
|
-
* Copyright (c) 2010-
|
|
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>
|
|
4
6
|
*
|
|
5
7
|
* All rights reserved.
|
|
6
8
|
*
|
|
@@ -73,6 +75,9 @@ void freeReplyObject(void *reply) {
|
|
|
73
75
|
redisReply *r = reply;
|
|
74
76
|
size_t j;
|
|
75
77
|
|
|
78
|
+
if (r == NULL)
|
|
79
|
+
return;
|
|
80
|
+
|
|
76
81
|
switch(r->type) {
|
|
77
82
|
case REDIS_REPLY_INTEGER:
|
|
78
83
|
break; /* Nothing to free */
|
|
@@ -183,504 +188,23 @@ static void *createNilObject(const redisReadTask *task) {
|
|
|
183
188
|
return r;
|
|
184
189
|
}
|
|
185
190
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
r->pos = r->len = 0;
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
/* Reset task stack. */
|
|
202
|
-
r->ridx = -1;
|
|
203
|
-
|
|
204
|
-
/* Set error. */
|
|
205
|
-
r->err = type;
|
|
206
|
-
len = strlen(str);
|
|
207
|
-
len = len < (sizeof(r->errstr)-1) ? len : (sizeof(r->errstr)-1);
|
|
208
|
-
memcpy(r->errstr,str,len);
|
|
209
|
-
r->errstr[len] = '\0';
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
static size_t chrtos(char *buf, size_t size, char byte) {
|
|
213
|
-
size_t len = 0;
|
|
214
|
-
|
|
215
|
-
switch(byte) {
|
|
216
|
-
case '\\':
|
|
217
|
-
case '"':
|
|
218
|
-
len = snprintf(buf,size,"\"\\%c\"",byte);
|
|
219
|
-
break;
|
|
220
|
-
case '\n': len = snprintf(buf,size,"\"\\n\""); break;
|
|
221
|
-
case '\r': len = snprintf(buf,size,"\"\\r\""); break;
|
|
222
|
-
case '\t': len = snprintf(buf,size,"\"\\t\""); break;
|
|
223
|
-
case '\a': len = snprintf(buf,size,"\"\\a\""); break;
|
|
224
|
-
case '\b': len = snprintf(buf,size,"\"\\b\""); break;
|
|
225
|
-
default:
|
|
226
|
-
if (isprint(byte))
|
|
227
|
-
len = snprintf(buf,size,"\"%c\"",byte);
|
|
228
|
-
else
|
|
229
|
-
len = snprintf(buf,size,"\"\\x%02x\"",(unsigned char)byte);
|
|
230
|
-
break;
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
return len;
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
static void __redisReaderSetErrorProtocolByte(redisReader *r, char byte) {
|
|
237
|
-
char cbuf[8], sbuf[128];
|
|
238
|
-
|
|
239
|
-
chrtos(cbuf,sizeof(cbuf),byte);
|
|
240
|
-
snprintf(sbuf,sizeof(sbuf),
|
|
241
|
-
"Protocol error, got %s as reply type byte", cbuf);
|
|
242
|
-
__redisReaderSetError(r,REDIS_ERR_PROTOCOL,sbuf);
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
static void __redisReaderSetErrorOOM(redisReader *r) {
|
|
246
|
-
__redisReaderSetError(r,REDIS_ERR_OOM,"Out of memory");
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
static char *readBytes(redisReader *r, unsigned int bytes) {
|
|
250
|
-
char *p;
|
|
251
|
-
if (r->len-r->pos >= bytes) {
|
|
252
|
-
p = r->buf+r->pos;
|
|
253
|
-
r->pos += bytes;
|
|
254
|
-
return p;
|
|
255
|
-
}
|
|
256
|
-
return NULL;
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
/* Find pointer to \r\n. */
|
|
260
|
-
static char *seekNewline(char *s, size_t len) {
|
|
261
|
-
int pos = 0;
|
|
262
|
-
int _len = len-1;
|
|
263
|
-
|
|
264
|
-
/* Position should be < len-1 because the character at "pos" should be
|
|
265
|
-
* followed by a \n. Note that strchr cannot be used because it doesn't
|
|
266
|
-
* allow to search a limited length and the buffer that is being searched
|
|
267
|
-
* might not have a trailing NULL character. */
|
|
268
|
-
while (pos < _len) {
|
|
269
|
-
while(pos < _len && s[pos] != '\r') pos++;
|
|
270
|
-
if (s[pos] != '\r') {
|
|
271
|
-
/* Not found. */
|
|
272
|
-
return NULL;
|
|
273
|
-
} else {
|
|
274
|
-
if (s[pos+1] == '\n') {
|
|
275
|
-
/* Found. */
|
|
276
|
-
return s+pos;
|
|
277
|
-
} else {
|
|
278
|
-
/* Continue searching. */
|
|
279
|
-
pos++;
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
return NULL;
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
/* Read a long long value starting at *s, under the assumption that it will be
|
|
287
|
-
* terminated by \r\n. Ambiguously returns -1 for unexpected input. */
|
|
288
|
-
static long long readLongLong(char *s) {
|
|
289
|
-
long long v = 0;
|
|
290
|
-
int dec, mult = 1;
|
|
291
|
-
char c;
|
|
292
|
-
|
|
293
|
-
if (*s == '-') {
|
|
294
|
-
mult = -1;
|
|
295
|
-
s++;
|
|
296
|
-
} else if (*s == '+') {
|
|
297
|
-
mult = 1;
|
|
298
|
-
s++;
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
while ((c = *(s++)) != '\r') {
|
|
302
|
-
dec = c - '0';
|
|
303
|
-
if (dec >= 0 && dec < 10) {
|
|
304
|
-
v *= 10;
|
|
305
|
-
v += dec;
|
|
306
|
-
} else {
|
|
307
|
-
/* Should not happen... */
|
|
308
|
-
return -1;
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
return mult*v;
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
static char *readLine(redisReader *r, int *_len) {
|
|
316
|
-
char *p, *s;
|
|
317
|
-
int len;
|
|
318
|
-
|
|
319
|
-
p = r->buf+r->pos;
|
|
320
|
-
s = seekNewline(p,(r->len-r->pos));
|
|
321
|
-
if (s != NULL) {
|
|
322
|
-
len = s-(r->buf+r->pos);
|
|
323
|
-
r->pos += len+2; /* skip \r\n */
|
|
324
|
-
if (_len) *_len = len;
|
|
325
|
-
return p;
|
|
326
|
-
}
|
|
327
|
-
return NULL;
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
static void moveToNextTask(redisReader *r) {
|
|
331
|
-
redisReadTask *cur, *prv;
|
|
332
|
-
while (r->ridx >= 0) {
|
|
333
|
-
/* Return a.s.a.p. when the stack is now empty. */
|
|
334
|
-
if (r->ridx == 0) {
|
|
335
|
-
r->ridx--;
|
|
336
|
-
return;
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
cur = &(r->rstack[r->ridx]);
|
|
340
|
-
prv = &(r->rstack[r->ridx-1]);
|
|
341
|
-
assert(prv->type == REDIS_REPLY_ARRAY);
|
|
342
|
-
if (cur->idx == prv->elements-1) {
|
|
343
|
-
r->ridx--;
|
|
344
|
-
} else {
|
|
345
|
-
/* Reset the type because the next item can be anything */
|
|
346
|
-
assert(cur->idx < prv->elements);
|
|
347
|
-
cur->type = -1;
|
|
348
|
-
cur->elements = -1;
|
|
349
|
-
cur->idx++;
|
|
350
|
-
return;
|
|
351
|
-
}
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
static int processLineItem(redisReader *r) {
|
|
356
|
-
redisReadTask *cur = &(r->rstack[r->ridx]);
|
|
357
|
-
void *obj;
|
|
358
|
-
char *p;
|
|
359
|
-
int len;
|
|
360
|
-
|
|
361
|
-
if ((p = readLine(r,&len)) != NULL) {
|
|
362
|
-
if (cur->type == REDIS_REPLY_INTEGER) {
|
|
363
|
-
if (r->fn && r->fn->createInteger)
|
|
364
|
-
obj = r->fn->createInteger(cur,readLongLong(p));
|
|
365
|
-
else
|
|
366
|
-
obj = (void*)REDIS_REPLY_INTEGER;
|
|
367
|
-
} else {
|
|
368
|
-
/* Type will be error or status. */
|
|
369
|
-
if (r->fn && r->fn->createString)
|
|
370
|
-
obj = r->fn->createString(cur,p,len);
|
|
371
|
-
else
|
|
372
|
-
obj = (void*)(size_t)(cur->type);
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
if (obj == NULL) {
|
|
376
|
-
__redisReaderSetErrorOOM(r);
|
|
377
|
-
return REDIS_ERR;
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
/* Set reply if this is the root object. */
|
|
381
|
-
if (r->ridx == 0) r->reply = obj;
|
|
382
|
-
moveToNextTask(r);
|
|
383
|
-
return REDIS_OK;
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
return REDIS_ERR;
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
static int processBulkItem(redisReader *r) {
|
|
390
|
-
redisReadTask *cur = &(r->rstack[r->ridx]);
|
|
391
|
-
void *obj = NULL;
|
|
392
|
-
char *p, *s;
|
|
393
|
-
long len;
|
|
394
|
-
unsigned long bytelen;
|
|
395
|
-
int success = 0;
|
|
396
|
-
|
|
397
|
-
p = r->buf+r->pos;
|
|
398
|
-
s = seekNewline(p,r->len-r->pos);
|
|
399
|
-
if (s != NULL) {
|
|
400
|
-
p = r->buf+r->pos;
|
|
401
|
-
bytelen = s-(r->buf+r->pos)+2; /* include \r\n */
|
|
402
|
-
len = readLongLong(p);
|
|
403
|
-
|
|
404
|
-
if (len < 0) {
|
|
405
|
-
/* The nil object can always be created. */
|
|
406
|
-
if (r->fn && r->fn->createNil)
|
|
407
|
-
obj = r->fn->createNil(cur);
|
|
408
|
-
else
|
|
409
|
-
obj = (void*)REDIS_REPLY_NIL;
|
|
410
|
-
success = 1;
|
|
411
|
-
} else {
|
|
412
|
-
/* Only continue when the buffer contains the entire bulk item. */
|
|
413
|
-
bytelen += len+2; /* include \r\n */
|
|
414
|
-
if (r->pos+bytelen <= r->len) {
|
|
415
|
-
if (r->fn && r->fn->createString)
|
|
416
|
-
obj = r->fn->createString(cur,s+2,len);
|
|
417
|
-
else
|
|
418
|
-
obj = (void*)REDIS_REPLY_STRING;
|
|
419
|
-
success = 1;
|
|
420
|
-
}
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
/* Proceed when obj was created. */
|
|
424
|
-
if (success) {
|
|
425
|
-
if (obj == NULL) {
|
|
426
|
-
__redisReaderSetErrorOOM(r);
|
|
427
|
-
return REDIS_ERR;
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
r->pos += bytelen;
|
|
431
|
-
|
|
432
|
-
/* Set reply if this is the root object. */
|
|
433
|
-
if (r->ridx == 0) r->reply = obj;
|
|
434
|
-
moveToNextTask(r);
|
|
435
|
-
return REDIS_OK;
|
|
436
|
-
}
|
|
437
|
-
}
|
|
438
|
-
|
|
439
|
-
return REDIS_ERR;
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
static int processMultiBulkItem(redisReader *r) {
|
|
443
|
-
redisReadTask *cur = &(r->rstack[r->ridx]);
|
|
444
|
-
void *obj;
|
|
445
|
-
char *p;
|
|
446
|
-
long elements;
|
|
447
|
-
int root = 0;
|
|
448
|
-
|
|
449
|
-
/* Set error for nested multi bulks with depth > 7 */
|
|
450
|
-
if (r->ridx == 8) {
|
|
451
|
-
__redisReaderSetError(r,REDIS_ERR_PROTOCOL,
|
|
452
|
-
"No support for nested multi bulk replies with depth > 7");
|
|
453
|
-
return REDIS_ERR;
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
if ((p = readLine(r,NULL)) != NULL) {
|
|
457
|
-
elements = readLongLong(p);
|
|
458
|
-
root = (r->ridx == 0);
|
|
459
|
-
|
|
460
|
-
if (elements == -1) {
|
|
461
|
-
if (r->fn && r->fn->createNil)
|
|
462
|
-
obj = r->fn->createNil(cur);
|
|
463
|
-
else
|
|
464
|
-
obj = (void*)REDIS_REPLY_NIL;
|
|
465
|
-
|
|
466
|
-
if (obj == NULL) {
|
|
467
|
-
__redisReaderSetErrorOOM(r);
|
|
468
|
-
return REDIS_ERR;
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
moveToNextTask(r);
|
|
472
|
-
} else {
|
|
473
|
-
if (r->fn && r->fn->createArray)
|
|
474
|
-
obj = r->fn->createArray(cur,elements);
|
|
475
|
-
else
|
|
476
|
-
obj = (void*)REDIS_REPLY_ARRAY;
|
|
477
|
-
|
|
478
|
-
if (obj == NULL) {
|
|
479
|
-
__redisReaderSetErrorOOM(r);
|
|
480
|
-
return REDIS_ERR;
|
|
481
|
-
}
|
|
482
|
-
|
|
483
|
-
/* Modify task stack when there are more than 0 elements. */
|
|
484
|
-
if (elements > 0) {
|
|
485
|
-
cur->elements = elements;
|
|
486
|
-
cur->obj = obj;
|
|
487
|
-
r->ridx++;
|
|
488
|
-
r->rstack[r->ridx].type = -1;
|
|
489
|
-
r->rstack[r->ridx].elements = -1;
|
|
490
|
-
r->rstack[r->ridx].idx = 0;
|
|
491
|
-
r->rstack[r->ridx].obj = NULL;
|
|
492
|
-
r->rstack[r->ridx].parent = cur;
|
|
493
|
-
r->rstack[r->ridx].privdata = r->privdata;
|
|
494
|
-
} else {
|
|
495
|
-
moveToNextTask(r);
|
|
496
|
-
}
|
|
497
|
-
}
|
|
498
|
-
|
|
499
|
-
/* Set reply if this is the root object. */
|
|
500
|
-
if (root) r->reply = obj;
|
|
501
|
-
return REDIS_OK;
|
|
502
|
-
}
|
|
503
|
-
|
|
504
|
-
return REDIS_ERR;
|
|
505
|
-
}
|
|
506
|
-
|
|
507
|
-
static int processItem(redisReader *r) {
|
|
508
|
-
redisReadTask *cur = &(r->rstack[r->ridx]);
|
|
509
|
-
char *p;
|
|
510
|
-
|
|
511
|
-
/* check if we need to read type */
|
|
512
|
-
if (cur->type < 0) {
|
|
513
|
-
if ((p = readBytes(r,1)) != NULL) {
|
|
514
|
-
switch (p[0]) {
|
|
515
|
-
case '-':
|
|
516
|
-
cur->type = REDIS_REPLY_ERROR;
|
|
517
|
-
break;
|
|
518
|
-
case '+':
|
|
519
|
-
cur->type = REDIS_REPLY_STATUS;
|
|
520
|
-
break;
|
|
521
|
-
case ':':
|
|
522
|
-
cur->type = REDIS_REPLY_INTEGER;
|
|
523
|
-
break;
|
|
524
|
-
case '$':
|
|
525
|
-
cur->type = REDIS_REPLY_STRING;
|
|
526
|
-
break;
|
|
527
|
-
case '*':
|
|
528
|
-
cur->type = REDIS_REPLY_ARRAY;
|
|
529
|
-
break;
|
|
530
|
-
default:
|
|
531
|
-
__redisReaderSetErrorProtocolByte(r,*p);
|
|
532
|
-
return REDIS_ERR;
|
|
533
|
-
}
|
|
534
|
-
} else {
|
|
535
|
-
/* could not consume 1 byte */
|
|
536
|
-
return REDIS_ERR;
|
|
537
|
-
}
|
|
538
|
-
}
|
|
539
|
-
|
|
540
|
-
/* process typed item */
|
|
541
|
-
switch(cur->type) {
|
|
542
|
-
case REDIS_REPLY_ERROR:
|
|
543
|
-
case REDIS_REPLY_STATUS:
|
|
544
|
-
case REDIS_REPLY_INTEGER:
|
|
545
|
-
return processLineItem(r);
|
|
546
|
-
case REDIS_REPLY_STRING:
|
|
547
|
-
return processBulkItem(r);
|
|
548
|
-
case REDIS_REPLY_ARRAY:
|
|
549
|
-
return processMultiBulkItem(r);
|
|
550
|
-
default:
|
|
551
|
-
assert(NULL);
|
|
552
|
-
return REDIS_ERR; /* Avoid warning. */
|
|
553
|
-
}
|
|
554
|
-
}
|
|
555
|
-
|
|
556
|
-
redisReader *redisReaderCreate(void) {
|
|
557
|
-
redisReader *r;
|
|
558
|
-
|
|
559
|
-
r = calloc(sizeof(redisReader),1);
|
|
560
|
-
if (r == NULL)
|
|
561
|
-
return NULL;
|
|
562
|
-
|
|
563
|
-
r->err = 0;
|
|
564
|
-
r->errstr[0] = '\0';
|
|
565
|
-
r->fn = &defaultFunctions;
|
|
566
|
-
r->buf = sdsempty();
|
|
567
|
-
r->maxbuf = REDIS_READER_MAX_BUF;
|
|
568
|
-
if (r->buf == NULL) {
|
|
569
|
-
free(r);
|
|
570
|
-
return NULL;
|
|
571
|
-
}
|
|
572
|
-
|
|
573
|
-
r->ridx = -1;
|
|
574
|
-
return r;
|
|
575
|
-
}
|
|
576
|
-
|
|
577
|
-
void redisReaderFree(redisReader *r) {
|
|
578
|
-
if (r->reply != NULL && r->fn && r->fn->freeObject)
|
|
579
|
-
r->fn->freeObject(r->reply);
|
|
580
|
-
if (r->buf != NULL)
|
|
581
|
-
sdsfree(r->buf);
|
|
582
|
-
free(r);
|
|
583
|
-
}
|
|
584
|
-
|
|
585
|
-
int redisReaderFeed(redisReader *r, const char *buf, size_t len) {
|
|
586
|
-
sds newbuf;
|
|
587
|
-
|
|
588
|
-
/* Return early when this reader is in an erroneous state. */
|
|
589
|
-
if (r->err)
|
|
590
|
-
return REDIS_ERR;
|
|
591
|
-
|
|
592
|
-
/* Copy the provided buffer. */
|
|
593
|
-
if (buf != NULL && len >= 1) {
|
|
594
|
-
/* Destroy internal buffer when it is empty and is quite large. */
|
|
595
|
-
if (r->len == 0 && r->maxbuf != 0 && sdsavail(r->buf) > r->maxbuf) {
|
|
596
|
-
sdsfree(r->buf);
|
|
597
|
-
r->buf = sdsempty();
|
|
598
|
-
r->pos = 0;
|
|
599
|
-
|
|
600
|
-
/* r->buf should not be NULL since we just free'd a larger one. */
|
|
601
|
-
assert(r->buf != NULL);
|
|
602
|
-
}
|
|
603
|
-
|
|
604
|
-
newbuf = sdscatlen(r->buf,buf,len);
|
|
605
|
-
if (newbuf == NULL) {
|
|
606
|
-
__redisReaderSetErrorOOM(r);
|
|
607
|
-
return REDIS_ERR;
|
|
608
|
-
}
|
|
609
|
-
|
|
610
|
-
r->buf = newbuf;
|
|
611
|
-
r->len = sdslen(r->buf);
|
|
612
|
-
}
|
|
613
|
-
|
|
614
|
-
return REDIS_OK;
|
|
615
|
-
}
|
|
616
|
-
|
|
617
|
-
int redisReaderGetReply(redisReader *r, void **reply) {
|
|
618
|
-
/* Default target pointer to NULL. */
|
|
619
|
-
if (reply != NULL)
|
|
620
|
-
*reply = NULL;
|
|
621
|
-
|
|
622
|
-
/* Return early when this reader is in an erroneous state. */
|
|
623
|
-
if (r->err)
|
|
624
|
-
return REDIS_ERR;
|
|
625
|
-
|
|
626
|
-
/* When the buffer is empty, there will never be a reply. */
|
|
627
|
-
if (r->len == 0)
|
|
628
|
-
return REDIS_OK;
|
|
629
|
-
|
|
630
|
-
/* Set first item to process when the stack is empty. */
|
|
631
|
-
if (r->ridx == -1) {
|
|
632
|
-
r->rstack[0].type = -1;
|
|
633
|
-
r->rstack[0].elements = -1;
|
|
634
|
-
r->rstack[0].idx = -1;
|
|
635
|
-
r->rstack[0].obj = NULL;
|
|
636
|
-
r->rstack[0].parent = NULL;
|
|
637
|
-
r->rstack[0].privdata = r->privdata;
|
|
638
|
-
r->ridx = 0;
|
|
639
|
-
}
|
|
640
|
-
|
|
641
|
-
/* Process items in reply. */
|
|
642
|
-
while (r->ridx >= 0)
|
|
643
|
-
if (processItem(r) != REDIS_OK)
|
|
644
|
-
break;
|
|
645
|
-
|
|
646
|
-
/* Return ASAP when an error occurred. */
|
|
647
|
-
if (r->err)
|
|
648
|
-
return REDIS_ERR;
|
|
649
|
-
|
|
650
|
-
/* Discard part of the buffer when we've consumed at least 1k, to avoid
|
|
651
|
-
* doing unnecessary calls to memmove() in sds.c. */
|
|
652
|
-
if (r->pos >= 1024) {
|
|
653
|
-
sdsrange(r->buf,r->pos,-1);
|
|
654
|
-
r->pos = 0;
|
|
655
|
-
r->len = sdslen(r->buf);
|
|
656
|
-
}
|
|
657
|
-
|
|
658
|
-
/* Emit a reply when there is one. */
|
|
659
|
-
if (r->ridx == -1) {
|
|
660
|
-
if (reply != NULL)
|
|
661
|
-
*reply = r->reply;
|
|
662
|
-
r->reply = NULL;
|
|
663
|
-
}
|
|
664
|
-
return REDIS_OK;
|
|
665
|
-
}
|
|
666
|
-
|
|
667
|
-
/* Calculate the number of bytes needed to represent an integer as string. */
|
|
668
|
-
static int intlen(int i) {
|
|
669
|
-
int len = 0;
|
|
670
|
-
if (i < 0) {
|
|
671
|
-
len++;
|
|
672
|
-
i = -i;
|
|
673
|
-
}
|
|
674
|
-
do {
|
|
675
|
-
len++;
|
|
676
|
-
i /= 10;
|
|
677
|
-
} while(i);
|
|
678
|
-
return len;
|
|
191
|
+
/* Return the number of digits of 'v' when converted to string in radix 10.
|
|
192
|
+
* Implementation borrowed from link in redis/src/util.c:string2ll(). */
|
|
193
|
+
static uint32_t countDigits(uint64_t v) {
|
|
194
|
+
uint32_t result = 1;
|
|
195
|
+
for (;;) {
|
|
196
|
+
if (v < 10) return result;
|
|
197
|
+
if (v < 100) return result + 1;
|
|
198
|
+
if (v < 1000) return result + 2;
|
|
199
|
+
if (v < 10000) return result + 3;
|
|
200
|
+
v /= 10000U;
|
|
201
|
+
result += 4;
|
|
202
|
+
}
|
|
679
203
|
}
|
|
680
204
|
|
|
681
205
|
/* Helper that calculates the bulk length given a certain string length. */
|
|
682
206
|
static size_t bulklen(size_t len) {
|
|
683
|
-
return 1+
|
|
207
|
+
return 1+countDigits(len)+2+len+2;
|
|
684
208
|
}
|
|
685
209
|
|
|
686
210
|
int redisvFormatCommand(char **target, const char *format, va_list ap) {
|
|
@@ -692,6 +216,7 @@ int redisvFormatCommand(char **target, const char *format, va_list ap) {
|
|
|
692
216
|
char **curargv = NULL, **newargv = NULL;
|
|
693
217
|
int argc = 0;
|
|
694
218
|
int totlen = 0;
|
|
219
|
+
int error_type = 0; /* 0 = no error; -1 = memory error; -2 = format error */
|
|
695
220
|
int j;
|
|
696
221
|
|
|
697
222
|
/* Abort if there is not target to set */
|
|
@@ -708,19 +233,19 @@ int redisvFormatCommand(char **target, const char *format, va_list ap) {
|
|
|
708
233
|
if (*c == ' ') {
|
|
709
234
|
if (touched) {
|
|
710
235
|
newargv = realloc(curargv,sizeof(char*)*(argc+1));
|
|
711
|
-
if (newargv == NULL) goto
|
|
236
|
+
if (newargv == NULL) goto memory_err;
|
|
712
237
|
curargv = newargv;
|
|
713
238
|
curargv[argc++] = curarg;
|
|
714
239
|
totlen += bulklen(sdslen(curarg));
|
|
715
240
|
|
|
716
241
|
/* curarg is put in argv so it can be overwritten. */
|
|
717
242
|
curarg = sdsempty();
|
|
718
|
-
if (curarg == NULL) goto
|
|
243
|
+
if (curarg == NULL) goto memory_err;
|
|
719
244
|
touched = 0;
|
|
720
245
|
}
|
|
721
246
|
} else {
|
|
722
247
|
newarg = sdscatlen(curarg,c,1);
|
|
723
|
-
if (newarg == NULL) goto
|
|
248
|
+
if (newarg == NULL) goto memory_err;
|
|
724
249
|
curarg = newarg;
|
|
725
250
|
touched = 1;
|
|
726
251
|
}
|
|
@@ -751,17 +276,14 @@ int redisvFormatCommand(char **target, const char *format, va_list ap) {
|
|
|
751
276
|
/* Try to detect printf format */
|
|
752
277
|
{
|
|
753
278
|
static const char intfmts[] = "diouxX";
|
|
279
|
+
static const char flags[] = "#0-+ ";
|
|
754
280
|
char _format[16];
|
|
755
281
|
const char *_p = c+1;
|
|
756
282
|
size_t _l = 0;
|
|
757
283
|
va_list _cpy;
|
|
758
284
|
|
|
759
285
|
/* Flags */
|
|
760
|
-
|
|
761
|
-
if (*_p != '\0' && *_p == '0') _p++;
|
|
762
|
-
if (*_p != '\0' && *_p == '-') _p++;
|
|
763
|
-
if (*_p != '\0' && *_p == ' ') _p++;
|
|
764
|
-
if (*_p != '\0' && *_p == '+') _p++;
|
|
286
|
+
while (*_p != '\0' && strchr(flags,*_p) != NULL) _p++;
|
|
765
287
|
|
|
766
288
|
/* Field width */
|
|
767
289
|
while (*_p != '\0' && isdigit(*_p)) _p++;
|
|
@@ -829,7 +351,7 @@ int redisvFormatCommand(char **target, const char *format, va_list ap) {
|
|
|
829
351
|
|
|
830
352
|
fmt_invalid:
|
|
831
353
|
va_end(_cpy);
|
|
832
|
-
goto
|
|
354
|
+
goto format_err;
|
|
833
355
|
|
|
834
356
|
fmt_valid:
|
|
835
357
|
_l = (_p+1)-c;
|
|
@@ -848,7 +370,7 @@ int redisvFormatCommand(char **target, const char *format, va_list ap) {
|
|
|
848
370
|
}
|
|
849
371
|
}
|
|
850
372
|
|
|
851
|
-
if (newarg == NULL) goto
|
|
373
|
+
if (newarg == NULL) goto memory_err;
|
|
852
374
|
curarg = newarg;
|
|
853
375
|
|
|
854
376
|
touched = 1;
|
|
@@ -860,7 +382,7 @@ int redisvFormatCommand(char **target, const char *format, va_list ap) {
|
|
|
860
382
|
/* Add the last argument if needed */
|
|
861
383
|
if (touched) {
|
|
862
384
|
newargv = realloc(curargv,sizeof(char*)*(argc+1));
|
|
863
|
-
if (newargv == NULL) goto
|
|
385
|
+
if (newargv == NULL) goto memory_err;
|
|
864
386
|
curargv = newargv;
|
|
865
387
|
curargv[argc++] = curarg;
|
|
866
388
|
totlen += bulklen(sdslen(curarg));
|
|
@@ -872,11 +394,11 @@ int redisvFormatCommand(char **target, const char *format, va_list ap) {
|
|
|
872
394
|
curarg = NULL;
|
|
873
395
|
|
|
874
396
|
/* Add bytes needed to hold multi bulk count */
|
|
875
|
-
totlen += 1+
|
|
397
|
+
totlen += 1+countDigits(argc)+2;
|
|
876
398
|
|
|
877
399
|
/* Build the command at protocol level */
|
|
878
400
|
cmd = malloc(totlen+1);
|
|
879
|
-
if (cmd == NULL) goto
|
|
401
|
+
if (cmd == NULL) goto memory_err;
|
|
880
402
|
|
|
881
403
|
pos = sprintf(cmd,"*%d\r\n",argc);
|
|
882
404
|
for (j = 0; j < argc; j++) {
|
|
@@ -894,20 +416,29 @@ int redisvFormatCommand(char **target, const char *format, va_list ap) {
|
|
|
894
416
|
*target = cmd;
|
|
895
417
|
return totlen;
|
|
896
418
|
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
free(curargv);
|
|
419
|
+
format_err:
|
|
420
|
+
error_type = -2;
|
|
421
|
+
goto cleanup;
|
|
901
422
|
|
|
902
|
-
|
|
903
|
-
|
|
423
|
+
memory_err:
|
|
424
|
+
error_type = -1;
|
|
425
|
+
goto cleanup;
|
|
426
|
+
|
|
427
|
+
cleanup:
|
|
428
|
+
if (curargv) {
|
|
429
|
+
while(argc--)
|
|
430
|
+
sdsfree(curargv[argc]);
|
|
431
|
+
free(curargv);
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
sdsfree(curarg);
|
|
904
435
|
|
|
905
436
|
/* No need to check cmd since it is the last statement that can fail,
|
|
906
437
|
* but do it anyway to be as defensive as possible. */
|
|
907
438
|
if (cmd != NULL)
|
|
908
439
|
free(cmd);
|
|
909
440
|
|
|
910
|
-
return
|
|
441
|
+
return error_type;
|
|
911
442
|
}
|
|
912
443
|
|
|
913
444
|
/* Format a command according to the Redis protocol. This function
|
|
@@ -917,7 +448,7 @@ err:
|
|
|
917
448
|
* %b represents a binary safe string
|
|
918
449
|
*
|
|
919
450
|
* When using %b you need to provide both the pointer to the string
|
|
920
|
-
* and the length in bytes. Examples:
|
|
451
|
+
* and the length in bytes as a size_t. Examples:
|
|
921
452
|
*
|
|
922
453
|
* len = redisFormatCommand(target, "GET %s", mykey);
|
|
923
454
|
* len = redisFormatCommand(target, "SET %s %b", mykey, myval, myvallen);
|
|
@@ -928,9 +459,69 @@ int redisFormatCommand(char **target, const char *format, ...) {
|
|
|
928
459
|
va_start(ap,format);
|
|
929
460
|
len = redisvFormatCommand(target,format,ap);
|
|
930
461
|
va_end(ap);
|
|
462
|
+
|
|
463
|
+
/* The API says "-1" means bad result, but we now also return "-2" in some
|
|
464
|
+
* cases. Force the return value to always be -1. */
|
|
465
|
+
if (len < 0)
|
|
466
|
+
len = -1;
|
|
467
|
+
|
|
931
468
|
return len;
|
|
932
469
|
}
|
|
933
470
|
|
|
471
|
+
/* Format a command according to the Redis protocol using an sds string and
|
|
472
|
+
* sdscatfmt for the processing of arguments. This function takes the
|
|
473
|
+
* number of arguments, an array with arguments and an array with their
|
|
474
|
+
* lengths. If the latter is set to NULL, strlen will be used to compute the
|
|
475
|
+
* argument lengths.
|
|
476
|
+
*/
|
|
477
|
+
int redisFormatSdsCommandArgv(sds *target, int argc, const char **argv,
|
|
478
|
+
const size_t *argvlen)
|
|
479
|
+
{
|
|
480
|
+
sds cmd;
|
|
481
|
+
unsigned long long totlen;
|
|
482
|
+
int j;
|
|
483
|
+
size_t len;
|
|
484
|
+
|
|
485
|
+
/* Abort on a NULL target */
|
|
486
|
+
if (target == NULL)
|
|
487
|
+
return -1;
|
|
488
|
+
|
|
489
|
+
/* Calculate our total size */
|
|
490
|
+
totlen = 1+countDigits(argc)+2;
|
|
491
|
+
for (j = 0; j < argc; j++) {
|
|
492
|
+
len = argvlen ? argvlen[j] : strlen(argv[j]);
|
|
493
|
+
totlen += bulklen(len);
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
/* Use an SDS string for command construction */
|
|
497
|
+
cmd = sdsempty();
|
|
498
|
+
if (cmd == NULL)
|
|
499
|
+
return -1;
|
|
500
|
+
|
|
501
|
+
/* We already know how much storage we need */
|
|
502
|
+
cmd = sdsMakeRoomFor(cmd, totlen);
|
|
503
|
+
if (cmd == NULL)
|
|
504
|
+
return -1;
|
|
505
|
+
|
|
506
|
+
/* Construct command */
|
|
507
|
+
cmd = sdscatfmt(cmd, "*%i\r\n", argc);
|
|
508
|
+
for (j=0; j < argc; j++) {
|
|
509
|
+
len = argvlen ? argvlen[j] : strlen(argv[j]);
|
|
510
|
+
cmd = sdscatfmt(cmd, "$%T\r\n", len);
|
|
511
|
+
cmd = sdscatlen(cmd, argv[j], len);
|
|
512
|
+
cmd = sdscatlen(cmd, "\r\n", sizeof("\r\n")-1);
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
assert(sdslen(cmd)==totlen);
|
|
516
|
+
|
|
517
|
+
*target = cmd;
|
|
518
|
+
return totlen;
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
void redisFreeSdsCommand(sds cmd) {
|
|
522
|
+
sdsfree(cmd);
|
|
523
|
+
}
|
|
524
|
+
|
|
934
525
|
/* Format a command according to the Redis protocol. This function takes the
|
|
935
526
|
* number of arguments, an array with arguments and an array with their
|
|
936
527
|
* lengths. If the latter is set to NULL, strlen will be used to compute the
|
|
@@ -942,8 +533,12 @@ int redisFormatCommandArgv(char **target, int argc, const char **argv, const siz
|
|
|
942
533
|
size_t len;
|
|
943
534
|
int totlen, j;
|
|
944
535
|
|
|
536
|
+
/* Abort on a NULL target */
|
|
537
|
+
if (target == NULL)
|
|
538
|
+
return -1;
|
|
539
|
+
|
|
945
540
|
/* Calculate number of bytes needed for the command */
|
|
946
|
-
totlen = 1+
|
|
541
|
+
totlen = 1+countDigits(argc)+2;
|
|
947
542
|
for (j = 0; j < argc; j++) {
|
|
948
543
|
len = argvlen ? argvlen[j] : strlen(argv[j]);
|
|
949
544
|
totlen += bulklen(len);
|
|
@@ -970,6 +565,10 @@ int redisFormatCommandArgv(char **target, int argc, const char **argv, const siz
|
|
|
970
565
|
return totlen;
|
|
971
566
|
}
|
|
972
567
|
|
|
568
|
+
void redisFreeCommand(char *cmd) {
|
|
569
|
+
free(cmd);
|
|
570
|
+
}
|
|
571
|
+
|
|
973
572
|
void __redisSetError(redisContext *c, int type, const char *str) {
|
|
974
573
|
size_t len;
|
|
975
574
|
|
|
@@ -982,10 +581,14 @@ void __redisSetError(redisContext *c, int type, const char *str) {
|
|
|
982
581
|
} else {
|
|
983
582
|
/* Only REDIS_ERR_IO may lack a description! */
|
|
984
583
|
assert(type == REDIS_ERR_IO);
|
|
985
|
-
|
|
584
|
+
__redis_strerror_r(errno, c->errstr, sizeof(c->errstr));
|
|
986
585
|
}
|
|
987
586
|
}
|
|
988
587
|
|
|
588
|
+
redisReader *redisReaderCreate(void) {
|
|
589
|
+
return redisReaderCreateWithFunctions(&defaultFunctions);
|
|
590
|
+
}
|
|
591
|
+
|
|
989
592
|
static redisContext *redisContextInit(void) {
|
|
990
593
|
redisContext *c;
|
|
991
594
|
|
|
@@ -997,71 +600,192 @@ static redisContext *redisContextInit(void) {
|
|
|
997
600
|
c->errstr[0] = '\0';
|
|
998
601
|
c->obuf = sdsempty();
|
|
999
602
|
c->reader = redisReaderCreate();
|
|
603
|
+
c->tcp.host = NULL;
|
|
604
|
+
c->tcp.source_addr = NULL;
|
|
605
|
+
c->unix_sock.path = NULL;
|
|
606
|
+
c->timeout = NULL;
|
|
607
|
+
|
|
608
|
+
if (c->obuf == NULL || c->reader == NULL) {
|
|
609
|
+
redisFree(c);
|
|
610
|
+
return NULL;
|
|
611
|
+
}
|
|
612
|
+
|
|
1000
613
|
return c;
|
|
1001
614
|
}
|
|
1002
615
|
|
|
1003
616
|
void redisFree(redisContext *c) {
|
|
617
|
+
if (c == NULL)
|
|
618
|
+
return;
|
|
1004
619
|
if (c->fd > 0)
|
|
1005
620
|
close(c->fd);
|
|
1006
621
|
if (c->obuf != NULL)
|
|
1007
622
|
sdsfree(c->obuf);
|
|
1008
623
|
if (c->reader != NULL)
|
|
1009
624
|
redisReaderFree(c->reader);
|
|
625
|
+
if (c->tcp.host)
|
|
626
|
+
free(c->tcp.host);
|
|
627
|
+
if (c->tcp.source_addr)
|
|
628
|
+
free(c->tcp.source_addr);
|
|
629
|
+
if (c->unix_sock.path)
|
|
630
|
+
free(c->unix_sock.path);
|
|
631
|
+
if (c->timeout)
|
|
632
|
+
free(c->timeout);
|
|
1010
633
|
free(c);
|
|
1011
634
|
}
|
|
1012
635
|
|
|
636
|
+
int redisFreeKeepFd(redisContext *c) {
|
|
637
|
+
int fd = c->fd;
|
|
638
|
+
c->fd = -1;
|
|
639
|
+
redisFree(c);
|
|
640
|
+
return fd;
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
int redisReconnect(redisContext *c) {
|
|
644
|
+
c->err = 0;
|
|
645
|
+
memset(c->errstr, '\0', strlen(c->errstr));
|
|
646
|
+
|
|
647
|
+
if (c->fd > 0) {
|
|
648
|
+
close(c->fd);
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
sdsfree(c->obuf);
|
|
652
|
+
redisReaderFree(c->reader);
|
|
653
|
+
|
|
654
|
+
c->obuf = sdsempty();
|
|
655
|
+
c->reader = redisReaderCreate();
|
|
656
|
+
|
|
657
|
+
if (c->connection_type == REDIS_CONN_TCP) {
|
|
658
|
+
return redisContextConnectBindTcp(c, c->tcp.host, c->tcp.port,
|
|
659
|
+
c->timeout, c->tcp.source_addr);
|
|
660
|
+
} else if (c->connection_type == REDIS_CONN_UNIX) {
|
|
661
|
+
return redisContextConnectUnix(c, c->unix_sock.path, c->timeout);
|
|
662
|
+
} else {
|
|
663
|
+
/* Something bad happened here and shouldn't have. There isn't
|
|
664
|
+
enough information in the context to reconnect. */
|
|
665
|
+
__redisSetError(c,REDIS_ERR_OTHER,"Not enough information to reconnect");
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
return REDIS_ERR;
|
|
669
|
+
}
|
|
670
|
+
|
|
1013
671
|
/* Connect to a Redis instance. On error the field error in the returned
|
|
1014
672
|
* context will be set to the return value of the error function.
|
|
1015
673
|
* When no set of reply functions is given, the default set will be used. */
|
|
1016
674
|
redisContext *redisConnect(const char *ip, int port) {
|
|
1017
|
-
redisContext *c
|
|
675
|
+
redisContext *c;
|
|
676
|
+
|
|
677
|
+
c = redisContextInit();
|
|
678
|
+
if (c == NULL)
|
|
679
|
+
return NULL;
|
|
680
|
+
|
|
1018
681
|
c->flags |= REDIS_BLOCK;
|
|
1019
682
|
redisContextConnectTcp(c,ip,port,NULL);
|
|
1020
683
|
return c;
|
|
1021
684
|
}
|
|
1022
685
|
|
|
1023
|
-
redisContext *redisConnectWithTimeout(const char *ip, int port, struct timeval tv) {
|
|
1024
|
-
redisContext *c
|
|
686
|
+
redisContext *redisConnectWithTimeout(const char *ip, int port, const struct timeval tv) {
|
|
687
|
+
redisContext *c;
|
|
688
|
+
|
|
689
|
+
c = redisContextInit();
|
|
690
|
+
if (c == NULL)
|
|
691
|
+
return NULL;
|
|
692
|
+
|
|
1025
693
|
c->flags |= REDIS_BLOCK;
|
|
1026
694
|
redisContextConnectTcp(c,ip,port,&tv);
|
|
1027
695
|
return c;
|
|
1028
696
|
}
|
|
1029
697
|
|
|
1030
698
|
redisContext *redisConnectNonBlock(const char *ip, int port) {
|
|
1031
|
-
redisContext *c
|
|
699
|
+
redisContext *c;
|
|
700
|
+
|
|
701
|
+
c = redisContextInit();
|
|
702
|
+
if (c == NULL)
|
|
703
|
+
return NULL;
|
|
704
|
+
|
|
1032
705
|
c->flags &= ~REDIS_BLOCK;
|
|
1033
706
|
redisContextConnectTcp(c,ip,port,NULL);
|
|
1034
707
|
return c;
|
|
1035
708
|
}
|
|
1036
709
|
|
|
1037
|
-
redisContext *
|
|
710
|
+
redisContext *redisConnectBindNonBlock(const char *ip, int port,
|
|
711
|
+
const char *source_addr) {
|
|
1038
712
|
redisContext *c = redisContextInit();
|
|
713
|
+
c->flags &= ~REDIS_BLOCK;
|
|
714
|
+
redisContextConnectBindTcp(c,ip,port,NULL,source_addr);
|
|
715
|
+
return c;
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
redisContext *redisConnectBindNonBlockWithReuse(const char *ip, int port,
|
|
719
|
+
const char *source_addr) {
|
|
720
|
+
redisContext *c = redisContextInit();
|
|
721
|
+
c->flags &= ~REDIS_BLOCK;
|
|
722
|
+
c->flags |= REDIS_REUSEADDR;
|
|
723
|
+
redisContextConnectBindTcp(c,ip,port,NULL,source_addr);
|
|
724
|
+
return c;
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
redisContext *redisConnectUnix(const char *path) {
|
|
728
|
+
redisContext *c;
|
|
729
|
+
|
|
730
|
+
c = redisContextInit();
|
|
731
|
+
if (c == NULL)
|
|
732
|
+
return NULL;
|
|
733
|
+
|
|
1039
734
|
c->flags |= REDIS_BLOCK;
|
|
1040
735
|
redisContextConnectUnix(c,path,NULL);
|
|
1041
736
|
return c;
|
|
1042
737
|
}
|
|
1043
738
|
|
|
1044
|
-
redisContext *redisConnectUnixWithTimeout(const char *path, struct timeval tv) {
|
|
1045
|
-
redisContext *c
|
|
739
|
+
redisContext *redisConnectUnixWithTimeout(const char *path, const struct timeval tv) {
|
|
740
|
+
redisContext *c;
|
|
741
|
+
|
|
742
|
+
c = redisContextInit();
|
|
743
|
+
if (c == NULL)
|
|
744
|
+
return NULL;
|
|
745
|
+
|
|
1046
746
|
c->flags |= REDIS_BLOCK;
|
|
1047
747
|
redisContextConnectUnix(c,path,&tv);
|
|
1048
748
|
return c;
|
|
1049
749
|
}
|
|
1050
750
|
|
|
1051
751
|
redisContext *redisConnectUnixNonBlock(const char *path) {
|
|
1052
|
-
redisContext *c
|
|
752
|
+
redisContext *c;
|
|
753
|
+
|
|
754
|
+
c = redisContextInit();
|
|
755
|
+
if (c == NULL)
|
|
756
|
+
return NULL;
|
|
757
|
+
|
|
1053
758
|
c->flags &= ~REDIS_BLOCK;
|
|
1054
759
|
redisContextConnectUnix(c,path,NULL);
|
|
1055
760
|
return c;
|
|
1056
761
|
}
|
|
1057
762
|
|
|
763
|
+
redisContext *redisConnectFd(int fd) {
|
|
764
|
+
redisContext *c;
|
|
765
|
+
|
|
766
|
+
c = redisContextInit();
|
|
767
|
+
if (c == NULL)
|
|
768
|
+
return NULL;
|
|
769
|
+
|
|
770
|
+
c->fd = fd;
|
|
771
|
+
c->flags |= REDIS_BLOCK | REDIS_CONNECTED;
|
|
772
|
+
return c;
|
|
773
|
+
}
|
|
774
|
+
|
|
1058
775
|
/* Set read/write timeout on a blocking socket. */
|
|
1059
|
-
int redisSetTimeout(redisContext *c, struct timeval tv) {
|
|
776
|
+
int redisSetTimeout(redisContext *c, const struct timeval tv) {
|
|
1060
777
|
if (c->flags & REDIS_BLOCK)
|
|
1061
778
|
return redisContextSetTimeout(c,tv);
|
|
1062
779
|
return REDIS_ERR;
|
|
1063
780
|
}
|
|
1064
781
|
|
|
782
|
+
/* Enable connection KeepAlive. */
|
|
783
|
+
int redisEnableKeepAlive(redisContext *c) {
|
|
784
|
+
if (redisKeepAlive(c, REDIS_KEEPALIVE_INTERVAL) != REDIS_OK)
|
|
785
|
+
return REDIS_ERR;
|
|
786
|
+
return REDIS_OK;
|
|
787
|
+
}
|
|
788
|
+
|
|
1065
789
|
/* Use this function to handle a read event on the descriptor. It will try
|
|
1066
790
|
* and read some bytes from the socket and feed them to the reply parser.
|
|
1067
791
|
*
|
|
@@ -1077,7 +801,7 @@ int redisBufferRead(redisContext *c) {
|
|
|
1077
801
|
|
|
1078
802
|
nread = read(c->fd,buf,sizeof(buf));
|
|
1079
803
|
if (nread == -1) {
|
|
1080
|
-
if (errno == EAGAIN && !(c->flags & REDIS_BLOCK)) {
|
|
804
|
+
if ((errno == EAGAIN && !(c->flags & REDIS_BLOCK)) || (errno == EINTR)) {
|
|
1081
805
|
/* Try again later */
|
|
1082
806
|
} else {
|
|
1083
807
|
__redisSetError(c,REDIS_ERR_IO,NULL);
|
|
@@ -1114,7 +838,7 @@ int redisBufferWrite(redisContext *c, int *done) {
|
|
|
1114
838
|
if (sdslen(c->obuf) > 0) {
|
|
1115
839
|
nwritten = write(c->fd,c->obuf,sdslen(c->obuf));
|
|
1116
840
|
if (nwritten == -1) {
|
|
1117
|
-
if (errno == EAGAIN && !(c->flags & REDIS_BLOCK)) {
|
|
841
|
+
if ((errno == EAGAIN && !(c->flags & REDIS_BLOCK)) || (errno == EINTR)) {
|
|
1118
842
|
/* Try again later */
|
|
1119
843
|
} else {
|
|
1120
844
|
__redisSetError(c,REDIS_ERR_IO,NULL);
|
|
@@ -1180,7 +904,7 @@ int redisGetReply(redisContext *c, void **reply) {
|
|
|
1180
904
|
* is used, you need to call redisGetReply yourself to retrieve
|
|
1181
905
|
* the reply (or replies in pub/sub).
|
|
1182
906
|
*/
|
|
1183
|
-
int __redisAppendCommand(redisContext *c, char *cmd, size_t len) {
|
|
907
|
+
int __redisAppendCommand(redisContext *c, const char *cmd, size_t len) {
|
|
1184
908
|
sds newbuf;
|
|
1185
909
|
|
|
1186
910
|
newbuf = sdscatlen(c->obuf,cmd,len);
|
|
@@ -1193,6 +917,15 @@ int __redisAppendCommand(redisContext *c, char *cmd, size_t len) {
|
|
|
1193
917
|
return REDIS_OK;
|
|
1194
918
|
}
|
|
1195
919
|
|
|
920
|
+
int redisAppendFormattedCommand(redisContext *c, const char *cmd, size_t len) {
|
|
921
|
+
|
|
922
|
+
if (__redisAppendCommand(c, cmd, len) != REDIS_OK) {
|
|
923
|
+
return REDIS_ERR;
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
return REDIS_OK;
|
|
927
|
+
}
|
|
928
|
+
|
|
1196
929
|
int redisvAppendCommand(redisContext *c, const char *format, va_list ap) {
|
|
1197
930
|
char *cmd;
|
|
1198
931
|
int len;
|
|
@@ -1201,6 +934,9 @@ int redisvAppendCommand(redisContext *c, const char *format, va_list ap) {
|
|
|
1201
934
|
if (len == -1) {
|
|
1202
935
|
__redisSetError(c,REDIS_ERR_OOM,"Out of memory");
|
|
1203
936
|
return REDIS_ERR;
|
|
937
|
+
} else if (len == -2) {
|
|
938
|
+
__redisSetError(c,REDIS_ERR_OTHER,"Invalid format string");
|
|
939
|
+
return REDIS_ERR;
|
|
1204
940
|
}
|
|
1205
941
|
|
|
1206
942
|
if (__redisAppendCommand(c,cmd,len) != REDIS_OK) {
|
|
@@ -1223,21 +959,21 @@ int redisAppendCommand(redisContext *c, const char *format, ...) {
|
|
|
1223
959
|
}
|
|
1224
960
|
|
|
1225
961
|
int redisAppendCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen) {
|
|
1226
|
-
|
|
962
|
+
sds cmd;
|
|
1227
963
|
int len;
|
|
1228
964
|
|
|
1229
|
-
len =
|
|
965
|
+
len = redisFormatSdsCommandArgv(&cmd,argc,argv,argvlen);
|
|
1230
966
|
if (len == -1) {
|
|
1231
967
|
__redisSetError(c,REDIS_ERR_OOM,"Out of memory");
|
|
1232
968
|
return REDIS_ERR;
|
|
1233
969
|
}
|
|
1234
970
|
|
|
1235
971
|
if (__redisAppendCommand(c,cmd,len) != REDIS_OK) {
|
|
1236
|
-
|
|
972
|
+
sdsfree(cmd);
|
|
1237
973
|
return REDIS_ERR;
|
|
1238
974
|
}
|
|
1239
975
|
|
|
1240
|
-
|
|
976
|
+
sdsfree(cmd);
|
|
1241
977
|
return REDIS_OK;
|
|
1242
978
|
}
|
|
1243
979
|
|