LCOV - code coverage report
Current view: top level - lib/jsonrpc - jsonrpc_server.c (source / functions) Hit Total Coverage
Test: ut_cov_unit.info Lines: 144 215 67.0 %
Date: 2024-12-07 12:08:24 Functions: 13 20 65.0 %

          Line data    Source code
       1             : /*   SPDX-License-Identifier: BSD-3-Clause
       2             :  *   Copyright (C) 2016 Intel Corporation. All rights reserved.
       3             :  *   Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
       4             :  */
       5             : 
       6             : #include "jsonrpc_internal.h"
       7             : 
       8             : #include "spdk/util.h"
       9             : 
      10             : static enum spdk_log_level g_rpc_log_level = SPDK_LOG_DISABLED;
      11             : static FILE *g_rpc_log_file = NULL;
      12             : 
      13             : struct jsonrpc_request {
      14             :         const struct spdk_json_val *version;
      15             :         const struct spdk_json_val *method;
      16             :         const struct spdk_json_val *params;
      17             :         const struct spdk_json_val *id;
      18             : };
      19             : 
      20             : void
      21           0 : spdk_jsonrpc_set_log_level(enum spdk_log_level level)
      22             : {
      23           0 :         assert(level >= SPDK_LOG_DISABLED);
      24           0 :         assert(level <= SPDK_LOG_DEBUG);
      25           0 :         g_rpc_log_level = level;
      26           0 : }
      27             : 
      28             : void
      29           0 : spdk_jsonrpc_set_log_file(FILE *file)
      30             : {
      31           0 :         g_rpc_log_file = file;
      32           0 : }
      33             : 
      34             : static void
      35           0 : remove_newlines(char *text)
      36             : {
      37           0 :         int i = 0, j = 0;
      38             : 
      39           0 :         while (text[i] != '\0') {
      40           0 :                 if (text[i] != '\n') {
      41           0 :                         text[j++] = text[i];
      42             :                 }
      43           0 :                 i++;
      44             :         }
      45           0 :         text[j] = '\0';
      46           0 : }
      47             : 
      48             : static void
      49          15 : jsonrpc_log(char *buf, const char *prefix)
      50             : {
      51             :         /* Some custom applications have enabled SPDK_JSON_PARSE_FLAG_ALLOW_COMMENTS
      52             :          * to allow comments in JSON RPC objects. To keep backward compatibility of
      53             :          * these applications, remove newlines only if JSON RPC logging is enabled.
      54             :          */
      55          15 :         if (g_rpc_log_level != SPDK_LOG_DISABLED || g_rpc_log_file != NULL) {
      56           0 :                 remove_newlines(buf);
      57             :         }
      58             : 
      59          15 :         if (g_rpc_log_level != SPDK_LOG_DISABLED) {
      60           0 :                 spdk_log(g_rpc_log_level, NULL, 0, NULL, "%s%s\n", prefix, buf);
      61             :         }
      62             : 
      63          15 :         if (g_rpc_log_file != NULL) {
      64           0 :                 spdk_flog(g_rpc_log_file, NULL, 0, NULL, "%s%s\n", prefix, buf);
      65             :         }
      66          15 : }
      67             : 
      68             : static int
      69          30 : capture_val(const struct spdk_json_val *val, void *out)
      70             : {
      71          30 :         const struct spdk_json_val **vptr = out;
      72             : 
      73          30 :         *vptr = val;
      74          30 :         return 0;
      75             : }
      76             : 
      77             : static const struct spdk_json_object_decoder jsonrpc_request_decoders[] = {
      78             :         {"jsonrpc", offsetof(struct jsonrpc_request, version), capture_val, true},
      79             :         {"method", offsetof(struct jsonrpc_request, method), capture_val},
      80             :         {"params", offsetof(struct jsonrpc_request, params), capture_val, true},
      81             :         {"id", offsetof(struct jsonrpc_request, id), capture_val, true},
      82             : };
      83             : 
      84             : static void
      85          10 : parse_single_request(struct spdk_jsonrpc_request *request, struct spdk_json_val *values)
      86             : {
      87          10 :         struct jsonrpc_request req = {};
      88          10 :         const struct spdk_json_val *params = NULL;
      89             : 
      90          10 :         if (spdk_json_decode_object(values, jsonrpc_request_decoders,
      91             :                                     SPDK_COUNTOF(jsonrpc_request_decoders),
      92             :                                     &req)) {
      93           1 :                 goto invalid;
      94             :         }
      95             : 
      96           9 :         if (req.version && (req.version->type != SPDK_JSON_VAL_STRING ||
      97           9 :                             !spdk_json_strequal(req.version, "2.0"))) {
      98           1 :                 goto invalid;
      99             :         }
     100             : 
     101           8 :         if (!req.method || req.method->type != SPDK_JSON_VAL_STRING) {
     102           2 :                 goto invalid;
     103             :         }
     104             : 
     105           6 :         if (req.id) {
     106           5 :                 if (req.id->type == SPDK_JSON_VAL_STRING ||
     107           5 :                     req.id->type == SPDK_JSON_VAL_NUMBER ||
     108           1 :                     req.id->type == SPDK_JSON_VAL_NULL) {
     109           5 :                         request->id = req.id;
     110             :                 } else  {
     111           0 :                         goto invalid;
     112             :                 }
     113             :         }
     114             : 
     115           6 :         if (req.params) {
     116             :                 /* null json value is as if there were no parameters */
     117           6 :                 if (req.params->type != SPDK_JSON_VAL_NULL) {
     118           6 :                         if (req.params->type != SPDK_JSON_VAL_ARRAY_BEGIN &&
     119           1 :                             req.params->type != SPDK_JSON_VAL_OBJECT_BEGIN) {
     120           0 :                                 goto invalid;
     121             :                         }
     122           6 :                         params = req.params;
     123             :                 }
     124             :         }
     125             : 
     126           6 :         jsonrpc_server_handle_request(request, req.method, params);
     127           6 :         return;
     128             : 
     129           4 : invalid:
     130           4 :         jsonrpc_server_handle_error(request, SPDK_JSONRPC_ERROR_INVALID_REQUEST);
     131             : }
     132             : 
     133             : static int
     134          28 : jsonrpc_server_write_cb(void *cb_ctx, const void *data, size_t size)
     135             : {
     136          28 :         struct spdk_jsonrpc_request *request = cb_ctx;
     137          28 :         size_t new_size = request->send_buf_size;
     138             : 
     139          28 :         while (new_size - request->send_len < size) {
     140           0 :                 if (new_size >= SPDK_JSONRPC_SEND_BUF_SIZE_MAX) {
     141           0 :                         SPDK_ERRLOG("Send buf exceeded maximum size (%zu)\n",
     142             :                                     (size_t)SPDK_JSONRPC_SEND_BUF_SIZE_MAX);
     143           0 :                         return -1;
     144             :                 }
     145             : 
     146           0 :                 new_size *= 2;
     147             :         }
     148             : 
     149          28 :         if (new_size != request->send_buf_size) {
     150             :                 uint8_t *new_buf;
     151             : 
     152             :                 /* Add extra byte for the null terminator. */
     153           0 :                 new_buf = realloc(request->send_buf, new_size + 1);
     154           0 :                 if (new_buf == NULL) {
     155           0 :                         SPDK_ERRLOG("Resizing send_buf failed (current size %zu, new size %zu)\n",
     156             :                                     request->send_buf_size, new_size);
     157           0 :                         return -1;
     158             :                 }
     159             : 
     160           0 :                 request->send_buf = new_buf;
     161           0 :                 request->send_buf_size = new_size;
     162             :         }
     163             : 
     164          28 :         memcpy(request->send_buf + request->send_len, data, size);
     165          28 :         request->send_len += size;
     166             : 
     167          28 :         return 0;
     168             : }
     169             : 
     170             : int
     171          69 : jsonrpc_parse_request(struct spdk_jsonrpc_server_conn *conn, const void *json, size_t size)
     172             : {
     173             :         struct spdk_jsonrpc_request *request;
     174             :         ssize_t rc;
     175             :         size_t len;
     176          69 :         void *end = NULL;
     177             : 
     178             :         /* Check to see if we have received a full JSON value. It is safe to cast away const
     179             :          * as we don't decode in place. */
     180          69 :         rc = spdk_json_parse((void *)json, size, NULL, 0, &end, 0);
     181          69 :         if (rc == SPDK_JSON_PARSE_INCOMPLETE) {
     182          54 :                 return 0;
     183             :         }
     184             : 
     185          15 :         request = calloc(1, sizeof(*request));
     186          15 :         if (request == NULL) {
     187           0 :                 SPDK_DEBUGLOG(rpc, "Out of memory allocating request\n");
     188           0 :                 return -1;
     189             :         }
     190             : 
     191          15 :         pthread_spin_lock(&conn->queue_lock);
     192          15 :         conn->outstanding_requests++;
     193          15 :         STAILQ_INSERT_TAIL(&conn->outstanding_queue, request, link);
     194          15 :         pthread_spin_unlock(&conn->queue_lock);
     195             : 
     196          15 :         request->conn = conn;
     197             : 
     198          15 :         len = end - json;
     199          15 :         request->recv_buffer = malloc(len + 1);
     200          15 :         if (request->recv_buffer == NULL) {
     201           0 :                 SPDK_ERRLOG("Failed to allocate buffer to copy request (%zu bytes)\n", len + 1);
     202           0 :                 jsonrpc_free_request(request);
     203           0 :                 return -1;
     204             :         }
     205             : 
     206          15 :         memcpy(request->recv_buffer, json, len);
     207          15 :         request->recv_buffer[len] = '\0';
     208             : 
     209          15 :         jsonrpc_log(request->recv_buffer, "request: ");
     210             : 
     211          15 :         if (rc > 0 && rc <= SPDK_JSONRPC_MAX_VALUES) {
     212          12 :                 request->values_cnt = rc;
     213          12 :                 request->values = malloc(request->values_cnt * sizeof(request->values[0]));
     214          12 :                 if (request->values == NULL) {
     215           0 :                         SPDK_ERRLOG("Failed to allocate buffer for JSON values (%zu bytes)\n",
     216             :                                     request->values_cnt * sizeof(request->values[0]));
     217           0 :                         jsonrpc_free_request(request);
     218           0 :                         return -1;
     219             :                 }
     220             :         }
     221             : 
     222          15 :         request->send_offset = 0;
     223          15 :         request->send_len = 0;
     224          15 :         request->send_buf_size = SPDK_JSONRPC_SEND_BUF_SIZE_INIT;
     225             :         /* Add extra byte for the null terminator. */
     226          15 :         request->send_buf = malloc(request->send_buf_size + 1);
     227          15 :         if (request->send_buf == NULL) {
     228           0 :                 SPDK_ERRLOG("Failed to allocate send_buf (%zu bytes)\n", request->send_buf_size);
     229           0 :                 jsonrpc_free_request(request);
     230           0 :                 return -1;
     231             :         }
     232             : 
     233          15 :         request->response = spdk_json_write_begin(jsonrpc_server_write_cb, request, 0);
     234          15 :         if (request->response == NULL) {
     235           0 :                 SPDK_ERRLOG("Failed to allocate response JSON write context.\n");
     236           0 :                 jsonrpc_free_request(request);
     237           0 :                 return -1;
     238             :         }
     239             : 
     240          15 :         if (rc <= 0 || rc > SPDK_JSONRPC_MAX_VALUES) {
     241           3 :                 SPDK_DEBUGLOG(rpc, "JSON parse error\n");
     242           3 :                 jsonrpc_server_handle_error(request, SPDK_JSONRPC_ERROR_PARSE_ERROR);
     243             : 
     244             :                 /*
     245             :                  * Can't recover from parse error (no guaranteed resync point in streaming JSON).
     246             :                  * Return an error to indicate that the connection should be closed.
     247             :                  */
     248           3 :                 return -1;
     249             :         }
     250             : 
     251             :         /* Decode a second time now that there is a full JSON value available. */
     252          12 :         rc = spdk_json_parse(request->recv_buffer, size, request->values, request->values_cnt, &end,
     253             :                              SPDK_JSON_PARSE_FLAG_DECODE_IN_PLACE);
     254          12 :         if (rc < 0 || rc > SPDK_JSONRPC_MAX_VALUES) {
     255           0 :                 SPDK_DEBUGLOG(rpc, "JSON parse error on second pass\n");
     256           0 :                 jsonrpc_server_handle_error(request, SPDK_JSONRPC_ERROR_PARSE_ERROR);
     257           0 :                 return -1;
     258             :         }
     259             : 
     260          12 :         assert(end != NULL);
     261             : 
     262          12 :         if (request->values[0].type == SPDK_JSON_VAL_OBJECT_BEGIN) {
     263          10 :                 parse_single_request(request, request->values);
     264           2 :         } else if (request->values[0].type == SPDK_JSON_VAL_ARRAY_BEGIN) {
     265           2 :                 SPDK_DEBUGLOG(rpc, "Got batch array (not currently supported)\n");
     266           2 :                 jsonrpc_server_handle_error(request, SPDK_JSONRPC_ERROR_INVALID_REQUEST);
     267             :         } else {
     268           0 :                 SPDK_DEBUGLOG(rpc, "top-level JSON value was not array or object\n");
     269           0 :                 jsonrpc_server_handle_error(request, SPDK_JSONRPC_ERROR_INVALID_REQUEST);
     270             :         }
     271             : 
     272          12 :         return len;
     273             : }
     274             : 
     275             : struct spdk_jsonrpc_server_conn *
     276           0 : spdk_jsonrpc_get_conn(struct spdk_jsonrpc_request *request)
     277             : {
     278           0 :         return request->conn;
     279             : }
     280             : 
     281             : /* Never return NULL */
     282             : static struct spdk_json_write_ctx *
     283          15 : begin_response(struct spdk_jsonrpc_request *request)
     284             : {
     285          15 :         struct spdk_json_write_ctx *w = request->response;
     286             : 
     287          15 :         spdk_json_write_object_begin(w);
     288          15 :         spdk_json_write_named_string(w, "jsonrpc", "2.0");
     289             : 
     290          15 :         spdk_json_write_name(w, "id");
     291          15 :         if (request->id) {
     292           5 :                 spdk_json_write_val(w, request->id);
     293             :         } else {
     294          10 :                 spdk_json_write_null(w);
     295             :         }
     296             : 
     297          15 :         return w;
     298             : }
     299             : 
     300             : static void
     301           2 : skip_response(struct spdk_jsonrpc_request *request)
     302             : {
     303           2 :         request->send_len = 0;
     304           2 :         spdk_json_write_end(request->response);
     305           2 :         request->response = NULL;
     306           2 :         jsonrpc_server_send_response(request);
     307           2 : }
     308             : 
     309             : static void
     310          13 : end_response(struct spdk_jsonrpc_request *request)
     311             : {
     312          13 :         spdk_json_write_object_end(request->response);
     313          13 :         spdk_json_write_end(request->response);
     314          13 :         request->response = NULL;
     315             : 
     316          13 :         jsonrpc_server_write_cb(request, "\n", 1);
     317          13 :         jsonrpc_server_send_response(request);
     318          13 : }
     319             : 
     320             : void
     321          15 : jsonrpc_free_request(struct spdk_jsonrpc_request *request)
     322             : {
     323             :         struct spdk_jsonrpc_request *req;
     324             :         struct spdk_jsonrpc_server_conn *conn;
     325             : 
     326          15 :         if (!request) {
     327           0 :                 return;
     328             :         }
     329             : 
     330             :         /* We must send or skip response explicitly */
     331          15 :         assert(request->response == NULL);
     332             : 
     333          15 :         conn = request->conn;
     334          15 :         if (conn != NULL) {
     335          15 :                 pthread_spin_lock(&conn->queue_lock);
     336          15 :                 conn->outstanding_requests--;
     337          15 :                 STAILQ_FOREACH(req, &conn->outstanding_queue, link) {
     338          15 :                         if (req == request) {
     339          15 :                                 STAILQ_REMOVE(&conn->outstanding_queue,
     340             :                                               req, spdk_jsonrpc_request, link);
     341          15 :                                 break;
     342             :                         }
     343             :                 }
     344          15 :                 pthread_spin_unlock(&conn->queue_lock);
     345             :         }
     346          15 :         free(request->recv_buffer);
     347          15 :         free(request->values);
     348          15 :         free(request->send_buf);
     349          15 :         free(request);
     350             : }
     351             : 
     352             : void
     353           0 : jsonrpc_complete_request(struct spdk_jsonrpc_request *request)
     354             : {
     355           0 :         jsonrpc_log(request->send_buf, "response: ");
     356             : 
     357           0 :         jsonrpc_free_request(request);
     358           0 : }
     359             : 
     360             : struct spdk_json_write_ctx *
     361           6 : spdk_jsonrpc_begin_result(struct spdk_jsonrpc_request *request)
     362             : {
     363           6 :         struct spdk_json_write_ctx *w = begin_response(request);
     364             : 
     365           6 :         spdk_json_write_name(w, "result");
     366           6 :         return w;
     367             : }
     368             : 
     369             : void
     370           6 : spdk_jsonrpc_end_result(struct spdk_jsonrpc_request *request, struct spdk_json_write_ctx *w)
     371             : {
     372           6 :         assert(w != NULL);
     373           6 :         assert(w == request->response);
     374             : 
     375             :         /* If there was no ID in request we skip response. */
     376           6 :         if (request->id && request->id->type != SPDK_JSON_VAL_NULL) {
     377           4 :                 end_response(request);
     378             :         } else {
     379           2 :                 skip_response(request);
     380             :         }
     381           6 : }
     382             : 
     383             : void
     384           0 : spdk_jsonrpc_send_bool_response(struct spdk_jsonrpc_request *request, bool value)
     385             : {
     386             :         struct spdk_json_write_ctx *w;
     387             : 
     388           0 :         w = spdk_jsonrpc_begin_result(request);
     389           0 :         assert(w != NULL);
     390           0 :         spdk_json_write_bool(w, value);
     391           0 :         spdk_jsonrpc_end_result(request, w);
     392           0 : }
     393             : 
     394             : void
     395           0 : spdk_jsonrpc_send_error_response(struct spdk_jsonrpc_request *request,
     396             :                                  int error_code, const char *msg)
     397             : {
     398           0 :         struct spdk_json_write_ctx *w = begin_response(request);
     399             : 
     400           0 :         spdk_json_write_named_object_begin(w, "error");
     401           0 :         spdk_json_write_named_int32(w, "code", error_code);
     402           0 :         spdk_json_write_named_string(w, "message", msg);
     403           0 :         spdk_json_write_object_end(w);
     404             : 
     405           0 :         end_response(request);
     406           0 : }
     407             : 
     408             : void
     409           9 : spdk_jsonrpc_send_error_response_fmt(struct spdk_jsonrpc_request *request,
     410             :                                      int error_code, const char *fmt, ...)
     411             : {
     412           9 :         struct spdk_json_write_ctx *w = begin_response(request);
     413           9 :         va_list args;
     414             : 
     415           9 :         spdk_json_write_named_object_begin(w, "error");
     416           9 :         spdk_json_write_named_int32(w, "code", error_code);
     417           9 :         va_start(args, fmt);
     418           9 :         spdk_json_write_named_string_fmt_v(w, "message", fmt, args);
     419           9 :         va_end(args);
     420           9 :         spdk_json_write_object_end(w);
     421             : 
     422           9 :         end_response(request);
     423           9 : }
     424             : 
     425           2 : SPDK_LOG_REGISTER_COMPONENT(rpc)

Generated by: LCOV version 1.15