]> git.proxmox.com Git - ceph.git/blobdiff - ceph/src/spdk/lib/jsonrpc/jsonrpc_server.c
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / spdk / lib / jsonrpc / jsonrpc_server.c
index c500c96926e564401678c67806dc8c1db3acb492..774612b251fa49c8aaef62af0f2a61edd0418512 100644 (file)
@@ -62,6 +62,7 @@ static void
 parse_single_request(struct spdk_jsonrpc_request *request, struct spdk_json_val *values)
 {
        struct jsonrpc_request req = {};
+       const struct spdk_json_val *params = NULL;
 
        if (spdk_json_decode_object(values, jsonrpc_request_decoders,
                                    SPDK_COUNTOF(jsonrpc_request_decoders),
@@ -89,21 +90,61 @@ parse_single_request(struct spdk_jsonrpc_request *request, struct spdk_json_val
        }
 
        if (req.params) {
-               if (req.params->type != SPDK_JSON_VAL_ARRAY_BEGIN &&
-                   req.params->type != SPDK_JSON_VAL_OBJECT_BEGIN) {
-                       goto invalid;
+               /* null json value is as if there were no parameters */
+               if (req.params->type != SPDK_JSON_VAL_NULL) {
+                       if (req.params->type != SPDK_JSON_VAL_ARRAY_BEGIN &&
+                           req.params->type != SPDK_JSON_VAL_OBJECT_BEGIN) {
+                               goto invalid;
+                       }
+                       params = req.params;
                }
        }
 
-       spdk_jsonrpc_server_handle_request(request, req.method, req.params);
+       jsonrpc_server_handle_request(request, req.method, params);
        return;
 
 invalid:
-       spdk_jsonrpc_server_handle_error(request, SPDK_JSONRPC_ERROR_INVALID_REQUEST);
+       jsonrpc_server_handle_error(request, SPDK_JSONRPC_ERROR_INVALID_REQUEST);
+}
+
+static int
+jsonrpc_server_write_cb(void *cb_ctx, const void *data, size_t size)
+{
+       struct spdk_jsonrpc_request *request = cb_ctx;
+       size_t new_size = request->send_buf_size;
+
+       while (new_size - request->send_len < size) {
+               if (new_size >= SPDK_JSONRPC_SEND_BUF_SIZE_MAX) {
+                       SPDK_ERRLOG("Send buf exceeded maximum size (%zu)\n",
+                                   (size_t)SPDK_JSONRPC_SEND_BUF_SIZE_MAX);
+                       return -1;
+               }
+
+               new_size *= 2;
+       }
+
+       if (new_size != request->send_buf_size) {
+               uint8_t *new_buf;
+
+               new_buf = realloc(request->send_buf, new_size);
+               if (new_buf == NULL) {
+                       SPDK_ERRLOG("Resizing send_buf failed (current size %zu, new size %zu)\n",
+                                   request->send_buf_size, new_size);
+                       return -1;
+               }
+
+               request->send_buf = new_buf;
+               request->send_buf_size = new_size;
+       }
+
+       memcpy(request->send_buf + request->send_len, data, size);
+       request->send_len += size;
+
+       return 0;
 }
 
 int
-spdk_jsonrpc_parse_request(struct spdk_jsonrpc_server_conn *conn, const void *json, size_t size)
+jsonrpc_parse_request(struct spdk_jsonrpc_server_conn *conn, const void *json, size_t size)
 {
        struct spdk_jsonrpc_request *request;
        ssize_t rc;
@@ -131,7 +172,7 @@ spdk_jsonrpc_parse_request(struct spdk_jsonrpc_server_conn *conn, const void *js
        request->recv_buffer = malloc(len + 1);
        if (request->recv_buffer == NULL) {
                SPDK_ERRLOG("Failed to allocate buffer to copy request (%zu bytes)\n", len + 1);
-               spdk_jsonrpc_free_request(request);
+               jsonrpc_free_request(request);
                return -1;
        }
 
@@ -144,7 +185,7 @@ spdk_jsonrpc_parse_request(struct spdk_jsonrpc_server_conn *conn, const void *js
                if (request->values == NULL) {
                        SPDK_ERRLOG("Failed to allocate buffer for JSON values (%zu bytes)\n",
                                    request->values_cnt * sizeof(request->values[0]));
-                       spdk_jsonrpc_free_request(request);
+                       jsonrpc_free_request(request);
                        return -1;
                }
        }
@@ -155,13 +196,20 @@ spdk_jsonrpc_parse_request(struct spdk_jsonrpc_server_conn *conn, const void *js
        request->send_buf = malloc(request->send_buf_size);
        if (request->send_buf == NULL) {
                SPDK_ERRLOG("Failed to allocate send_buf (%zu bytes)\n", request->send_buf_size);
-               spdk_jsonrpc_free_request(request);
+               jsonrpc_free_request(request);
+               return -1;
+       }
+
+       request->response = spdk_json_write_begin(jsonrpc_server_write_cb, request, 0);
+       if (request->response == NULL) {
+               SPDK_ERRLOG("Failed to allocate response JSON write context.\n");
+               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);
+               jsonrpc_server_handle_error(request, SPDK_JSONRPC_ERROR_PARSE_ERROR);
 
                /*
                 * Can't recover from parse error (no guaranteed resync point in streaming JSON).
@@ -175,7 +223,7 @@ spdk_jsonrpc_parse_request(struct spdk_jsonrpc_server_conn *conn, const void *js
                             SPDK_JSON_PARSE_FLAG_DECODE_IN_PLACE);
        if (rc < 0 || rc > SPDK_JSONRPC_MAX_VALUES) {
                SPDK_DEBUGLOG(SPDK_LOG_RPC, "JSON parse error on second pass\n");
-               spdk_jsonrpc_server_handle_error(request, SPDK_JSONRPC_ERROR_PARSE_ERROR);
+               jsonrpc_server_handle_error(request, SPDK_JSONRPC_ERROR_PARSE_ERROR);
                return -1;
        }
 
@@ -185,10 +233,10 @@ spdk_jsonrpc_parse_request(struct spdk_jsonrpc_server_conn *conn, const void *js
                parse_single_request(request, request->values);
        } else if (request->values[0].type == SPDK_JSON_VAL_ARRAY_BEGIN) {
                SPDK_DEBUGLOG(SPDK_LOG_RPC, "Got batch array (not currently supported)\n");
-               spdk_jsonrpc_server_handle_error(request, SPDK_JSONRPC_ERROR_INVALID_REQUEST);
+               jsonrpc_server_handle_error(request, SPDK_JSONRPC_ERROR_INVALID_REQUEST);
        } else {
                SPDK_DEBUGLOG(SPDK_LOG_RPC, "top-level JSON value was not array or object\n");
-               spdk_jsonrpc_server_handle_error(request, SPDK_JSONRPC_ERROR_INVALID_REQUEST);
+               jsonrpc_server_handle_error(request, SPDK_JSONRPC_ERROR_INVALID_REQUEST);
        }
 
        return len;
@@ -200,51 +248,11 @@ spdk_jsonrpc_get_conn(struct spdk_jsonrpc_request *request)
        return request->conn;
 }
 
-static int
-spdk_jsonrpc_server_write_cb(void *cb_ctx, const void *data, size_t size)
-{
-       struct spdk_jsonrpc_request *request = cb_ctx;
-       size_t new_size = request->send_buf_size;
-
-       while (new_size - request->send_len < size) {
-               if (new_size >= SPDK_JSONRPC_SEND_BUF_SIZE_MAX) {
-                       SPDK_ERRLOG("Send buf exceeded maximum size (%zu)\n",
-                                   (size_t)SPDK_JSONRPC_SEND_BUF_SIZE_MAX);
-                       return -1;
-               }
-
-               new_size *= 2;
-       }
-
-       if (new_size != request->send_buf_size) {
-               uint8_t *new_buf;
-
-               new_buf = realloc(request->send_buf, new_size);
-               if (new_buf == NULL) {
-                       SPDK_ERRLOG("Resizing send_buf failed (current size %zu, new size %zu)\n",
-                                   request->send_buf_size, new_size);
-                       return -1;
-               }
-
-               request->send_buf = new_buf;
-               request->send_buf_size = new_size;
-       }
-
-       memcpy(request->send_buf + request->send_len, data, size);
-       request->send_len += size;
-
-       return 0;
-}
-
+/* 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,25 +271,32 @@ static void
 skip_response(struct spdk_jsonrpc_request *request)
 {
        request->send_len = 0;
-       spdk_jsonrpc_server_send_response(request);
+       spdk_json_write_end(request->response);
+       request->response = NULL;
+       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_jsonrpc_server_write_cb(request, "\n", 1);
-       spdk_jsonrpc_server_send_response(request);
+       spdk_json_write_object_end(request->response);
+       spdk_json_write_end(request->response);
+       request->response = NULL;
+
+       jsonrpc_server_write_cb(request, "\n", 1);
+       jsonrpc_server_send_response(request);
 }
 
 void
-spdk_jsonrpc_free_request(struct spdk_jsonrpc_request *request)
+jsonrpc_free_request(struct spdk_jsonrpc_request *request)
 {
        if (!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 +307,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 +317,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 +355,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)