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