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,51 +0,0 @@
1
- /* Extracted from anet.c to work properly with Hiredis error reporting.
2
- *
3
- * Copyright (c) 2006-2011, Salvatore Sanfilippo <antirez at gmail dot com>
4
- * Copyright (c) 2010-2011, Pieter Noordhuis <pcnoordhuis at gmail dot com>
5
- *
6
- * All rights reserved.
7
- *
8
- * Redistribution and use in source and binary forms, with or without
9
- * modification, are permitted provided that the following conditions are met:
10
- *
11
- * * Redistributions of source code must retain the above copyright notice,
12
- * this list of conditions and the following disclaimer.
13
- * * Redistributions in binary form must reproduce the above copyright
14
- * notice, this list of conditions and the following disclaimer in the
15
- * documentation and/or other materials provided with the distribution.
16
- * * Neither the name of Redis nor the names of its contributors may be used
17
- * to endorse or promote products derived from this software without
18
- * specific prior written permission.
19
- *
20
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30
- * POSSIBILITY OF SUCH DAMAGE.
31
- */
32
-
33
- #ifndef __NET_H
34
- #define __NET_H
35
-
36
- #include "hiredis.h"
37
-
38
- #if defined(__sun)
39
- #define AF_LOCAL AF_UNIX
40
- #endif
41
-
42
- int redisCheckSocketError(redisContext *c);
43
- int redisContextSetTimeout(redisContext *c, const struct timeval tv);
44
- int redisContextConnectTcp(redisContext *c, const char *addr, int port, const struct timeval *timeout);
45
- int redisContextConnectBindTcp(redisContext *c, const char *addr, int port,
46
- const struct timeval *timeout,
47
- const char *source_addr);
48
- int redisContextConnectUnix(redisContext *c, const char *path, const struct timeval *timeout);
49
- int redisKeepAlive(redisContext *c, int interval);
50
-
51
- #endif
@@ -1,523 +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
-
33
- #include "fmacros.h"
34
- #include <string.h>
35
- #include <stdlib.h>
36
- #include <unistd.h>
37
- #include <assert.h>
38
- #include <errno.h>
39
- #include <ctype.h>
40
-
41
- #include "read.h"
42
- #include "sds.h"
43
-
44
- static void __redisReaderSetError(redisReader *r, int type, const char *str) {
45
- size_t len;
46
-
47
- if (r->reply != NULL && r->fn && r->fn->freeObject) {
48
- r->fn->freeObject(r->reply);
49
- r->reply = NULL;
50
- }
51
-
52
- /* Clear input buffer on errors. */
53
- if (r->buf != NULL) {
54
- sdsfree(r->buf);
55
- r->buf = NULL;
56
- r->pos = r->len = 0;
57
- }
58
-
59
- /* Reset task stack. */
60
- r->ridx = -1;
61
-
62
- /* Set error. */
63
- r->err = type;
64
- len = strlen(str);
65
- len = len < (sizeof(r->errstr)-1) ? len : (sizeof(r->errstr)-1);
66
- memcpy(r->errstr,str,len);
67
- r->errstr[len] = '\0';
68
- }
69
-
70
- static size_t chrtos(char *buf, size_t size, char byte) {
71
- size_t len = 0;
72
-
73
- switch(byte) {
74
- case '\\':
75
- case '"':
76
- len = snprintf(buf,size,"\"\\%c\"",byte);
77
- break;
78
- case '\n': len = snprintf(buf,size,"\"\\n\""); break;
79
- case '\r': len = snprintf(buf,size,"\"\\r\""); break;
80
- case '\t': len = snprintf(buf,size,"\"\\t\""); break;
81
- case '\a': len = snprintf(buf,size,"\"\\a\""); break;
82
- case '\b': len = snprintf(buf,size,"\"\\b\""); break;
83
- default:
84
- if (isprint(byte))
85
- len = snprintf(buf,size,"\"%c\"",byte);
86
- else
87
- len = snprintf(buf,size,"\"\\x%02x\"",(unsigned char)byte);
88
- break;
89
- }
90
-
91
- return len;
92
- }
93
-
94
- static void __redisReaderSetErrorProtocolByte(redisReader *r, char byte) {
95
- char cbuf[8], sbuf[128];
96
-
97
- chrtos(cbuf,sizeof(cbuf),byte);
98
- snprintf(sbuf,sizeof(sbuf),
99
- "Protocol error, got %s as reply type byte", cbuf);
100
- __redisReaderSetError(r,REDIS_ERR_PROTOCOL,sbuf);
101
- }
102
-
103
- static void __redisReaderSetErrorOOM(redisReader *r) {
104
- __redisReaderSetError(r,REDIS_ERR_OOM,"Out of memory");
105
- }
106
-
107
- static char *readBytes(redisReader *r, unsigned int bytes) {
108
- char *p;
109
- if (r->len-r->pos >= bytes) {
110
- p = r->buf+r->pos;
111
- r->pos += bytes;
112
- return p;
113
- }
114
- return NULL;
115
- }
116
-
117
- /* Find pointer to \r\n. */
118
- static char *seekNewline(char *s, size_t len) {
119
- int pos = 0;
120
- int _len = len-1;
121
-
122
- /* Position should be < len-1 because the character at "pos" should be
123
- * followed by a \n. Note that strchr cannot be used because it doesn't
124
- * allow to search a limited length and the buffer that is being searched
125
- * might not have a trailing NULL character. */
126
- while (pos < _len) {
127
- while(pos < _len && s[pos] != '\r') pos++;
128
- if (s[pos] != '\r') {
129
- /* Not found. */
130
- return NULL;
131
- } else {
132
- if (s[pos+1] == '\n') {
133
- /* Found. */
134
- return s+pos;
135
- } else {
136
- /* Continue searching. */
137
- pos++;
138
- }
139
- }
140
- }
141
- return NULL;
142
- }
143
-
144
- /* Read a long long value starting at *s, under the assumption that it will be
145
- * terminated by \r\n. Ambiguously returns -1 for unexpected input. */
146
- static long long readLongLong(char *s) {
147
- long long v = 0;
148
- int dec, mult = 1;
149
- char c;
150
-
151
- if (*s == '-') {
152
- mult = -1;
153
- s++;
154
- } else if (*s == '+') {
155
- mult = 1;
156
- s++;
157
- }
158
-
159
- while ((c = *(s++)) != '\r') {
160
- dec = c - '0';
161
- if (dec >= 0 && dec < 10) {
162
- v *= 10;
163
- v += dec;
164
- } else {
165
- /* Should not happen... */
166
- return -1;
167
- }
168
- }
169
-
170
- return mult*v;
171
- }
172
-
173
- static char *readLine(redisReader *r, int *_len) {
174
- char *p, *s;
175
- int len;
176
-
177
- p = r->buf+r->pos;
178
- s = seekNewline(p,(r->len-r->pos));
179
- if (s != NULL) {
180
- len = s-(r->buf+r->pos);
181
- r->pos += len+2; /* skip \r\n */
182
- if (_len) *_len = len;
183
- return p;
184
- }
185
- return NULL;
186
- }
187
-
188
- static void moveToNextTask(redisReader *r) {
189
- redisReadTask *cur, *prv;
190
- while (r->ridx >= 0) {
191
- /* Return a.s.a.p. when the stack is now empty. */
192
- if (r->ridx == 0) {
193
- r->ridx--;
194
- return;
195
- }
196
-
197
- cur = &(r->rstack[r->ridx]);
198
- prv = &(r->rstack[r->ridx-1]);
199
- assert(prv->type == REDIS_REPLY_ARRAY);
200
- if (cur->idx == prv->elements-1) {
201
- r->ridx--;
202
- } else {
203
- /* Reset the type because the next item can be anything */
204
- assert(cur->idx < prv->elements);
205
- cur->type = -1;
206
- cur->elements = -1;
207
- cur->idx++;
208
- return;
209
- }
210
- }
211
- }
212
-
213
- static int processLineItem(redisReader *r) {
214
- redisReadTask *cur = &(r->rstack[r->ridx]);
215
- void *obj;
216
- char *p;
217
- int len;
218
-
219
- if ((p = readLine(r,&len)) != NULL) {
220
- if (cur->type == REDIS_REPLY_INTEGER) {
221
- if (r->fn && r->fn->createInteger)
222
- obj = r->fn->createInteger(cur,readLongLong(p));
223
- else
224
- obj = (void*)REDIS_REPLY_INTEGER;
225
- } else {
226
- /* Type will be error or status. */
227
- if (r->fn && r->fn->createString)
228
- obj = r->fn->createString(cur,p,len);
229
- else
230
- obj = (void*)(size_t)(cur->type);
231
- }
232
-
233
- if (obj == NULL) {
234
- __redisReaderSetErrorOOM(r);
235
- return REDIS_ERR;
236
- }
237
-
238
- /* Set reply if this is the root object. */
239
- if (r->ridx == 0) r->reply = obj;
240
- moveToNextTask(r);
241
- return REDIS_OK;
242
- }
243
-
244
- return REDIS_ERR;
245
- }
246
-
247
- static int processBulkItem(redisReader *r) {
248
- redisReadTask *cur = &(r->rstack[r->ridx]);
249
- void *obj = NULL;
250
- char *p, *s;
251
- long len;
252
- unsigned long bytelen;
253
- int success = 0;
254
-
255
- p = r->buf+r->pos;
256
- s = seekNewline(p,r->len-r->pos);
257
- if (s != NULL) {
258
- p = r->buf+r->pos;
259
- bytelen = s-(r->buf+r->pos)+2; /* include \r\n */
260
- len = readLongLong(p);
261
-
262
- if (len < 0) {
263
- /* The nil object can always be created. */
264
- if (r->fn && r->fn->createNil)
265
- obj = r->fn->createNil(cur);
266
- else
267
- obj = (void*)REDIS_REPLY_NIL;
268
- success = 1;
269
- } else {
270
- /* Only continue when the buffer contains the entire bulk item. */
271
- bytelen += len+2; /* include \r\n */
272
- if (r->pos+bytelen <= r->len) {
273
- if (r->fn && r->fn->createString)
274
- obj = r->fn->createString(cur,s+2,len);
275
- else
276
- obj = (void*)REDIS_REPLY_STRING;
277
- success = 1;
278
- }
279
- }
280
-
281
- /* Proceed when obj was created. */
282
- if (success) {
283
- if (obj == NULL) {
284
- __redisReaderSetErrorOOM(r);
285
- return REDIS_ERR;
286
- }
287
-
288
- r->pos += bytelen;
289
-
290
- /* Set reply if this is the root object. */
291
- if (r->ridx == 0) r->reply = obj;
292
- moveToNextTask(r);
293
- return REDIS_OK;
294
- }
295
- }
296
-
297
- return REDIS_ERR;
298
- }
299
-
300
- static int processMultiBulkItem(redisReader *r) {
301
- redisReadTask *cur = &(r->rstack[r->ridx]);
302
- void *obj;
303
- char *p;
304
- long elements;
305
- int root = 0;
306
-
307
- /* Set error for nested multi bulks with depth > 7 */
308
- if (r->ridx == 8) {
309
- __redisReaderSetError(r,REDIS_ERR_PROTOCOL,
310
- "No support for nested multi bulk replies with depth > 7");
311
- return REDIS_ERR;
312
- }
313
-
314
- if ((p = readLine(r,NULL)) != NULL) {
315
- elements = readLongLong(p);
316
- root = (r->ridx == 0);
317
-
318
- if (elements == -1) {
319
- if (r->fn && r->fn->createNil)
320
- obj = r->fn->createNil(cur);
321
- else
322
- obj = (void*)REDIS_REPLY_NIL;
323
-
324
- if (obj == NULL) {
325
- __redisReaderSetErrorOOM(r);
326
- return REDIS_ERR;
327
- }
328
-
329
- moveToNextTask(r);
330
- } else {
331
- if (r->fn && r->fn->createArray)
332
- obj = r->fn->createArray(cur,elements);
333
- else
334
- obj = (void*)REDIS_REPLY_ARRAY;
335
-
336
- if (obj == NULL) {
337
- __redisReaderSetErrorOOM(r);
338
- return REDIS_ERR;
339
- }
340
-
341
- /* Modify task stack when there are more than 0 elements. */
342
- if (elements > 0) {
343
- cur->elements = elements;
344
- cur->obj = obj;
345
- r->ridx++;
346
- r->rstack[r->ridx].type = -1;
347
- r->rstack[r->ridx].elements = -1;
348
- r->rstack[r->ridx].idx = 0;
349
- r->rstack[r->ridx].obj = NULL;
350
- r->rstack[r->ridx].parent = cur;
351
- r->rstack[r->ridx].privdata = r->privdata;
352
- } else {
353
- moveToNextTask(r);
354
- }
355
- }
356
-
357
- /* Set reply if this is the root object. */
358
- if (root) r->reply = obj;
359
- return REDIS_OK;
360
- }
361
-
362
- return REDIS_ERR;
363
- }
364
-
365
- static int processItem(redisReader *r) {
366
- redisReadTask *cur = &(r->rstack[r->ridx]);
367
- char *p;
368
-
369
- /* check if we need to read type */
370
- if (cur->type < 0) {
371
- if ((p = readBytes(r,1)) != NULL) {
372
- switch (p[0]) {
373
- case '-':
374
- cur->type = REDIS_REPLY_ERROR;
375
- break;
376
- case '+':
377
- cur->type = REDIS_REPLY_STATUS;
378
- break;
379
- case ':':
380
- cur->type = REDIS_REPLY_INTEGER;
381
- break;
382
- case '$':
383
- cur->type = REDIS_REPLY_STRING;
384
- break;
385
- case '*':
386
- cur->type = REDIS_REPLY_ARRAY;
387
- break;
388
- default:
389
- __redisReaderSetErrorProtocolByte(r,*p);
390
- return REDIS_ERR;
391
- }
392
- } else {
393
- /* could not consume 1 byte */
394
- return REDIS_ERR;
395
- }
396
- }
397
-
398
- /* process typed item */
399
- switch(cur->type) {
400
- case REDIS_REPLY_ERROR:
401
- case REDIS_REPLY_STATUS:
402
- case REDIS_REPLY_INTEGER:
403
- return processLineItem(r);
404
- case REDIS_REPLY_STRING:
405
- return processBulkItem(r);
406
- case REDIS_REPLY_ARRAY:
407
- return processMultiBulkItem(r);
408
- default:
409
- assert(NULL);
410
- return REDIS_ERR; /* Avoid warning. */
411
- }
412
- }
413
-
414
- redisReader *redisReaderCreateWithFunctions(redisReplyObjectFunctions *fn) {
415
- redisReader *r;
416
-
417
- r = calloc(sizeof(redisReader),1);
418
- if (r == NULL)
419
- return NULL;
420
-
421
- r->err = 0;
422
- r->errstr[0] = '\0';
423
- r->fn = fn;
424
- r->buf = sdsempty();
425
- r->maxbuf = REDIS_READER_MAX_BUF;
426
- if (r->buf == NULL) {
427
- free(r);
428
- return NULL;
429
- }
430
-
431
- r->ridx = -1;
432
- return r;
433
- }
434
-
435
- void redisReaderFree(redisReader *r) {
436
- if (r->reply != NULL && r->fn && r->fn->freeObject)
437
- r->fn->freeObject(r->reply);
438
- if (r->buf != NULL)
439
- sdsfree(r->buf);
440
- free(r);
441
- }
442
-
443
- int redisReaderFeed(redisReader *r, const char *buf, size_t len) {
444
- sds newbuf;
445
-
446
- /* Return early when this reader is in an erroneous state. */
447
- if (r->err)
448
- return REDIS_ERR;
449
-
450
- /* Copy the provided buffer. */
451
- if (buf != NULL && len >= 1) {
452
- /* Destroy internal buffer when it is empty and is quite large. */
453
- if (r->len == 0 && r->maxbuf != 0 && sdsavail(r->buf) > r->maxbuf) {
454
- sdsfree(r->buf);
455
- r->buf = sdsempty();
456
- r->pos = 0;
457
-
458
- /* r->buf should not be NULL since we just free'd a larger one. */
459
- assert(r->buf != NULL);
460
- }
461
-
462
- newbuf = sdscatlen(r->buf,buf,len);
463
- if (newbuf == NULL) {
464
- __redisReaderSetErrorOOM(r);
465
- return REDIS_ERR;
466
- }
467
-
468
- r->buf = newbuf;
469
- r->len = sdslen(r->buf);
470
- }
471
-
472
- return REDIS_OK;
473
- }
474
-
475
- int redisReaderGetReply(redisReader *r, void **reply) {
476
- /* Default target pointer to NULL. */
477
- if (reply != NULL)
478
- *reply = NULL;
479
-
480
- /* Return early when this reader is in an erroneous state. */
481
- if (r->err)
482
- return REDIS_ERR;
483
-
484
- /* When the buffer is empty, there will never be a reply. */
485
- if (r->len == 0)
486
- return REDIS_OK;
487
-
488
- /* Set first item to process when the stack is empty. */
489
- if (r->ridx == -1) {
490
- r->rstack[0].type = -1;
491
- r->rstack[0].elements = -1;
492
- r->rstack[0].idx = -1;
493
- r->rstack[0].obj = NULL;
494
- r->rstack[0].parent = NULL;
495
- r->rstack[0].privdata = r->privdata;
496
- r->ridx = 0;
497
- }
498
-
499
- /* Process items in reply. */
500
- while (r->ridx >= 0)
501
- if (processItem(r) != REDIS_OK)
502
- break;
503
-
504
- /* Return ASAP when an error occurred. */
505
- if (r->err)
506
- return REDIS_ERR;
507
-
508
- /* Discard part of the buffer when we've consumed at least 1k, to avoid
509
- * doing unnecessary calls to memmove() in sds.c. */
510
- if (r->pos >= 1024) {
511
- sdsrange(r->buf,r->pos,-1);
512
- r->pos = 0;
513
- r->len = sdslen(r->buf);
514
- }
515
-
516
- /* Emit a reply when there is one. */
517
- if (r->ridx == -1) {
518
- if (reply != NULL)
519
- *reply = r->reply;
520
- r->reply = NULL;
521
- }
522
- return REDIS_OK;
523
- }