hiredis.c 36 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219
  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 <assert.h>
  37. #include <errno.h>
  38. #include <ctype.h>
  39. #include "hiredis.h"
  40. #include "net.h"
  41. #include "sds.h"
  42. #include "async.h"
  43. #include "win32.h"
  44. extern int redisContextUpdateConnectTimeout(redisContext *c, const struct timeval *timeout);
  45. extern int redisContextUpdateCommandTimeout(redisContext *c, const struct timeval *timeout);
  46. static redisContextFuncs redisContextDefaultFuncs = {
  47. .close = redisNetClose,
  48. .free_privctx = NULL,
  49. .async_read = redisAsyncRead,
  50. .async_write = redisAsyncWrite,
  51. .read = redisNetRead,
  52. .write = redisNetWrite
  53. };
  54. static redisReply *createReplyObject(int type);
  55. static void *createStringObject(const redisReadTask *task, char *str, size_t len);
  56. static void *createArrayObject(const redisReadTask *task, size_t elements);
  57. static void *createIntegerObject(const redisReadTask *task, long long value);
  58. static void *createDoubleObject(const redisReadTask *task, double value, char *str, size_t len);
  59. static void *createNilObject(const redisReadTask *task);
  60. static void *createBoolObject(const redisReadTask *task, int bval);
  61. /* Default set of functions to build the reply. Keep in mind that such a
  62. * function returning NULL is interpreted as OOM. */
  63. static redisReplyObjectFunctions defaultFunctions = {
  64. createStringObject,
  65. createArrayObject,
  66. createIntegerObject,
  67. createDoubleObject,
  68. createNilObject,
  69. createBoolObject,
  70. freeReplyObject
  71. };
  72. /* Create a reply object */
  73. static redisReply *createReplyObject(int type) {
  74. redisReply *r = hi_calloc(1,sizeof(*r));
  75. if (r == NULL)
  76. return NULL;
  77. r->type = type;
  78. return r;
  79. }
  80. /* Free a reply object */
  81. void freeReplyObject(void *reply) {
  82. redisReply *r = reply;
  83. size_t j;
  84. if (r == NULL)
  85. return;
  86. switch(r->type) {
  87. case REDIS_REPLY_INTEGER:
  88. case REDIS_REPLY_NIL:
  89. case REDIS_REPLY_BOOL:
  90. break; /* Nothing to free */
  91. case REDIS_REPLY_ARRAY:
  92. case REDIS_REPLY_MAP:
  93. case REDIS_REPLY_SET:
  94. case REDIS_REPLY_PUSH:
  95. if (r->element != NULL) {
  96. for (j = 0; j < r->elements; j++)
  97. freeReplyObject(r->element[j]);
  98. hi_free(r->element);
  99. }
  100. break;
  101. case REDIS_REPLY_ERROR:
  102. case REDIS_REPLY_STATUS:
  103. case REDIS_REPLY_STRING:
  104. case REDIS_REPLY_DOUBLE:
  105. case REDIS_REPLY_VERB:
  106. case REDIS_REPLY_BIGNUM:
  107. hi_free(r->str);
  108. break;
  109. }
  110. hi_free(r);
  111. }
  112. static void *createStringObject(const redisReadTask *task, char *str, size_t len) {
  113. redisReply *r, *parent;
  114. char *buf;
  115. r = createReplyObject(task->type);
  116. if (r == NULL)
  117. return NULL;
  118. assert(task->type == REDIS_REPLY_ERROR ||
  119. task->type == REDIS_REPLY_STATUS ||
  120. task->type == REDIS_REPLY_STRING ||
  121. task->type == REDIS_REPLY_VERB ||
  122. task->type == REDIS_REPLY_BIGNUM);
  123. /* Copy string value */
  124. if (task->type == REDIS_REPLY_VERB) {
  125. buf = hi_malloc(len-4+1); /* Skip 4 bytes of verbatim type header. */
  126. if (buf == NULL) goto oom;
  127. memcpy(r->vtype,str,3);
  128. r->vtype[3] = '\0';
  129. memcpy(buf,str+4,len-4);
  130. buf[len-4] = '\0';
  131. r->len = len - 4;
  132. } else {
  133. buf = hi_malloc(len+1);
  134. if (buf == NULL) goto oom;
  135. memcpy(buf,str,len);
  136. buf[len] = '\0';
  137. r->len = len;
  138. }
  139. r->str = buf;
  140. if (task->parent) {
  141. parent = task->parent->obj;
  142. assert(parent->type == REDIS_REPLY_ARRAY ||
  143. parent->type == REDIS_REPLY_MAP ||
  144. parent->type == REDIS_REPLY_SET ||
  145. parent->type == REDIS_REPLY_PUSH);
  146. parent->element[task->idx] = r;
  147. }
  148. return r;
  149. oom:
  150. freeReplyObject(r);
  151. return NULL;
  152. }
  153. static void *createArrayObject(const redisReadTask *task, size_t elements) {
  154. redisReply *r, *parent;
  155. r = createReplyObject(task->type);
  156. if (r == NULL)
  157. return NULL;
  158. if (elements > 0) {
  159. r->element = hi_calloc(elements,sizeof(redisReply*));
  160. if (r->element == NULL) {
  161. freeReplyObject(r);
  162. return NULL;
  163. }
  164. }
  165. r->elements = elements;
  166. if (task->parent) {
  167. parent = task->parent->obj;
  168. assert(parent->type == REDIS_REPLY_ARRAY ||
  169. parent->type == REDIS_REPLY_MAP ||
  170. parent->type == REDIS_REPLY_SET ||
  171. parent->type == REDIS_REPLY_PUSH);
  172. parent->element[task->idx] = r;
  173. }
  174. return r;
  175. }
  176. static void *createIntegerObject(const redisReadTask *task, long long value) {
  177. redisReply *r, *parent;
  178. r = createReplyObject(REDIS_REPLY_INTEGER);
  179. if (r == NULL)
  180. return NULL;
  181. r->integer = value;
  182. if (task->parent) {
  183. parent = task->parent->obj;
  184. assert(parent->type == REDIS_REPLY_ARRAY ||
  185. parent->type == REDIS_REPLY_MAP ||
  186. parent->type == REDIS_REPLY_SET ||
  187. parent->type == REDIS_REPLY_PUSH);
  188. parent->element[task->idx] = r;
  189. }
  190. return r;
  191. }
  192. static void *createDoubleObject(const redisReadTask *task, double value, char *str, size_t len) {
  193. redisReply *r, *parent;
  194. if (len == SIZE_MAX) // Prevents hi_malloc(0) if len equals to SIZE_MAX
  195. return NULL;
  196. r = createReplyObject(REDIS_REPLY_DOUBLE);
  197. if (r == NULL)
  198. return NULL;
  199. r->dval = value;
  200. r->str = hi_malloc(len+1);
  201. if (r->str == NULL) {
  202. freeReplyObject(r);
  203. return NULL;
  204. }
  205. /* The double reply also has the original protocol string representing a
  206. * double as a null terminated string. This way the caller does not need
  207. * to format back for string conversion, especially since Redis does efforts
  208. * to make the string more human readable avoiding the calssical double
  209. * decimal string conversion artifacts. */
  210. memcpy(r->str, str, len);
  211. r->str[len] = '\0';
  212. r->len = len;
  213. if (task->parent) {
  214. parent = task->parent->obj;
  215. assert(parent->type == REDIS_REPLY_ARRAY ||
  216. parent->type == REDIS_REPLY_MAP ||
  217. parent->type == REDIS_REPLY_SET ||
  218. parent->type == REDIS_REPLY_PUSH);
  219. parent->element[task->idx] = r;
  220. }
  221. return r;
  222. }
  223. static void *createNilObject(const redisReadTask *task) {
  224. redisReply *r, *parent;
  225. r = createReplyObject(REDIS_REPLY_NIL);
  226. if (r == NULL)
  227. return NULL;
  228. if (task->parent) {
  229. parent = task->parent->obj;
  230. assert(parent->type == REDIS_REPLY_ARRAY ||
  231. parent->type == REDIS_REPLY_MAP ||
  232. parent->type == REDIS_REPLY_SET ||
  233. parent->type == REDIS_REPLY_PUSH);
  234. parent->element[task->idx] = r;
  235. }
  236. return r;
  237. }
  238. static void *createBoolObject(const redisReadTask *task, int bval) {
  239. redisReply *r, *parent;
  240. r = createReplyObject(REDIS_REPLY_BOOL);
  241. if (r == NULL)
  242. return NULL;
  243. r->integer = bval != 0;
  244. if (task->parent) {
  245. parent = task->parent->obj;
  246. assert(parent->type == REDIS_REPLY_ARRAY ||
  247. parent->type == REDIS_REPLY_MAP ||
  248. parent->type == REDIS_REPLY_SET ||
  249. parent->type == REDIS_REPLY_PUSH);
  250. parent->element[task->idx] = r;
  251. }
  252. return r;
  253. }
  254. /* Return the number of digits of 'v' when converted to string in radix 10.
  255. * Implementation borrowed from link in redis/src/util.c:string2ll(). */
  256. static uint32_t countDigits(uint64_t v) {
  257. uint32_t result = 1;
  258. for (;;) {
  259. if (v < 10) return result;
  260. if (v < 100) return result + 1;
  261. if (v < 1000) return result + 2;
  262. if (v < 10000) return result + 3;
  263. v /= 10000U;
  264. result += 4;
  265. }
  266. }
  267. /* Helper that calculates the bulk length given a certain string length. */
  268. static size_t bulklen(size_t len) {
  269. return 1+countDigits(len)+2+len+2;
  270. }
  271. int redisvFormatCommand(char **target, const char *format, va_list ap) {
  272. const char *c = format;
  273. char *cmd = NULL; /* final command */
  274. int pos; /* position in final command */
  275. sds curarg, newarg; /* current argument */
  276. int touched = 0; /* was the current argument touched? */
  277. char **curargv = NULL, **newargv = NULL;
  278. int argc = 0;
  279. int totlen = 0;
  280. int error_type = 0; /* 0 = no error; -1 = memory error; -2 = format error */
  281. int j;
  282. /* Abort if there is not target to set */
  283. if (target == NULL)
  284. return -1;
  285. /* Build the command string accordingly to protocol */
  286. curarg = sdsempty();
  287. if (curarg == NULL)
  288. return -1;
  289. while(*c != '\0') {
  290. if (*c != '%' || c[1] == '\0') {
  291. if (*c == ' ') {
  292. if (touched) {
  293. newargv = hi_realloc(curargv,sizeof(char*)*(argc+1));
  294. if (newargv == NULL) goto memory_err;
  295. curargv = newargv;
  296. curargv[argc++] = curarg;
  297. totlen += bulklen(sdslen(curarg));
  298. /* curarg is put in argv so it can be overwritten. */
  299. curarg = sdsempty();
  300. if (curarg == NULL) goto memory_err;
  301. touched = 0;
  302. }
  303. } else {
  304. newarg = sdscatlen(curarg,c,1);
  305. if (newarg == NULL) goto memory_err;
  306. curarg = newarg;
  307. touched = 1;
  308. }
  309. } else {
  310. char *arg;
  311. size_t size;
  312. /* Set newarg so it can be checked even if it is not touched. */
  313. newarg = curarg;
  314. switch(c[1]) {
  315. case 's':
  316. arg = va_arg(ap,char*);
  317. size = strlen(arg);
  318. if (size > 0)
  319. newarg = sdscatlen(curarg,arg,size);
  320. break;
  321. case 'b':
  322. arg = va_arg(ap,char*);
  323. size = va_arg(ap,size_t);
  324. if (size > 0)
  325. newarg = sdscatlen(curarg,arg,size);
  326. break;
  327. case '%':
  328. newarg = sdscat(curarg,"%");
  329. break;
  330. default:
  331. /* Try to detect printf format */
  332. {
  333. static const char intfmts[] = "diouxX";
  334. static const char flags[] = "#0-+ ";
  335. char _format[16];
  336. const char *_p = c+1;
  337. size_t _l = 0;
  338. va_list _cpy;
  339. /* Flags */
  340. while (*_p != '\0' && strchr(flags,*_p) != NULL) _p++;
  341. /* Field width */
  342. while (*_p != '\0' && isdigit((int) *_p)) _p++;
  343. /* Precision */
  344. if (*_p == '.') {
  345. _p++;
  346. while (*_p != '\0' && isdigit((int) *_p)) _p++;
  347. }
  348. /* Copy va_list before consuming with va_arg */
  349. va_copy(_cpy,ap);
  350. /* Make sure we have more characters otherwise strchr() accepts
  351. * '\0' as an integer specifier. This is checked after above
  352. * va_copy() to avoid UB in fmt_invalid's call to va_end(). */
  353. if (*_p == '\0') goto fmt_invalid;
  354. /* Integer conversion (without modifiers) */
  355. if (strchr(intfmts,*_p) != NULL) {
  356. va_arg(ap,int);
  357. goto fmt_valid;
  358. }
  359. /* Double conversion (without modifiers) */
  360. if (strchr("eEfFgGaA",*_p) != NULL) {
  361. va_arg(ap,double);
  362. goto fmt_valid;
  363. }
  364. /* Size: char */
  365. if (_p[0] == 'h' && _p[1] == 'h') {
  366. _p += 2;
  367. if (*_p != '\0' && strchr(intfmts,*_p) != NULL) {
  368. va_arg(ap,int); /* char gets promoted to int */
  369. goto fmt_valid;
  370. }
  371. goto fmt_invalid;
  372. }
  373. /* Size: short */
  374. if (_p[0] == 'h') {
  375. _p += 1;
  376. if (*_p != '\0' && strchr(intfmts,*_p) != NULL) {
  377. va_arg(ap,int); /* short gets promoted to int */
  378. goto fmt_valid;
  379. }
  380. goto fmt_invalid;
  381. }
  382. /* Size: long long */
  383. if (_p[0] == 'l' && _p[1] == 'l') {
  384. _p += 2;
  385. if (*_p != '\0' && strchr(intfmts,*_p) != NULL) {
  386. va_arg(ap,long long);
  387. goto fmt_valid;
  388. }
  389. goto fmt_invalid;
  390. }
  391. /* Size: long */
  392. if (_p[0] == 'l') {
  393. _p += 1;
  394. if (*_p != '\0' && strchr(intfmts,*_p) != NULL) {
  395. va_arg(ap,long);
  396. goto fmt_valid;
  397. }
  398. goto fmt_invalid;
  399. }
  400. fmt_invalid:
  401. va_end(_cpy);
  402. goto format_err;
  403. fmt_valid:
  404. _l = (_p+1)-c;
  405. if (_l < sizeof(_format)-2) {
  406. memcpy(_format,c,_l);
  407. _format[_l] = '\0';
  408. newarg = sdscatvprintf(curarg,_format,_cpy);
  409. /* Update current position (note: outer blocks
  410. * increment c twice so compensate here) */
  411. c = _p-1;
  412. }
  413. va_end(_cpy);
  414. break;
  415. }
  416. }
  417. if (newarg == NULL) goto memory_err;
  418. curarg = newarg;
  419. touched = 1;
  420. c++;
  421. if (*c == '\0')
  422. break;
  423. }
  424. c++;
  425. }
  426. /* Add the last argument if needed */
  427. if (touched) {
  428. newargv = hi_realloc(curargv,sizeof(char*)*(argc+1));
  429. if (newargv == NULL) goto memory_err;
  430. curargv = newargv;
  431. curargv[argc++] = curarg;
  432. totlen += bulklen(sdslen(curarg));
  433. } else {
  434. sdsfree(curarg);
  435. }
  436. /* Clear curarg because it was put in curargv or was free'd. */
  437. curarg = NULL;
  438. /* Add bytes needed to hold multi bulk count */
  439. totlen += 1+countDigits(argc)+2;
  440. /* Build the command at protocol level */
  441. cmd = hi_malloc(totlen+1);
  442. if (cmd == NULL) goto memory_err;
  443. pos = sprintf(cmd,"*%d\r\n",argc);
  444. for (j = 0; j < argc; j++) {
  445. pos += sprintf(cmd+pos,"$%zu\r\n",sdslen(curargv[j]));
  446. memcpy(cmd+pos,curargv[j],sdslen(curargv[j]));
  447. pos += sdslen(curargv[j]);
  448. sdsfree(curargv[j]);
  449. cmd[pos++] = '\r';
  450. cmd[pos++] = '\n';
  451. }
  452. assert(pos == totlen);
  453. cmd[pos] = '\0';
  454. hi_free(curargv);
  455. *target = cmd;
  456. return totlen;
  457. format_err:
  458. error_type = -2;
  459. goto cleanup;
  460. memory_err:
  461. error_type = -1;
  462. goto cleanup;
  463. cleanup:
  464. if (curargv) {
  465. while(argc--)
  466. sdsfree(curargv[argc]);
  467. hi_free(curargv);
  468. }
  469. sdsfree(curarg);
  470. hi_free(cmd);
  471. return error_type;
  472. }
  473. /* Format a command according to the Redis protocol. This function
  474. * takes a format similar to printf:
  475. *
  476. * %s represents a C null terminated string you want to interpolate
  477. * %b represents a binary safe string
  478. *
  479. * When using %b you need to provide both the pointer to the string
  480. * and the length in bytes as a size_t. Examples:
  481. *
  482. * len = redisFormatCommand(target, "GET %s", mykey);
  483. * len = redisFormatCommand(target, "SET %s %b", mykey, myval, myvallen);
  484. */
  485. int redisFormatCommand(char **target, const char *format, ...) {
  486. va_list ap;
  487. int len;
  488. va_start(ap,format);
  489. len = redisvFormatCommand(target,format,ap);
  490. va_end(ap);
  491. /* The API says "-1" means bad result, but we now also return "-2" in some
  492. * cases. Force the return value to always be -1. */
  493. if (len < 0)
  494. len = -1;
  495. return len;
  496. }
  497. /* Format a command according to the Redis protocol using an sds string and
  498. * sdscatfmt for the processing of arguments. This function takes the
  499. * number of arguments, an array with arguments and an array with their
  500. * lengths. If the latter is set to NULL, strlen will be used to compute the
  501. * argument lengths.
  502. */
  503. long long redisFormatSdsCommandArgv(sds *target, int argc, const char **argv,
  504. const size_t *argvlen)
  505. {
  506. sds cmd, aux;
  507. unsigned long long totlen, len;
  508. int j;
  509. /* Abort on a NULL target */
  510. if (target == NULL)
  511. return -1;
  512. /* Calculate our total size */
  513. totlen = 1+countDigits(argc)+2;
  514. for (j = 0; j < argc; j++) {
  515. len = argvlen ? argvlen[j] : strlen(argv[j]);
  516. totlen += bulklen(len);
  517. }
  518. /* Use an SDS string for command construction */
  519. cmd = sdsempty();
  520. if (cmd == NULL)
  521. return -1;
  522. /* We already know how much storage we need */
  523. aux = sdsMakeRoomFor(cmd, totlen);
  524. if (aux == NULL) {
  525. sdsfree(cmd);
  526. return -1;
  527. }
  528. cmd = aux;
  529. /* Construct command */
  530. cmd = sdscatfmt(cmd, "*%i\r\n", argc);
  531. for (j=0; j < argc; j++) {
  532. len = argvlen ? argvlen[j] : strlen(argv[j]);
  533. cmd = sdscatfmt(cmd, "$%U\r\n", len);
  534. cmd = sdscatlen(cmd, argv[j], len);
  535. cmd = sdscatlen(cmd, "\r\n", sizeof("\r\n")-1);
  536. }
  537. assert(sdslen(cmd)==totlen);
  538. *target = cmd;
  539. return totlen;
  540. }
  541. void redisFreeSdsCommand(sds cmd) {
  542. sdsfree(cmd);
  543. }
  544. /* Format a command according to the Redis protocol. This function takes the
  545. * number of arguments, an array with arguments and an array with their
  546. * lengths. If the latter is set to NULL, strlen will be used to compute the
  547. * argument lengths.
  548. */
  549. long long redisFormatCommandArgv(char **target, int argc, const char **argv, const size_t *argvlen) {
  550. char *cmd = NULL; /* final command */
  551. size_t pos; /* position in final command */
  552. size_t len, totlen;
  553. int j;
  554. /* Abort on a NULL target */
  555. if (target == NULL)
  556. return -1;
  557. /* Calculate number of bytes needed for the command */
  558. totlen = 1+countDigits(argc)+2;
  559. for (j = 0; j < argc; j++) {
  560. len = argvlen ? argvlen[j] : strlen(argv[j]);
  561. totlen += bulklen(len);
  562. }
  563. /* Build the command at protocol level */
  564. cmd = hi_malloc(totlen+1);
  565. if (cmd == NULL)
  566. return -1;
  567. pos = sprintf(cmd,"*%d\r\n",argc);
  568. for (j = 0; j < argc; j++) {
  569. len = argvlen ? argvlen[j] : strlen(argv[j]);
  570. pos += sprintf(cmd+pos,"$%zu\r\n",len);
  571. memcpy(cmd+pos,argv[j],len);
  572. pos += len;
  573. cmd[pos++] = '\r';
  574. cmd[pos++] = '\n';
  575. }
  576. assert(pos == totlen);
  577. cmd[pos] = '\0';
  578. *target = cmd;
  579. return totlen;
  580. }
  581. void redisFreeCommand(char *cmd) {
  582. hi_free(cmd);
  583. }
  584. void __redisSetError(redisContext *c, int type, const char *str) {
  585. size_t len;
  586. c->err = type;
  587. if (str != NULL) {
  588. len = strlen(str);
  589. len = len < (sizeof(c->errstr)-1) ? len : (sizeof(c->errstr)-1);
  590. memcpy(c->errstr,str,len);
  591. c->errstr[len] = '\0';
  592. } else {
  593. /* Only REDIS_ERR_IO may lack a description! */
  594. assert(type == REDIS_ERR_IO);
  595. strerror_r(errno, c->errstr, sizeof(c->errstr));
  596. }
  597. }
  598. redisReader *redisReaderCreate(void) {
  599. return redisReaderCreateWithFunctions(&defaultFunctions);
  600. }
  601. static void redisPushAutoFree(void *privdata, void *reply) {
  602. (void)privdata;
  603. freeReplyObject(reply);
  604. }
  605. static redisContext *redisContextInit(void) {
  606. redisContext *c;
  607. c = hi_calloc(1, sizeof(*c));
  608. if (c == NULL)
  609. return NULL;
  610. c->funcs = &redisContextDefaultFuncs;
  611. c->obuf = sdsempty();
  612. c->reader = redisReaderCreate();
  613. c->fd = REDIS_INVALID_FD;
  614. if (c->obuf == NULL || c->reader == NULL) {
  615. redisFree(c);
  616. return NULL;
  617. }
  618. return c;
  619. }
  620. void redisFree(redisContext *c) {
  621. if (c == NULL)
  622. return;
  623. if (c->funcs && c->funcs->close) {
  624. c->funcs->close(c);
  625. }
  626. sdsfree(c->obuf);
  627. redisReaderFree(c->reader);
  628. hi_free(c->tcp.host);
  629. hi_free(c->tcp.source_addr);
  630. hi_free(c->unix_sock.path);
  631. hi_free(c->connect_timeout);
  632. hi_free(c->command_timeout);
  633. hi_free(c->saddr);
  634. if (c->privdata && c->free_privdata)
  635. c->free_privdata(c->privdata);
  636. if (c->funcs && c->funcs->free_privctx)
  637. c->funcs->free_privctx(c->privctx);
  638. memset(c, 0xff, sizeof(*c));
  639. hi_free(c);
  640. }
  641. redisFD redisFreeKeepFd(redisContext *c) {
  642. redisFD fd = c->fd;
  643. c->fd = REDIS_INVALID_FD;
  644. redisFree(c);
  645. return fd;
  646. }
  647. int redisReconnect(redisContext *c) {
  648. c->err = 0;
  649. memset(c->errstr, '\0', strlen(c->errstr));
  650. if (c->privctx && c->funcs->free_privctx) {
  651. c->funcs->free_privctx(c->privctx);
  652. c->privctx = NULL;
  653. }
  654. if (c->funcs && c->funcs->close) {
  655. c->funcs->close(c);
  656. }
  657. sdsfree(c->obuf);
  658. redisReaderFree(c->reader);
  659. c->obuf = sdsempty();
  660. c->reader = redisReaderCreate();
  661. if (c->obuf == NULL || c->reader == NULL) {
  662. __redisSetError(c, REDIS_ERR_OOM, "Out of memory");
  663. return REDIS_ERR;
  664. }
  665. int ret = REDIS_ERR;
  666. if (c->connection_type == REDIS_CONN_TCP) {
  667. ret = redisContextConnectBindTcp(c, c->tcp.host, c->tcp.port,
  668. c->connect_timeout, c->tcp.source_addr);
  669. } else if (c->connection_type == REDIS_CONN_UNIX) {
  670. ret = redisContextConnectUnix(c, c->unix_sock.path, c->connect_timeout);
  671. } else {
  672. /* Something bad happened here and shouldn't have. There isn't
  673. enough information in the context to reconnect. */
  674. __redisSetError(c,REDIS_ERR_OTHER,"Not enough information to reconnect");
  675. ret = REDIS_ERR;
  676. }
  677. if (c->command_timeout != NULL && (c->flags & REDIS_BLOCK) && c->fd != REDIS_INVALID_FD) {
  678. redisContextSetTimeout(c, *c->command_timeout);
  679. }
  680. return ret;
  681. }
  682. redisContext *redisConnectWithOptions(const redisOptions *options) {
  683. redisContext *c = redisContextInit();
  684. if (c == NULL) {
  685. return NULL;
  686. }
  687. if (!(options->options & REDIS_OPT_NONBLOCK)) {
  688. c->flags |= REDIS_BLOCK;
  689. }
  690. if (options->options & REDIS_OPT_REUSEADDR) {
  691. c->flags |= REDIS_REUSEADDR;
  692. }
  693. if (options->options & REDIS_OPT_NOAUTOFREE) {
  694. c->flags |= REDIS_NO_AUTO_FREE;
  695. }
  696. if (options->options & REDIS_OPT_NOAUTOFREEREPLIES) {
  697. c->flags |= REDIS_NO_AUTO_FREE_REPLIES;
  698. }
  699. if (options->options & REDIS_OPT_PREFER_IPV4) {
  700. c->flags |= REDIS_PREFER_IPV4;
  701. }
  702. if (options->options & REDIS_OPT_PREFER_IPV6) {
  703. c->flags |= REDIS_PREFER_IPV6;
  704. }
  705. /* Set any user supplied RESP3 PUSH handler or use freeReplyObject
  706. * as a default unless specifically flagged that we don't want one. */
  707. if (options->push_cb != NULL)
  708. redisSetPushCallback(c, options->push_cb);
  709. else if (!(options->options & REDIS_OPT_NO_PUSH_AUTOFREE))
  710. redisSetPushCallback(c, redisPushAutoFree);
  711. c->privdata = options->privdata;
  712. c->free_privdata = options->free_privdata;
  713. if (redisContextUpdateConnectTimeout(c, options->connect_timeout) != REDIS_OK ||
  714. redisContextUpdateCommandTimeout(c, options->command_timeout) != REDIS_OK) {
  715. __redisSetError(c, REDIS_ERR_OOM, "Out of memory");
  716. return c;
  717. }
  718. if (options->type == REDIS_CONN_TCP) {
  719. redisContextConnectBindTcp(c, options->endpoint.tcp.ip,
  720. options->endpoint.tcp.port, options->connect_timeout,
  721. options->endpoint.tcp.source_addr);
  722. } else if (options->type == REDIS_CONN_UNIX) {
  723. redisContextConnectUnix(c, options->endpoint.unix_socket,
  724. options->connect_timeout);
  725. } else if (options->type == REDIS_CONN_USERFD) {
  726. c->fd = options->endpoint.fd;
  727. c->flags |= REDIS_CONNECTED;
  728. } else {
  729. redisFree(c);
  730. return NULL;
  731. }
  732. if (c->err == 0 && c->fd != REDIS_INVALID_FD &&
  733. options->command_timeout != NULL && (c->flags & REDIS_BLOCK))
  734. {
  735. redisContextSetTimeout(c, *options->command_timeout);
  736. }
  737. return c;
  738. }
  739. /* Connect to a Redis instance. On error the field error in the returned
  740. * context will be set to the return value of the error function.
  741. * When no set of reply functions is given, the default set will be used. */
  742. redisContext *redisConnect(const char *ip, int port) {
  743. redisOptions options = {0};
  744. REDIS_OPTIONS_SET_TCP(&options, ip, port);
  745. return redisConnectWithOptions(&options);
  746. }
  747. redisContext *redisConnectWithTimeout(const char *ip, int port, const struct timeval tv) {
  748. redisOptions options = {0};
  749. REDIS_OPTIONS_SET_TCP(&options, ip, port);
  750. options.connect_timeout = &tv;
  751. return redisConnectWithOptions(&options);
  752. }
  753. redisContext *redisConnectNonBlock(const char *ip, int port) {
  754. redisOptions options = {0};
  755. REDIS_OPTIONS_SET_TCP(&options, ip, port);
  756. options.options |= REDIS_OPT_NONBLOCK;
  757. return redisConnectWithOptions(&options);
  758. }
  759. redisContext *redisConnectBindNonBlock(const char *ip, int port,
  760. const char *source_addr) {
  761. redisOptions options = {0};
  762. REDIS_OPTIONS_SET_TCP(&options, ip, port);
  763. options.endpoint.tcp.source_addr = source_addr;
  764. options.options |= REDIS_OPT_NONBLOCK;
  765. return redisConnectWithOptions(&options);
  766. }
  767. redisContext *redisConnectBindNonBlockWithReuse(const char *ip, int port,
  768. const char *source_addr) {
  769. redisOptions options = {0};
  770. REDIS_OPTIONS_SET_TCP(&options, ip, port);
  771. options.endpoint.tcp.source_addr = source_addr;
  772. options.options |= REDIS_OPT_NONBLOCK|REDIS_OPT_REUSEADDR;
  773. return redisConnectWithOptions(&options);
  774. }
  775. redisContext *redisConnectUnix(const char *path) {
  776. redisOptions options = {0};
  777. REDIS_OPTIONS_SET_UNIX(&options, path);
  778. return redisConnectWithOptions(&options);
  779. }
  780. redisContext *redisConnectUnixWithTimeout(const char *path, const struct timeval tv) {
  781. redisOptions options = {0};
  782. REDIS_OPTIONS_SET_UNIX(&options, path);
  783. options.connect_timeout = &tv;
  784. return redisConnectWithOptions(&options);
  785. }
  786. redisContext *redisConnectUnixNonBlock(const char *path) {
  787. redisOptions options = {0};
  788. REDIS_OPTIONS_SET_UNIX(&options, path);
  789. options.options |= REDIS_OPT_NONBLOCK;
  790. return redisConnectWithOptions(&options);
  791. }
  792. redisContext *redisConnectFd(redisFD fd) {
  793. redisOptions options = {0};
  794. options.type = REDIS_CONN_USERFD;
  795. options.endpoint.fd = fd;
  796. return redisConnectWithOptions(&options);
  797. }
  798. /* Set read/write timeout on a blocking socket. */
  799. int redisSetTimeout(redisContext *c, const struct timeval tv) {
  800. if (c->flags & REDIS_BLOCK)
  801. return redisContextSetTimeout(c,tv);
  802. return REDIS_ERR;
  803. }
  804. int redisEnableKeepAliveWithInterval(redisContext *c, int interval) {
  805. return redisKeepAlive(c, interval);
  806. }
  807. /* Enable connection KeepAlive. */
  808. int redisEnableKeepAlive(redisContext *c) {
  809. return redisKeepAlive(c, REDIS_KEEPALIVE_INTERVAL);
  810. }
  811. /* Set the socket option TCP_USER_TIMEOUT. */
  812. int redisSetTcpUserTimeout(redisContext *c, unsigned int timeout) {
  813. return redisContextSetTcpUserTimeout(c, timeout);
  814. }
  815. /* Set a user provided RESP3 PUSH handler and return any old one set. */
  816. redisPushFn *redisSetPushCallback(redisContext *c, redisPushFn *fn) {
  817. redisPushFn *old = c->push_cb;
  818. c->push_cb = fn;
  819. return old;
  820. }
  821. /* Use this function to handle a read event on the descriptor. It will try
  822. * and read some bytes from the socket and feed them to the reply parser.
  823. *
  824. * After this function is called, you may use redisGetReplyFromReader to
  825. * see if there is a reply available. */
  826. int redisBufferRead(redisContext *c) {
  827. char buf[1024*16];
  828. int nread;
  829. /* Return early when the context has seen an error. */
  830. if (c->err)
  831. return REDIS_ERR;
  832. nread = c->funcs->read(c, buf, sizeof(buf));
  833. if (nread < 0) {
  834. return REDIS_ERR;
  835. }
  836. if (nread > 0 && redisReaderFeed(c->reader, buf, nread) != REDIS_OK) {
  837. __redisSetError(c, c->reader->err, c->reader->errstr);
  838. return REDIS_ERR;
  839. }
  840. return REDIS_OK;
  841. }
  842. /* Write the output buffer to the socket.
  843. *
  844. * Returns REDIS_OK when the buffer is empty, or (a part of) the buffer was
  845. * successfully written to the socket. When the buffer is empty after the
  846. * write operation, "done" is set to 1 (if given).
  847. *
  848. * Returns REDIS_ERR if an unrecoverable error occurred in the underlying
  849. * c->funcs->write function.
  850. */
  851. int redisBufferWrite(redisContext *c, int *done) {
  852. /* Return early when the context has seen an error. */
  853. if (c->err)
  854. return REDIS_ERR;
  855. if (sdslen(c->obuf) > 0) {
  856. ssize_t nwritten = c->funcs->write(c);
  857. if (nwritten < 0) {
  858. return REDIS_ERR;
  859. } else if (nwritten > 0) {
  860. if (nwritten == (ssize_t)sdslen(c->obuf)) {
  861. sdsfree(c->obuf);
  862. c->obuf = sdsempty();
  863. if (c->obuf == NULL)
  864. goto oom;
  865. } else {
  866. if (sdsrange(c->obuf,nwritten,-1) < 0) goto oom;
  867. }
  868. }
  869. }
  870. if (done != NULL) *done = (sdslen(c->obuf) == 0);
  871. return REDIS_OK;
  872. oom:
  873. __redisSetError(c, REDIS_ERR_OOM, "Out of memory");
  874. return REDIS_ERR;
  875. }
  876. /* Internal helper that returns 1 if the reply was a RESP3 PUSH
  877. * message and we handled it with a user-provided callback. */
  878. static int redisHandledPushReply(redisContext *c, void *reply) {
  879. if (reply && c->push_cb && redisIsPushReply(reply)) {
  880. c->push_cb(c->privdata, reply);
  881. return 1;
  882. }
  883. return 0;
  884. }
  885. /* Get a reply from our reader or set an error in the context. */
  886. int redisGetReplyFromReader(redisContext *c, void **reply) {
  887. if (redisReaderGetReply(c->reader, reply) == REDIS_ERR) {
  888. __redisSetError(c,c->reader->err,c->reader->errstr);
  889. return REDIS_ERR;
  890. }
  891. return REDIS_OK;
  892. }
  893. /* Internal helper to get the next reply from our reader while handling
  894. * any PUSH messages we encounter along the way. This is separate from
  895. * redisGetReplyFromReader so as to not change its behavior. */
  896. static int redisNextInBandReplyFromReader(redisContext *c, void **reply) {
  897. do {
  898. if (redisGetReplyFromReader(c, reply) == REDIS_ERR)
  899. return REDIS_ERR;
  900. } while (redisHandledPushReply(c, *reply));
  901. return REDIS_OK;
  902. }
  903. int redisGetReply(redisContext *c, void **reply) {
  904. int wdone = 0;
  905. void *aux = NULL;
  906. /* Try to read pending replies */
  907. if (redisNextInBandReplyFromReader(c,&aux) == REDIS_ERR)
  908. return REDIS_ERR;
  909. /* For the blocking context, flush output buffer and read reply */
  910. if (aux == NULL && c->flags & REDIS_BLOCK) {
  911. /* Write until done */
  912. do {
  913. if (redisBufferWrite(c,&wdone) == REDIS_ERR)
  914. return REDIS_ERR;
  915. } while (!wdone);
  916. /* Read until there is a reply */
  917. do {
  918. if (redisBufferRead(c) == REDIS_ERR)
  919. return REDIS_ERR;
  920. if (redisNextInBandReplyFromReader(c,&aux) == REDIS_ERR)
  921. return REDIS_ERR;
  922. } while (aux == NULL);
  923. }
  924. /* Set reply or free it if we were passed NULL */
  925. if (reply != NULL) {
  926. *reply = aux;
  927. } else {
  928. freeReplyObject(aux);
  929. }
  930. return REDIS_OK;
  931. }
  932. /* Helper function for the redisAppendCommand* family of functions.
  933. *
  934. * Write a formatted command to the output buffer. When this family
  935. * is used, you need to call redisGetReply yourself to retrieve
  936. * the reply (or replies in pub/sub).
  937. */
  938. int __redisAppendCommand(redisContext *c, const char *cmd, size_t len) {
  939. sds newbuf;
  940. newbuf = sdscatlen(c->obuf,cmd,len);
  941. if (newbuf == NULL) {
  942. __redisSetError(c,REDIS_ERR_OOM,"Out of memory");
  943. return REDIS_ERR;
  944. }
  945. c->obuf = newbuf;
  946. return REDIS_OK;
  947. }
  948. int redisAppendFormattedCommand(redisContext *c, const char *cmd, size_t len) {
  949. if (__redisAppendCommand(c, cmd, len) != REDIS_OK) {
  950. return REDIS_ERR;
  951. }
  952. return REDIS_OK;
  953. }
  954. int redisvAppendCommand(redisContext *c, const char *format, va_list ap) {
  955. char *cmd;
  956. int len;
  957. len = redisvFormatCommand(&cmd,format,ap);
  958. if (len == -1) {
  959. __redisSetError(c,REDIS_ERR_OOM,"Out of memory");
  960. return REDIS_ERR;
  961. } else if (len == -2) {
  962. __redisSetError(c,REDIS_ERR_OTHER,"Invalid format string");
  963. return REDIS_ERR;
  964. }
  965. if (__redisAppendCommand(c,cmd,len) != REDIS_OK) {
  966. hi_free(cmd);
  967. return REDIS_ERR;
  968. }
  969. hi_free(cmd);
  970. return REDIS_OK;
  971. }
  972. int redisAppendCommand(redisContext *c, const char *format, ...) {
  973. va_list ap;
  974. int ret;
  975. va_start(ap,format);
  976. ret = redisvAppendCommand(c,format,ap);
  977. va_end(ap);
  978. return ret;
  979. }
  980. int redisAppendCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen) {
  981. sds cmd;
  982. long long len;
  983. len = redisFormatSdsCommandArgv(&cmd,argc,argv,argvlen);
  984. if (len == -1) {
  985. __redisSetError(c,REDIS_ERR_OOM,"Out of memory");
  986. return REDIS_ERR;
  987. }
  988. if (__redisAppendCommand(c,cmd,len) != REDIS_OK) {
  989. sdsfree(cmd);
  990. return REDIS_ERR;
  991. }
  992. sdsfree(cmd);
  993. return REDIS_OK;
  994. }
  995. /* Helper function for the redisCommand* family of functions.
  996. *
  997. * Write a formatted command to the output buffer. If the given context is
  998. * blocking, immediately read the reply into the "reply" pointer. When the
  999. * context is non-blocking, the "reply" pointer will not be used and the
  1000. * command is simply appended to the write buffer.
  1001. *
  1002. * Returns the reply when a reply was successfully retrieved. Returns NULL
  1003. * otherwise. When NULL is returned in a blocking context, the error field
  1004. * in the context will be set.
  1005. */
  1006. static void *__redisBlockForReply(redisContext *c) {
  1007. void *reply;
  1008. if (c->flags & REDIS_BLOCK) {
  1009. if (redisGetReply(c,&reply) != REDIS_OK)
  1010. return NULL;
  1011. return reply;
  1012. }
  1013. return NULL;
  1014. }
  1015. void *redisvCommand(redisContext *c, const char *format, va_list ap) {
  1016. if (redisvAppendCommand(c,format,ap) != REDIS_OK)
  1017. return NULL;
  1018. return __redisBlockForReply(c);
  1019. }
  1020. void *redisCommand(redisContext *c, const char *format, ...) {
  1021. va_list ap;
  1022. va_start(ap,format);
  1023. void *reply = redisvCommand(c,format,ap);
  1024. va_end(ap);
  1025. return reply;
  1026. }
  1027. void *redisCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen) {
  1028. if (redisAppendCommandArgv(c,argc,argv,argvlen) != REDIS_OK)
  1029. return NULL;
  1030. return __redisBlockForReply(c);
  1031. }