xref: /redis-3.2.3/src/networking.c (revision 87faf906)
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