LCOV - code coverage report
Current view: top level - spdk/lib/jsonrpc - jsonrpc_client.c (source / functions) Hit Total Coverage
Test: Combined Lines: 64 92 69.6 %
Date: 2024-07-12 15:04:35 Functions: 8 8 100.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 23 48 47.9 %

           Branch data     Line data    Source code
       1                 :            : /*   SPDX-License-Identifier: BSD-3-Clause
       2                 :            :  *   Copyright (C) 2018 Intel Corporation.
       3                 :            :  *   All rights reserved.
       4                 :            :  */
       5                 :            : 
       6                 :            : #include "spdk/util.h"
       7                 :            : #include "jsonrpc_internal.h"
       8                 :            : 
       9                 :            : static int
      10                 :       4889 : capture_version(const struct spdk_json_val *val, void *out)
      11                 :            : {
      12                 :       4889 :         const struct spdk_json_val **vptr = out;
      13                 :            : 
      14         [ -  + ]:       4889 :         if (spdk_json_strequal(val, "2.0") != true) {
      15                 :          0 :                 return SPDK_JSON_PARSE_INVALID;
      16                 :            :         }
      17                 :            : 
      18                 :       4889 :         *vptr = val;
      19                 :       4889 :         return 0;
      20                 :            : }
      21                 :            : 
      22                 :            : static int
      23                 :       4889 : capture_id(const struct spdk_json_val *val, void *out)
      24                 :            : {
      25                 :       4889 :         const struct spdk_json_val **vptr = out;
      26                 :            : 
      27   [ +  -  -  + ]:       4889 :         if (val->type != SPDK_JSON_VAL_STRING && val->type != SPDK_JSON_VAL_NUMBER) {
      28                 :          0 :                 return -EINVAL;
      29                 :            :         }
      30                 :            : 
      31                 :       4889 :         *vptr = val;
      32                 :       4889 :         return 0;
      33                 :            : }
      34                 :            : 
      35                 :            : static int
      36                 :       4889 : capture_any(const struct spdk_json_val *val, void *out)
      37                 :            : {
      38                 :       4889 :         const struct spdk_json_val **vptr = out;
      39                 :            : 
      40                 :       4889 :         *vptr = val;
      41                 :       4889 :         return 0;
      42                 :            : }
      43                 :            : 
      44                 :            : static const struct spdk_json_object_decoder jsonrpc_response_decoders[] = {
      45                 :            :         {"jsonrpc", offsetof(struct spdk_jsonrpc_client_response, version), capture_version},
      46                 :            :         {"id", offsetof(struct spdk_jsonrpc_client_response, id), capture_id, true},
      47                 :            :         {"result", offsetof(struct spdk_jsonrpc_client_response, result), capture_any, true},
      48                 :            :         {"error", offsetof(struct spdk_jsonrpc_client_response, error), capture_any, true},
      49                 :            : };
      50                 :            : 
      51                 :            : int
      52                 :       4889 : jsonrpc_parse_response(struct spdk_jsonrpc_client *client)
      53                 :            : {
      54                 :            :         struct spdk_jsonrpc_client_response_internal *r;
      55                 :            :         ssize_t rc;
      56                 :            :         size_t buf_len;
      57                 :            :         size_t values_cnt;
      58                 :       4889 :         void *end = NULL;
      59                 :            : 
      60                 :            : 
      61                 :            :         /* Check to see if we have received a full JSON value. */
      62                 :       4889 :         rc = spdk_json_parse(client->recv_buf, client->recv_offset, NULL, 0, &end, 0);
      63         [ -  + ]:       4889 :         if (rc == SPDK_JSON_PARSE_INCOMPLETE) {
      64                 :          0 :                 return 0;
      65                 :            :         }
      66                 :            : 
      67   [ -  +  -  + ]:       4889 :         SPDK_DEBUGLOG(rpc_client, "JSON string is :\n%s\n", client->recv_buf);
      68   [ +  -  -  + ]:       4889 :         if (rc < 0 || rc > SPDK_JSONRPC_CLIENT_MAX_VALUES) {
      69                 :          0 :                 SPDK_ERRLOG("JSON parse error (rc: %zd)\n", rc);
      70                 :            :                 /*
      71                 :            :                  * Can't recover from parse error (no guaranteed resync point in streaming JSON).
      72                 :            :                  * Return an error to indicate that the connection should be closed.
      73                 :            :                  */
      74                 :          0 :                 return -EINVAL;
      75                 :            :         }
      76                 :            : 
      77                 :       4889 :         values_cnt = rc;
      78                 :            : 
      79                 :       4889 :         r = calloc(1, sizeof(*r) + sizeof(struct spdk_json_val) * (values_cnt + 1));
      80         [ -  + ]:       4889 :         if (!r) {
      81                 :          0 :                 return -errno;
      82                 :            :         }
      83                 :            : 
      84         [ -  + ]:       4889 :         if (client->resp) {
      85                 :          0 :                 free(r);
      86                 :          0 :                 return -ENOSPC;
      87                 :            :         }
      88                 :            : 
      89                 :       4889 :         client->resp = r;
      90                 :            : 
      91                 :       4889 :         r->buf = client->recv_buf;
      92                 :       4889 :         buf_len = client->recv_offset;
      93                 :       4889 :         r->values_cnt = values_cnt;
      94                 :            : 
      95                 :       4889 :         client->recv_buf_size = 0;
      96                 :       4889 :         client->recv_offset = 0;
      97                 :       4889 :         client->recv_buf = NULL;
      98                 :            : 
      99                 :            :         /* Decode a second time now that there is a full JSON value available. */
     100                 :       4889 :         rc = spdk_json_parse(r->buf, buf_len, r->values, values_cnt, &end,
     101                 :            :                              SPDK_JSON_PARSE_FLAG_DECODE_IN_PLACE);
     102         [ -  + ]:       4889 :         if (rc != (ssize_t)values_cnt) {
     103                 :          0 :                 SPDK_ERRLOG("JSON parse error on second pass (rc: %zd, expected: %zu)\n", rc, values_cnt);
     104                 :          0 :                 goto err;
     105                 :            :         }
     106                 :            : 
     107         [ -  + ]:       4889 :         assert(end != NULL);
     108                 :            : 
     109         [ -  + ]:       4889 :         if (r->values[0].type != SPDK_JSON_VAL_OBJECT_BEGIN) {
     110                 :          0 :                 SPDK_ERRLOG("top-level JSON value was not object\n");
     111                 :          0 :                 goto err;
     112                 :            :         }
     113                 :            : 
     114         [ -  + ]:       4889 :         if (spdk_json_decode_object(r->values, jsonrpc_response_decoders,
     115                 :       4889 :                                     SPDK_COUNTOF(jsonrpc_response_decoders), &r->jsonrpc)) {
     116                 :          0 :                 goto err;
     117                 :            :         }
     118                 :            : 
     119                 :       4889 :         r->ready = 1;
     120                 :       4889 :         return 1;
     121                 :            : 
     122                 :          0 : err:
     123                 :          0 :         client->resp = NULL;
     124                 :          0 :         spdk_jsonrpc_client_free_response(&r->jsonrpc);
     125                 :          0 :         return -EINVAL;
     126                 :            : }
     127                 :            : 
     128                 :            : static int
     129                 :       9778 : jsonrpc_client_write_cb(void *cb_ctx, const void *data, size_t size)
     130                 :            : {
     131                 :       9778 :         struct spdk_jsonrpc_client_request *request = cb_ctx;
     132                 :       9778 :         size_t new_size = request->send_buf_size;
     133                 :            : 
     134         [ -  + ]:       9778 :         while (new_size - request->send_len < size) {
     135         [ #  # ]:          0 :                 if (new_size >= SPDK_JSONRPC_SEND_BUF_SIZE_MAX) {
     136                 :          0 :                         SPDK_ERRLOG("Send buf exceeded maximum size (%zu)\n",
     137                 :            :                                     (size_t)SPDK_JSONRPC_SEND_BUF_SIZE_MAX);
     138                 :          0 :                         return -ENOSPC;
     139                 :            :                 }
     140                 :            : 
     141                 :          0 :                 new_size *= 2;
     142                 :            :         }
     143                 :            : 
     144         [ -  + ]:       9778 :         if (new_size != request->send_buf_size) {
     145                 :            :                 uint8_t *new_buf;
     146                 :            : 
     147                 :          0 :                 new_buf = realloc(request->send_buf, new_size);
     148         [ #  # ]:          0 :                 if (new_buf == NULL) {
     149                 :          0 :                         SPDK_ERRLOG("Resizing send_buf failed (current size %zu, new size %zu)\n",
     150                 :            :                                     request->send_buf_size, new_size);
     151                 :          0 :                         return -ENOMEM;
     152                 :            :                 }
     153                 :            : 
     154                 :          0 :                 request->send_buf = new_buf;
     155                 :          0 :                 request->send_buf_size = new_size;
     156                 :            :         }
     157                 :            : 
     158   [ -  +  -  + ]:       9778 :         memcpy(request->send_buf + request->send_len, data, size);
     159                 :       9778 :         request->send_len += size;
     160                 :            : 
     161                 :       9778 :         return 0;
     162                 :            : }
     163                 :            : 
     164                 :            : struct spdk_json_write_ctx *
     165                 :       4889 : spdk_jsonrpc_begin_request(struct spdk_jsonrpc_client_request *request, int32_t id,
     166                 :            :                            const char *method)
     167                 :            : {
     168                 :            :         struct spdk_json_write_ctx *w;
     169                 :            : 
     170                 :       4889 :         w = spdk_json_write_begin(jsonrpc_client_write_cb, request, 0);
     171         [ -  + ]:       4889 :         if (w == NULL) {
     172                 :          0 :                 return NULL;
     173                 :            :         }
     174                 :            : 
     175                 :       4889 :         spdk_json_write_object_begin(w);
     176                 :       4889 :         spdk_json_write_named_string(w, "jsonrpc", "2.0");
     177                 :            : 
     178         [ +  - ]:       4889 :         if (id >= 0) {
     179                 :       4889 :                 spdk_json_write_named_int32(w, "id", id);
     180                 :            :         }
     181                 :            : 
     182         [ +  + ]:       4889 :         if (method) {
     183                 :         60 :                 spdk_json_write_named_string(w, "method", method);
     184                 :            :         }
     185                 :            : 
     186                 :       4889 :         return w;
     187                 :            : }
     188                 :            : 
     189                 :            : void
     190                 :       4889 : spdk_jsonrpc_end_request(struct spdk_jsonrpc_client_request *request, struct spdk_json_write_ctx *w)
     191                 :            : {
     192         [ -  + ]:       4889 :         assert(w != NULL);
     193                 :            : 
     194                 :       4889 :         spdk_json_write_object_end(w);
     195                 :       4889 :         spdk_json_write_end(w);
     196                 :       4889 :         jsonrpc_client_write_cb(request, "\n", 1);
     197                 :       4889 : }
     198                 :            : 
     199                 :       3395 : SPDK_LOG_REGISTER_COMPONENT(rpc_client)

Generated by: LCOV version 1.14