summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorantirez <antirez@gmail.com>2011-03-31 16:44:43 +0200
committerantirez <antirez@gmail.com>2011-03-31 16:45:05 +0200
commit97d3b7dc8dfe32965b9d17711a519bb591259dfb (patch)
tree765ee4257ea06eb5875cfd59b459d75cc6021976
parent048c0f0f37a67f3f33bdd5b179225ec853c1d8dc (diff)
downloadredis-97d3b7dc8dfe32965b9d17711a519bb591259dfb.tar.gz
Fixed issue #503. MONITOR + QUIT could crash the server, there are actually other interactions that could have the same effect (for instance Pub/Sub).
-rw-r--r--src/networking.c23
1 files changed, 20 insertions, 3 deletions
diff --git a/src/networking.c b/src/networking.c
index 758344a50..dd26f7452 100644
--- a/src/networking.c
+++ b/src/networking.c
@@ -60,9 +60,6 @@ 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) {
- /* When CLOSE_AFTER_REPLY is set, no more replies may be added! */
- redisAssert(!(c->flags & REDIS_CLOSE_AFTER_REPLY));
-
if (c->fd <= 0) return REDIS_ERR;
if (c->bufpos == 0 && listLength(c->reply) == 0 &&
(c->replstate == REDIS_REPL_NONE ||
@@ -88,9 +85,15 @@ robj *dupLastObjectIfNeeded(list *reply) {
return listNodeValue(ln);
}
+/* -----------------------------------------------------------------------------
+ * Low level functions to add more data to output buffers.
+ * -------------------------------------------------------------------------- */
+
int _addReplyToBuffer(redisClient *c, char *s, size_t len) {
size_t available = sizeof(c->buf)-c->bufpos;
+ if (c->flags & REDIS_CLOSE_AFTER_REPLY) return REDIS_OK;
+
/* If there already are entries in the reply list, we cannot
* add anything more to the static buffer. */
if (listLength(c->reply) > 0) return REDIS_ERR;
@@ -105,6 +108,9 @@ int _addReplyToBuffer(redisClient *c, char *s, size_t len) {
void _addReplyObjectToList(redisClient *c, robj *o) {
robj *tail;
+
+ if (c->flags & REDIS_CLOSE_AFTER_REPLY) return;
+
if (listLength(c->reply) == 0) {
incrRefCount(o);
listAddNodeTail(c->reply,o);
@@ -128,6 +134,9 @@ void _addReplyObjectToList(redisClient *c, robj *o) {
* needed it will be free'd, otherwise it ends up in a robj. */
void _addReplySdsToList(redisClient *c, sds s) {
robj *tail;
+
+ if (c->flags & REDIS_CLOSE_AFTER_REPLY) return;
+
if (listLength(c->reply) == 0) {
listAddNodeTail(c->reply,createObject(REDIS_STRING,s));
} else {
@@ -148,6 +157,9 @@ void _addReplySdsToList(redisClient *c, sds s) {
void _addReplyStringToList(redisClient *c, char *s, size_t len) {
robj *tail;
+
+ if (c->flags & REDIS_CLOSE_AFTER_REPLY) return;
+
if (listLength(c->reply) == 0) {
listAddNodeTail(c->reply,createStringObject(s,len));
} else {
@@ -165,6 +177,11 @@ void _addReplyStringToList(redisClient *c, char *s, size_t len) {
}
}
+/* -----------------------------------------------------------------------------
+ * Higher level functions to queue data on the client output buffer.
+ * The following functions are the ones that commands implementations will call.
+ * -------------------------------------------------------------------------- */
+
void addReply(redisClient *c, robj *obj) {
if (_installWriteEvent(c) != REDIS_OK) return;
redisAssert(!server.vm_enabled || obj->storage == REDIS_VM_MEMORY);