diff --git a/src/nc_message.c b/src/nc_message.c index 06cfb5ad..4689cc76 100644 --- a/src/nc_message.c +++ b/src/nc_message.c @@ -229,6 +229,7 @@ _msg_get(void) msg->result = MSG_PARSE_OK; msg->fragment = NULL; + msg->reply = NULL; msg->pre_coalesce = NULL; msg->post_coalesce = NULL; @@ -262,6 +263,7 @@ _msg_get(void) msg->request = 0; msg->quit = 0; msg->noreply = 0; + msg->noforward = 0; msg->done = 0; msg->fdone = 0; msg->swallow = 0; @@ -291,6 +293,7 @@ msg_get(struct conn *conn, bool request, bool redis) msg->parser = redis_parse_rsp; } msg->fragment = redis_fragment; + msg->reply = redis_reply; msg->pre_coalesce = redis_pre_coalesce; msg->post_coalesce = redis_post_coalesce; } else { diff --git a/src/nc_message.h b/src/nc_message.h index 1bcc0720..0d202691 100644 --- a/src/nc_message.h +++ b/src/nc_message.h @@ -23,6 +23,7 @@ typedef void (*msg_parse_t)(struct msg *); typedef rstatus_t (*msg_fragment_t)(struct msg *, uint32_t, struct msg_tqh *); typedef void (*msg_coalesce_t)(struct msg *r); +typedef rstatus_t (*msg_reply_t)(struct msg *r); typedef enum msg_parse_result { MSG_PARSE_OK, /* parsing ok */ @@ -157,6 +158,8 @@ typedef enum msg_parse_result { ACTION( REQ_REDIS_ZSCAN) \ ACTION( REQ_REDIS_EVAL ) /* redis requests - eval */ \ ACTION( REQ_REDIS_EVALSHA ) \ + ACTION( REQ_REDIS_PING ) /* redis requests - ping/quit */ \ + ACTION( REQ_REDIS_QUIT) \ ACTION( RSP_REDIS_STATUS ) /* redis response */ \ ACTION( RSP_REDIS_ERROR ) \ ACTION( RSP_REDIS_INTEGER ) \ @@ -199,6 +202,7 @@ struct msg { msg_parse_result_t result; /* message parsing result */ msg_fragment_t fragment; /* message fragment */ + msg_reply_t reply; /* gen message reply (example: ping) */ msg_coalesce_t pre_coalesce; /* message pre-coalesce */ msg_coalesce_t post_coalesce; /* message post-coalesce */ @@ -228,6 +232,7 @@ struct msg { unsigned request:1; /* request? or response? */ unsigned quit:1; /* quit request? */ unsigned noreply:1; /* noreply? */ + unsigned noforward:1; /* not need forward (example: ping) */ unsigned done:1; /* done? */ unsigned fdone:1; /* all fragments are done? */ unsigned swallow:1; /* swallow response? */ diff --git a/src/nc_request.c b/src/nc_request.c index 7d00ff2a..d59adda3 100644 --- a/src/nc_request.c +++ b/src/nc_request.c @@ -586,6 +586,27 @@ req_recv_done(struct context *ctx, struct conn *conn, struct msg *msg, return; } + if (msg->noforward) { + status = req_make_reply(ctx, conn, msg); + if (status != NC_OK) { + conn->err = errno; + return; + } + + status = msg->reply(msg); + if (status != NC_OK) { + conn->err = errno; + return; + } + + status = event_add_out(ctx->evb, conn); + if (status != NC_OK) { + conn->err = errno; + } + + return; + } + /* do fragment */ pool = conn->owner; TAILQ_INIT(&frag_msgq); diff --git a/src/proto/nc_proto.h b/src/proto/nc_proto.h index 253f3bec..c5b8790c 100644 --- a/src/proto/nc_proto.h +++ b/src/proto/nc_proto.h @@ -149,5 +149,6 @@ void redis_parse_rsp(struct msg *r); void redis_pre_coalesce(struct msg *r); void redis_post_coalesce(struct msg *r); rstatus_t redis_fragment(struct msg *r, uint32_t ncontinuum, struct msg_tqh *frag_msgq); +rstatus_t redis_reply(struct msg *r); #endif diff --git a/src/proto/nc_redis.c b/src/proto/nc_redis.c index ce9621ed..8277ec92 100644 --- a/src/proto/nc_redis.c +++ b/src/proto/nc_redis.c @@ -21,6 +21,25 @@ #include #include +/* + * Return true, if the redis command take no key, otherwise + * return false + */ +static bool +redis_argz(struct msg *r) +{ + switch (r->type) { + case MSG_REQ_REDIS_PING: + case MSG_REQ_REDIS_QUIT: + return true; + + default: + break; + } + + return false; +} + /* * Return true, if the redis command accepts no arguments, otherwise * return false @@ -594,6 +613,18 @@ redis_parse_req(struct msg *r) break; } + if (str4icmp(m, 'p', 'i', 'n', 'g')) { + r->type = MSG_REQ_REDIS_PING; + r->noforward = 1; + break; + } + + if (str4icmp(m, 'q', 'u', 'i', 't')) { + r->type = MSG_REQ_REDIS_QUIT; + r->quit = 1; + break; + } + break; case 5: @@ -1018,7 +1049,9 @@ redis_parse_req(struct msg *r) case SW_REQ_TYPE_LF: switch (ch) { case LF: - if (redis_argeval(r)) { + if (redis_argz(r)) { + goto done; + } else if (redis_argeval(r)) { state = SW_ARG1_LEN; } else { state = SW_KEY_LEN; @@ -2417,6 +2450,23 @@ redis_fragment(struct msg *r, uint32_t ncontinuum, struct msg_tqh *frag_msgq) } } +rstatus_t +redis_reply(struct msg *r) +{ + struct msg *response = r->peer; + + ASSERT(response != NULL); + + switch (r->type) { + case MSG_REQ_REDIS_PING: + return msg_append(response, (uint8_t *)"+PONG\r\n", 7); + + default: + NOT_REACHED(); + return NC_ERROR; + } +} + void redis_post_coalesce_mset(struct msg *request) {