X-Git-Url: https://git.saurik.com/redis.git/blobdiff_plain/af0e51f2e15bc9c63d11229e64ce7884e1a1402a..7229d60d0356e94f553623e0492f636687ac39e6:/src/networking.c?ds=sidebyside diff --git a/src/networking.c b/src/networking.c index 48febb09..976b472a 100644 --- a/src/networking.c +++ b/src/networking.c @@ -14,14 +14,20 @@ redisClient *createClient(int fd) { redisClient *c = zmalloc(sizeof(redisClient)); c->bufpos = 0; - anetNonBlock(NULL,fd); - anetTcpNoDelay(NULL,fd); - if (aeCreateFileEvent(server.el,fd,AE_READABLE, - readQueryFromClient, c) == AE_ERR) - { - close(fd); - zfree(c); - return NULL; + /* passing -1 as fd it is possible to create a non connected client. + * This is useful since all the Redis commands needs to be executed + * in the context of a client. When commands are executed in other + * contexts (for instance a Lua script) we need a non connected client. */ + if (fd != -1) { + anetNonBlock(NULL,fd); + anetTcpNoDelay(NULL,fd); + if (aeCreateFileEvent(server.el,fd,AE_READABLE, + readQueryFromClient, c) == AE_ERR) + { + close(fd); + zfree(c); + return NULL; + } } selectDb(c,0); @@ -51,7 +57,7 @@ redisClient *createClient(int fd) { c->pubsub_patterns = listCreate(); listSetFreeMethod(c->pubsub_patterns,decrRefCount); listSetMatchMethod(c->pubsub_patterns,listMatchObjects); - listAddNodeTail(server.clients,c); + if (fd != -1) listAddNodeTail(server.clients,c); initClientMultiState(c); return c; } @@ -59,6 +65,7 @@ redisClient *createClient(int fd) { /* Set the event loop to listen for write events on the client's socket. * Typically gets called every time a reply is built. */ int _installWriteEvent(redisClient *c) { + if (c->flags & REDIS_LUA_CLIENT) return REDIS_OK; if (c->fd <= 0) return REDIS_ERR; if (c->bufpos == 0 && listLength(c->reply) == 0 && (c->replstate == REDIS_REPL_NONE || @@ -419,7 +426,7 @@ void acceptTcpHandler(aeEventLoop *el, int fd, void *privdata, int mask) { cfd = anetTcpAccept(server.neterr, fd, cip, &cport); if (cfd == AE_ERR) { - redisLog(REDIS_VERBOSE,"Accepting client connection: %s", server.neterr); + redisLog(REDIS_WARNING,"Accepting client connection: %s", server.neterr); return; } redisLog(REDIS_VERBOSE,"Accepted %s:%d", cip, cport); @@ -434,7 +441,7 @@ void acceptUnixHandler(aeEventLoop *el, int fd, void *privdata, int mask) { cfd = anetUnixAccept(server.neterr, fd); if (cfd == AE_ERR) { - redisLog(REDIS_VERBOSE,"Accepting client connection: %s", server.neterr); + redisLog(REDIS_WARNING,"Accepting client connection: %s", server.neterr); return; } redisLog(REDIS_VERBOSE,"Accepted connection to %s", server.unixsocket); @@ -712,6 +719,10 @@ int processMultibulkBuffer(redisClient *c) { if (newline == NULL) return REDIS_ERR; + /* Buffer should also contain \n */ + if (newline-(c->querybuf) > ((signed)sdslen(c->querybuf)-2)) + return REDIS_ERR; + /* We know for sure there is a whole line since newline != NULL, * so go ahead and find out the multi bulk length. */ redisAssert(c->querybuf[0] == '*'); @@ -733,9 +744,6 @@ int processMultibulkBuffer(redisClient *c) { /* Setup argv array on client structure */ if (c->argv) zfree(c->argv); c->argv = zmalloc(sizeof(robj*)*c->multibulklen); - - /* Search new newline */ - newline = strchr(c->querybuf+pos,'\r'); } redisAssert(c->multibulklen > 0); @@ -743,27 +751,30 @@ int processMultibulkBuffer(redisClient *c) { /* Read bulk length if unknown */ if (c->bulklen == -1) { newline = strchr(c->querybuf+pos,'\r'); - if (newline != NULL) { - if (c->querybuf[pos] != '$') { - addReplyErrorFormat(c, - "Protocol error: expected '$', got '%c'", - c->querybuf[pos]); - setProtocolError(c,pos); - return REDIS_ERR; - } + if (newline == NULL) + break; - ok = string2ll(c->querybuf+pos+1,newline-(c->querybuf+pos+1),&ll); - if (!ok || ll < 0 || ll > 512*1024*1024) { - addReplyError(c,"Protocol error: invalid bulk length"); - setProtocolError(c,pos); - return REDIS_ERR; - } - pos += newline-(c->querybuf+pos)+2; - c->bulklen = ll; - } else { - /* No newline in current buffer, so wait for more data */ + /* Buffer should also contain \n */ + if (newline-(c->querybuf) > ((signed)sdslen(c->querybuf)-2)) break; + + if (c->querybuf[pos] != '$') { + addReplyErrorFormat(c, + "Protocol error: expected '$', got '%c'", + c->querybuf[pos]); + setProtocolError(c,pos); + return REDIS_ERR; } + + ok = string2ll(c->querybuf+pos+1,newline-(c->querybuf+pos+1),&ll); + if (!ok || ll < 0 || ll > 512*1024*1024) { + addReplyError(c,"Protocol error: invalid bulk length"); + setProtocolError(c,pos); + return REDIS_ERR; + } + + pos += newline-(c->querybuf+pos)+2; + c->bulklen = ll; } /* Read bulk argument */