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