diff --git a/include/spdk/jsonrpc.h b/include/spdk/jsonrpc.h index 127e30d2b..650a06ff4 100644 --- a/include/spdk/jsonrpc.h +++ b/include/spdk/jsonrpc.h @@ -186,8 +186,7 @@ int spdk_jsonrpc_conn_del_close_cb(struct spdk_jsonrpc_server_conn *conn, * * \param request JSON-RPC request to respond to. - * \return JSON write context to write the response object to, or NULL if no - * response is necessary. + * \return Non-NULL pointer to JSON write context to write the response object to. */ struct spdk_json_write_ctx *spdk_jsonrpc_begin_result(struct spdk_jsonrpc_request *request); diff --git a/lib/jsonrpc/jsonrpc_internal.h b/lib/jsonrpc/jsonrpc_internal.h index ab3d91c7e..e51d9c9df 100644 --- a/lib/jsonrpc/jsonrpc_internal.h +++ b/lib/jsonrpc/jsonrpc_internal.h @@ -67,6 +67,8 @@ struct spdk_jsonrpc_request { uint8_t *send_buf; + struct spdk_json_write_ctx *response; + STAILQ_ENTRY(spdk_jsonrpc_request) link; }; diff --git a/lib/jsonrpc/jsonrpc_server.c b/lib/jsonrpc/jsonrpc_server.c index 8bc4198cc..52cd4605f 100644 --- a/lib/jsonrpc/jsonrpc_server.c +++ b/lib/jsonrpc/jsonrpc_server.c @@ -195,6 +195,13 @@ spdk_jsonrpc_parse_request(struct spdk_jsonrpc_server_conn *conn, const void *js return -1; } + request->response = spdk_json_write_begin(spdk_jsonrpc_server_write_cb, request, 0); + if (request->response == NULL) { + SPDK_ERRLOG("Failed to allocate response JSON write context.\n"); + spdk_jsonrpc_free_request(request); + return -1; + } + if (rc <= 0 || rc > SPDK_JSONRPC_MAX_VALUES) { SPDK_DEBUGLOG(SPDK_LOG_RPC, "JSON parse error\n"); spdk_jsonrpc_server_handle_error(request, SPDK_JSONRPC_ERROR_PARSE_ERROR); @@ -236,15 +243,11 @@ spdk_jsonrpc_get_conn(struct spdk_jsonrpc_request *request) return request->conn; } +/* Never return NULL */ static struct spdk_json_write_ctx * begin_response(struct spdk_jsonrpc_request *request) { - struct spdk_json_write_ctx *w; - - w = spdk_json_write_begin(spdk_jsonrpc_server_write_cb, request, 0); - if (w == NULL) { - return NULL; - } + struct spdk_json_write_ctx *w = request->response; spdk_json_write_object_begin(w); spdk_json_write_named_string(w, "jsonrpc", "2.0"); @@ -263,14 +266,18 @@ static void skip_response(struct spdk_jsonrpc_request *request) { request->send_len = 0; + spdk_json_write_end(request->response); + request->response = NULL; spdk_jsonrpc_server_send_response(request); } static void -end_response(struct spdk_jsonrpc_request *request, struct spdk_json_write_ctx *w) +end_response(struct spdk_jsonrpc_request *request) { - spdk_json_write_object_end(w); - spdk_json_write_end(w); + spdk_json_write_object_end(request->response); + spdk_json_write_end(request->response); + request->response = NULL; + spdk_jsonrpc_server_write_cb(request, "\n", 1); spdk_jsonrpc_server_send_response(request); } @@ -282,6 +289,9 @@ spdk_jsonrpc_free_request(struct spdk_jsonrpc_request *request) return; } + /* We must send or skip response explicitly */ + assert(request->response == NULL); + request->conn->outstanding_requests--; free(request->recv_buffer); free(request->values); @@ -292,22 +302,9 @@ spdk_jsonrpc_free_request(struct spdk_jsonrpc_request *request) struct spdk_json_write_ctx * spdk_jsonrpc_begin_result(struct spdk_jsonrpc_request *request) { - struct spdk_json_write_ctx *w; - - if (request->id == NULL || request->id->type == SPDK_JSON_VAL_NULL) { - /* Notification - no response required */ - skip_response(request); - return NULL; - } - - w = begin_response(request); - if (w == NULL) { - skip_response(request); - return NULL; - } + struct spdk_json_write_ctx *w = begin_response(request); spdk_json_write_name(w, "result"); - return w; } @@ -315,43 +312,37 @@ void spdk_jsonrpc_end_result(struct spdk_jsonrpc_request *request, struct spdk_json_write_ctx *w) { assert(w != NULL); + assert(w == request->response); - end_response(request, w); + /* If there was no ID in request we skip response. */ + if (request->id && request->id->type != SPDK_JSON_VAL_NULL) { + end_response(request); + } else { + skip_response(request); + } } void spdk_jsonrpc_send_error_response(struct spdk_jsonrpc_request *request, int error_code, const char *msg) { - struct spdk_json_write_ctx *w; - - w = begin_response(request); - if (w == NULL) { - skip_response(request); - return; - } + struct spdk_json_write_ctx *w = begin_response(request); spdk_json_write_named_object_begin(w, "error"); spdk_json_write_named_int32(w, "code", error_code); spdk_json_write_named_string(w, "message", msg); spdk_json_write_object_end(w); - end_response(request, w); + end_response(request); } void spdk_jsonrpc_send_error_response_fmt(struct spdk_jsonrpc_request *request, int error_code, const char *fmt, ...) { - struct spdk_json_write_ctx *w; + struct spdk_json_write_ctx *w = begin_response(request); va_list args; - w = begin_response(request); - if (w == NULL) { - skip_response(request); - return; - } - spdk_json_write_named_object_begin(w, "error"); spdk_json_write_named_int32(w, "code", error_code); va_start(args, fmt); @@ -359,7 +350,7 @@ spdk_jsonrpc_send_error_response_fmt(struct spdk_jsonrpc_request *request, va_end(args); spdk_json_write_object_end(w); - end_response(request, w); + end_response(request); } SPDK_LOG_REGISTER_COMPONENT("rpc", SPDK_LOG_RPC) diff --git a/test/unit/lib/jsonrpc/jsonrpc_server.c/jsonrpc_server_ut.c b/test/unit/lib/jsonrpc/jsonrpc_server.c/jsonrpc_server_ut.c index c1bf4466d..a60d4e6ad 100644 --- a/test/unit/lib/jsonrpc/jsonrpc_server.c/jsonrpc_server_ut.c +++ b/test/unit/lib/jsonrpc/jsonrpc_server.c/jsonrpc_server_ut.c @@ -133,13 +133,33 @@ const struct spdk_json_val *g_cur_param; g_cur_param++ #define FREE_REQUEST() \ - spdk_jsonrpc_free_request(g_request); \ + ut_jsonrpc_free_request(g_request, g_parse_error); \ g_request = NULL; \ g_cur_param = NULL; \ g_parse_error = 0; \ g_method = NULL; \ g_cur_param = g_params = NULL +static void +ut_jsonrpc_free_request(struct spdk_jsonrpc_request *request, int err) +{ + struct spdk_json_write_ctx *w; + + if (!request) { + return; + } + + /* Need to emulate response to get the response write contex free */ + if (err == 0) { + w = spdk_jsonrpc_begin_result(request); + spdk_json_write_string(w, "UT PASS response"); + spdk_jsonrpc_end_result(request, w); + } else { + spdk_jsonrpc_send_error_response_fmt(request, err, "UT error response"); + } + + spdk_jsonrpc_free_request(request); +} static void ut_handle(struct spdk_jsonrpc_request *request, int error, const struct spdk_json_val *method, @@ -168,7 +188,6 @@ spdk_jsonrpc_server_handle_request(struct spdk_jsonrpc_request *request, void spdk_jsonrpc_server_send_response(struct spdk_jsonrpc_request *request) { - /* TODO */ } static void