LCOV - code coverage report
Current view: top level - lib - unixctl.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 186 199 93.5 %
Date: 2016-09-14 01:02:56 Functions: 26 26 100.0 %
Branches: 89 120 74.2 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2016 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                 :            : #include "unixctl.h"
      19                 :            : #include <errno.h>
      20                 :            : #include <unistd.h>
      21                 :            : #include "coverage.h"
      22                 :            : #include "dirs.h"
      23                 :            : #include "openvswitch/dynamic-string.h"
      24                 :            : #include "openvswitch/json.h"
      25                 :            : #include "jsonrpc.h"
      26                 :            : #include "openvswitch/list.h"
      27                 :            : #include "poll-loop.h"
      28                 :            : #include "openvswitch/shash.h"
      29                 :            : #include "stream.h"
      30                 :            : #include "stream-provider.h"
      31                 :            : #include "svec.h"
      32                 :            : #include "openvswitch/vlog.h"
      33                 :            : 
      34                 :      53956 : VLOG_DEFINE_THIS_MODULE(unixctl);
      35                 :            : 
      36                 :     205630 : COVERAGE_DEFINE(unixctl_received);
      37                 :     205630 : COVERAGE_DEFINE(unixctl_replied);
      38                 :            : 
      39                 :            : struct unixctl_command {
      40                 :            :     const char *usage;
      41                 :            :     int min_args, max_args;
      42                 :            :     unixctl_cb_func *cb;
      43                 :            :     void *aux;
      44                 :            : };
      45                 :            : 
      46                 :            : struct unixctl_conn {
      47                 :            :     struct ovs_list node;
      48                 :            :     struct jsonrpc *rpc;
      49                 :            : 
      50                 :            :     /* Only one request can be in progress at a time.  While the request is
      51                 :            :      * being processed, 'request_id' is populated, otherwise it is null. */
      52                 :            :     struct json *request_id;   /* ID of the currently active request. */
      53                 :            : };
      54                 :            : 
      55                 :            : /* Server for control connection. */
      56                 :            : struct unixctl_server {
      57                 :            :     struct pstream *listener;
      58                 :            :     struct ovs_list conns;
      59                 :            : };
      60                 :            : 
      61                 :            : static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 5);
      62                 :            : 
      63                 :            : static struct shash commands = SHASH_INITIALIZER(&commands);
      64                 :            : 
      65                 :            : static void
      66                 :         29 : unixctl_list_commands(struct unixctl_conn *conn, int argc OVS_UNUSED,
      67                 :            :                       const char *argv[] OVS_UNUSED, void *aux OVS_UNUSED)
      68                 :            : {
      69                 :         29 :     struct ds ds = DS_EMPTY_INITIALIZER;
      70                 :         29 :     const struct shash_node **nodes = shash_sort(&commands);
      71                 :            :     size_t i;
      72                 :            : 
      73                 :         29 :     ds_put_cstr(&ds, "The available commands are:\n");
      74                 :            : 
      75         [ +  + ]:       2471 :     for (i = 0; i < shash_count(&commands); i++) {
      76                 :       2442 :         const struct shash_node *node = nodes[i];
      77                 :       2442 :         const struct unixctl_command *command = node->data;
      78                 :            : 
      79                 :       2442 :         ds_put_format(&ds, "  %-23s %s\n", node->name, command->usage);
      80                 :            :     }
      81                 :         29 :     free(nodes);
      82                 :            : 
      83                 :         29 :     unixctl_command_reply(conn, ds_cstr(&ds));
      84                 :         29 :     ds_destroy(&ds);
      85                 :         29 : }
      86                 :            : 
      87                 :            : static void
      88                 :          5 : unixctl_version(struct unixctl_conn *conn, int argc OVS_UNUSED,
      89                 :            :                 const char *argv[] OVS_UNUSED, void *aux OVS_UNUSED)
      90                 :            : {
      91                 :          5 :     unixctl_command_reply(conn, ovs_get_program_version());
      92                 :          5 : }
      93                 :            : 
      94                 :            : /* Registers a unixctl command with the given 'name'.  'usage' describes the
      95                 :            :  * arguments to the command; it is used only for presentation to the user in
      96                 :            :  * "list-commands" output.
      97                 :            :  *
      98                 :            :  * 'cb' is called when the command is received.  It is passed an array
      99                 :            :  * containing the command name and arguments, plus a copy of 'aux'.  Normally
     100                 :            :  * 'cb' should reply by calling unixctl_command_reply() or
     101                 :            :  * unixctl_command_reply_error() before it returns, but if the command cannot
     102                 :            :  * be handled immediately then it can defer the reply until later.  A given
     103                 :            :  * connection can only process a single request at a time, so a reply must be
     104                 :            :  * made eventually to avoid blocking that connection. */
     105                 :            : void
     106                 :     149112 : unixctl_command_register(const char *name, const char *usage,
     107                 :            :                          int min_args, int max_args,
     108                 :            :                          unixctl_cb_func *cb, void *aux)
     109                 :            : {
     110                 :            :     struct unixctl_command *command;
     111                 :     149112 :     struct unixctl_command *lookup = shash_find_data(&commands, name);
     112                 :            : 
     113 [ +  + ][ -  + ]:     149112 :     ovs_assert(!lookup || lookup->cb == cb);
     114                 :            : 
     115         [ +  + ]:     149112 :     if (lookup) {
     116                 :       1827 :         return;
     117                 :            :     }
     118                 :            : 
     119                 :     147285 :     command = xmalloc(sizeof *command);
     120                 :     147285 :     command->usage = usage;
     121                 :     147285 :     command->min_args = min_args;
     122                 :     147285 :     command->max_args = max_args;
     123                 :     147285 :     command->cb = cb;
     124                 :     147285 :     command->aux = aux;
     125                 :     147285 :     shash_add(&commands, name, command);
     126                 :            : }
     127                 :            : 
     128                 :            : static void
     129                 :      10599 : unixctl_command_reply__(struct unixctl_conn *conn,
     130                 :            :                         bool success, const char *body)
     131                 :            : {
     132                 :            :     struct json *body_json;
     133                 :            :     struct jsonrpc_msg *reply;
     134                 :            : 
     135                 :      10599 :     COVERAGE_INC(unixctl_replied);
     136         [ -  + ]:      10599 :     ovs_assert(conn->request_id);
     137                 :            : 
     138         [ +  + ]:      10599 :     if (!body) {
     139                 :       6277 :         body = "";
     140                 :            :     }
     141                 :            : 
     142 [ +  + ][ +  + ]:      10599 :     if (body[0] && body[strlen(body) - 1] != '\n') {
     143                 :       3141 :         body_json = json_string_create_nocopy(xasprintf("%s\n", body));
     144                 :            :     } else {
     145                 :       7458 :         body_json = json_string_create(body);
     146                 :            :     }
     147                 :            : 
     148         [ +  + ]:      10599 :     if (success) {
     149                 :      10529 :         reply = jsonrpc_create_reply(body_json, conn->request_id);
     150                 :            :     } else {
     151                 :         70 :         reply = jsonrpc_create_error(body_json, conn->request_id);
     152                 :            :     }
     153                 :            : 
     154         [ +  + ]:      10599 :     if (VLOG_IS_DBG_ENABLED()) {
     155                 :       8871 :         char *id = json_to_string(conn->request_id, 0);
     156 [ +  - ][ +  + ]:       8871 :         VLOG_DBG("replying with %s, id=%s: \"%s\"",
     157                 :            :                  success ? "success" : "error", id, body);
     158                 :       8871 :         free(id);
     159                 :            :     }
     160                 :            : 
     161                 :            :     /* If jsonrpc_send() returns an error, the run loop will take care of the
     162                 :            :      * problem eventually. */
     163                 :      10599 :     jsonrpc_send(conn->rpc, reply);
     164                 :      10599 :     json_destroy(conn->request_id);
     165                 :      10599 :     conn->request_id = NULL;
     166                 :      10599 : }
     167                 :            : 
     168                 :            : /* Replies to the active unixctl connection 'conn'.  'result' is sent to the
     169                 :            :  * client indicating the command was processed successfully.  Only one call to
     170                 :            :  * unixctl_command_reply() or unixctl_command_reply_error() may be made per
     171                 :            :  * request. */
     172                 :            : void
     173                 :      10529 : unixctl_command_reply(struct unixctl_conn *conn, const char *result)
     174                 :            : {
     175                 :      10529 :     unixctl_command_reply__(conn, true, result);
     176                 :      10529 : }
     177                 :            : 
     178                 :            : /* Replies to the active unixctl connection 'conn'. 'error' is sent to the
     179                 :            :  * client indicating an error occurred processing the command.  Only one call to
     180                 :            :  * unixctl_command_reply() or unixctl_command_reply_error() may be made per
     181                 :            :  * request. */
     182                 :            : void
     183                 :         70 : unixctl_command_reply_error(struct unixctl_conn *conn, const char *error)
     184                 :            : {
     185                 :         70 :     unixctl_command_reply__(conn, false, error);
     186                 :         70 : }
     187                 :            : 
     188                 :            : /* Creates a unixctl server listening on 'path', which for POSIX may be:
     189                 :            :  *
     190                 :            :  *      - NULL, in which case <rundir>/<program>.<pid>.ctl is used.
     191                 :            :  *
     192                 :            :  *      - A name that does not start with '/', in which case it is put in
     193                 :            :  *        <rundir>.
     194                 :            :  *
     195                 :            :  *      - An absolute path (starting with '/') that gives the exact name of
     196                 :            :  *        the Unix domain socket to listen on.
     197                 :            :  *
     198                 :            :  * For Windows, a local named pipe is used. A file is created in 'path'
     199                 :            :  * which may be:
     200                 :            :  *
     201                 :            :  *      - NULL, in which case <rundir>/<program>.ctl is used.
     202                 :            :  *
     203                 :            :  *      - An absolute path that gives the name of the file.
     204                 :            :  *
     205                 :            :  * For both POSIX and Windows, if the path is "none", the function will
     206                 :            :  * return successfully but no socket will actually be created.
     207                 :            :  *
     208                 :            :  * A program that (optionally) daemonizes itself should call this function
     209                 :            :  * *after* daemonization, so that the socket name contains the pid of the
     210                 :            :  * daemon instead of the pid of the program that exited.  (Otherwise,
     211                 :            :  * "ovs-appctl --target=<program>" will fail.)
     212                 :            :  *
     213                 :            :  * Returns 0 if successful, otherwise a positive errno value.  If successful,
     214                 :            :  * sets '*serverp' to the new unixctl_server (or to NULL if 'path' was "none"),
     215                 :            :  * otherwise to NULL. */
     216                 :            : int
     217                 :       2178 : unixctl_server_create(const char *path, struct unixctl_server **serverp)
     218                 :            : {
     219                 :            :     struct unixctl_server *server;
     220                 :            :     struct pstream *listener;
     221                 :            :     char *punix_path;
     222                 :            :     int error;
     223                 :            : 
     224                 :       2178 :     *serverp = NULL;
     225 [ +  + ][ -  + ]:       2178 :     if (path && !strcmp(path, "none")) {
     226                 :          0 :         return 0;
     227                 :            :     }
     228                 :            : 
     229         [ +  + ]:       2178 :     if (path) {
     230                 :            :         char *abs_path;
     231                 :            : #ifndef _WIN32
     232                 :        555 :         abs_path = abs_file_name(ovs_rundir(), path);
     233                 :            : #else
     234                 :            :         abs_path = xstrdup(path);
     235                 :            : #endif
     236                 :        555 :         punix_path = xasprintf("punix:%s", abs_path);
     237                 :        555 :         free(abs_path);
     238                 :            :     } else {
     239                 :            : #ifndef _WIN32
     240                 :       1623 :         punix_path = xasprintf("punix:%s/%s.%ld.ctl", ovs_rundir(),
     241                 :       1623 :                                program_name, (long int) getpid());
     242                 :            : #else
     243                 :            :         punix_path = xasprintf("punix:%s/%s.ctl", ovs_rundir(), program_name);
     244                 :            : #endif
     245                 :            :     }
     246                 :            : 
     247                 :       2178 :     error = pstream_open(punix_path, &listener, 0);
     248         [ +  + ]:       2178 :     if (error) {
     249                 :          2 :         ovs_error(error, "could not initialize control socket %s", punix_path);
     250                 :          2 :         goto exit;
     251                 :            :     }
     252                 :            : 
     253                 :       2176 :     unixctl_command_register("list-commands", "", 0, 0, unixctl_list_commands,
     254                 :            :                              NULL);
     255                 :       2176 :     unixctl_command_register("version", "", 0, 0, unixctl_version, NULL);
     256                 :            : 
     257                 :       2176 :     server = xmalloc(sizeof *server);
     258                 :       2176 :     server->listener = listener;
     259                 :       2176 :     ovs_list_init(&server->conns);
     260                 :       2176 :     *serverp = server;
     261                 :            : 
     262                 :            : exit:
     263                 :       2178 :     free(punix_path);
     264                 :       2178 :     return error;
     265                 :            : }
     266                 :            : 
     267                 :            : static void
     268                 :      10599 : process_command(struct unixctl_conn *conn, struct jsonrpc_msg *request)
     269                 :            : {
     270                 :      10599 :     char *error = NULL;
     271                 :            : 
     272                 :            :     struct unixctl_command *command;
     273                 :            :     struct json_array *params;
     274                 :            : 
     275                 :      10599 :     COVERAGE_INC(unixctl_received);
     276                 :      10599 :     conn->request_id = json_clone(request->id);
     277                 :            : 
     278         [ +  + ]:      10599 :     if (VLOG_IS_DBG_ENABLED()) {
     279                 :       8869 :         char *params_s = json_to_string(request->params, 0);
     280                 :       8869 :         char *id_s = json_to_string(request->id, 0);
     281         [ +  - ]:       8869 :         VLOG_DBG("received request %s%s, id=%s",
     282                 :            :                  request->method, params_s, id_s);
     283                 :       8869 :         free(params_s);
     284                 :       8869 :         free(id_s);
     285                 :            :     }
     286                 :            : 
     287                 :      10599 :     params = json_array(request->params);
     288                 :      10599 :     command = shash_find_data(&commands, request->method);
     289         [ +  + ]:      10599 :     if (!command) {
     290                 :          1 :         error = xasprintf("\"%s\" is not a valid command", request->method);
     291         [ +  + ]:      10598 :     } else if (params->n < command->min_args) {
     292                 :          5 :         error = xasprintf("\"%s\" command requires at least %d arguments",
     293                 :            :                           request->method, command->min_args);
     294         [ +  + ]:      10593 :     } else if (params->n > command->max_args) {
     295                 :          5 :         error = xasprintf("\"%s\" command takes at most %d arguments",
     296                 :            :                           request->method, command->max_args);
     297                 :            :     } else {
     298                 :      10588 :         struct svec argv = SVEC_EMPTY_INITIALIZER;
     299                 :            :         int  i;
     300                 :            : 
     301                 :      10588 :         svec_add(&argv, request->method);
     302         [ +  + ]:      23945 :         for (i = 0; i < params->n; i++) {
     303         [ -  + ]:      13357 :             if (params->elems[i]->type != JSON_STRING) {
     304                 :          0 :                 error = xasprintf("\"%s\" command has non-string argument",
     305                 :            :                                   request->method);
     306                 :          0 :                 break;
     307                 :            :             }
     308                 :      13357 :             svec_add(&argv, json_string(params->elems[i]));
     309                 :            :         }
     310                 :      10588 :         svec_terminate(&argv);
     311                 :            : 
     312         [ +  - ]:      10588 :         if (!error) {
     313                 :      10588 :             command->cb(conn, argv.n, (const char **) argv.names,
     314                 :            :                         command->aux);
     315                 :            :         }
     316                 :            : 
     317                 :      10588 :         svec_destroy(&argv);
     318                 :            :     }
     319                 :            : 
     320         [ +  + ]:      10599 :     if (error) {
     321                 :         11 :         unixctl_command_reply_error(conn, error);
     322                 :         11 :         free(error);
     323                 :            :     }
     324                 :      10599 : }
     325                 :            : 
     326                 :            : static int
     327                 :      32245 : run_connection(struct unixctl_conn *conn)
     328                 :            : {
     329                 :            :     int error, i;
     330                 :            : 
     331                 :      32245 :     jsonrpc_run(conn->rpc);
     332                 :      32245 :     error = jsonrpc_get_status(conn->rpc);
     333 [ +  - ][ +  + ]:      32245 :     if (error || jsonrpc_get_backlog(conn->rpc)) {
     334                 :        375 :         return error;
     335                 :            :     }
     336                 :            : 
     337         [ +  + ]:     257595 :     for (i = 0; i < 10; i++) {
     338                 :            :         struct jsonrpc_msg *msg;
     339                 :            : 
     340 [ +  + ][ +  + ]:     225725 :         if (error || conn->request_id) {
     341                 :            :             break;
     342                 :            :         }
     343                 :            : 
     344                 :     214200 :         jsonrpc_recv(conn->rpc, &msg);
     345         [ +  + ]:     214200 :         if (msg) {
     346         [ +  - ]:      10599 :             if (msg->type == JSONRPC_REQUEST) {
     347                 :      10599 :                 process_command(conn, msg);
     348                 :            :             } else {
     349         [ #  # ]:          0 :                 VLOG_WARN_RL(&rl, "%s: received unexpected %s message",
     350                 :            :                              jsonrpc_get_name(conn->rpc),
     351                 :            :                              jsonrpc_msg_type_to_string(msg->type));
     352                 :          0 :                 error = EINVAL;
     353                 :            :             }
     354                 :      10599 :             jsonrpc_msg_destroy(msg);
     355                 :            :         }
     356         [ +  - ]:     214200 :         error = error ? error : jsonrpc_get_status(conn->rpc);
     357                 :            :     }
     358                 :            : 
     359                 :      31870 :     return error;
     360                 :            : }
     361                 :            : 
     362                 :            : static void
     363                 :      10599 : kill_connection(struct unixctl_conn *conn)
     364                 :            : {
     365                 :      10599 :     ovs_list_remove(&conn->node);
     366                 :      10599 :     jsonrpc_close(conn->rpc);
     367                 :      10599 :     json_destroy(conn->request_id);
     368                 :      10599 :     free(conn);
     369                 :      10599 : }
     370                 :            : 
     371                 :            : void
     372                 :     173471 : unixctl_server_run(struct unixctl_server *server)
     373                 :            : {
     374                 :            :     struct unixctl_conn *conn, *next;
     375                 :            :     int i;
     376                 :            : 
     377         [ -  + ]:     173471 :     if (!server) {
     378                 :          0 :         return;
     379                 :            :     }
     380                 :            : 
     381         [ +  - ]:     184070 :     for (i = 0; i < 10; i++) {
     382                 :            :         struct stream *stream;
     383                 :            :         int error;
     384                 :            : 
     385                 :     184070 :         error = pstream_accept(server->listener, &stream);
     386         [ +  + ]:     184070 :         if (!error) {
     387                 :      10599 :             struct unixctl_conn *conn = xzalloc(sizeof *conn);
     388                 :      10599 :             ovs_list_push_back(&server->conns, &conn->node);
     389                 :      10599 :             conn->rpc = jsonrpc_open(stream);
     390         [ +  - ]:     173471 :         } else if (error == EAGAIN) {
     391                 :     173471 :             break;
     392                 :            :         } else {
     393         [ #  # ]:          0 :             VLOG_WARN_RL(&rl, "%s: accept failed: %s",
     394                 :            :                          pstream_get_name(server->listener),
     395                 :            :                          ovs_strerror(error));
     396                 :            :         }
     397                 :            :     }
     398                 :            : 
     399 [ +  + ][ +  + ]:     205716 :     LIST_FOR_EACH_SAFE (conn, next, node, &server->conns) {
     400                 :      32245 :         int error = run_connection(conn);
     401 [ +  + ][ +  - ]:      32245 :         if (error && error != EAGAIN) {
     402                 :       8586 :             kill_connection(conn);
     403                 :            :         }
     404                 :            :     }
     405                 :            : }
     406                 :            : 
     407                 :            : void
     408                 :     173265 : unixctl_server_wait(struct unixctl_server *server)
     409                 :            : {
     410                 :            :     struct unixctl_conn *conn;
     411                 :            : 
     412         [ -  + ]:     173265 :     if (!server) {
     413                 :          0 :         return;
     414                 :            :     }
     415                 :            : 
     416                 :     173265 :     pstream_wait(server->listener);
     417         [ +  + ]:     196768 :     LIST_FOR_EACH (conn, node, &server->conns) {
     418                 :      23503 :         jsonrpc_wait(conn->rpc);
     419         [ +  + ]:      23503 :         if (!jsonrpc_get_backlog(conn->rpc)) {
     420                 :      23126 :             jsonrpc_recv_wait(conn->rpc);
     421                 :            :         }
     422                 :            :     }
     423                 :            : }
     424                 :            : 
     425                 :            : /* Destroys 'server' and stops listening for connections. */
     426                 :            : void
     427                 :       2126 : unixctl_server_destroy(struct unixctl_server *server)
     428                 :            : {
     429         [ +  - ]:       2126 :     if (server) {
     430                 :            :         struct unixctl_conn *conn, *next;
     431                 :            : 
     432 [ +  + ][ +  + ]:       4139 :         LIST_FOR_EACH_SAFE (conn, next, node, &server->conns) {
     433                 :       2013 :             kill_connection(conn);
     434                 :            :         }
     435                 :            : 
     436                 :       2126 :         pstream_close(server->listener);
     437                 :       2126 :         free(server);
     438                 :            :     }
     439                 :       2126 : }
     440                 :            : 
     441                 :            : /* On POSIX based systems, connects to a unixctl server socket.  'path' should
     442                 :            :  * be the name of a unixctl server socket.  If it does not start with '/', it
     443                 :            :  * will be prefixed with the rundir (e.g. /usr/local/var/run/openvswitch).
     444                 :            :  *
     445                 :            :  * On Windows, connects to a local named pipe. A file which resides in
     446                 :            :  * 'path' is used to mimic the behavior of a Unix domain socket.
     447                 :            :  * 'path' should be an absolute path of the file.
     448                 :            :  *
     449                 :            :  * Returns 0 if successful, otherwise a positive errno value.  If successful,
     450                 :            :  * sets '*client' to the new jsonrpc, otherwise to NULL. */
     451                 :            : int
     452                 :      10956 : unixctl_client_create(const char *path, struct jsonrpc **client)
     453                 :            : {
     454                 :            :     char *abs_path, *unix_path;
     455                 :            :     struct stream *stream;
     456                 :            :     int error;
     457                 :            : 
     458                 :            : #ifdef _WIN32
     459                 :            :     abs_path = xstrdup(path);
     460                 :            : #else
     461                 :      10956 :     abs_path = abs_file_name(ovs_rundir(), path);
     462                 :            : #endif
     463                 :      10956 :     unix_path = xasprintf("unix:%s", abs_path);
     464                 :            : 
     465                 :      10956 :     *client = NULL;
     466                 :            : 
     467                 :      10956 :     error = stream_open_block(stream_open(unix_path, &stream, DSCP_DEFAULT),
     468                 :            :                               &stream);
     469                 :      10956 :     free(unix_path);
     470                 :      10956 :     free(abs_path);
     471                 :            : 
     472         [ +  + ]:      10956 :     if (error) {
     473         [ +  - ]:         10 :         VLOG_WARN("failed to connect to %s", path);
     474                 :         10 :         return error;
     475                 :            :     }
     476                 :            : 
     477                 :      10946 :     *client = jsonrpc_open(stream);
     478                 :      10956 :     return 0;
     479                 :            : }
     480                 :            : 
     481                 :            : /* Executes 'command' on the server with an argument vector 'argv' containing
     482                 :            :  * 'argc' elements.  If successfully communicated with the server, returns 0
     483                 :            :  * and sets '*result', or '*err' (not both) to the result or error the server
     484                 :            :  * returned.  Otherwise, sets '*result' and '*err' to NULL and returns a
     485                 :            :  * positive errno value.  The caller is responsible for freeing '*result' or
     486                 :            :  * '*err' if not NULL. */
     487                 :            : int
     488                 :      10946 : unixctl_client_transact(struct jsonrpc *client, const char *command, int argc,
     489                 :            :                         char *argv[], char **result, char **err)
     490                 :            : {
     491                 :            :     struct jsonrpc_msg *request, *reply;
     492                 :            :     struct json **json_args, *params;
     493                 :            :     int error, i;
     494                 :            : 
     495                 :      10946 :     *result = NULL;
     496                 :      10946 :     *err = NULL;
     497                 :            : 
     498                 :      10946 :     json_args = xmalloc(argc * sizeof *json_args);
     499         [ +  + ]:      24948 :     for (i = 0; i < argc; i++) {
     500                 :      14002 :         json_args[i] = json_string_create(argv[i]);
     501                 :            :     }
     502                 :      10946 :     params = json_array_create(json_args, argc);
     503                 :      10946 :     request = jsonrpc_create_request(command, params, NULL);
     504                 :            : 
     505                 :      10946 :     error = jsonrpc_transact_block(client, request, &reply);
     506         [ -  + ]:      10946 :     if (error) {
     507         [ #  # ]:          0 :         VLOG_WARN("error communicating with %s: %s", jsonrpc_get_name(client),
     508                 :            :                   ovs_retval_to_string(error));
     509                 :          0 :         return error;
     510                 :            :     }
     511                 :            : 
     512         [ +  + ]:      10946 :     if (reply->error) {
     513         [ +  - ]:         68 :         if (reply->error->type == JSON_STRING) {
     514                 :         68 :             *err = xstrdup(json_string(reply->error));
     515                 :            :         } else {
     516         [ #  # ]:          0 :             VLOG_WARN("%s: unexpected error type in JSON RPC reply: %s",
     517                 :            :                       jsonrpc_get_name(client),
     518                 :            :                       json_type_to_string(reply->error->type));
     519                 :         68 :             error = EINVAL;
     520                 :            :         }
     521         [ +  - ]:      10878 :     } else if (reply->result) {
     522         [ +  - ]:      10878 :         if (reply->result->type == JSON_STRING) {
     523                 :      10878 :             *result = xstrdup(json_string(reply->result));
     524                 :            :         } else {
     525         [ #  # ]:          0 :             VLOG_WARN("%s: unexpected result type in JSON rpc reply: %s",
     526                 :            :                       jsonrpc_get_name(client),
     527                 :            :                       json_type_to_string(reply->result->type));
     528                 :          0 :             error = EINVAL;
     529                 :            :         }
     530                 :            :     }
     531                 :            : 
     532                 :      10946 :     jsonrpc_msg_destroy(reply);
     533                 :      10946 :     return error;
     534                 :            : }

Generated by: LCOV version 1.12