诸暨麻将添加redis
25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1079 lines
32 KiB

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