2
0

hiredis.c 29 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021
  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. #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. #include "hiredis.h"
  41. #include "net.h"
  42. #include "sds.h"
  43. static redisReply *createReplyObject(int type);
  44. static void *createStringObject(const redisReadTask *task, char *str, size_t len);
  45. static void *createArrayObject(const redisReadTask *task, int elements);
  46. static void *createIntegerObject(const redisReadTask *task, long long value);
  47. static void *createNilObject(const redisReadTask *task);
  48. /* Default set of functions to build the reply. Keep in mind that such a
  49. * function returning NULL is interpreted as OOM. */
  50. static redisReplyObjectFunctions defaultFunctions = {
  51. createStringObject,
  52. createArrayObject,
  53. createIntegerObject,
  54. createNilObject,
  55. freeReplyObject
  56. };
  57. /* Create a reply object */
  58. static redisReply *createReplyObject(int type) {
  59. redisReply *r = calloc(1,sizeof(*r));
  60. if (r == NULL)
  61. return NULL;
  62. r->type = type;
  63. return r;
  64. }
  65. /* Free a reply object */
  66. void freeReplyObject(void *reply) {
  67. redisReply *r = reply;
  68. size_t j;
  69. if (r == NULL)
  70. return;
  71. switch(r->type) {
  72. case REDIS_REPLY_INTEGER:
  73. break; /* Nothing to free */
  74. case REDIS_REPLY_ARRAY:
  75. if (r->element != NULL) {
  76. for (j = 0; j < r->elements; j++)
  77. if (r->element[j] != NULL)
  78. freeReplyObject(r->element[j]);
  79. free(r->element);
  80. }
  81. break;
  82. case REDIS_REPLY_ERROR:
  83. case REDIS_REPLY_STATUS:
  84. case REDIS_REPLY_STRING:
  85. if (r->str != NULL)
  86. free(r->str);
  87. break;
  88. }
  89. free(r);
  90. }
  91. static void *createStringObject(const redisReadTask *task, char *str, size_t len) {
  92. redisReply *r, *parent;
  93. char *buf;
  94. r = createReplyObject(task->type);
  95. if (r == NULL)
  96. return NULL;
  97. buf = malloc(len+1);
  98. if (buf == NULL) {
  99. freeReplyObject(r);
  100. return NULL;
  101. }
  102. assert(task->type == REDIS_REPLY_ERROR ||
  103. task->type == REDIS_REPLY_STATUS ||
  104. task->type == REDIS_REPLY_STRING);
  105. /* Copy string value */
  106. memcpy(buf,str,len);
  107. buf[len] = '\0';
  108. r->str = buf;
  109. r->len = len;
  110. if (task->parent) {
  111. parent = task->parent->obj;
  112. assert(parent->type == REDIS_REPLY_ARRAY);
  113. parent->element[task->idx] = r;
  114. }
  115. return r;
  116. }
  117. static void *createArrayObject(const redisReadTask *task, int elements) {
  118. redisReply *r, *parent;
  119. r = createReplyObject(REDIS_REPLY_ARRAY);
  120. if (r == NULL)
  121. return NULL;
  122. if (elements > 0) {
  123. r->element = calloc(elements,sizeof(redisReply*));
  124. if (r->element == NULL) {
  125. freeReplyObject(r);
  126. return NULL;
  127. }
  128. }
  129. r->elements = elements;
  130. if (task->parent) {
  131. parent = task->parent->obj;
  132. assert(parent->type == REDIS_REPLY_ARRAY);
  133. parent->element[task->idx] = r;
  134. }
  135. return r;
  136. }
  137. static void *createIntegerObject(const redisReadTask *task, long long value) {
  138. redisReply *r, *parent;
  139. r = createReplyObject(REDIS_REPLY_INTEGER);
  140. if (r == NULL)
  141. return NULL;
  142. r->integer = value;
  143. if (task->parent) {
  144. parent = task->parent->obj;
  145. assert(parent->type == REDIS_REPLY_ARRAY);
  146. parent->element[task->idx] = r;
  147. }
  148. return r;
  149. }
  150. static void *createNilObject(const redisReadTask *task) {
  151. redisReply *r, *parent;
  152. r = createReplyObject(REDIS_REPLY_NIL);
  153. if (r == NULL)
  154. return NULL;
  155. if (task->parent) {
  156. parent = task->parent->obj;
  157. assert(parent->type == REDIS_REPLY_ARRAY);
  158. parent->element[task->idx] = r;
  159. }
  160. return r;
  161. }
  162. /* Return the number of digits of 'v' when converted to string in radix 10.
  163. * Implementation borrowed from link in redis/src/util.c:string2ll(). */
  164. static uint32_t countDigits(uint64_t v) {
  165. uint32_t result = 1;
  166. for (;;) {
  167. if (v < 10) return result;
  168. if (v < 100) return result + 1;
  169. if (v < 1000) return result + 2;
  170. if (v < 10000) return result + 3;
  171. v /= 10000U;
  172. result += 4;
  173. }
  174. }
  175. /* Helper that calculates the bulk length given a certain string length. */
  176. static size_t bulklen(size_t len) {
  177. return 1+countDigits(len)+2+len+2;
  178. }
  179. int redisvFormatCommand(char **target, const char *format, va_list ap) {
  180. const char *c = format;
  181. char *cmd = NULL; /* final command */
  182. int pos; /* position in final command */
  183. sds curarg, newarg; /* current argument */
  184. int touched = 0; /* was the current argument touched? */
  185. char **curargv = NULL, **newargv = NULL;
  186. int argc = 0;
  187. int totlen = 0;
  188. int error_type = 0; /* 0 = no error; -1 = memory error; -2 = format error */
  189. int j;
  190. /* Abort if there is not target to set */
  191. if (target == NULL)
  192. return -1;
  193. /* Build the command string accordingly to protocol */
  194. curarg = sdsempty();
  195. if (curarg == NULL)
  196. return -1;
  197. while(*c != '\0') {
  198. if (*c != '%' || c[1] == '\0') {
  199. if (*c == ' ') {
  200. if (touched) {
  201. newargv = realloc(curargv,sizeof(char*)*(argc+1));
  202. if (newargv == NULL) goto memory_err;
  203. curargv = newargv;
  204. curargv[argc++] = curarg;
  205. totlen += bulklen(sdslen(curarg));
  206. /* curarg is put in argv so it can be overwritten. */
  207. curarg = sdsempty();
  208. if (curarg == NULL) goto memory_err;
  209. touched = 0;
  210. }
  211. } else {
  212. newarg = sdscatlen(curarg,c,1);
  213. if (newarg == NULL) goto memory_err;
  214. curarg = newarg;
  215. touched = 1;
  216. }
  217. } else {
  218. char *arg;
  219. size_t size;
  220. /* Set newarg so it can be checked even if it is not touched. */
  221. newarg = curarg;
  222. switch(c[1]) {
  223. case 's':
  224. arg = va_arg(ap,char*);
  225. size = strlen(arg);
  226. if (size > 0)
  227. newarg = sdscatlen(curarg,arg,size);
  228. break;
  229. case 'b':
  230. arg = va_arg(ap,char*);
  231. size = va_arg(ap,size_t);
  232. if (size > 0)
  233. newarg = sdscatlen(curarg,arg,size);
  234. break;
  235. case '%':
  236. newarg = sdscat(curarg,"%");
  237. break;
  238. default:
  239. /* Try to detect printf format */
  240. {
  241. static const char intfmts[] = "diouxX";
  242. static const char flags[] = "#0-+ ";
  243. char _format[16];
  244. const char *_p = c+1;
  245. size_t _l = 0;
  246. va_list _cpy;
  247. /* Flags */
  248. while (*_p != '\0' && strchr(flags,*_p) != NULL) _p++;
  249. /* Field width */
  250. while (*_p != '\0' && isdigit(*_p)) _p++;
  251. /* Precision */
  252. if (*_p == '.') {
  253. _p++;
  254. while (*_p != '\0' && isdigit(*_p)) _p++;
  255. }
  256. /* Copy va_list before consuming with va_arg */
  257. va_copy(_cpy,ap);
  258. /* Integer conversion (without modifiers) */
  259. if (strchr(intfmts,*_p) != NULL) {
  260. va_arg(ap,int);
  261. goto fmt_valid;
  262. }
  263. /* Double conversion (without modifiers) */
  264. if (strchr("eEfFgGaA",*_p) != NULL) {
  265. va_arg(ap,double);
  266. goto fmt_valid;
  267. }
  268. /* Size: char */
  269. if (_p[0] == 'h' && _p[1] == 'h') {
  270. _p += 2;
  271. if (*_p != '\0' && strchr(intfmts,*_p) != NULL) {
  272. va_arg(ap,int); /* char gets promoted to int */
  273. goto fmt_valid;
  274. }
  275. goto fmt_invalid;
  276. }
  277. /* Size: short */
  278. if (_p[0] == 'h') {
  279. _p += 1;
  280. if (*_p != '\0' && strchr(intfmts,*_p) != NULL) {
  281. va_arg(ap,int); /* short gets promoted to int */
  282. goto fmt_valid;
  283. }
  284. goto fmt_invalid;
  285. }
  286. /* Size: long long */
  287. if (_p[0] == 'l' && _p[1] == 'l') {
  288. _p += 2;
  289. if (*_p != '\0' && strchr(intfmts,*_p) != NULL) {
  290. va_arg(ap,long long);
  291. goto fmt_valid;
  292. }
  293. goto fmt_invalid;
  294. }
  295. /* Size: long */
  296. if (_p[0] == 'l') {
  297. _p += 1;
  298. if (*_p != '\0' && strchr(intfmts,*_p) != NULL) {
  299. va_arg(ap,long);
  300. goto fmt_valid;
  301. }
  302. goto fmt_invalid;
  303. }
  304. fmt_invalid:
  305. va_end(_cpy);
  306. goto format_err;
  307. fmt_valid:
  308. _l = (_p+1)-c;
  309. if (_l < sizeof(_format)-2) {
  310. memcpy(_format,c,_l);
  311. _format[_l] = '\0';
  312. newarg = sdscatvprintf(curarg,_format,_cpy);
  313. /* Update current position (note: outer blocks
  314. * increment c twice so compensate here) */
  315. c = _p-1;
  316. }
  317. va_end(_cpy);
  318. break;
  319. }
  320. }
  321. if (newarg == NULL) goto memory_err;
  322. curarg = newarg;
  323. touched = 1;
  324. c++;
  325. }
  326. c++;
  327. }
  328. /* Add the last argument if needed */
  329. if (touched) {
  330. newargv = realloc(curargv,sizeof(char*)*(argc+1));
  331. if (newargv == NULL) goto memory_err;
  332. curargv = newargv;
  333. curargv[argc++] = curarg;
  334. totlen += bulklen(sdslen(curarg));
  335. } else {
  336. sdsfree(curarg);
  337. }
  338. /* Clear curarg because it was put in curargv or was free'd. */
  339. curarg = NULL;
  340. /* Add bytes needed to hold multi bulk count */
  341. totlen += 1+countDigits(argc)+2;
  342. /* Build the command at protocol level */
  343. cmd = malloc(totlen+1);
  344. if (cmd == NULL) goto memory_err;
  345. pos = sprintf(cmd,"*%d\r\n",argc);
  346. for (j = 0; j < argc; j++) {
  347. pos += sprintf(cmd+pos,"$%zu\r\n",sdslen(curargv[j]));
  348. memcpy(cmd+pos,curargv[j],sdslen(curargv[j]));
  349. pos += sdslen(curargv[j]);
  350. sdsfree(curargv[j]);
  351. cmd[pos++] = '\r';
  352. cmd[pos++] = '\n';
  353. }
  354. assert(pos == totlen);
  355. cmd[pos] = '\0';
  356. free(curargv);
  357. *target = cmd;
  358. return totlen;
  359. format_err:
  360. error_type = -2;
  361. goto cleanup;
  362. memory_err:
  363. error_type = -1;
  364. goto cleanup;
  365. cleanup:
  366. if (curargv) {
  367. while(argc--)
  368. sdsfree(curargv[argc]);
  369. free(curargv);
  370. }
  371. sdsfree(curarg);
  372. /* No need to check cmd since it is the last statement that can fail,
  373. * but do it anyway to be as defensive as possible. */
  374. if (cmd != NULL)
  375. free(cmd);
  376. return error_type;
  377. }
  378. /* Format a command according to the Redis protocol. This function
  379. * takes a format similar to printf:
  380. *
  381. * %s represents a C null terminated string you want to interpolate
  382. * %b represents a binary safe string
  383. *
  384. * When using %b you need to provide both the pointer to the string
  385. * and the length in bytes as a size_t. Examples:
  386. *
  387. * len = redisFormatCommand(target, "GET %s", mykey);
  388. * len = redisFormatCommand(target, "SET %s %b", mykey, myval, myvallen);
  389. */
  390. int redisFormatCommand(char **target, const char *format, ...) {
  391. va_list ap;
  392. int len;
  393. va_start(ap,format);
  394. len = redisvFormatCommand(target,format,ap);
  395. va_end(ap);
  396. /* The API says "-1" means bad result, but we now also return "-2" in some
  397. * cases. Force the return value to always be -1. */
  398. if (len < 0)
  399. len = -1;
  400. return len;
  401. }
  402. /* Format a command according to the Redis protocol using an sds string and
  403. * sdscatfmt for the processing of arguments. This function takes the
  404. * number of arguments, an array with arguments and an array with their
  405. * lengths. If the latter is set to NULL, strlen will be used to compute the
  406. * argument lengths.
  407. */
  408. int redisFormatSdsCommandArgv(sds *target, int argc, const char **argv,
  409. const size_t *argvlen)
  410. {
  411. sds cmd;
  412. unsigned long long totlen;
  413. int j;
  414. size_t len;
  415. /* Abort on a NULL target */
  416. if (target == NULL)
  417. return -1;
  418. /* Calculate our total size */
  419. totlen = 1+countDigits(argc)+2;
  420. for (j = 0; j < argc; j++) {
  421. len = argvlen ? argvlen[j] : strlen(argv[j]);
  422. totlen += bulklen(len);
  423. }
  424. /* Use an SDS string for command construction */
  425. cmd = sdsempty();
  426. if (cmd == NULL)
  427. return -1;
  428. /* We already know how much storage we need */
  429. cmd = sdsMakeRoomFor(cmd, totlen);
  430. if (cmd == NULL)
  431. return -1;
  432. /* Construct command */
  433. cmd = sdscatfmt(cmd, "*%i\r\n", argc);
  434. for (j=0; j < argc; j++) {
  435. len = argvlen ? argvlen[j] : strlen(argv[j]);
  436. cmd = sdscatfmt(cmd, "$%u\r\n", len);
  437. cmd = sdscatlen(cmd, argv[j], len);
  438. cmd = sdscatlen(cmd, "\r\n", sizeof("\r\n")-1);
  439. }
  440. assert(sdslen(cmd)==totlen);
  441. *target = cmd;
  442. return totlen;
  443. }
  444. void redisFreeSdsCommand(sds cmd) {
  445. sdsfree(cmd);
  446. }
  447. /* Format a command according to the Redis protocol. This function takes the
  448. * number of arguments, an array with arguments and an array with their
  449. * lengths. If the latter is set to NULL, strlen will be used to compute the
  450. * argument lengths.
  451. */
  452. int redisFormatCommandArgv(char **target, int argc, const char **argv, const size_t *argvlen) {
  453. char *cmd = NULL; /* final command */
  454. int pos; /* position in final command */
  455. size_t len;
  456. int totlen, j;
  457. /* Abort on a NULL target */
  458. if (target == NULL)
  459. return -1;
  460. /* Calculate number of bytes needed for the command */
  461. totlen = 1+countDigits(argc)+2;
  462. for (j = 0; j < argc; j++) {
  463. len = argvlen ? argvlen[j] : strlen(argv[j]);
  464. totlen += bulklen(len);
  465. }
  466. /* Build the command at protocol level */
  467. cmd = malloc(totlen+1);
  468. if (cmd == NULL)
  469. return -1;
  470. pos = sprintf(cmd,"*%d\r\n",argc);
  471. for (j = 0; j < argc; j++) {
  472. len = argvlen ? argvlen[j] : strlen(argv[j]);
  473. pos += sprintf(cmd+pos,"$%zu\r\n",len);
  474. memcpy(cmd+pos,argv[j],len);
  475. pos += len;
  476. cmd[pos++] = '\r';
  477. cmd[pos++] = '\n';
  478. }
  479. assert(pos == totlen);
  480. cmd[pos] = '\0';
  481. *target = cmd;
  482. return totlen;
  483. }
  484. void redisFreeCommand(char *cmd) {
  485. free(cmd);
  486. }
  487. void __redisSetError(redisContext *c, int type, const char *str) {
  488. size_t len;
  489. c->err = type;
  490. if (str != NULL) {
  491. len = strlen(str);
  492. len = len < (sizeof(c->errstr)-1) ? len : (sizeof(c->errstr)-1);
  493. memcpy(c->errstr,str,len);
  494. c->errstr[len] = '\0';
  495. } else {
  496. /* Only REDIS_ERR_IO may lack a description! */
  497. assert(type == REDIS_ERR_IO);
  498. __redis_strerror_r(errno, c->errstr, sizeof(c->errstr));
  499. }
  500. }
  501. redisReader *redisReaderCreate(void) {
  502. return redisReaderCreateWithFunctions(&defaultFunctions);
  503. }
  504. static redisContext *redisContextInit(void) {
  505. redisContext *c;
  506. c = calloc(1,sizeof(redisContext));
  507. if (c == NULL)
  508. return NULL;
  509. c->err = 0;
  510. c->errstr[0] = '\0';
  511. c->obuf = sdsempty();
  512. c->reader = redisReaderCreate();
  513. c->tcp.host = NULL;
  514. c->tcp.source_addr = NULL;
  515. c->unix_sock.path = NULL;
  516. c->timeout = NULL;
  517. if (c->obuf == NULL || c->reader == NULL) {
  518. redisFree(c);
  519. return NULL;
  520. }
  521. return c;
  522. }
  523. void redisFree(redisContext *c) {
  524. if (c == NULL)
  525. return;
  526. if (c->fd > 0)
  527. close(c->fd);
  528. if (c->obuf != NULL)
  529. sdsfree(c->obuf);
  530. if (c->reader != NULL)
  531. redisReaderFree(c->reader);
  532. if (c->tcp.host)
  533. free(c->tcp.host);
  534. if (c->tcp.source_addr)
  535. free(c->tcp.source_addr);
  536. if (c->unix_sock.path)
  537. free(c->unix_sock.path);
  538. if (c->timeout)
  539. free(c->timeout);
  540. free(c);
  541. }
  542. int redisFreeKeepFd(redisContext *c) {
  543. int fd = c->fd;
  544. c->fd = -1;
  545. redisFree(c);
  546. return fd;
  547. }
  548. int redisReconnect(redisContext *c) {
  549. c->err = 0;
  550. memset(c->errstr, '\0', strlen(c->errstr));
  551. if (c->fd > 0) {
  552. close(c->fd);
  553. }
  554. sdsfree(c->obuf);
  555. redisReaderFree(c->reader);
  556. c->obuf = sdsempty();
  557. c->reader = redisReaderCreate();
  558. if (c->connection_type == REDIS_CONN_TCP) {
  559. return redisContextConnectBindTcp(c, c->tcp.host, c->tcp.port,
  560. c->timeout, c->tcp.source_addr);
  561. } else if (c->connection_type == REDIS_CONN_UNIX) {
  562. return redisContextConnectUnix(c, c->unix_sock.path, c->timeout);
  563. } else {
  564. /* Something bad happened here and shouldn't have. There isn't
  565. enough information in the context to reconnect. */
  566. __redisSetError(c,REDIS_ERR_OTHER,"Not enough information to reconnect");
  567. }
  568. return REDIS_ERR;
  569. }
  570. /* Connect to a Redis instance. On error the field error in the returned
  571. * context will be set to the return value of the error function.
  572. * When no set of reply functions is given, the default set will be used. */
  573. redisContext *redisConnect(const char *ip, int port) {
  574. redisContext *c;
  575. c = redisContextInit();
  576. if (c == NULL)
  577. return NULL;
  578. c->flags |= REDIS_BLOCK;
  579. redisContextConnectTcp(c,ip,port,NULL);
  580. return c;
  581. }
  582. redisContext *redisConnectWithTimeout(const char *ip, int port, const struct timeval tv) {
  583. redisContext *c;
  584. c = redisContextInit();
  585. if (c == NULL)
  586. return NULL;
  587. c->flags |= REDIS_BLOCK;
  588. redisContextConnectTcp(c,ip,port,&tv);
  589. return c;
  590. }
  591. redisContext *redisConnectNonBlock(const char *ip, int port) {
  592. redisContext *c;
  593. c = redisContextInit();
  594. if (c == NULL)
  595. return NULL;
  596. c->flags &= ~REDIS_BLOCK;
  597. redisContextConnectTcp(c,ip,port,NULL);
  598. return c;
  599. }
  600. redisContext *redisConnectBindNonBlock(const char *ip, int port,
  601. const char *source_addr) {
  602. redisContext *c = redisContextInit();
  603. c->flags &= ~REDIS_BLOCK;
  604. redisContextConnectBindTcp(c,ip,port,NULL,source_addr);
  605. return c;
  606. }
  607. redisContext *redisConnectBindNonBlockWithReuse(const char *ip, int port,
  608. const char *source_addr) {
  609. redisContext *c = redisContextInit();
  610. c->flags &= ~REDIS_BLOCK;
  611. c->flags |= REDIS_REUSEADDR;
  612. redisContextConnectBindTcp(c,ip,port,NULL,source_addr);
  613. return c;
  614. }
  615. redisContext *redisConnectUnix(const char *path) {
  616. redisContext *c;
  617. c = redisContextInit();
  618. if (c == NULL)
  619. return NULL;
  620. c->flags |= REDIS_BLOCK;
  621. redisContextConnectUnix(c,path,NULL);
  622. return c;
  623. }
  624. redisContext *redisConnectUnixWithTimeout(const char *path, const struct timeval tv) {
  625. redisContext *c;
  626. c = redisContextInit();
  627. if (c == NULL)
  628. return NULL;
  629. c->flags |= REDIS_BLOCK;
  630. redisContextConnectUnix(c,path,&tv);
  631. return c;
  632. }
  633. redisContext *redisConnectUnixNonBlock(const char *path) {
  634. redisContext *c;
  635. c = redisContextInit();
  636. if (c == NULL)
  637. return NULL;
  638. c->flags &= ~REDIS_BLOCK;
  639. redisContextConnectUnix(c,path,NULL);
  640. return c;
  641. }
  642. redisContext *redisConnectFd(int fd) {
  643. redisContext *c;
  644. c = redisContextInit();
  645. if (c == NULL)
  646. return NULL;
  647. c->fd = fd;
  648. c->flags |= REDIS_BLOCK | REDIS_CONNECTED;
  649. return c;
  650. }
  651. /* Set read/write timeout on a blocking socket. */
  652. int redisSetTimeout(redisContext *c, const struct timeval tv) {
  653. if (c->flags & REDIS_BLOCK)
  654. return redisContextSetTimeout(c,tv);
  655. return REDIS_ERR;
  656. }
  657. /* Enable connection KeepAlive. */
  658. int redisEnableKeepAlive(redisContext *c) {
  659. if (redisKeepAlive(c, REDIS_KEEPALIVE_INTERVAL) != REDIS_OK)
  660. return REDIS_ERR;
  661. return REDIS_OK;
  662. }
  663. /* Use this function to handle a read event on the descriptor. It will try
  664. * and read some bytes from the socket and feed them to the reply parser.
  665. *
  666. * After this function is called, you may use redisContextReadReply to
  667. * see if there is a reply available. */
  668. int redisBufferRead(redisContext *c) {
  669. char buf[1024*16];
  670. int nread;
  671. /* Return early when the context has seen an error. */
  672. if (c->err)
  673. return REDIS_ERR;
  674. nread = read(c->fd,buf,sizeof(buf));
  675. if (nread == -1) {
  676. if ((errno == EAGAIN && !(c->flags & REDIS_BLOCK)) || (errno == EINTR)) {
  677. /* Try again later */
  678. } else {
  679. __redisSetError(c,REDIS_ERR_IO,NULL);
  680. return REDIS_ERR;
  681. }
  682. } else if (nread == 0) {
  683. __redisSetError(c,REDIS_ERR_EOF,"Server closed the connection");
  684. return REDIS_ERR;
  685. } else {
  686. if (redisReaderFeed(c->reader,buf,nread) != REDIS_OK) {
  687. __redisSetError(c,c->reader->err,c->reader->errstr);
  688. return REDIS_ERR;
  689. }
  690. }
  691. return REDIS_OK;
  692. }
  693. /* Write the output buffer to the socket.
  694. *
  695. * Returns REDIS_OK when the buffer is empty, or (a part of) the buffer was
  696. * successfully written to the socket. When the buffer is empty after the
  697. * write operation, "done" is set to 1 (if given).
  698. *
  699. * Returns REDIS_ERR if an error occurred trying to write and sets
  700. * c->errstr to hold the appropriate error string.
  701. */
  702. int redisBufferWrite(redisContext *c, int *done) {
  703. int nwritten;
  704. /* Return early when the context has seen an error. */
  705. if (c->err)
  706. return REDIS_ERR;
  707. if (sdslen(c->obuf) > 0) {
  708. nwritten = write(c->fd,c->obuf,sdslen(c->obuf));
  709. if (nwritten == -1) {
  710. if ((errno == EAGAIN && !(c->flags & REDIS_BLOCK)) || (errno == EINTR)) {
  711. /* Try again later */
  712. } else {
  713. __redisSetError(c,REDIS_ERR_IO,NULL);
  714. return REDIS_ERR;
  715. }
  716. } else if (nwritten > 0) {
  717. if (nwritten == (signed)sdslen(c->obuf)) {
  718. sdsfree(c->obuf);
  719. c->obuf = sdsempty();
  720. } else {
  721. sdsrange(c->obuf,nwritten,-1);
  722. }
  723. }
  724. }
  725. if (done != NULL) *done = (sdslen(c->obuf) == 0);
  726. return REDIS_OK;
  727. }
  728. /* Internal helper function to try and get a reply from the reader,
  729. * or set an error in the context otherwise. */
  730. int redisGetReplyFromReader(redisContext *c, void **reply) {
  731. if (redisReaderGetReply(c->reader,reply) == REDIS_ERR) {
  732. __redisSetError(c,c->reader->err,c->reader->errstr);
  733. return REDIS_ERR;
  734. }
  735. return REDIS_OK;
  736. }
  737. int redisGetReply(redisContext *c, void **reply) {
  738. int wdone = 0;
  739. void *aux = NULL;
  740. /* Try to read pending replies */
  741. if (redisGetReplyFromReader(c,&aux) == REDIS_ERR)
  742. return REDIS_ERR;
  743. /* For the blocking context, flush output buffer and read reply */
  744. if (aux == NULL && c->flags & REDIS_BLOCK) {
  745. /* Write until done */
  746. do {
  747. if (redisBufferWrite(c,&wdone) == REDIS_ERR)
  748. return REDIS_ERR;
  749. } while (!wdone);
  750. /* Read until there is a reply */
  751. do {
  752. if (redisBufferRead(c) == REDIS_ERR)
  753. return REDIS_ERR;
  754. if (redisGetReplyFromReader(c,&aux) == REDIS_ERR)
  755. return REDIS_ERR;
  756. } while (aux == NULL);
  757. }
  758. /* Set reply object */
  759. if (reply != NULL) *reply = aux;
  760. return REDIS_OK;
  761. }
  762. /* Helper function for the redisAppendCommand* family of functions.
  763. *
  764. * Write a formatted command to the output buffer. When this family
  765. * is used, you need to call redisGetReply yourself to retrieve
  766. * the reply (or replies in pub/sub).
  767. */
  768. int __redisAppendCommand(redisContext *c, const char *cmd, size_t len) {
  769. sds newbuf;
  770. newbuf = sdscatlen(c->obuf,cmd,len);
  771. if (newbuf == NULL) {
  772. __redisSetError(c,REDIS_ERR_OOM,"Out of memory");
  773. return REDIS_ERR;
  774. }
  775. c->obuf = newbuf;
  776. return REDIS_OK;
  777. }
  778. int redisAppendFormattedCommand(redisContext *c, const char *cmd, size_t len) {
  779. if (__redisAppendCommand(c, cmd, len) != REDIS_OK) {
  780. return REDIS_ERR;
  781. }
  782. return REDIS_OK;
  783. }
  784. int redisvAppendCommand(redisContext *c, const char *format, va_list ap) {
  785. char *cmd;
  786. int len;
  787. len = redisvFormatCommand(&cmd,format,ap);
  788. if (len == -1) {
  789. __redisSetError(c,REDIS_ERR_OOM,"Out of memory");
  790. return REDIS_ERR;
  791. } else if (len == -2) {
  792. __redisSetError(c,REDIS_ERR_OTHER,"Invalid format string");
  793. return REDIS_ERR;
  794. }
  795. if (__redisAppendCommand(c,cmd,len) != REDIS_OK) {
  796. free(cmd);
  797. return REDIS_ERR;
  798. }
  799. free(cmd);
  800. return REDIS_OK;
  801. }
  802. int redisAppendCommand(redisContext *c, const char *format, ...) {
  803. va_list ap;
  804. int ret;
  805. va_start(ap,format);
  806. ret = redisvAppendCommand(c,format,ap);
  807. va_end(ap);
  808. return ret;
  809. }
  810. int redisAppendCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen) {
  811. sds cmd;
  812. int len;
  813. len = redisFormatSdsCommandArgv(&cmd,argc,argv,argvlen);
  814. if (len == -1) {
  815. __redisSetError(c,REDIS_ERR_OOM,"Out of memory");
  816. return REDIS_ERR;
  817. }
  818. if (__redisAppendCommand(c,cmd,len) != REDIS_OK) {
  819. sdsfree(cmd);
  820. return REDIS_ERR;
  821. }
  822. sdsfree(cmd);
  823. return REDIS_OK;
  824. }
  825. /* Helper function for the redisCommand* family of functions.
  826. *
  827. * Write a formatted command to the output buffer. If the given context is
  828. * blocking, immediately read the reply into the "reply" pointer. When the
  829. * context is non-blocking, the "reply" pointer will not be used and the
  830. * command is simply appended to the write buffer.
  831. *
  832. * Returns the reply when a reply was successfully retrieved. Returns NULL
  833. * otherwise. When NULL is returned in a blocking context, the error field
  834. * in the context will be set.
  835. */
  836. static void *__redisBlockForReply(redisContext *c) {
  837. void *reply;
  838. if (c->flags & REDIS_BLOCK) {
  839. if (redisGetReply(c,&reply) != REDIS_OK)
  840. return NULL;
  841. return reply;
  842. }
  843. return NULL;
  844. }
  845. void *redisvCommand(redisContext *c, const char *format, va_list ap) {
  846. if (redisvAppendCommand(c,format,ap) != REDIS_OK)
  847. return NULL;
  848. return __redisBlockForReply(c);
  849. }
  850. void *redisCommand(redisContext *c, const char *format, ...) {
  851. va_list ap;
  852. void *reply = NULL;
  853. va_start(ap,format);
  854. reply = redisvCommand(c,format,ap);
  855. va_end(ap);
  856. return reply;
  857. }
  858. void *redisCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen) {
  859. if (redisAppendCommandArgv(c,argc,argv,argvlen) != REDIS_OK)
  860. return NULL;
  861. return __redisBlockForReply(c);
  862. }