1 #include "redis.h" 2 #include <sys/uio.h> 3 4 static void setProtocolError(redisClient *c, int pos); 5 6 /* To evaluate the output buffer size of a client we need to get size of 7 * allocated objects, however we can't used zmalloc_size() directly on sds 8 * strings because of the trick they use to work (the header is before the 9 * returned pointer), so we use this helper function. */ 10 size_t zmalloc_size_sds(sds s) { 11 return zmalloc_size(s-sizeof(struct sdshdr)); 12 } 13 14 void *dupClientReplyValue(void *o) { 15 incrRefCount((robj*)o); 16 return o; 17 } 18 19 int listMatchObjects(void *a, void *b) { 20 return equalStringObjects(a,b); 21 } 22 23 redisClient *createClient(int fd) { 24 redisClient *c = zmalloc(sizeof(redisClient)); 25 26 /* passing -1 as fd it is possible to create a non connected client. 27 * This is useful since all the Redis commands needs to be executed 28 * in the context of a client. When commands are executed in other 29 * contexts (for instance a Lua script) we need a non connected client. */ 30 if (fd != -1) { 31 anetNonBlock(NULL,fd); 32 anetTcpNoDelay(NULL,fd); 33 if (aeCreateFileEvent(server.el,fd,AE_READABLE, 34 readQueryFromClient, c) == AE_ERR) 35 { 36 close(fd); 37 zfree(c); 38 return NULL; 39 } 40 } 41 42 selectDb(c,0); 43 c->fd = fd; 44 c->bufpos = 0; 45 c->querybuf = sdsempty(); 46 c->querybuf_peak = 0; 47 c->reqtype = 0; 48 c->argc = 0; 49 c->argv = NULL; 50 c->cmd = c->lastcmd = NULL; 51 c->multibulklen = 0; 52 c->bulklen = -1; 53 c->sentlen = 0; 54 c->flags = 0; 55 c->ctime = c->lastinteraction = time(NULL); 56 c->authenticated = 0; 57 c->replstate = REDIS_REPL_NONE; 58 c->reply = listCreate(); 59 c->reply_bytes = 0; 60 c->obuf_soft_limit_reached_time = 0; 61 listSetFreeMethod(c->reply,decrRefCount); 62 listSetDupMethod(c->reply,dupClientReplyValue); 63 c->bpop.keys = NULL; 64 c->bpop.count = 0; 65 c->bpop.timeout = 0; 66 c->bpop.target = NULL; 67 c->io_keys = listCreate(); 68 c->watched_keys = listCreate(); 69 listSetFreeMethod(c->io_keys,decrRefCount); 70 c->pubsub_channels = dictCreate(&setDictType,NULL); 71 c->pubsub_patterns = listCreate(); 72 listSetFreeMethod(c->pubsub_patterns,decrRefCount); 73 listSetMatchMethod(c->pubsub_patterns,listMatchObjects); 74 if (fd != -1) listAddNodeTail(server.clients,c); 75 initClientMultiState(c); 76 return c; 77 } 78 79 /* This function is called every time we are going to transmit new data 80 * to the client. The behavior is the following: 81 * 82 * If the client should receive new data (normal clients will) the function 83 * returns REDIS_OK, and make sure to install the write handler in our event 84 * loop so that when the socket is writable new data gets written. 85 * 86 * If the client should not receive new data, because it is a fake client 87 * or a slave, or because the setup of the write handler failed, the function 88 * returns REDIS_ERR. 89 * 90 * Typically gets called every time a reply is built, before adding more 91 * data to the clients output buffers. If the function returns REDIS_ERR no 92 * data should be appended to the output buffers. */ 93 int prepareClientToWrite(redisClient *c) { 94 if (c->flags & REDIS_LUA_CLIENT) return REDIS_OK; 95 if (c->fd <= 0) return REDIS_ERR; /* Fake client */ 96 if (c->bufpos == 0 && listLength(c->reply) == 0 && 97 (c->replstate == REDIS_REPL_NONE || 98 c->replstate == REDIS_REPL_ONLINE) && 99 aeCreateFileEvent(server.el, c->fd, AE_WRITABLE, 100 sendReplyToClient, c) == AE_ERR) return REDIS_ERR; 101 return REDIS_OK; 102 } 103 104 /* Create a duplicate of the last object in the reply list when 105 * it is not exclusively owned by the reply list. */ 106 robj *dupLastObjectIfNeeded(list *reply) { 107 robj *new, *cur; 108 listNode *ln; 109 redisAssert(listLength(reply) > 0); 110 ln = listLast(reply); 111 cur = listNodeValue(ln); 112 if (cur->refcount > 1) { 113 new = dupStringObject(cur); 114 decrRefCount(cur); 115 listNodeValue(ln) = new; 116 } 117 return listNodeValue(ln); 118 } 119 120 /* ----------------------------------------------------------------------------- 121 * Low level functions to add more data to output buffers. 122 * -------------------------------------------------------------------------- */ 123 124 int _addReplyToBuffer(redisClient *c, char *s, size_t len) { 125 size_t available = sizeof(c->buf)-c->bufpos; 126 127 if (c->flags & REDIS_CLOSE_AFTER_REPLY) return REDIS_OK; 128 129 /* If there already are entries in the reply list, we cannot 130 * add anything more to the static buffer. */ 131 if (listLength(c->reply) > 0) return REDIS_ERR; 132 133 /* Check that the buffer has enough space available for this string. */ 134 if (len > available) return REDIS_ERR; 135 136 memcpy(c->buf+c->bufpos,s,len); 137 c->bufpos+=len; 138 return REDIS_OK; 139 } 140 141 void _addReplyObjectToList(redisClient *c, robj *o) { 142 robj *tail; 143 144 if (c->flags & REDIS_CLOSE_AFTER_REPLY) return; 145 146 if (listLength(c->reply) == 0) { 147 incrRefCount(o); 148 listAddNodeTail(c->reply,o); 149 c->reply_bytes += zmalloc_size_sds(o->ptr); 150 } else { 151 tail = listNodeValue(listLast(c->reply)); 152 153 /* Append to this object when possible. */ 154 if (tail->ptr != NULL && 155 sdslen(tail->ptr)+sdslen(o->ptr) <= REDIS_REPLY_CHUNK_BYTES) 156 { 157 c->reply_bytes -= zmalloc_size_sds(tail->ptr); 158 tail = dupLastObjectIfNeeded(c->reply); 159 tail->ptr = sdscatlen(tail->ptr,o->ptr,sdslen(o->ptr)); 160 c->reply_bytes += zmalloc_size_sds(tail->ptr); 161 } else { 162 incrRefCount(o); 163 listAddNodeTail(c->reply,o); 164 c->reply_bytes += zmalloc_size_sds(o->ptr); 165 } 166 } 167 asyncCloseClientOnOutputBufferLimitReached(c); 168 } 169 170 /* This method takes responsibility over the sds. When it is no longer 171 * needed it will be free'd, otherwise it ends up in a robj. */ 172 void _addReplySdsToList(redisClient *c, sds s) { 173 robj *tail; 174 175 if (c->flags & REDIS_CLOSE_AFTER_REPLY) { 176 sdsfree(s); 177 return; 178 } 179 180 if (listLength(c->reply) == 0) { 181 listAddNodeTail(c->reply,createObject(REDIS_STRING,s)); 182 c->reply_bytes += zmalloc_size_sds(s); 183 } else { 184 tail = listNodeValue(listLast(c->reply)); 185 186 /* Append to this object when possible. */ 187 if (tail->ptr != NULL && 188 sdslen(tail->ptr)+sdslen(s) <= REDIS_REPLY_CHUNK_BYTES) 189 { 190 c->reply_bytes -= zmalloc_size_sds(tail->ptr); 191 tail = dupLastObjectIfNeeded(c->reply); 192 tail->ptr = sdscatlen(tail->ptr,s,sdslen(s)); 193 c->reply_bytes += zmalloc_size_sds(tail->ptr); 194 sdsfree(s); 195 } else { 196 listAddNodeTail(c->reply,createObject(REDIS_STRING,s)); 197 c->reply_bytes += zmalloc_size_sds(s); 198 } 199 } 200 asyncCloseClientOnOutputBufferLimitReached(c); 201 } 202 203 void _addReplyStringToList(redisClient *c, char *s, size_t len) { 204 robj *tail; 205 206 if (c->flags & REDIS_CLOSE_AFTER_REPLY) return; 207 208 if (listLength(c->reply) == 0) { 209 robj *o = createStringObject(s,len); 210 211 listAddNodeTail(c->reply,o); 212 c->reply_bytes += zmalloc_size_sds(o->ptr); 213 } else { 214 tail = listNodeValue(listLast(c->reply)); 215 216 /* Append to this object when possible. */ 217 if (tail->ptr != NULL && 218 sdslen(tail->ptr)+len <= REDIS_REPLY_CHUNK_BYTES) 219 { 220 c->reply_bytes -= zmalloc_size_sds(tail->ptr); 221 tail = dupLastObjectIfNeeded(c->reply); 222 tail->ptr = sdscatlen(tail->ptr,s,len); 223 c->reply_bytes += zmalloc_size_sds(tail->ptr); 224 } else { 225 robj *o = createStringObject(s,len); 226 227 listAddNodeTail(c->reply,o); 228 c->reply_bytes += zmalloc_size_sds(o->ptr); 229 } 230 } 231 asyncCloseClientOnOutputBufferLimitReached(c); 232 } 233 234 /* ----------------------------------------------------------------------------- 235 * Higher level functions to queue data on the client output buffer. 236 * The following functions are the ones that commands implementations will call. 237 * -------------------------------------------------------------------------- */ 238 239 void addReply(redisClient *c, robj *obj) { 240 if (prepareClientToWrite(c) != REDIS_OK) return; 241 242 /* This is an important place where we can avoid copy-on-write 243 * when there is a saving child running, avoiding touching the 244 * refcount field of the object if it's not needed. 245 * 246 * If the encoding is RAW and there is room in the static buffer 247 * we'll be able to send the object to the client without 248 * messing with its page. */ 249 if (obj->encoding == REDIS_ENCODING_RAW) { 250 if (_addReplyToBuffer(c,obj->ptr,sdslen(obj->ptr)) != REDIS_OK) 251 _addReplyObjectToList(c,obj); 252 } else if (obj->encoding == REDIS_ENCODING_INT) { 253 /* Optimization: if there is room in the static buffer for 32 bytes 254 * (more than the max chars a 64 bit integer can take as string) we 255 * avoid decoding the object and go for the lower level approach. */ 256 if (listLength(c->reply) == 0 && (sizeof(c->buf) - c->bufpos) >= 32) { 257 char buf[32]; 258 int len; 259 260 len = ll2string(buf,sizeof(buf),(long)obj->ptr); 261 if (_addReplyToBuffer(c,buf,len) == REDIS_OK) 262 return; 263 /* else... continue with the normal code path, but should never 264 * happen actually since we verified there is room. */ 265 } 266 obj = getDecodedObject(obj); 267 if (_addReplyToBuffer(c,obj->ptr,sdslen(obj->ptr)) != REDIS_OK) 268 _addReplyObjectToList(c,obj); 269 decrRefCount(obj); 270 } else { 271 redisPanic("Wrong obj->encoding in addReply()"); 272 } 273 } 274 275 void addReplySds(redisClient *c, sds s) { 276 if (prepareClientToWrite(c) != REDIS_OK) { 277 /* The caller expects the sds to be free'd. */ 278 sdsfree(s); 279 return; 280 } 281 if (_addReplyToBuffer(c,s,sdslen(s)) == REDIS_OK) { 282 sdsfree(s); 283 } else { 284 /* This method free's the sds when it is no longer needed. */ 285 _addReplySdsToList(c,s); 286 } 287 } 288 289 void addReplyString(redisClient *c, char *s, size_t len) { 290 if (prepareClientToWrite(c) != REDIS_OK) return; 291 if (_addReplyToBuffer(c,s,len) != REDIS_OK) 292 _addReplyStringToList(c,s,len); 293 } 294 295 void addReplyErrorLength(redisClient *c, char *s, size_t len) { 296 addReplyString(c,"-ERR ",5); 297 addReplyString(c,s,len); 298 addReplyString(c,"\r\n",2); 299 } 300 301 void addReplyError(redisClient *c, char *err) { 302 addReplyErrorLength(c,err,strlen(err)); 303 } 304 305 void addReplyErrorFormat(redisClient *c, const char *fmt, ...) { 306 size_t l, j; 307 va_list ap; 308 va_start(ap,fmt); 309 sds s = sdscatvprintf(sdsempty(),fmt,ap); 310 va_end(ap); 311 /* Make sure there are no newlines in the string, otherwise invalid protocol 312 * is emitted. */ 313 l = sdslen(s); 314 for (j = 0; j < l; j++) { 315 if (s[j] == '\r' || s[j] == '\n') s[j] = ' '; 316 } 317 addReplyErrorLength(c,s,sdslen(s)); 318 sdsfree(s); 319 } 320 321 void addReplyStatusLength(redisClient *c, char *s, size_t len) { 322 addReplyString(c,"+",1); 323 addReplyString(c,s,len); 324 addReplyString(c,"\r\n",2); 325 } 326 327 void addReplyStatus(redisClient *c, char *status) { 328 addReplyStatusLength(c,status,strlen(status)); 329 } 330 331 void addReplyStatusFormat(redisClient *c, const char *fmt, ...) { 332 va_list ap; 333 va_start(ap,fmt); 334 sds s = sdscatvprintf(sdsempty(),fmt,ap); 335 va_end(ap); 336 addReplyStatusLength(c,s,sdslen(s)); 337 sdsfree(s); 338 } 339 340 /* Adds an empty object to the reply list that will contain the multi bulk 341 * length, which is not known when this function is called. */ 342 void *addDeferredMultiBulkLength(redisClient *c) { 343 /* Note that we install the write event here even if the object is not 344 * ready to be sent, since we are sure that before returning to the 345 * event loop setDeferredMultiBulkLength() will be called. */ 346 if (prepareClientToWrite(c) != REDIS_OK) return NULL; 347 listAddNodeTail(c->reply,createObject(REDIS_STRING,NULL)); 348 return listLast(c->reply); 349 } 350 351 /* Populate the length object and try glueing it to the next chunk. */ 352 void setDeferredMultiBulkLength(redisClient *c, void *node, long length) { 353 listNode *ln = (listNode*)node; 354 robj *len, *next; 355 356 /* Abort when *node is NULL (see addDeferredMultiBulkLength). */ 357 if (node == NULL) return; 358 359 len = listNodeValue(ln); 360 len->ptr = sdscatprintf(sdsempty(),"*%ld\r\n",length); 361 c->reply_bytes += zmalloc_size_sds(len->ptr); 362 if (ln->next != NULL) { 363 next = listNodeValue(ln->next); 364 365 /* Only glue when the next node is non-NULL (an sds in this case) */ 366 if (next->ptr != NULL) { 367 len->ptr = sdscatlen(len->ptr,next->ptr,sdslen(next->ptr)); 368 listDelNode(c->reply,ln->next); 369 } 370 } 371 asyncCloseClientOnOutputBufferLimitReached(c); 372 } 373 374 /* Add a duble as a bulk reply */ 375 void addReplyDouble(redisClient *c, double d) { 376 char dbuf[128], sbuf[128]; 377 int dlen, slen; 378 dlen = snprintf(dbuf,sizeof(dbuf),"%.17g",d); 379 slen = snprintf(sbuf,sizeof(sbuf),"$%d\r\n%s\r\n",dlen,dbuf); 380 addReplyString(c,sbuf,slen); 381 } 382 383 /* Add a long long as integer reply or bulk len / multi bulk count. 384 * Basically this is used to output <prefix><long long><crlf>. */ 385 void addReplyLongLongWithPrefix(redisClient *c, long long ll, char prefix) { 386 char buf[128]; 387 int len; 388 389 /* Things like $3\r\n or *2\r\n are emitted very often by the protocol 390 * so we have a few shared objects to use if the integer is small 391 * like it is most of the times. */ 392 if (prefix == '*' && ll < REDIS_SHARED_BULKHDR_LEN) { 393 addReply(c,shared.mbulkhdr[ll]); 394 return; 395 } else if (prefix == '$' && ll < REDIS_SHARED_BULKHDR_LEN) { 396 addReply(c,shared.bulkhdr[ll]); 397 return; 398 } 399 400 buf[0] = prefix; 401 len = ll2string(buf+1,sizeof(buf)-1,ll); 402 buf[len+1] = '\r'; 403 buf[len+2] = '\n'; 404 addReplyString(c,buf,len+3); 405 } 406 407 void addReplyLongLong(redisClient *c, long long ll) { 408 if (ll == 0) 409 addReply(c,shared.czero); 410 else if (ll == 1) 411 addReply(c,shared.cone); 412 else 413 addReplyLongLongWithPrefix(c,ll,':'); 414 } 415 416 void addReplyMultiBulkLen(redisClient *c, long length) { 417 addReplyLongLongWithPrefix(c,length,'*'); 418 } 419 420 /* Create the length prefix of a bulk reply, example: $2234 */ 421 void addReplyBulkLen(redisClient *c, robj *obj) { 422 size_t len; 423 424 if (obj->encoding == REDIS_ENCODING_RAW) { 425 len = sdslen(obj->ptr); 426 } else { 427 long n = (long)obj->ptr; 428 429 /* Compute how many bytes will take this integer as a radix 10 string */ 430 len = 1; 431 if (n < 0) { 432 len++; 433 n = -n; 434 } 435 while((n = n/10) != 0) { 436 len++; 437 } 438 } 439 addReplyLongLongWithPrefix(c,len,'$'); 440 } 441 442 /* Add a Redis Object as a bulk reply */ 443 void addReplyBulk(redisClient *c, robj *obj) { 444 addReplyBulkLen(c,obj); 445 addReply(c,obj); 446 addReply(c,shared.crlf); 447 } 448 449 /* Add a C buffer as bulk reply */ 450 void addReplyBulkCBuffer(redisClient *c, void *p, size_t len) { 451 addReplyLongLongWithPrefix(c,len,'$'); 452 addReplyString(c,p,len); 453 addReply(c,shared.crlf); 454 } 455 456 /* Add a C nul term string as bulk reply */ 457 void addReplyBulkCString(redisClient *c, char *s) { 458 if (s == NULL) { 459 addReply(c,shared.nullbulk); 460 } else { 461 addReplyBulkCBuffer(c,s,strlen(s)); 462 } 463 } 464 465 /* Add a long long as a bulk reply */ 466 void addReplyBulkLongLong(redisClient *c, long long ll) { 467 char buf[64]; 468 int len; 469 470 len = ll2string(buf,64,ll); 471 addReplyBulkCBuffer(c,buf,len); 472 } 473 474 /* Copy 'src' client output buffers into 'dst' client output buffers. 475 * The function takes care of freeing the old output buffers of the 476 * destination client. */ 477 void copyClientOutputBuffer(redisClient *dst, redisClient *src) { 478 listRelease(dst->reply); 479 dst->reply = listDup(src->reply); 480 memcpy(dst->buf,src->buf,src->bufpos); 481 dst->bufpos = src->bufpos; 482 dst->reply_bytes = src->reply_bytes; 483 } 484 485 static void acceptCommonHandler(int fd) { 486 redisClient *c; 487 if ((c = createClient(fd)) == NULL) { 488 redisLog(REDIS_WARNING,"Error allocating resoures for the client"); 489 close(fd); /* May be already closed, just ingore errors */ 490 return; 491 } 492 /* If maxclient directive is set and this is one client more... close the 493 * connection. Note that we create the client instead to check before 494 * for this condition, since now the socket is already set in nonblocking 495 * mode and we can send an error for free using the Kernel I/O */ 496 if (listLength(server.clients) > server.maxclients) { 497 char *err = "-ERR max number of clients reached\r\n"; 498 499 /* That's a best effort error message, don't check write errors */ 500 if (write(c->fd,err,strlen(err)) == -1) { 501 /* Nothing to do, Just to avoid the warning... */ 502 } 503 server.stat_rejected_conn++; 504 freeClient(c); 505 return; 506 } 507 server.stat_numconnections++; 508 } 509 510 void acceptTcpHandler(aeEventLoop *el, int fd, void *privdata, int mask) { 511 int cport, cfd; 512 char cip[128]; 513 REDIS_NOTUSED(el); 514 REDIS_NOTUSED(mask); 515 REDIS_NOTUSED(privdata); 516 517 cfd = anetTcpAccept(server.neterr, fd, cip, &cport); 518 if (cfd == AE_ERR) { 519 redisLog(REDIS_WARNING,"Accepting client connection: %s", server.neterr); 520 return; 521 } 522 redisLog(REDIS_VERBOSE,"Accepted %s:%d", cip, cport); 523 acceptCommonHandler(cfd); 524 } 525 526 void acceptUnixHandler(aeEventLoop *el, int fd, void *privdata, int mask) { 527 int cfd; 528 REDIS_NOTUSED(el); 529 REDIS_NOTUSED(mask); 530 REDIS_NOTUSED(privdata); 531 532 cfd = anetUnixAccept(server.neterr, fd); 533 if (cfd == AE_ERR) { 534 redisLog(REDIS_WARNING,"Accepting client connection: %s", server.neterr); 535 return; 536 } 537 redisLog(REDIS_VERBOSE,"Accepted connection to %s", server.unixsocket); 538 acceptCommonHandler(cfd); 539 } 540 541 542 static void freeClientArgv(redisClient *c) { 543 int j; 544 for (j = 0; j < c->argc; j++) 545 decrRefCount(c->argv[j]); 546 c->argc = 0; 547 c->cmd = NULL; 548 } 549 550 void freeClient(redisClient *c) { 551 listNode *ln; 552 553 /* If this is marked as current client unset it */ 554 if (server.current_client == c) server.current_client = NULL; 555 556 /* Note that if the client we are freeing is blocked into a blocking 557 * call, we have to set querybuf to NULL *before* to call 558 * unblockClientWaitingData() to avoid processInputBuffer() will get 559 * called. Also it is important to remove the file events after 560 * this, because this call adds the READABLE event. */ 561 sdsfree(c->querybuf); 562 c->querybuf = NULL; 563 if (c->flags & REDIS_BLOCKED) 564 unblockClientWaitingData(c); 565 566 /* UNWATCH all the keys */ 567 unwatchAllKeys(c); 568 listRelease(c->watched_keys); 569 /* Unsubscribe from all the pubsub channels */ 570 pubsubUnsubscribeAllChannels(c,0); 571 pubsubUnsubscribeAllPatterns(c,0); 572 dictRelease(c->pubsub_channels); 573 listRelease(c->pubsub_patterns); 574 /* Obvious cleanup */ 575 aeDeleteFileEvent(server.el,c->fd,AE_READABLE); 576 aeDeleteFileEvent(server.el,c->fd,AE_WRITABLE); 577 listRelease(c->reply); 578 freeClientArgv(c); 579 close(c->fd); 580 /* Remove from the list of clients */ 581 ln = listSearchKey(server.clients,c); 582 redisAssert(ln != NULL); 583 listDelNode(server.clients,ln); 584 /* When client was just unblocked because of a blocking operation, 585 * remove it from the list with unblocked clients. */ 586 if (c->flags & REDIS_UNBLOCKED) { 587 ln = listSearchKey(server.unblocked_clients,c); 588 redisAssert(ln != NULL); 589 listDelNode(server.unblocked_clients,ln); 590 } 591 listRelease(c->io_keys); 592 /* Master/slave cleanup. 593 * Case 1: we lost the connection with a slave. */ 594 if (c->flags & REDIS_SLAVE) { 595 if (c->replstate == REDIS_REPL_SEND_BULK && c->repldbfd != -1) 596 close(c->repldbfd); 597 list *l = (c->flags & REDIS_MONITOR) ? server.monitors : server.slaves; 598 ln = listSearchKey(l,c); 599 redisAssert(ln != NULL); 600 listDelNode(l,ln); 601 } 602 603 /* Case 2: we lost the connection with the master. */ 604 if (c->flags & REDIS_MASTER) { 605 server.master = NULL; 606 server.repl_state = REDIS_REPL_CONNECT; 607 server.repl_down_since = time(NULL); 608 /* Since we lost the connection with the master, we should also 609 * close the connection with all our slaves if we have any, so 610 * when we'll resync with the master the other slaves will sync again 611 * with us as well. Note that also when the slave is not connected 612 * to the master it will keep refusing connections by other slaves. 613 * 614 * We do this only if server.masterhost != NULL. If it is NULL this 615 * means the user called SLAVEOF NO ONE and we are freeing our 616 * link with the master, so no need to close link with slaves. */ 617 if (server.masterhost != NULL) { 618 while (listLength(server.slaves)) { 619 ln = listFirst(server.slaves); 620 freeClient((redisClient*)ln->value); 621 } 622 } 623 } 624 625 /* If this client was scheduled for async freeing we need to remove it 626 * from the queue. */ 627 if (c->flags & REDIS_CLOSE_ASAP) { 628 ln = listSearchKey(server.clients_to_close,c); 629 redisAssert(ln != NULL); 630 listDelNode(server.clients_to_close,ln); 631 } 632 633 /* Release memory */ 634 zfree(c->argv); 635 freeClientMultiState(c); 636 zfree(c); 637 } 638 639 /* Schedule a client to free it at a safe time in the serverCron() function. 640 * This function is useful when we need to terminate a client but we are in 641 * a context where calling freeClient() is not possible, because the client 642 * should be valid for the continuation of the flow of the program. */ 643 void freeClientAsync(redisClient *c) { 644 if (c->flags & REDIS_CLOSE_ASAP) return; 645 c->flags |= REDIS_CLOSE_ASAP; 646 listAddNodeTail(server.clients_to_close,c); 647 } 648 649 void freeClientsInAsyncFreeQueue(void) { 650 while (listLength(server.clients_to_close)) { 651 listNode *ln = listFirst(server.clients_to_close); 652 redisClient *c = listNodeValue(ln); 653 654 c->flags &= ~REDIS_CLOSE_ASAP; 655 freeClient(c); 656 listDelNode(server.clients_to_close,ln); 657 } 658 } 659 660 void sendReplyToClient(aeEventLoop *el, int fd, void *privdata, int mask) { 661 redisClient *c = privdata; 662 int nwritten = 0, totwritten = 0, objlen; 663 size_t objmem; 664 robj *o; 665 REDIS_NOTUSED(el); 666 REDIS_NOTUSED(mask); 667 668 while(c->bufpos > 0 || listLength(c->reply)) { 669 if (c->bufpos > 0) { 670 if (c->flags & REDIS_MASTER) { 671 /* Don't reply to a master */ 672 nwritten = c->bufpos - c->sentlen; 673 } else { 674 nwritten = write(fd,c->buf+c->sentlen,c->bufpos-c->sentlen); 675 if (nwritten <= 0) break; 676 } 677 c->sentlen += nwritten; 678 totwritten += nwritten; 679 680 /* If the buffer was sent, set bufpos to zero to continue with 681 * the remainder of the reply. */ 682 if (c->sentlen == c->bufpos) { 683 c->bufpos = 0; 684 c->sentlen = 0; 685 } 686 } else { 687 o = listNodeValue(listFirst(c->reply)); 688 objlen = sdslen(o->ptr); 689 objmem = zmalloc_size_sds(o->ptr); 690 691 if (objlen == 0) { 692 listDelNode(c->reply,listFirst(c->reply)); 693 continue; 694 } 695 696 if (c->flags & REDIS_MASTER) { 697 /* Don't reply to a master */ 698 nwritten = objlen - c->sentlen; 699 } else { 700 nwritten = write(fd, ((char*)o->ptr)+c->sentlen,objlen-c->sentlen); 701 if (nwritten <= 0) break; 702 } 703 c->sentlen += nwritten; 704 totwritten += nwritten; 705 706 /* If we fully sent the object on head go to the next one */ 707 if (c->sentlen == objlen) { 708 listDelNode(c->reply,listFirst(c->reply)); 709 c->sentlen = 0; 710 c->reply_bytes -= objmem; 711 } 712 } 713 /* Note that we avoid to send more than REDIS_MAX_WRITE_PER_EVENT 714 * bytes, in a single threaded server it's a good idea to serve 715 * other clients as well, even if a very large request comes from 716 * super fast link that is always able to accept data (in real world 717 * scenario think about 'KEYS *' against the loopback interface). 718 * 719 * However if we are over the maxmemory limit we ignore that and 720 * just deliver as much data as it is possible to deliver. */ 721 if (totwritten > REDIS_MAX_WRITE_PER_EVENT && 722 (server.maxmemory == 0 || 723 zmalloc_used_memory() < server.maxmemory)) break; 724 } 725 if (nwritten == -1) { 726 if (errno == EAGAIN) { 727 nwritten = 0; 728 } else { 729 redisLog(REDIS_VERBOSE, 730 "Error writing to client: %s", strerror(errno)); 731 freeClient(c); 732 return; 733 } 734 } 735 if (totwritten > 0) c->lastinteraction = time(NULL); 736 if (c->bufpos == 0 && listLength(c->reply) == 0) { 737 c->sentlen = 0; 738 aeDeleteFileEvent(server.el,c->fd,AE_WRITABLE); 739 740 /* Close connection after entire reply has been sent. */ 741 if (c->flags & REDIS_CLOSE_AFTER_REPLY) freeClient(c); 742 } 743 } 744 745 /* resetClient prepare the client to process the next command */ 746 void resetClient(redisClient *c) { 747 freeClientArgv(c); 748 c->reqtype = 0; 749 c->multibulklen = 0; 750 c->bulklen = -1; 751 /* We clear the ASKING flag as well if we are not inside a MULTI. */ 752 if (!(c->flags & REDIS_MULTI)) c->flags &= (~REDIS_ASKING); 753 } 754 755 int processInlineBuffer(redisClient *c) { 756 char *newline = strstr(c->querybuf,"\r\n"); 757 int argc, j; 758 sds *argv; 759 size_t querylen; 760 761 /* Nothing to do without a \r\n */ 762 if (newline == NULL) { 763 if (sdslen(c->querybuf) > REDIS_INLINE_MAX_SIZE) { 764 addReplyError(c,"Protocol error: too big inline request"); 765 setProtocolError(c,0); 766 } 767 return REDIS_ERR; 768 } 769 770 /* Split the input buffer up to the \r\n */ 771 querylen = newline-(c->querybuf); 772 argv = sdssplitlen(c->querybuf,querylen," ",1,&argc); 773 774 /* Leave data after the first line of the query in the buffer */ 775 c->querybuf = sdsrange(c->querybuf,querylen+2,-1); 776 777 /* Setup argv array on client structure */ 778 if (c->argv) zfree(c->argv); 779 c->argv = zmalloc(sizeof(robj*)*argc); 780 781 /* Create redis objects for all arguments. */ 782 for (c->argc = 0, j = 0; j < argc; j++) { 783 if (sdslen(argv[j])) { 784 c->argv[c->argc] = createObject(REDIS_STRING,argv[j]); 785 c->argc++; 786 } else { 787 sdsfree(argv[j]); 788 } 789 } 790 zfree(argv); 791 return REDIS_OK; 792 } 793 794 /* Helper function. Trims query buffer to make the function that processes 795 * multi bulk requests idempotent. */ 796 static void setProtocolError(redisClient *c, int pos) { 797 if (server.verbosity >= REDIS_VERBOSE) { 798 sds client = getClientInfoString(c); 799 redisLog(REDIS_VERBOSE, 800 "Protocol error from client: %s", client); 801 sdsfree(client); 802 } 803 c->flags |= REDIS_CLOSE_AFTER_REPLY; 804 c->querybuf = sdsrange(c->querybuf,pos,-1); 805 } 806 807 int processMultibulkBuffer(redisClient *c) { 808 char *newline = NULL; 809 int pos = 0, ok; 810 long long ll; 811 812 if (c->multibulklen == 0) { 813 /* The client should have been reset */ 814 redisAssertWithInfo(c,NULL,c->argc == 0); 815 816 /* Multi bulk length cannot be read without a \r\n */ 817 newline = strchr(c->querybuf,'\r'); 818 if (newline == NULL) { 819 if (sdslen(c->querybuf) > REDIS_INLINE_MAX_SIZE) { 820 addReplyError(c,"Protocol error: too big mbulk count string"); 821 setProtocolError(c,0); 822 } 823 return REDIS_ERR; 824 } 825 826 /* Buffer should also contain \n */ 827 if (newline-(c->querybuf) > ((signed)sdslen(c->querybuf)-2)) 828 return REDIS_ERR; 829 830 /* We know for sure there is a whole line since newline != NULL, 831 * so go ahead and find out the multi bulk length. */ 832 redisAssertWithInfo(c,NULL,c->querybuf[0] == '*'); 833 ok = string2ll(c->querybuf+1,newline-(c->querybuf+1),&ll); 834 if (!ok || ll > 1024*1024) { 835 addReplyError(c,"Protocol error: invalid multibulk length"); 836 setProtocolError(c,pos); 837 return REDIS_ERR; 838 } 839 840 pos = (newline-c->querybuf)+2; 841 if (ll <= 0) { 842 c->querybuf = sdsrange(c->querybuf,pos,-1); 843 return REDIS_OK; 844 } 845 846 c->multibulklen = ll; 847 848 /* Setup argv array on client structure */ 849 if (c->argv) zfree(c->argv); 850 c->argv = zmalloc(sizeof(robj*)*c->multibulklen); 851 } 852 853 redisAssertWithInfo(c,NULL,c->multibulklen > 0); 854 while(c->multibulklen) { 855 /* Read bulk length if unknown */ 856 if (c->bulklen == -1) { 857 newline = strchr(c->querybuf+pos,'\r'); 858 if (newline == NULL) { 859 if (sdslen(c->querybuf) > REDIS_INLINE_MAX_SIZE) { 860 addReplyError(c,"Protocol error: too big bulk count string"); 861 setProtocolError(c,0); 862 } 863 break; 864 } 865 866 /* Buffer should also contain \n */ 867 if (newline-(c->querybuf) > ((signed)sdslen(c->querybuf)-2)) 868 break; 869 870 if (c->querybuf[pos] != '$') { 871 addReplyErrorFormat(c, 872 "Protocol error: expected '$', got '%c'", 873 c->querybuf[pos]); 874 setProtocolError(c,pos); 875 return REDIS_ERR; 876 } 877 878 ok = string2ll(c->querybuf+pos+1,newline-(c->querybuf+pos+1),&ll); 879 if (!ok || ll < 0 || ll > 512*1024*1024) { 880 addReplyError(c,"Protocol error: invalid bulk length"); 881 setProtocolError(c,pos); 882 return REDIS_ERR; 883 } 884 885 pos += newline-(c->querybuf+pos)+2; 886 if (ll >= REDIS_MBULK_BIG_ARG) { 887 /* If we are going to read a large object from network 888 * try to make it likely that it will start at c->querybuf 889 * boundary so that we can optimized object creation 890 * avoiding a large copy of data. */ 891 c->querybuf = sdsrange(c->querybuf,pos,-1); 892 pos = 0; 893 /* Hint the sds library about the amount of bytes this string is 894 * going to contain. */ 895 c->querybuf = sdsMakeRoomFor(c->querybuf,ll+2); 896 } 897 c->bulklen = ll; 898 } 899 900 /* Read bulk argument */ 901 if (sdslen(c->querybuf)-pos < (unsigned)(c->bulklen+2)) { 902 /* Not enough data (+2 == trailing \r\n) */ 903 break; 904 } else { 905 /* Optimization: if the buffer contanins JUST our bulk element 906 * instead of creating a new object by *copying* the sds we 907 * just use the current sds string. */ 908 if (pos == 0 && 909 c->bulklen >= REDIS_MBULK_BIG_ARG && 910 (signed) sdslen(c->querybuf) == c->bulklen+2) 911 { 912 c->argv[c->argc++] = createObject(REDIS_STRING,c->querybuf); 913 sdsIncrLen(c->querybuf,-2); /* remove CRLF */ 914 c->querybuf = sdsempty(); 915 /* Assume that if we saw a fat argument we'll see another one 916 * likely... */ 917 c->querybuf = sdsMakeRoomFor(c->querybuf,c->bulklen+2); 918 pos = 0; 919 } else { 920 c->argv[c->argc++] = 921 createStringObject(c->querybuf+pos,c->bulklen); 922 pos += c->bulklen+2; 923 } 924 c->bulklen = -1; 925 c->multibulklen--; 926 } 927 } 928 929 /* Trim to pos */ 930 if (pos) c->querybuf = sdsrange(c->querybuf,pos,-1); 931 932 /* We're done when c->multibulk == 0 */ 933 if (c->multibulklen == 0) return REDIS_OK; 934 935 /* Still not read to process the command */ 936 return REDIS_ERR; 937 } 938 939 void processInputBuffer(redisClient *c) { 940 /* Keep processing while there is something in the input buffer */ 941 while(sdslen(c->querybuf)) { 942 /* Immediately abort if the client is in the middle of something. */ 943 if (c->flags & REDIS_BLOCKED) return; 944 945 /* REDIS_CLOSE_AFTER_REPLY closes the connection once the reply is 946 * written to the client. Make sure to not let the reply grow after 947 * this flag has been set (i.e. don't process more commands). */ 948 if (c->flags & REDIS_CLOSE_AFTER_REPLY) return; 949 950 /* Determine request type when unknown. */ 951 if (!c->reqtype) { 952 if (c->querybuf[0] == '*') { 953 c->reqtype = REDIS_REQ_MULTIBULK; 954 } else { 955 c->reqtype = REDIS_REQ_INLINE; 956 } 957 } 958 959 if (c->reqtype == REDIS_REQ_INLINE) { 960 if (processInlineBuffer(c) != REDIS_OK) break; 961 } else if (c->reqtype == REDIS_REQ_MULTIBULK) { 962 if (processMultibulkBuffer(c) != REDIS_OK) break; 963 } else { 964 redisPanic("Unknown request type"); 965 } 966 967 /* Multibulk processing could see a <= 0 length. */ 968 if (c->argc == 0) { 969 resetClient(c); 970 } else { 971 /* Only reset the client when the command was executed. */ 972 if (processCommand(c) == REDIS_OK) 973 resetClient(c); 974 } 975 } 976 } 977 978 void readQueryFromClient(aeEventLoop *el, int fd, void *privdata, int mask) { 979 redisClient *c = (redisClient*) privdata; 980 int nread, readlen; 981 size_t qblen; 982 REDIS_NOTUSED(el); 983 REDIS_NOTUSED(mask); 984 985 server.current_client = c; 986 readlen = REDIS_IOBUF_LEN; 987 /* If this is a multi bulk request, and we are processing a bulk reply 988 * that is large enough, try to maximize the probabilty that the query 989 * buffer contains excatly the SDS string representing the object, even 990 * at the risk of requring more read(2) calls. This way the function 991 * processMultiBulkBuffer() can avoid copying buffers to create the 992 * Redis Object representing the argument. */ 993 if (c->reqtype == REDIS_REQ_MULTIBULK && c->multibulklen && c->bulklen != -1 994 && c->bulklen >= REDIS_MBULK_BIG_ARG) 995 { 996 int remaining = (unsigned)(c->bulklen+2)-sdslen(c->querybuf); 997 998 if (remaining < readlen) readlen = remaining; 999 } 1000 1001 qblen = sdslen(c->querybuf); 1002 if (c->querybuf_peak < qblen) c->querybuf_peak = qblen; 1003 c->querybuf = sdsMakeRoomFor(c->querybuf, readlen); 1004 nread = read(fd, c->querybuf+qblen, readlen); 1005 if (nread == -1) { 1006 if (errno == EAGAIN) { 1007 nread = 0; 1008 } else { 1009 redisLog(REDIS_VERBOSE, "Reading from client: %s",strerror(errno)); 1010 freeClient(c); 1011 return; 1012 } 1013 } else if (nread == 0) { 1014 redisLog(REDIS_VERBOSE, "Client closed connection"); 1015 freeClient(c); 1016 return; 1017 } 1018 if (nread) { 1019 sdsIncrLen(c->querybuf,nread); 1020 c->lastinteraction = time(NULL); 1021 } else { 1022 server.current_client = NULL; 1023 return; 1024 } 1025 if (sdslen(c->querybuf) > server.client_max_querybuf_len) { 1026 sds ci = getClientInfoString(c), bytes = sdsempty(); 1027 1028 bytes = sdscatrepr(bytes,c->querybuf,64); 1029 redisLog(REDIS_WARNING,"Closing client that reached max query buffer length: %s (qbuf initial bytes: %s)", ci, bytes); 1030 sdsfree(ci); 1031 sdsfree(bytes); 1032 freeClient(c); 1033 return; 1034 } 1035 processInputBuffer(c); 1036 server.current_client = NULL; 1037 } 1038 1039 void getClientsMaxBuffers(unsigned long *longest_output_list, 1040 unsigned long *biggest_input_buffer) { 1041 redisClient *c; 1042 listNode *ln; 1043 listIter li; 1044 unsigned long lol = 0, bib = 0; 1045 1046 listRewind(server.clients,&li); 1047 while ((ln = listNext(&li)) != NULL) { 1048 c = listNodeValue(ln); 1049 1050 if (listLength(c->reply) > lol) lol = listLength(c->reply); 1051 if (sdslen(c->querybuf) > bib) bib = sdslen(c->querybuf); 1052 } 1053 *longest_output_list = lol; 1054 *biggest_input_buffer = bib; 1055 } 1056 1057 /* Turn a Redis client into an sds string representing its state. */ 1058 sds getClientInfoString(redisClient *client) { 1059 char ip[32], flags[16], events[3], *p; 1060 int port; 1061 time_t now = time(NULL); 1062 int emask; 1063 1064 anetPeerToString(client->fd,ip,&port); 1065 p = flags; 1066 if (client->flags & REDIS_SLAVE) { 1067 if (client->flags & REDIS_MONITOR) 1068 *p++ = 'O'; 1069 else 1070 *p++ = 'S'; 1071 } 1072 if (client->flags & REDIS_MASTER) *p++ = 'M'; 1073 if (client->flags & REDIS_MULTI) *p++ = 'x'; 1074 if (client->flags & REDIS_BLOCKED) *p++ = 'b'; 1075 if (client->flags & REDIS_DIRTY_CAS) *p++ = 'd'; 1076 if (client->flags & REDIS_CLOSE_AFTER_REPLY) *p++ = 'c'; 1077 if (client->flags & REDIS_UNBLOCKED) *p++ = 'u'; 1078 if (client->flags & REDIS_CLOSE_ASAP) *p++ = 'A'; 1079 if (p == flags) *p++ = 'N'; 1080 *p++ = '\0'; 1081 1082 emask = client->fd == -1 ? 0 : aeGetFileEvents(server.el,client->fd); 1083 p = events; 1084 if (emask & AE_READABLE) *p++ = 'r'; 1085 if (emask & AE_WRITABLE) *p++ = 'w'; 1086 *p = '\0'; 1087 return sdscatprintf(sdsempty(), 1088 "addr=%s:%d fd=%d age=%ld idle=%ld flags=%s db=%d sub=%d psub=%d qbuf=%lu qbuf-free=%lu obl=%lu oll=%lu omem=%lu events=%s cmd=%s", 1089 ip,port,client->fd, 1090 (long)(now - client->ctime), 1091 (long)(now - client->lastinteraction), 1092 flags, 1093 client->db->id, 1094 (int) dictSize(client->pubsub_channels), 1095 (int) listLength(client->pubsub_patterns), 1096 (unsigned long) sdslen(client->querybuf), 1097 (unsigned long) sdsavail(client->querybuf), 1098 (unsigned long) client->bufpos, 1099 (unsigned long) listLength(client->reply), 1100 getClientOutputBufferMemoryUsage(client), 1101 events, 1102 client->lastcmd ? client->lastcmd->name : "NULL"); 1103 } 1104 1105 sds getAllClientsInfoString(void) { 1106 listNode *ln; 1107 listIter li; 1108 redisClient *client; 1109 sds o = sdsempty(); 1110 1111 listRewind(server.clients,&li); 1112 while ((ln = listNext(&li)) != NULL) { 1113 sds cs; 1114 1115 client = listNodeValue(ln); 1116 cs = getClientInfoString(client); 1117 o = sdscatsds(o,cs); 1118 sdsfree(cs); 1119 o = sdscatlen(o,"\n",1); 1120 } 1121 return o; 1122 } 1123 1124 void clientCommand(redisClient *c) { 1125 listNode *ln; 1126 listIter li; 1127 redisClient *client; 1128 1129 if (!strcasecmp(c->argv[1]->ptr,"list") && c->argc == 2) { 1130 sds o = getAllClientsInfoString(); 1131 addReplyBulkCBuffer(c,o,sdslen(o)); 1132 sdsfree(o); 1133 } else if (!strcasecmp(c->argv[1]->ptr,"kill") && c->argc == 3) { 1134 listRewind(server.clients,&li); 1135 while ((ln = listNext(&li)) != NULL) { 1136 char ip[32], addr[64]; 1137 int port; 1138 1139 client = listNodeValue(ln); 1140 if (anetPeerToString(client->fd,ip,&port) == -1) continue; 1141 snprintf(addr,sizeof(addr),"%s:%d",ip,port); 1142 if (strcmp(addr,c->argv[2]->ptr) == 0) { 1143 addReply(c,shared.ok); 1144 if (c == client) { 1145 client->flags |= REDIS_CLOSE_AFTER_REPLY; 1146 } else { 1147 freeClient(client); 1148 } 1149 return; 1150 } 1151 } 1152 addReplyError(c,"No such client"); 1153 } else { 1154 addReplyError(c, "Syntax error, try CLIENT (LIST | KILL ip:port)"); 1155 } 1156 } 1157 1158 /* Rewrite the command vector of the client. All the new objects ref count 1159 * is incremented. The old command vector is freed, and the old objects 1160 * ref count is decremented. */ 1161 void rewriteClientCommandVector(redisClient *c, int argc, ...) { 1162 va_list ap; 1163 int j; 1164 robj **argv; /* The new argument vector */ 1165 1166 argv = zmalloc(sizeof(robj*)*argc); 1167 va_start(ap,argc); 1168 for (j = 0; j < argc; j++) { 1169 robj *a; 1170 1171 a = va_arg(ap, robj*); 1172 argv[j] = a; 1173 incrRefCount(a); 1174 } 1175 /* We free the objects in the original vector at the end, so we are 1176 * sure that if the same objects are reused in the new vector the 1177 * refcount gets incremented before it gets decremented. */ 1178 for (j = 0; j < c->argc; j++) decrRefCount(c->argv[j]); 1179 zfree(c->argv); 1180 /* Replace argv and argc with our new versions. */ 1181 c->argv = argv; 1182 c->argc = argc; 1183 c->cmd = lookupCommand(c->argv[0]->ptr); 1184 redisAssertWithInfo(c,NULL,c->cmd != NULL); 1185 va_end(ap); 1186 } 1187 1188 /* Rewrite a single item in the command vector. 1189 * The new val ref count is incremented, and the old decremented. */ 1190 void rewriteClientCommandArgument(redisClient *c, int i, robj *newval) { 1191 robj *oldval; 1192 1193 redisAssertWithInfo(c,NULL,i < c->argc); 1194 oldval = c->argv[i]; 1195 c->argv[i] = newval; 1196 incrRefCount(newval); 1197 decrRefCount(oldval); 1198 1199 /* If this is the command name make sure to fix c->cmd. */ 1200 if (i == 0) { 1201 c->cmd = lookupCommand(c->argv[0]->ptr); 1202 redisAssertWithInfo(c,NULL,c->cmd != NULL); 1203 } 1204 } 1205 1206 /* This function returns the number of bytes that Redis is virtually 1207 * using to store the reply still not read by the client. 1208 * It is "virtual" since the reply output list may contain objects that 1209 * are shared and are not really using additional memory. 1210 * 1211 * The function returns the total sum of the length of all the objects 1212 * stored in the output list, plus the memory used to allocate every 1213 * list node. The static reply buffer is not taken into account since it 1214 * is allocated anyway. 1215 * 1216 * Note: this function is very fast so can be called as many time as 1217 * the caller wishes. The main usage of this function currently is 1218 * enforcing the client output length limits. */ 1219 unsigned long getClientOutputBufferMemoryUsage(redisClient *c) { 1220 unsigned long list_item_size = sizeof(listNode)+sizeof(robj); 1221 1222 return c->reply_bytes + (list_item_size*listLength(c->reply)); 1223 } 1224 1225 /* Get the class of a client, used in order to envorce limits to different 1226 * classes of clients. 1227 * 1228 * The function will return one of the following: 1229 * REDIS_CLIENT_LIMIT_CLASS_NORMAL -> Normal client 1230 * REDIS_CLIENT_LIMIT_CLASS_SLAVE -> Slave or client executing MONITOR command 1231 * REDIS_CLIENT_LIMIT_CLASS_PUBSUB -> Client subscribed to Pub/Sub channels 1232 */ 1233 int getClientLimitClass(redisClient *c) { 1234 if (c->flags & REDIS_SLAVE) return REDIS_CLIENT_LIMIT_CLASS_SLAVE; 1235 if (dictSize(c->pubsub_channels) || listLength(c->pubsub_patterns)) 1236 return REDIS_CLIENT_LIMIT_CLASS_PUBSUB; 1237 return REDIS_CLIENT_LIMIT_CLASS_NORMAL; 1238 } 1239 1240 int getClientLimitClassByName(char *name) { 1241 if (!strcasecmp(name,"normal")) return REDIS_CLIENT_LIMIT_CLASS_NORMAL; 1242 else if (!strcasecmp(name,"slave")) return REDIS_CLIENT_LIMIT_CLASS_SLAVE; 1243 else if (!strcasecmp(name,"pubsub")) return REDIS_CLIENT_LIMIT_CLASS_PUBSUB; 1244 else return -1; 1245 } 1246 1247 char *getClientLimitClassName(int class) { 1248 switch(class) { 1249 case REDIS_CLIENT_LIMIT_CLASS_NORMAL: return "normal"; 1250 case REDIS_CLIENT_LIMIT_CLASS_SLAVE: return "slave"; 1251 case REDIS_CLIENT_LIMIT_CLASS_PUBSUB: return "pubsub"; 1252 default: return NULL; 1253 } 1254 } 1255 1256 /* The function checks if the client reached output buffer soft or hard 1257 * limit, and also update the state needed to check the soft limit as 1258 * a side effect. 1259 * 1260 * Return value: non-zero if the client reached the soft or the hard limit. 1261 * Otherwise zero is returned. */ 1262 int checkClientOutputBufferLimits(redisClient *c) { 1263 int soft = 0, hard = 0, class; 1264 unsigned long used_mem = getClientOutputBufferMemoryUsage(c); 1265 1266 class = getClientLimitClass(c); 1267 if (server.client_obuf_limits[class].hard_limit_bytes && 1268 used_mem >= server.client_obuf_limits[class].hard_limit_bytes) 1269 hard = 1; 1270 if (server.client_obuf_limits[class].soft_limit_bytes && 1271 used_mem >= server.client_obuf_limits[class].soft_limit_bytes) 1272 soft = 1; 1273 1274 /* We need to check if the soft limit is reached continuously for the 1275 * specified amount of seconds. */ 1276 if (soft) { 1277 if (c->obuf_soft_limit_reached_time == 0) { 1278 c->obuf_soft_limit_reached_time = server.unixtime; 1279 soft = 0; /* First time we see the soft limit reached */ 1280 } else { 1281 time_t elapsed = server.unixtime - c->obuf_soft_limit_reached_time; 1282 1283 if (elapsed <= 1284 server.client_obuf_limits[class].soft_limit_seconds) { 1285 soft = 0; /* The client still did not reached the max number of 1286 seconds for the soft limit to be considered 1287 reached. */ 1288 } 1289 } 1290 } else { 1291 c->obuf_soft_limit_reached_time = 0; 1292 } 1293 return soft || hard; 1294 } 1295 1296 /* Asynchronously close a client if soft or hard limit is reached on the 1297 * output buffer size. The caller can check if the client will be closed 1298 * checking if the client REDIS_CLOSE_ASAP flag is set. 1299 * 1300 * Note: we need to close the client asynchronously because this function is 1301 * called from contexts where the client can't be freed safely, i.e. from the 1302 * lower level functions pushing data inside the client output buffers. */ 1303 void asyncCloseClientOnOutputBufferLimitReached(redisClient *c) { 1304 if (c->reply_bytes == 0 || c->flags & REDIS_CLOSE_ASAP) return; 1305 if (checkClientOutputBufferLimits(c)) { 1306 sds client = getClientInfoString(c); 1307 1308 freeClientAsync(c); 1309 redisLog(REDIS_WARNING,"Client %s scheduled to be closed ASAP for overcoming of output buffer limits.", client); 1310 sdsfree(client); 1311 } 1312 } 1313 1314 /* Helper function used by freeMemoryIfNeeded() in order to flush slaves 1315 * output buffers without returning control to the event loop. */ 1316 void flushSlavesOutputBuffers(void) { 1317 listIter li; 1318 listNode *ln; 1319 1320 listRewind(server.slaves,&li); 1321 while((ln = listNext(&li))) { 1322 redisClient *slave = listNodeValue(ln); 1323 int events; 1324 1325 events = aeGetFileEvents(server.el,slave->fd); 1326 if (events & AE_WRITABLE && 1327 slave->replstate == REDIS_REPL_ONLINE && 1328 listLength(slave->reply)) 1329 { 1330 sendReplyToClient(server.el,slave->fd,slave,0); 1331 } 1332 } 1333 } 1334