You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

hiredis.c 29KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025
  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, "$%T\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. if (c == NULL)
  604. return NULL;
  605. c->flags &= ~REDIS_BLOCK;
  606. redisContextConnectBindTcp(c,ip,port,NULL,source_addr);
  607. return c;
  608. }
  609. redisContext *redisConnectBindNonBlockWithReuse(const char *ip, int port,
  610. const char *source_addr) {
  611. redisContext *c = redisContextInit();
  612. if (c == NULL)
  613. return NULL;
  614. c->flags &= ~REDIS_BLOCK;
  615. c->flags |= REDIS_REUSEADDR;
  616. redisContextConnectBindTcp(c,ip,port,NULL,source_addr);
  617. return c;
  618. }
  619. redisContext *redisConnectUnix(const char *path) {
  620. redisContext *c;
  621. c = redisContextInit();
  622. if (c == NULL)
  623. return NULL;
  624. c->flags |= REDIS_BLOCK;
  625. redisContextConnectUnix(c,path,NULL);
  626. return c;
  627. }
  628. redisContext *redisConnectUnixWithTimeout(const char *path, const struct timeval tv) {
  629. redisContext *c;
  630. c = redisContextInit();
  631. if (c == NULL)
  632. return NULL;
  633. c->flags |= REDIS_BLOCK;
  634. redisContextConnectUnix(c,path,&tv);
  635. return c;
  636. }
  637. redisContext *redisConnectUnixNonBlock(const char *path) {
  638. redisContext *c;
  639. c = redisContextInit();
  640. if (c == NULL)
  641. return NULL;
  642. c->flags &= ~REDIS_BLOCK;
  643. redisContextConnectUnix(c,path,NULL);
  644. return c;
  645. }
  646. redisContext *redisConnectFd(int fd) {
  647. redisContext *c;
  648. c = redisContextInit();
  649. if (c == NULL)
  650. return NULL;
  651. c->fd = fd;
  652. c->flags |= REDIS_BLOCK | REDIS_CONNECTED;
  653. return c;
  654. }
  655. /* Set read/write timeout on a blocking socket. */
  656. int redisSetTimeout(redisContext *c, const struct timeval tv) {
  657. if (c->flags & REDIS_BLOCK)
  658. return redisContextSetTimeout(c,tv);
  659. return REDIS_ERR;
  660. }
  661. /* Enable connection KeepAlive. */
  662. int redisEnableKeepAlive(redisContext *c) {
  663. if (redisKeepAlive(c, REDIS_KEEPALIVE_INTERVAL) != REDIS_OK)
  664. return REDIS_ERR;
  665. return REDIS_OK;
  666. }
  667. /* Use this function to handle a read event on the descriptor. It will try
  668. * and read some bytes from the socket and feed them to the reply parser.
  669. *
  670. * After this function is called, you may use redisContextReadReply to
  671. * see if there is a reply available. */
  672. int redisBufferRead(redisContext *c) {
  673. char buf[1024*16];
  674. int nread;
  675. /* Return early when the context has seen an error. */
  676. if (c->err)
  677. return REDIS_ERR;
  678. nread = read(c->fd,buf,sizeof(buf));
  679. if (nread == -1) {
  680. if ((errno == EAGAIN && !(c->flags & REDIS_BLOCK)) || (errno == EINTR)) {
  681. /* Try again later */
  682. } else {
  683. __redisSetError(c,REDIS_ERR_IO,NULL);
  684. return REDIS_ERR;
  685. }
  686. } else if (nread == 0) {
  687. __redisSetError(c,REDIS_ERR_EOF,"Server closed the connection");
  688. return REDIS_ERR;
  689. } else {
  690. if (redisReaderFeed(c->reader,buf,nread) != REDIS_OK) {
  691. __redisSetError(c,c->reader->err,c->reader->errstr);
  692. return REDIS_ERR;
  693. }
  694. }
  695. return REDIS_OK;
  696. }
  697. /* Write the output buffer to the socket.
  698. *
  699. * Returns REDIS_OK when the buffer is empty, or (a part of) the buffer was
  700. * successfully written to the socket. When the buffer is empty after the
  701. * write operation, "done" is set to 1 (if given).
  702. *
  703. * Returns REDIS_ERR if an error occurred trying to write and sets
  704. * c->errstr to hold the appropriate error string.
  705. */
  706. int redisBufferWrite(redisContext *c, int *done) {
  707. int nwritten;
  708. /* Return early when the context has seen an error. */
  709. if (c->err)
  710. return REDIS_ERR;
  711. if (sdslen(c->obuf) > 0) {
  712. nwritten = write(c->fd,c->obuf,sdslen(c->obuf));
  713. if (nwritten == -1) {
  714. if ((errno == EAGAIN && !(c->flags & REDIS_BLOCK)) || (errno == EINTR)) {
  715. /* Try again later */
  716. } else {
  717. __redisSetError(c,REDIS_ERR_IO,NULL);
  718. return REDIS_ERR;
  719. }
  720. } else if (nwritten > 0) {
  721. if (nwritten == (signed)sdslen(c->obuf)) {
  722. sdsfree(c->obuf);
  723. c->obuf = sdsempty();
  724. } else {
  725. sdsrange(c->obuf,nwritten,-1);
  726. }
  727. }
  728. }
  729. if (done != NULL) *done = (sdslen(c->obuf) == 0);
  730. return REDIS_OK;
  731. }
  732. /* Internal helper function to try and get a reply from the reader,
  733. * or set an error in the context otherwise. */
  734. int redisGetReplyFromReader(redisContext *c, void **reply) {
  735. if (redisReaderGetReply(c->reader,reply) == REDIS_ERR) {
  736. __redisSetError(c,c->reader->err,c->reader->errstr);
  737. return REDIS_ERR;
  738. }
  739. return REDIS_OK;
  740. }
  741. int redisGetReply(redisContext *c, void **reply) {
  742. int wdone = 0;
  743. void *aux = NULL;
  744. /* Try to read pending replies */
  745. if (redisGetReplyFromReader(c,&aux) == REDIS_ERR)
  746. return REDIS_ERR;
  747. /* For the blocking context, flush output buffer and read reply */
  748. if (aux == NULL && c->flags & REDIS_BLOCK) {
  749. /* Write until done */
  750. do {
  751. if (redisBufferWrite(c,&wdone) == REDIS_ERR)
  752. return REDIS_ERR;
  753. } while (!wdone);
  754. /* Read until there is a reply */
  755. do {
  756. if (redisBufferRead(c) == REDIS_ERR)
  757. return REDIS_ERR;
  758. if (redisGetReplyFromReader(c,&aux) == REDIS_ERR)
  759. return REDIS_ERR;
  760. } while (aux == NULL);
  761. }
  762. /* Set reply object */
  763. if (reply != NULL) *reply = aux;
  764. return REDIS_OK;
  765. }
  766. /* Helper function for the redisAppendCommand* family of functions.
  767. *
  768. * Write a formatted command to the output buffer. When this family
  769. * is used, you need to call redisGetReply yourself to retrieve
  770. * the reply (or replies in pub/sub).
  771. */
  772. int __redisAppendCommand(redisContext *c, const char *cmd, size_t len) {
  773. sds newbuf;
  774. newbuf = sdscatlen(c->obuf,cmd,len);
  775. if (newbuf == NULL) {
  776. __redisSetError(c,REDIS_ERR_OOM,"Out of memory");
  777. return REDIS_ERR;
  778. }
  779. c->obuf = newbuf;
  780. return REDIS_OK;
  781. }
  782. int redisAppendFormattedCommand(redisContext *c, const char *cmd, size_t len) {
  783. if (__redisAppendCommand(c, cmd, len) != REDIS_OK) {
  784. return REDIS_ERR;
  785. }
  786. return REDIS_OK;
  787. }
  788. int redisvAppendCommand(redisContext *c, const char *format, va_list ap) {
  789. char *cmd;
  790. int len;
  791. len = redisvFormatCommand(&cmd,format,ap);
  792. if (len == -1) {
  793. __redisSetError(c,REDIS_ERR_OOM,"Out of memory");
  794. return REDIS_ERR;
  795. } else if (len == -2) {
  796. __redisSetError(c,REDIS_ERR_OTHER,"Invalid format string");
  797. return REDIS_ERR;
  798. }
  799. if (__redisAppendCommand(c,cmd,len) != REDIS_OK) {
  800. free(cmd);
  801. return REDIS_ERR;
  802. }
  803. free(cmd);
  804. return REDIS_OK;
  805. }
  806. int redisAppendCommand(redisContext *c, const char *format, ...) {
  807. va_list ap;
  808. int ret;
  809. va_start(ap,format);
  810. ret = redisvAppendCommand(c,format,ap);
  811. va_end(ap);
  812. return ret;
  813. }
  814. int redisAppendCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen) {
  815. sds cmd;
  816. int len;
  817. len = redisFormatSdsCommandArgv(&cmd,argc,argv,argvlen);
  818. if (len == -1) {
  819. __redisSetError(c,REDIS_ERR_OOM,"Out of memory");
  820. return REDIS_ERR;
  821. }
  822. if (__redisAppendCommand(c,cmd,len) != REDIS_OK) {
  823. sdsfree(cmd);
  824. return REDIS_ERR;
  825. }
  826. sdsfree(cmd);
  827. return REDIS_OK;
  828. }
  829. /* Helper function for the redisCommand* family of functions.
  830. *
  831. * Write a formatted command to the output buffer. If the given context is
  832. * blocking, immediately read the reply into the "reply" pointer. When the
  833. * context is non-blocking, the "reply" pointer will not be used and the
  834. * command is simply appended to the write buffer.
  835. *
  836. * Returns the reply when a reply was successfully retrieved. Returns NULL
  837. * otherwise. When NULL is returned in a blocking context, the error field
  838. * in the context will be set.
  839. */
  840. static void *__redisBlockForReply(redisContext *c) {
  841. void *reply;
  842. if (c->flags & REDIS_BLOCK) {
  843. if (redisGetReply(c,&reply) != REDIS_OK)
  844. return NULL;
  845. return reply;
  846. }
  847. return NULL;
  848. }
  849. void *redisvCommand(redisContext *c, const char *format, va_list ap) {
  850. if (redisvAppendCommand(c,format,ap) != REDIS_OK)
  851. return NULL;
  852. return __redisBlockForReply(c);
  853. }
  854. void *redisCommand(redisContext *c, const char *format, ...) {
  855. va_list ap;
  856. void *reply = NULL;
  857. va_start(ap,format);
  858. reply = redisvCommand(c,format,ap);
  859. va_end(ap);
  860. return reply;
  861. }
  862. void *redisCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen) {
  863. if (redisAppendCommandArgv(c,argc,argv,argvlen) != REDIS_OK)
  864. return NULL;
  865. return __redisBlockForReply(c);
  866. }