unixctl: Log commands received and their replies (at debug level).
[cascardo/ovs.git] / lib / unixctl.c
index e59056e..c1a5048 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira, Inc.
+ * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2016 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -27,8 +27,9 @@
 #include "poll-loop.h"
 #include "shash.h"
 #include "stream.h"
+#include "stream-provider.h"
 #include "svec.h"
-#include "vlog.h"
+#include "openvswitch/vlog.h"
 
 VLOG_DEFINE_THIS_MODULE(unixctl);
 
@@ -43,7 +44,7 @@ struct unixctl_command {
 };
 
 struct unixctl_conn {
-    struct list node;
+    struct ovs_list node;
     struct jsonrpc *rpc;
 
     /* Only one request can be in progress at a time.  While the request is
@@ -54,7 +55,7 @@ struct unixctl_conn {
 /* Server for control connection. */
 struct unixctl_server {
     struct pstream *listener;
-    struct list conns;
+    struct ovs_list conns;
 };
 
 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 5);
@@ -62,8 +63,8 @@ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 5);
 static struct shash commands = SHASH_INITIALIZER(&commands);
 
 static void
-unixctl_help(struct unixctl_conn *conn, int argc OVS_UNUSED,
-             const char *argv[] OVS_UNUSED, void *aux OVS_UNUSED)
+unixctl_list_commands(struct unixctl_conn *conn, int argc OVS_UNUSED,
+                      const char *argv[] OVS_UNUSED, void *aux OVS_UNUSED)
 {
     struct ds ds = DS_EMPTY_INITIALIZER;
     const struct shash_node **nodes = shash_sort(&commands);
@@ -87,12 +88,12 @@ static void
 unixctl_version(struct unixctl_conn *conn, int argc OVS_UNUSED,
                 const char *argv[] OVS_UNUSED, void *aux OVS_UNUSED)
 {
-    unixctl_command_reply(conn, get_program_version());
+    unixctl_command_reply(conn, ovs_get_program_version());
 }
 
 /* Registers a unixctl command with the given 'name'.  'usage' describes the
  * arguments to the command; it is used only for presentation to the user in
- * "help" output.
+ * "list-commands" output.
  *
  * 'cb' is called when the command is received.  It is passed an array
  * containing the command name and arguments, plus a copy of 'aux'.  Normally
@@ -150,6 +151,13 @@ unixctl_command_reply__(struct unixctl_conn *conn,
         reply = jsonrpc_create_error(body_json, conn->request_id);
     }
 
+    if (VLOG_IS_DBG_ENABLED()) {
+        char *id = json_to_string(conn->request_id, 0);
+        VLOG_DBG("replying with %s, id=%s: \"%s\"",
+                 success ? "success" : "error", id, body);
+        free(id);
+    }
+
     /* If jsonrpc_send() returns an error, the run loop will take care of the
      * problem eventually. */
     jsonrpc_send(conn->rpc, reply);
@@ -168,7 +176,7 @@ unixctl_command_reply(struct unixctl_conn *conn, const char *result)
 }
 
 /* Replies to the active unixctl connection 'conn'. 'error' is sent to the
- * client indicating an error occured processing the command.  Only one call to
+ * client indicating an error occurred processing the command.  Only one call to
  * unixctl_command_reply() or unixctl_command_reply_error() may be made per
  * request. */
 void
@@ -177,19 +185,26 @@ unixctl_command_reply_error(struct unixctl_conn *conn, const char *error)
     unixctl_command_reply__(conn, false, error);
 }
 
-/* Creates a unixctl server listening on 'path', which may be:
+/* Creates a unixctl server listening on 'path', which for POSIX may be:
  *
  *      - NULL, in which case <rundir>/<program>.<pid>.ctl is used.
  *
- *      - "none", in which case the function will return successfully but
- *        no socket will actually be created.
- *
  *      - A name that does not start with '/', in which case it is put in
  *        <rundir>.
  *
  *      - An absolute path (starting with '/') that gives the exact name of
  *        the Unix domain socket to listen on.
  *
+ * For Windows, a kernel assigned TCP port is used and written in 'path'
+ * which may be:
+ *
+ *      - NULL, in which case <rundir>/<program>.ctl is used.
+ *
+ *      - An absolute path that gives the name of the file.
+ *
+ * For both POSIX and Windows, if the path is "none", the function will
+ * return successfully but no socket will actually be created.
+ *
  * A program that (optionally) daemonizes itself should call this function
  * *after* daemonization, so that the socket name contains the pid of the
  * daemon instead of the pid of the program that exited.  (Otherwise,
@@ -212,12 +227,21 @@ unixctl_server_create(const char *path, struct unixctl_server **serverp)
     }
 
     if (path) {
-        char *abs_path = abs_file_name(ovs_rundir(), path);
+        char *abs_path;
+#ifndef _WIN32
+        abs_path = abs_file_name(ovs_rundir(), path);
+#else
+        abs_path = xstrdup(path);
+#endif
         punix_path = xasprintf("punix:%s", abs_path);
         free(abs_path);
     } else {
+#ifndef _WIN32
         punix_path = xasprintf("punix:%s/%s.%ld.ctl", ovs_rundir(),
                                program_name, (long int) getpid());
+#else
+        punix_path = xasprintf("punix:%s/%s.ctl", ovs_rundir(), program_name);
+#endif
     }
 
     error = pstream_open(punix_path, &listener, 0);
@@ -226,7 +250,8 @@ unixctl_server_create(const char *path, struct unixctl_server **serverp)
         goto exit;
     }
 
-    unixctl_command_register("help", "", 0, 0, unixctl_help, NULL);
+    unixctl_command_register("list-commands", "", 0, 0, unixctl_list_commands,
+                             NULL);
     unixctl_command_register("version", "", 0, 0, unixctl_version, NULL);
 
     server = xmalloc(sizeof *server);
@@ -250,6 +275,15 @@ process_command(struct unixctl_conn *conn, struct jsonrpc_msg *request)
     COVERAGE_INC(unixctl_received);
     conn->request_id = json_clone(request->id);
 
+    if (VLOG_IS_DBG_ENABLED()) {
+        char *params_s = json_to_string(request->params, 0);
+        char *id_s = json_to_string(request->id, 0);
+        VLOG_DBG("received request %s%s, id=%s",
+                 request->method, params_s, id_s);
+        free(params_s);
+        free(id_s);
+    }
+
     params = json_array(request->params);
     command = shash_find_data(&commands, request->method);
     if (!command) {
@@ -358,7 +392,7 @@ unixctl_server_run(struct unixctl_server *server)
         } else {
             VLOG_WARN_RL(&rl, "%s: accept failed: %s",
                          pstream_get_name(server->listener),
-                         strerror(error));
+                         ovs_strerror(error));
         }
     }
 
@@ -404,9 +438,12 @@ unixctl_server_destroy(struct unixctl_server *server)
     }
 }
 \f
-/* Connects to a unixctl server socket.  'path' should be the name of a unixctl
- * server socket.  If it does not start with '/', it will be prefixed with the
- * rundir (e.g. /usr/local/var/run/openvswitch).
+/* On POSIX based systems, connects to a unixctl server socket.  'path' should
+ * be the name of a unixctl server socket.  If it does not start with '/', it
+ * will be prefixed with the rundir (e.g. /usr/local/var/run/openvswitch).
+ *
+ * On Windows, connects to a localhost TCP port as written inside 'path'.
+ * 'path' should be an absolute path of the file.
  *
  * Returns 0 if successful, otherwise a positive errno value.  If successful,
  * sets '*client' to the new jsonrpc, otherwise to NULL. */
@@ -417,10 +454,15 @@ unixctl_client_create(const char *path, struct jsonrpc **client)
     struct stream *stream;
     int error;
 
-    *client = NULL;
-
+#ifdef _WIN32
+    abs_path = xstrdup(path);
+#else
     abs_path = abs_file_name(ovs_rundir(), path);
+#endif
     unix_path = xasprintf("unix:%s", abs_path);
+
+    *client = NULL;
+
     error = stream_open_block(stream_open(unix_path, &stream, DSCP_DEFAULT),
                               &stream);
     free(unix_path);
@@ -462,7 +504,7 @@ unixctl_client_transact(struct jsonrpc *client, const char *command, int argc,
     error = jsonrpc_transact_block(client, request, &reply);
     if (error) {
         VLOG_WARN("error communicating with %s: %s", jsonrpc_get_name(client),
-                  strerror(error));
+                  ovs_retval_to_string(error));
         return error;
     }