1 #include "redis.h" 2 #include <sys/uio.h> 3 4 void *dupClientReplyValue(void *o) { 5 incrRefCount((robj*)o); 6 return o; 7 } 8 9 int listMatchObjects(void *a, void *b) { 10 return equalStringObjects(a,b); 11 } 12 13 redisClient *createClient(int fd) { 14 redisClient *c = zmalloc(sizeof(redisClient)); 15 c->bufpos = 0; 16 17 anetNonBlock(NULL,fd); 18 anetTcpNoDelay(NULL,fd); 19 if (!c) return NULL; 20 if (aeCreateFileEvent(server.el,fd,AE_READABLE, 21 readQueryFromClient, c) == AE_ERR) 22 { 23 close(fd); 24 zfree(c); 25 return NULL; 26 } 27 28 selectDb(c,0); 29 c->fd = fd; 30 c->querybuf = sdsempty(); 31 c->reqtype = 0; 32 c->argc = 0; 33 c->argv = NULL; 34 c->multibulklen = 0; 35 c->bulklen = -1; 36 c->sentlen = 0; 37 c->flags = 0; 38 c->lastinteraction = time(NULL); 39 c->authenticated = 0; 40 c->replstate = REDIS_REPL_NONE; 41 c->reply = listCreate(); 42 listSetFreeMethod(c->reply,decrRefCount); 43 listSetDupMethod(c->reply,dupClientReplyValue); 44 c->bpop.keys = NULL; 45 c->bpop.count = 0; 46 c->bpop.timeout = 0; 47 c->bpop.target = NULL; 48 c->io_keys = listCreate(); 49 c->watched_keys = listCreate(); 50 listSetFreeMethod(c->io_keys,decrRefCount); 51 c->pubsub_channels = dictCreate(&setDictType,NULL); 52 c->pubsub_patterns = listCreate(); 53 listSetFreeMethod(c->pubsub_patterns,decrRefCount); 54 listSetMatchMethod(c->pubsub_patterns,listMatchObjects); 55 listAddNodeTail(server.clients,c); 56 initClientMultiState(c); 57 return c; 58 } 59 60 /* Set the event loop to listen for write events on the client's socket. 61 * Typically gets called every time a reply is built. */ 62 int _installWriteEvent(redisClient *c) { 63 /* When CLOSE_AFTER_REPLY is set, no more replies may be added! */ 64 redisAssert(!(c->flags & REDIS_CLOSE_AFTER_REPLY)); 65 66 if (c->fd <= 0) return REDIS_ERR; 67 if (c->bufpos == 0 && listLength(c->reply) == 0 && 68 (c->replstate == REDIS_REPL_NONE || 69 c->replstate == REDIS_REPL_ONLINE) && 70 aeCreateFileEvent(server.el, c->fd, AE_WRITABLE, 71 sendReplyToClient, c) == AE_ERR) return REDIS_ERR; 72 return REDIS_OK; 73 } 74 75 /* Create a duplicate of the last object in the reply list when 76 * it is not exclusively owned by the reply list. */ 77 robj *dupLastObjectIfNeeded(list *reply) { 78 robj *new, *cur; 79 listNode *ln; 80 redisAssert(listLength(reply) > 0); 81 ln = listLast(reply); 82 cur = listNodeValue(ln); 83 if (cur->refcount > 1) { 84 new = dupStringObject(cur); 85 decrRefCount(cur); 86 listNodeValue(ln) = new; 87 } 88 return listNodeValue(ln); 89 } 90 91 int _addReplyToBuffer(redisClient *c, char *s, size_t len) { 92 size_t available = sizeof(c->buf)-c->bufpos; 93 94 /* If there already are entries in the reply list, we cannot 95 * add anything more to the static buffer. */ 96 if (listLength(c->reply) > 0) return REDIS_ERR; 97 98 /* Check that the buffer has enough space available for this string. */ 99 if (len > available) return REDIS_ERR; 100 101 memcpy(c->buf+c->bufpos,s,len); 102 c->bufpos+=len; 103 return REDIS_OK; 104 } 105 106 void _addReplyObjectToList(redisClient *c, robj *o) { 107 robj *tail; 108 if (listLength(c->reply) == 0) { 109 incrRefCount(o); 110 listAddNodeTail(c->reply,o); 111 } else { 112 tail = listNodeValue(listLast(c->reply)); 113 114 /* Append to this object when possible. */ 115 if (tail->ptr != NULL && 116 sdslen(tail->ptr)+sdslen(o->ptr) <= REDIS_REPLY_CHUNK_BYTES) 117 { 118 tail = dupLastObjectIfNeeded(c->reply); 119 tail->ptr = sdscatlen(tail->ptr,o->ptr,sdslen(o->ptr)); 120 } else { 121 incrRefCount(o); 122 listAddNodeTail(c->reply,o); 123 } 124 } 125 } 126 127 /* This method takes responsibility over the sds. When it is no longer 128 * needed it will be free'd, otherwise it ends up in a robj. */ 129 void _addReplySdsToList(redisClient *c, sds s) { 130 robj *tail; 131 if (listLength(c->reply) == 0) { 132 listAddNodeTail(c->reply,createObject(REDIS_STRING,s)); 133 } else { 134 tail = listNodeValue(listLast(c->reply)); 135 136 /* Append to this object when possible. */ 137 if (tail->ptr != NULL && 138 sdslen(tail->ptr)+sdslen(s) <= REDIS_REPLY_CHUNK_BYTES) 139 { 140 tail = dupLastObjectIfNeeded(c->reply); 141 tail->ptr = sdscatlen(tail->ptr,s,sdslen(s)); 142 sdsfree(s); 143 } else { 144 listAddNodeTail(c->reply,createObject(REDIS_STRING,s)); 145 } 146 } 147 } 148 149 void _addReplyStringToList(redisClient *c, char *s, size_t len) { 150 robj *tail; 151 if (listLength(c->reply) == 0) { 152 listAddNodeTail(c->reply,createStringObject(s,len)); 153 } else { 154 tail = listNodeValue(listLast(c->reply)); 155 156 /* Append to this object when possible. */ 157 if (tail->ptr != NULL && 158 sdslen(tail->ptr)+len <= REDIS_REPLY_CHUNK_BYTES) 159 { 160 tail = dupLastObjectIfNeeded(c->reply); 161 tail->ptr = sdscatlen(tail->ptr,s,len); 162 } else { 163 listAddNodeTail(c->reply,createStringObject(s,len)); 164 } 165 } 166 } 167 168 void addReply(redisClient *c, robj *obj) { 169 if (_installWriteEvent(c) != REDIS_OK) return; 170 171 /* This is an important place where we can avoid copy-on-write 172 * when there is a saving child running, avoiding touching the 173 * refcount field of the object if it's not needed. 174 * 175 * If the encoding is RAW and there is room in the static buffer 176 * we'll be able to send the object to the client without 177 * messing with its page. */ 178 if (obj->encoding == REDIS_ENCODING_RAW) { 179 if (_addReplyToBuffer(c,obj->ptr,sdslen(obj->ptr)) != REDIS_OK) 180 _addReplyObjectToList(c,obj); 181 } else { 182 /* FIXME: convert the long into string and use _addReplyToBuffer() 183 * instead of calling getDecodedObject. As this place in the 184 * code is too performance critical. */ 185 obj = getDecodedObject(obj); 186 if (_addReplyToBuffer(c,obj->ptr,sdslen(obj->ptr)) != REDIS_OK) 187 _addReplyObjectToList(c,obj); 188 decrRefCount(obj); 189 } 190 } 191 192 void addReplySds(redisClient *c, sds s) { 193 if (_installWriteEvent(c) != REDIS_OK) { 194 /* The caller expects the sds to be free'd. */ 195 sdsfree(s); 196 return; 197 } 198 if (_addReplyToBuffer(c,s,sdslen(s)) == REDIS_OK) { 199 sdsfree(s); 200 } else { 201 /* This method free's the sds when it is no longer needed. */ 202 _addReplySdsToList(c,s); 203 } 204 } 205 206 void addReplyString(redisClient *c, char *s, size_t len) { 207 if (_installWriteEvent(c) != REDIS_OK) return; 208 if (_addReplyToBuffer(c,s,len) != REDIS_OK) 209 _addReplyStringToList(c,s,len); 210 } 211 212 void _addReplyError(redisClient *c, char *s, size_t len) { 213 addReplyString(c,"-ERR ",5); 214 addReplyString(c,s,len); 215 addReplyString(c,"\r\n",2); 216 } 217 218 void addReplyError(redisClient *c, char *err) { 219 _addReplyError(c,err,strlen(err)); 220 } 221 222 void addReplyErrorFormat(redisClient *c, const char *fmt, ...) { 223 va_list ap; 224 va_start(ap,fmt); 225 sds s = sdscatvprintf(sdsempty(),fmt,ap); 226 va_end(ap); 227 _addReplyError(c,s,sdslen(s)); 228 sdsfree(s); 229 } 230 231 void _addReplyStatus(redisClient *c, char *s, size_t len) { 232 addReplyString(c,"+",1); 233 addReplyString(c,s,len); 234 addReplyString(c,"\r\n",2); 235 } 236 237 void addReplyStatus(redisClient *c, char *status) { 238 _addReplyStatus(c,status,strlen(status)); 239 } 240 241 void addReplyStatusFormat(redisClient *c, const char *fmt, ...) { 242 va_list ap; 243 va_start(ap,fmt); 244 sds s = sdscatvprintf(sdsempty(),fmt,ap); 245 va_end(ap); 246 _addReplyStatus(c,s,sdslen(s)); 247 sdsfree(s); 248 } 249 250 /* Adds an empty object to the reply list that will contain the multi bulk 251 * length, which is not known when this function is called. */ 252 void *addDeferredMultiBulkLength(redisClient *c) { 253 /* Note that we install the write event here even if the object is not 254 * ready to be sent, since we are sure that before returning to the 255 * event loop setDeferredMultiBulkLength() will be called. */ 256 if (_installWriteEvent(c) != REDIS_OK) return NULL; 257 listAddNodeTail(c->reply,createObject(REDIS_STRING,NULL)); 258 return listLast(c->reply); 259 } 260 261 /* Populate the length object and try glueing it to the next chunk. */ 262 void setDeferredMultiBulkLength(redisClient *c, void *node, long length) { 263 listNode *ln = (listNode*)node; 264 robj *len, *next; 265 266 /* Abort when *node is NULL (see addDeferredMultiBulkLength). */ 267 if (node == NULL) return; 268 269 len = listNodeValue(ln); 270 len->ptr = sdscatprintf(sdsempty(),"*%ld\r\n",length); 271 if (ln->next != NULL) { 272 next = listNodeValue(ln->next); 273 274 /* Only glue when the next node is non-NULL (an sds in this case) */ 275 if (next->ptr != NULL) { 276 len->ptr = sdscatlen(len->ptr,next->ptr,sdslen(next->ptr)); 277 listDelNode(c->reply,ln->next); 278 } 279 } 280 } 281 282 /* Add a duble as a bulk reply */ 283 void addReplyDouble(redisClient *c, double d) { 284 char dbuf[128], sbuf[128]; 285 int dlen, slen; 286 dlen = snprintf(dbuf,sizeof(dbuf),"%.17g",d); 287 slen = snprintf(sbuf,sizeof(sbuf),"$%d\r\n%s\r\n",dlen,dbuf); 288 addReplyString(c,sbuf,slen); 289 } 290 291 /* Add a long long as integer reply or bulk len / multi bulk count. 292 * Basically this is used to output <prefix><long long><crlf>. */ 293 void _addReplyLongLong(redisClient *c, long long ll, char prefix) { 294 char buf[128]; 295 int len; 296 buf[0] = prefix; 297 len = ll2string(buf+1,sizeof(buf)-1,ll); 298 buf[len+1] = '\r'; 299 buf[len+2] = '\n'; 300 addReplyString(c,buf,len+3); 301 } 302 303 void addReplyLongLong(redisClient *c, long long ll) { 304 _addReplyLongLong(c,ll,':'); 305 } 306 307 void addReplyMultiBulkLen(redisClient *c, long length) { 308 _addReplyLongLong(c,length,'*'); 309 } 310 311 /* Create the length prefix of a bulk reply, example: $2234 */ 312 void addReplyBulkLen(redisClient *c, robj *obj) { 313 size_t len; 314 315 if (obj->encoding == REDIS_ENCODING_RAW) { 316 len = sdslen(obj->ptr); 317 } else { 318 long n = (long)obj->ptr; 319 320 /* Compute how many bytes will take this integer as a radix 10 string */ 321 len = 1; 322 if (n < 0) { 323 len++; 324 n = -n; 325 } 326 while((n = n/10) != 0) { 327 len++; 328 } 329 } 330 _addReplyLongLong(c,len,'$'); 331 } 332 333 /* Add a Redis Object as a bulk reply */ 334 void addReplyBulk(redisClient *c, robj *obj) { 335 addReplyBulkLen(c,obj); 336 addReply(c,obj); 337 addReply(c,shared.crlf); 338 } 339 340 /* Add a C buffer as bulk reply */ 341 void addReplyBulkCBuffer(redisClient *c, void *p, size_t len) { 342 _addReplyLongLong(c,len,'$'); 343 addReplyString(c,p,len); 344 addReply(c,shared.crlf); 345 } 346 347 /* Add a C nul term string as bulk reply */ 348 void addReplyBulkCString(redisClient *c, char *s) { 349 if (s == NULL) { 350 addReply(c,shared.nullbulk); 351 } else { 352 addReplyBulkCBuffer(c,s,strlen(s)); 353 } 354 } 355 356 /* Add a long long as a bulk reply */ 357 void addReplyBulkLongLong(redisClient *c, long long ll) { 358 char buf[64]; 359 int len; 360 361 len = ll2string(buf,64,ll); 362 addReplyBulkCBuffer(c,buf,len); 363 } 364 365 static void acceptCommonHandler(int fd) { 366 redisClient *c; 367 if ((c = createClient(fd)) == NULL) { 368 redisLog(REDIS_WARNING,"Error allocating resoures for the client"); 369 close(fd); /* May be already closed, just ingore errors */ 370 return; 371 } 372 /* If maxclient directive is set and this is one client more... close the 373 * connection. Note that we create the client instead to check before 374 * for this condition, since now the socket is already set in nonblocking 375 * mode and we can send an error for free using the Kernel I/O */ 376 if (server.maxclients && listLength(server.clients) > server.maxclients) { 377 char *err = "-ERR max number of clients reached\r\n"; 378 379 /* That's a best effort error message, don't check write errors */ 380 if (write(c->fd,err,strlen(err)) == -1) { 381 /* Nothing to do, Just to avoid the warning... */ 382 } 383 freeClient(c); 384 return; 385 } 386 server.stat_numconnections++; 387 } 388 389 void acceptTcpHandler(aeEventLoop *el, int fd, void *privdata, int mask) { 390 int cport, cfd; 391 char cip[128]; 392 REDIS_NOTUSED(el); 393 REDIS_NOTUSED(mask); 394 REDIS_NOTUSED(privdata); 395 396 cfd = anetTcpAccept(server.neterr, fd, cip, &cport); 397 if (cfd == AE_ERR) { 398 redisLog(REDIS_VERBOSE,"Accepting client connection: %s", server.neterr); 399 return; 400 } 401 redisLog(REDIS_VERBOSE,"Accepted %s:%d", cip, cport); 402 acceptCommonHandler(cfd); 403 } 404 405 void acceptUnixHandler(aeEventLoop *el, int fd, void *privdata, int mask) { 406 int cfd; 407 REDIS_NOTUSED(el); 408 REDIS_NOTUSED(mask); 409 REDIS_NOTUSED(privdata); 410 411 cfd = anetUnixAccept(server.neterr, fd); 412 if (cfd == AE_ERR) { 413 redisLog(REDIS_VERBOSE,"Accepting client connection: %s", server.neterr); 414 return; 415 } 416 redisLog(REDIS_VERBOSE,"Accepted connection to %s", server.unixsocket); 417 acceptCommonHandler(cfd); 418 } 419 420 421 static void freeClientArgv(redisClient *c) { 422 int j; 423 for (j = 0; j < c->argc; j++) 424 decrRefCount(c->argv[j]); 425 c->argc = 0; 426 } 427 428 void freeClient(redisClient *c) { 429 listNode *ln; 430 431 /* Note that if the client we are freeing is blocked into a blocking 432 * call, we have to set querybuf to NULL *before* to call 433 * unblockClientWaitingData() to avoid processInputBuffer() will get 434 * called. Also it is important to remove the file events after 435 * this, because this call adds the READABLE event. */ 436 sdsfree(c->querybuf); 437 c->querybuf = NULL; 438 if (c->flags & REDIS_BLOCKED) 439 unblockClientWaitingData(c); 440 441 /* UNWATCH all the keys */ 442 unwatchAllKeys(c); 443 listRelease(c->watched_keys); 444 /* Unsubscribe from all the pubsub channels */ 445 pubsubUnsubscribeAllChannels(c,0); 446 pubsubUnsubscribeAllPatterns(c,0); 447 dictRelease(c->pubsub_channels); 448 listRelease(c->pubsub_patterns); 449 /* Obvious cleanup */ 450 aeDeleteFileEvent(server.el,c->fd,AE_READABLE); 451 aeDeleteFileEvent(server.el,c->fd,AE_WRITABLE); 452 listRelease(c->reply); 453 freeClientArgv(c); 454 close(c->fd); 455 /* Remove from the list of clients */ 456 ln = listSearchKey(server.clients,c); 457 redisAssert(ln != NULL); 458 listDelNode(server.clients,ln); 459 /* Remove from the list of clients waiting for swapped keys, or ready 460 * to be restarted, but not yet woken up again. */ 461 if (c->flags & REDIS_IO_WAIT) { 462 redisAssert(server.ds_enabled); 463 if (listLength(c->io_keys) == 0) { 464 ln = listSearchKey(server.io_ready_clients,c); 465 466 /* When this client is waiting to be woken up (REDIS_IO_WAIT), 467 * it should be present in the list io_ready_clients */ 468 redisAssert(ln != NULL); 469 listDelNode(server.io_ready_clients,ln); 470 } else { 471 while (listLength(c->io_keys)) { 472 ln = listFirst(c->io_keys); 473 dontWaitForSwappedKey(c,ln->value); 474 } 475 } 476 server.cache_blocked_clients--; 477 } 478 listRelease(c->io_keys); 479 /* Master/slave cleanup. 480 * Case 1: we lost the connection with a slave. */ 481 if (c->flags & REDIS_SLAVE) { 482 if (c->replstate == REDIS_REPL_SEND_BULK && c->repldbfd != -1) 483 close(c->repldbfd); 484 list *l = (c->flags & REDIS_MONITOR) ? server.monitors : server.slaves; 485 ln = listSearchKey(l,c); 486 redisAssert(ln != NULL); 487 listDelNode(l,ln); 488 } 489 490 /* Case 2: we lost the connection with the master. */ 491 if (c->flags & REDIS_MASTER) { 492 server.master = NULL; 493 /* FIXME */ 494 server.replstate = REDIS_REPL_CONNECT; 495 /* Since we lost the connection with the master, we should also 496 * close the connection with all our slaves if we have any, so 497 * when we'll resync with the master the other slaves will sync again 498 * with us as well. Note that also when the slave is not connected 499 * to the master it will keep refusing connections by other slaves. */ 500 while (listLength(server.slaves)) { 501 ln = listFirst(server.slaves); 502 freeClient((redisClient*)ln->value); 503 } 504 } 505 /* Release memory */ 506 zfree(c->argv); 507 freeClientMultiState(c); 508 zfree(c); 509 } 510 511 void sendReplyToClient(aeEventLoop *el, int fd, void *privdata, int mask) { 512 redisClient *c = privdata; 513 int nwritten = 0, totwritten = 0, objlen; 514 robj *o; 515 REDIS_NOTUSED(el); 516 REDIS_NOTUSED(mask); 517 518 while(c->bufpos > 0 || listLength(c->reply)) { 519 if (c->bufpos > 0) { 520 if (c->flags & REDIS_MASTER) { 521 /* Don't reply to a master */ 522 nwritten = c->bufpos - c->sentlen; 523 } else { 524 nwritten = write(fd,c->buf+c->sentlen,c->bufpos-c->sentlen); 525 if (nwritten <= 0) break; 526 } 527 c->sentlen += nwritten; 528 totwritten += nwritten; 529 530 /* If the buffer was sent, set bufpos to zero to continue with 531 * the remainder of the reply. */ 532 if (c->sentlen == c->bufpos) { 533 c->bufpos = 0; 534 c->sentlen = 0; 535 } 536 } else { 537 o = listNodeValue(listFirst(c->reply)); 538 objlen = sdslen(o->ptr); 539 540 if (objlen == 0) { 541 listDelNode(c->reply,listFirst(c->reply)); 542 continue; 543 } 544 545 if (c->flags & REDIS_MASTER) { 546 /* Don't reply to a master */ 547 nwritten = objlen - c->sentlen; 548 } else { 549 nwritten = write(fd, ((char*)o->ptr)+c->sentlen,objlen-c->sentlen); 550 if (nwritten <= 0) break; 551 } 552 c->sentlen += nwritten; 553 totwritten += nwritten; 554 555 /* If we fully sent the object on head go to the next one */ 556 if (c->sentlen == objlen) { 557 listDelNode(c->reply,listFirst(c->reply)); 558 c->sentlen = 0; 559 } 560 } 561 /* Note that we avoid to send more thank REDIS_MAX_WRITE_PER_EVENT 562 * bytes, in a single threaded server it's a good idea to serve 563 * other clients as well, even if a very large request comes from 564 * super fast link that is always able to accept data (in real world 565 * scenario think about 'KEYS *' against the loopback interfae) */ 566 if (totwritten > REDIS_MAX_WRITE_PER_EVENT) break; 567 } 568 if (nwritten == -1) { 569 if (errno == EAGAIN) { 570 nwritten = 0; 571 } else { 572 redisLog(REDIS_VERBOSE, 573 "Error writing to client: %s", strerror(errno)); 574 freeClient(c); 575 return; 576 } 577 } 578 if (totwritten > 0) c->lastinteraction = time(NULL); 579 if (listLength(c->reply) == 0) { 580 c->sentlen = 0; 581 aeDeleteFileEvent(server.el,c->fd,AE_WRITABLE); 582 583 /* Close connection after entire reply has been sent. */ 584 if (c->flags & REDIS_CLOSE_AFTER_REPLY) freeClient(c); 585 } 586 } 587 588 /* resetClient prepare the client to process the next command */ 589 void resetClient(redisClient *c) { 590 freeClientArgv(c); 591 c->reqtype = 0; 592 c->multibulklen = 0; 593 c->bulklen = -1; 594 } 595 596 void closeTimedoutClients(void) { 597 redisClient *c; 598 listNode *ln; 599 time_t now = time(NULL); 600 listIter li; 601 602 listRewind(server.clients,&li); 603 while ((ln = listNext(&li)) != NULL) { 604 c = listNodeValue(ln); 605 if (server.maxidletime && 606 !(c->flags & REDIS_SLAVE) && /* no timeout for slaves */ 607 !(c->flags & REDIS_MASTER) && /* no timeout for masters */ 608 !(c->flags & REDIS_BLOCKED) && /* no timeout for BLPOP */ 609 dictSize(c->pubsub_channels) == 0 && /* no timeout for pubsub */ 610 listLength(c->pubsub_patterns) == 0 && 611 (now - c->lastinteraction > server.maxidletime)) 612 { 613 redisLog(REDIS_VERBOSE,"Closing idle client"); 614 freeClient(c); 615 } else if (c->flags & REDIS_BLOCKED) { 616 if (c->bpop.timeout != 0 && c->bpop.timeout < now) { 617 addReply(c,shared.nullmultibulk); 618 unblockClientWaitingData(c); 619 } 620 } 621 } 622 } 623 624 int processInlineBuffer(redisClient *c) { 625 char *newline = strstr(c->querybuf,"\r\n"); 626 int argc, j; 627 sds *argv; 628 size_t querylen; 629 630 /* Nothing to do without a \r\n */ 631 if (newline == NULL) 632 return REDIS_ERR; 633 634 /* Split the input buffer up to the \r\n */ 635 querylen = newline-(c->querybuf); 636 argv = sdssplitlen(c->querybuf,querylen," ",1,&argc); 637 638 /* Leave data after the first line of the query in the buffer */ 639 c->querybuf = sdsrange(c->querybuf,querylen+2,-1); 640 641 /* Setup argv array on client structure */ 642 if (c->argv) zfree(c->argv); 643 c->argv = zmalloc(sizeof(robj*)*argc); 644 645 /* Create redis objects for all arguments. */ 646 for (c->argc = 0, j = 0; j < argc; j++) { 647 if (sdslen(argv[j])) { 648 c->argv[c->argc] = createObject(REDIS_STRING,argv[j]); 649 c->argc++; 650 } else { 651 sdsfree(argv[j]); 652 } 653 } 654 zfree(argv); 655 return REDIS_OK; 656 } 657 658 /* Helper function. Trims query buffer to make the function that processes 659 * multi bulk requests idempotent. */ 660 static void setProtocolError(redisClient *c, int pos) { 661 c->flags |= REDIS_CLOSE_AFTER_REPLY; 662 c->querybuf = sdsrange(c->querybuf,pos,-1); 663 } 664 665 int processMultibulkBuffer(redisClient *c) { 666 char *newline = NULL; 667 char *eptr; 668 int pos = 0, tolerr; 669 long bulklen; 670 671 if (c->multibulklen == 0) { 672 /* The client should have been reset */ 673 redisAssert(c->argc == 0); 674 675 /* Multi bulk length cannot be read without a \r\n */ 676 newline = strstr(c->querybuf,"\r\n"); 677 if (newline == NULL) 678 return REDIS_ERR; 679 680 /* We know for sure there is a whole line since newline != NULL, 681 * so go ahead and find out the multi bulk length. */ 682 redisAssert(c->querybuf[0] == '*'); 683 c->multibulklen = strtol(c->querybuf+1,&eptr,10); 684 pos = (newline-c->querybuf)+2; 685 if (c->multibulklen <= 0) { 686 c->querybuf = sdsrange(c->querybuf,pos,-1); 687 return REDIS_OK; 688 } else if (c->multibulklen > 1024*1024) { 689 addReplyError(c,"Protocol error: invalid multibulk length"); 690 setProtocolError(c,pos); 691 return REDIS_ERR; 692 } 693 694 /* Setup argv array on client structure */ 695 if (c->argv) zfree(c->argv); 696 c->argv = zmalloc(sizeof(robj*)*c->multibulklen); 697 698 /* Search new newline */ 699 newline = strstr(c->querybuf+pos,"\r\n"); 700 } 701 702 redisAssert(c->multibulklen > 0); 703 while(c->multibulklen) { 704 /* Read bulk length if unknown */ 705 if (c->bulklen == -1) { 706 newline = strstr(c->querybuf+pos,"\r\n"); 707 if (newline != NULL) { 708 if (c->querybuf[pos] != '$') { 709 addReplyErrorFormat(c, 710 "Protocol error: expected '$', got '%c'", 711 c->querybuf[pos]); 712 setProtocolError(c,pos); 713 return REDIS_ERR; 714 } 715 716 bulklen = strtol(c->querybuf+pos+1,&eptr,10); 717 tolerr = (eptr[0] != '\r'); 718 if (tolerr || bulklen == LONG_MIN || bulklen == LONG_MAX || 719 bulklen < 0 || bulklen > 512*1024*1024) 720 { 721 addReplyError(c,"Protocol error: invalid bulk length"); 722 setProtocolError(c,pos); 723 return REDIS_ERR; 724 } 725 pos += eptr-(c->querybuf+pos)+2; 726 c->bulklen = bulklen; 727 } else { 728 /* No newline in current buffer, so wait for more data */ 729 break; 730 } 731 } 732 733 /* Read bulk argument */ 734 if (sdslen(c->querybuf)-pos < (unsigned)(c->bulklen+2)) { 735 /* Not enough data (+2 == trailing \r\n) */ 736 break; 737 } else { 738 c->argv[c->argc++] = createStringObject(c->querybuf+pos,c->bulklen); 739 pos += c->bulklen+2; 740 c->bulklen = -1; 741 c->multibulklen--; 742 } 743 } 744 745 /* Trim to pos */ 746 c->querybuf = sdsrange(c->querybuf,pos,-1); 747 748 /* We're done when c->multibulk == 0 */ 749 if (c->multibulklen == 0) { 750 return REDIS_OK; 751 } 752 return REDIS_ERR; 753 } 754 755 void processInputBuffer(redisClient *c) { 756 /* Keep processing while there is something in the input buffer */ 757 while(sdslen(c->querybuf)) { 758 /* Immediately abort if the client is in the middle of something. */ 759 if (c->flags & REDIS_BLOCKED || c->flags & REDIS_IO_WAIT) return; 760 761 /* REDIS_CLOSE_AFTER_REPLY closes the connection once the reply is 762 * written to the client. Make sure to not let the reply grow after 763 * this flag has been set (i.e. don't process more commands). */ 764 if (c->flags & REDIS_CLOSE_AFTER_REPLY) return; 765 766 /* Determine request type when unknown. */ 767 if (!c->reqtype) { 768 if (c->querybuf[0] == '*') { 769 c->reqtype = REDIS_REQ_MULTIBULK; 770 } else { 771 c->reqtype = REDIS_REQ_INLINE; 772 } 773 } 774 775 if (c->reqtype == REDIS_REQ_INLINE) { 776 if (processInlineBuffer(c) != REDIS_OK) break; 777 } else if (c->reqtype == REDIS_REQ_MULTIBULK) { 778 if (processMultibulkBuffer(c) != REDIS_OK) break; 779 } else { 780 redisPanic("Unknown request type"); 781 } 782 783 /* Multibulk processing could see a <= 0 length. */ 784 if (c->argc == 0) { 785 resetClient(c); 786 } else { 787 /* Only reset the client when the command was executed. */ 788 if (processCommand(c) == REDIS_OK) 789 resetClient(c); 790 } 791 } 792 } 793 794 void readQueryFromClient(aeEventLoop *el, int fd, void *privdata, int mask) { 795 redisClient *c = (redisClient*) privdata; 796 char buf[REDIS_IOBUF_LEN]; 797 int nread; 798 REDIS_NOTUSED(el); 799 REDIS_NOTUSED(mask); 800 801 nread = read(fd, buf, REDIS_IOBUF_LEN); 802 if (nread == -1) { 803 if (errno == EAGAIN) { 804 nread = 0; 805 } else { 806 redisLog(REDIS_VERBOSE, "Reading from client: %s",strerror(errno)); 807 freeClient(c); 808 return; 809 } 810 } else if (nread == 0) { 811 redisLog(REDIS_VERBOSE, "Client closed connection"); 812 freeClient(c); 813 return; 814 } 815 if (nread) { 816 c->querybuf = sdscatlen(c->querybuf,buf,nread); 817 c->lastinteraction = time(NULL); 818 } else { 819 return; 820 } 821 processInputBuffer(c); 822 } 823