LCOV - code coverage report
Current view: top level - tests - test-jsonrpc.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 113 153 73.9 %
Date: 2016-09-14 01:02:56 Functions: 11 13 84.6 %
Branches: 39 69 56.5 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015 Nicira, Inc.
       3                 :            :  *
       4                 :            :  * Licensed under the Apache License, Version 2.0 (the "License");
       5                 :            :  * you may not use this file except in compliance with the License.
       6                 :            :  * You may obtain a copy of the License at:
       7                 :            :  *
       8                 :            :  *     http://www.apache.org/licenses/LICENSE-2.0
       9                 :            :  *
      10                 :            :  * Unless required by applicable law or agreed to in writing, software
      11                 :            :  * distributed under the License is distributed on an "AS IS" BASIS,
      12                 :            :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      13                 :            :  * See the License for the specific language governing permissions and
      14                 :            :  * limitations under the License.
      15                 :            :  */
      16                 :            : 
      17                 :            : #include <config.h>
      18                 :            : #undef NDEBUG
      19                 :            : #include "jsonrpc.h"
      20                 :            : #include <errno.h>
      21                 :            : #include <fcntl.h>
      22                 :            : #include <getopt.h>
      23                 :            : #include <stdio.h>
      24                 :            : #include <stdlib.h>
      25                 :            : #include "command-line.h"
      26                 :            : #include "daemon.h"
      27                 :            : #include "openvswitch/json.h"
      28                 :            : #include "ovstest.h"
      29                 :            : #include "poll-loop.h"
      30                 :            : #include "stream-ssl.h"
      31                 :            : #include "stream.h"
      32                 :            : #include "timeval.h"
      33                 :            : #include "util.h"
      34                 :            : #include "openvswitch/vlog.h"
      35                 :            : 
      36                 :            : OVS_NO_RETURN static void usage(void);
      37                 :            : static void parse_options(int argc, char *argv[]);
      38                 :            : static struct ovs_cmdl_command *get_all_commands(void);
      39                 :            : 
      40                 :            : static void
      41                 :          7 : test_jsonrpc_main(int argc, char *argv[])
      42                 :            : {
      43                 :          7 :     struct ovs_cmdl_context ctx = { .argc = 0, };
      44                 :          7 :     ovs_cmdl_proctitle_init(argc, argv);
      45                 :          7 :     set_program_name(argv[0]);
      46                 :          7 :     service_start(&argc, &argv);
      47                 :          7 :     parse_options(argc, argv);
      48                 :          7 :     ctx.argc = argc - optind;
      49                 :          7 :     ctx.argv = argv + optind;
      50                 :          7 :     ovs_cmdl_run_command(&ctx, get_all_commands());
      51                 :          5 : }
      52                 :            : 
      53                 :            : static void
      54                 :          7 : parse_options(int argc, char *argv[])
      55                 :            : {
      56                 :            :     enum {
      57                 :            :         OPT_BOOTSTRAP_CA_CERT = UCHAR_MAX + 1,
      58                 :            :         DAEMON_OPTION_ENUMS
      59                 :            :     };
      60                 :            :     static const struct option long_options[] = {
      61                 :            :         {"verbose", optional_argument, NULL, 'v'},
      62                 :            :         {"help", no_argument, NULL, 'h'},
      63                 :            :         DAEMON_LONG_OPTIONS,
      64                 :            :         {"bootstrap-ca-cert", required_argument, NULL, OPT_BOOTSTRAP_CA_CERT},
      65                 :            :         STREAM_SSL_LONG_OPTIONS,
      66                 :            :         {NULL, 0, NULL, 0},
      67                 :            :     };
      68                 :          7 :     char *short_options = ovs_cmdl_long_options_to_short_options(long_options);
      69                 :            : 
      70                 :            :     for (;;) {
      71                 :         16 :         int c = getopt_long(argc, argv, short_options, long_options, NULL);
      72         [ +  + ]:         16 :         if (c == -1) {
      73                 :          7 :             break;
      74                 :            :         }
      75                 :            : 
      76   [ -  -  +  -  :          9 :         switch (c) {
          +  +  -  -  -  
          -  -  -  -  -  
                      - ]
      77                 :            :         case 'h':
      78                 :          0 :             usage();
      79                 :            : 
      80                 :            :         case 'v':
      81                 :          0 :             vlog_set_verbosity(optarg);
      82                 :          0 :             break;
      83                 :            : 
      84                 :          9 :         DAEMON_OPTION_HANDLERS
      85                 :            : 
      86                 :          0 :         STREAM_SSL_OPTION_HANDLERS
      87                 :            : 
      88                 :            :         case OPT_BOOTSTRAP_CA_CERT:
      89                 :          0 :             stream_ssl_set_ca_cert_file(optarg, true);
      90                 :          0 :             break;
      91                 :            : 
      92                 :            :         case '?':
      93                 :          0 :             exit(EXIT_FAILURE);
      94                 :            : 
      95                 :            :         default:
      96                 :          0 :             abort();
      97                 :            :         }
      98                 :          9 :     }
      99                 :          7 :     free(short_options);
     100                 :          7 : }
     101                 :            : 
     102                 :            : static void
     103                 :          0 : usage(void)
     104                 :            : {
     105                 :          0 :     printf("%s: JSON-RPC test utility\n"
     106                 :            :            "usage: %s [OPTIONS] COMMAND [ARG...]\n"
     107                 :            :            "  listen LOCAL             listen for connections on LOCAL\n"
     108                 :            :            "  request REMOTE METHOD PARAMS   send request, print reply\n"
     109                 :            :            "  notify REMOTE METHOD PARAMS  send notification and exit\n",
     110                 :            :            program_name, program_name);
     111                 :          0 :     stream_usage("JSON-RPC", true, true, true);
     112                 :          0 :     daemon_usage();
     113                 :          0 :     vlog_usage();
     114                 :          0 :     printf("\nOther options:\n"
     115                 :            :            "  -h, --help                  display this help message\n");
     116                 :          0 :     exit(EXIT_SUCCESS);
     117                 :            : }
     118                 :            : 
     119                 :            : /* Command helper functions. */
     120                 :            : 
     121                 :            : static struct json *
     122                 :          4 : parse_json(const char *s)
     123                 :            : {
     124                 :          4 :     struct json *json = json_from_string(s);
     125         [ -  + ]:          4 :     if (json->type == JSON_STRING) {
     126                 :          0 :         ovs_fatal(0, "\"%s\": %s", s, json->u.string);
     127                 :            :     }
     128                 :          4 :     return json;
     129                 :            : }
     130                 :            : 
     131                 :            : static void
     132                 :          3 : print_and_free_json(struct json *json)
     133                 :            : {
     134                 :          3 :     char *string = json_to_string(json, JSSF_SORT);
     135                 :          3 :     json_destroy(json);
     136                 :          3 :     puts(string);
     137                 :          3 :     free(string);
     138                 :          3 : }
     139                 :            : 
     140                 :            : /* Command implementations. */
     141                 :            : 
     142                 :            : static int
     143                 :          1 : handle_rpc(struct jsonrpc *rpc, struct jsonrpc_msg *msg, bool *done)
     144                 :            : {
     145         [ -  + ]:          1 :     if (msg->type == JSONRPC_REQUEST) {
     146                 :          0 :         struct jsonrpc_msg *reply = NULL;
     147         [ #  # ]:          0 :         if (!strcmp(msg->method, "echo")) {
     148                 :          0 :             reply = jsonrpc_create_reply(json_clone(msg->params), msg->id);
     149                 :            :         } else {
     150                 :          0 :             struct json *error = json_object_create();
     151                 :          0 :             json_object_put_string(error, "error", "unknown method");
     152                 :          0 :             reply = jsonrpc_create_error(error, msg->id);
     153                 :          0 :             ovs_error(0, "unknown request %s", msg->method);
     154                 :            :         }
     155                 :          0 :         jsonrpc_send(rpc, reply);
     156                 :          0 :         return 0;
     157         [ +  - ]:          1 :     } else if (msg->type == JSONRPC_NOTIFY) {
     158         [ +  - ]:          1 :         if (!strcmp(msg->method, "shutdown")) {
     159                 :          1 :             *done = true;
     160                 :          1 :             return 0;
     161                 :            :         } else {
     162                 :          0 :             ovs_error(0, "unknown notification %s", msg->method);
     163                 :          0 :             return ENOTTY;
     164                 :            :         }
     165                 :            :     } else {
     166                 :          0 :         ovs_error(0, "unsolicited JSON-RPC reply or error");
     167                 :          0 :         return EPROTO;
     168                 :            :     }
     169                 :            : }
     170                 :            : 
     171                 :            : static void
     172                 :          3 : do_listen(struct ovs_cmdl_context *ctx)
     173                 :            : {
     174                 :            :     struct pstream *pstream;
     175                 :            :     struct jsonrpc **rpcs;
     176                 :            :     size_t n_rpcs, allocated_rpcs;
     177                 :            :     bool done;
     178                 :            :     int error;
     179                 :            : 
     180                 :          3 :     error = jsonrpc_pstream_open(ctx->argv[1], &pstream, DSCP_DEFAULT);
     181         [ -  + ]:          3 :     if (error) {
     182                 :          0 :         ovs_fatal(error, "could not listen on \"%s\"", ctx->argv[1]);
     183                 :            :     }
     184                 :            : 
     185                 :          3 :     daemonize();
     186                 :            : 
     187                 :          1 :     rpcs = NULL;
     188                 :          1 :     n_rpcs = allocated_rpcs = 0;
     189                 :          1 :     done = false;
     190                 :            :     for (;;) {
     191                 :            :         struct stream *stream;
     192                 :            :         size_t i;
     193                 :            : 
     194                 :            :         /* Accept new connections. */
     195                 :          5 :         error = pstream_accept(pstream, &stream);
     196         [ +  + ]:          5 :         if (!error) {
     197         [ +  - ]:          1 :             if (n_rpcs >= allocated_rpcs) {
     198                 :          1 :                 rpcs = x2nrealloc(rpcs, &allocated_rpcs, sizeof *rpcs);
     199                 :            :             }
     200                 :          1 :             rpcs[n_rpcs++] = jsonrpc_open(stream);
     201         [ -  + ]:          4 :         } else if (error != EAGAIN) {
     202                 :          0 :             ovs_fatal(error, "pstream_accept failed");
     203                 :            :         }
     204                 :            : 
     205                 :            :         /* Service existing connections. */
     206         [ +  + ]:          8 :         for (i = 0; i < n_rpcs; ) {
     207                 :          3 :             struct jsonrpc *rpc = rpcs[i];
     208                 :            :             struct jsonrpc_msg *msg;
     209                 :            : 
     210                 :          3 :             jsonrpc_run(rpc);
     211         [ +  - ]:          3 :             if (!jsonrpc_get_backlog(rpc)) {
     212                 :          3 :                 error = jsonrpc_recv(rpc, &msg);
     213         [ +  + ]:          3 :                 if (!error) {
     214                 :          1 :                     error = handle_rpc(rpc, msg, &done);
     215                 :          1 :                     jsonrpc_msg_destroy(msg);
     216         [ +  + ]:          2 :                 } else if (error == EAGAIN) {
     217                 :          1 :                     error = 0;
     218                 :            :                 }
     219                 :            :             }
     220                 :            : 
     221         [ +  + ]:          3 :             if (!error) {
     222                 :          2 :                 error = jsonrpc_get_status(rpc);
     223                 :            :             }
     224         [ +  + ]:          3 :             if (error) {
     225                 :          1 :                 jsonrpc_close(rpc);
     226                 :          1 :                 ovs_error(error, "connection closed");
     227                 :          1 :                 memmove(&rpcs[i], &rpcs[i + 1],
     228                 :          1 :                         (n_rpcs - i - 1) * sizeof *rpcs);
     229                 :          1 :                 n_rpcs--;
     230                 :            :             } else {
     231                 :          3 :                 i++;
     232                 :            :             }
     233                 :            :         }
     234                 :            : 
     235                 :            :         /* Wait for something to do. */
     236 [ +  + ][ +  + ]:          5 :         if (done && !n_rpcs) {
     237                 :          1 :             break;
     238                 :            :         }
     239                 :          4 :         pstream_wait(pstream);
     240         [ +  + ]:          6 :         for (i = 0; i < n_rpcs; i++) {
     241                 :          2 :             struct jsonrpc *rpc = rpcs[i];
     242                 :            : 
     243                 :          2 :             jsonrpc_wait(rpc);
     244         [ +  - ]:          2 :             if (!jsonrpc_get_backlog(rpc)) {
     245                 :          2 :                 jsonrpc_recv_wait(rpc);
     246                 :            :             }
     247                 :            :         }
     248                 :          4 :         poll_block();
     249                 :          4 :     }
     250                 :          1 :     free(rpcs);
     251                 :          1 :     pstream_close(pstream);
     252                 :          1 : }
     253                 :            : 
     254                 :            : static void
     255                 :          3 : do_request(struct ovs_cmdl_context *ctx)
     256                 :            : {
     257                 :            :     struct jsonrpc_msg *msg;
     258                 :            :     struct jsonrpc *rpc;
     259                 :            :     struct json *params;
     260                 :            :     struct stream *stream;
     261                 :            :     const char *method;
     262                 :            :     char *string;
     263                 :            :     int error;
     264                 :            : 
     265                 :          3 :     method = ctx->argv[2];
     266                 :          3 :     params = parse_json(ctx->argv[3]);
     267                 :          3 :     msg = jsonrpc_create_request(method, params, NULL);
     268                 :          3 :     string = jsonrpc_msg_is_valid(msg);
     269         [ -  + ]:          3 :     if (string) {
     270                 :          0 :         ovs_fatal(0, "not a valid JSON-RPC request: %s", string);
     271                 :            :     }
     272                 :            : 
     273                 :          3 :     error = stream_open_block(jsonrpc_stream_open(ctx->argv[1], &stream,
     274                 :            :                               DSCP_DEFAULT), &stream);
     275         [ -  + ]:          3 :     if (error) {
     276                 :          0 :         ovs_fatal(error, "could not open \"%s\"", ctx->argv[1]);
     277                 :            :     }
     278                 :          3 :     rpc = jsonrpc_open(stream);
     279                 :            : 
     280                 :          3 :     error = jsonrpc_send(rpc, msg);
     281         [ -  + ]:          3 :     if (error) {
     282                 :          0 :         ovs_fatal(error, "could not send request");
     283                 :            :     }
     284                 :            : 
     285                 :          3 :     error = jsonrpc_recv_block(rpc, &msg);
     286         [ -  + ]:          3 :     if (error) {
     287                 :          0 :         ovs_fatal(error, "error waiting for reply");
     288                 :            :     }
     289                 :          3 :     print_and_free_json(jsonrpc_msg_to_json(msg));
     290                 :            : 
     291                 :          3 :     jsonrpc_close(rpc);
     292                 :          3 : }
     293                 :            : 
     294                 :            : static void
     295                 :          1 : do_notify(struct ovs_cmdl_context *ctx)
     296                 :            : {
     297                 :            :     struct jsonrpc_msg *msg;
     298                 :            :     struct jsonrpc *rpc;
     299                 :            :     struct json *params;
     300                 :            :     struct stream *stream;
     301                 :            :     const char *method;
     302                 :            :     char *string;
     303                 :            :     int error;
     304                 :            : 
     305                 :          1 :     method = ctx->argv[2];
     306                 :          1 :     params = parse_json(ctx->argv[3]);
     307                 :          1 :     msg = jsonrpc_create_notify(method, params);
     308                 :          1 :     string = jsonrpc_msg_is_valid(msg);
     309         [ -  + ]:          1 :     if (string) {
     310                 :          0 :         ovs_fatal(0, "not a JSON RPC-valid notification: %s", string);
     311                 :            :     }
     312                 :            : 
     313                 :          1 :     error = stream_open_block(jsonrpc_stream_open(ctx->argv[1], &stream,
     314                 :            :                               DSCP_DEFAULT), &stream);
     315         [ -  + ]:          1 :     if (error) {
     316                 :          0 :         ovs_fatal(error, "could not open \"%s\"", ctx->argv[1]);
     317                 :            :     }
     318                 :          1 :     rpc = jsonrpc_open(stream);
     319                 :            : 
     320                 :          1 :     error = jsonrpc_send_block(rpc, msg);
     321         [ -  + ]:          1 :     if (error) {
     322                 :          0 :         ovs_fatal(error, "could not send notification");
     323                 :            :     }
     324                 :          1 :     jsonrpc_close(rpc);
     325                 :          1 : }
     326                 :            : 
     327                 :            : static void
     328                 :          0 : do_help(struct ovs_cmdl_context *ctx OVS_UNUSED)
     329                 :            : {
     330                 :          0 :     usage();
     331                 :            : }
     332                 :            : 
     333                 :            : static struct ovs_cmdl_command all_commands[] = {
     334                 :            :     { "listen", NULL, 1, 1, do_listen, OVS_RO },
     335                 :            :     { "request", NULL, 3, 3, do_request, OVS_RO },
     336                 :            :     { "notify", NULL, 3, 3, do_notify, OVS_RO },
     337                 :            :     { "help", NULL, 0, INT_MAX, do_help, OVS_RO },
     338                 :            :     { NULL, NULL, 0, 0, NULL, OVS_RO },
     339                 :            : };
     340                 :            : 
     341                 :            : static struct ovs_cmdl_command *
     342                 :          7 : get_all_commands(void)
     343                 :            : {
     344                 :          7 :     return all_commands;
     345                 :            : }
     346                 :            : 
     347                 :       1186 : OVSTEST_REGISTER("test-jsonrpc", test_jsonrpc_main);

Generated by: LCOV version 1.12