/*
- * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira Networks.
+ * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#include <config.h>
#include "unixctl.h"
-#include <assert.h>
#include <errno.h>
#include <unistd.h>
#include "coverage.h"
#include "poll-loop.h"
#include "shash.h"
#include "stream.h"
+#include "stream-provider.h"
#include "svec.h"
#include "vlog.h"
* arguments to the command; it is used only for presentation to the user in
* "help" output.
*
- * 'cb' is called when the command is received. It is passed the actual set of
- * arguments, as a text string, plus a copy of 'aux'. Normally 'cb' should
- * reply by calling unixctl_command_reply() or unixctl_command_reply_error()
- * before it returns, but if the command cannot be handled immediately then it
- * can defer the reply until later. A given connection can only process a
- * single request at a time, so a reply must be made eventually to avoid
- * blocking that connection. */
+ * '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
+ * 'cb' should reply by calling unixctl_command_reply() or
+ * unixctl_command_reply_error() before it returns, but if the command cannot
+ * be handled immediately then it can defer the reply until later. A given
+ * connection can only process a single request at a time, so a reply must be
+ * made eventually to avoid blocking that connection. */
void
unixctl_command_register(const char *name, const char *usage,
int min_args, int max_args,
struct unixctl_command *command;
struct unixctl_command *lookup = shash_find_data(&commands, name);
- assert(!lookup || lookup->cb == cb);
+ ovs_assert(!lookup || lookup->cb == cb);
if (lookup) {
return;
struct jsonrpc_msg *reply;
COVERAGE_INC(unixctl_replied);
- assert(conn->request_id);
+ ovs_assert(conn->request_id);
if (!body) {
body = "";
}
/* 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
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,
{
struct unixctl_server *server;
struct pstream *listener;
- char *punix_path;
+ char *punix_path, *abs_path = NULL;
int error;
+#ifdef _WIN32
+ FILE *file;
+#endif
*serverp = NULL;
if (path && !strcmp(path, "none")) {
return 0;
}
+#ifndef _WIN32
if (path) {
- char *abs_path = abs_file_name(ovs_rundir(), path);
+ abs_path = abs_file_name(ovs_rundir(), path);
punix_path = xasprintf("punix:%s", abs_path);
- free(abs_path);
} else {
punix_path = xasprintf("punix:%s/%s.%ld.ctl", ovs_rundir(),
program_name, (long int) getpid());
}
+#else
+ punix_path = xstrdup("ptcp:0:127.0.0.1");
+#endif
error = pstream_open(punix_path, &listener, 0);
if (error) {
goto exit;
}
+#ifdef _WIN32
+ if (path) {
+ abs_path = xstrdup(path);
+ } else {
+ abs_path = xasprintf("%s/%s.ctl", ovs_rundir(), program_name);
+ }
+
+ file = fopen(abs_path, "w");
+ if (!file) {
+ error = errno;
+ ovs_error(error, "could not open %s", abs_path);
+ goto exit;
+ }
+
+ fprintf(file, "%d\n", ntohs(listener->bound_port));
+ if (fflush(file) == EOF) {
+ error = EIO;
+ ovs_error(error, "write failed for %s", abs_path);
+ fclose(file);
+ goto exit;
+ }
+ fclose(file);
+#endif
+
unixctl_command_register("help", "", 0, 0, unixctl_help, NULL);
unixctl_command_register("version", "", 0, 0, unixctl_version, NULL);
*serverp = server;
exit:
+ if (abs_path) {
+ free(abs_path);
+ }
free(punix_path);
return error;
}
} else {
VLOG_WARN_RL(&rl, "%s: accept failed: %s",
pstream_get_name(server->listener),
- strerror(error));
+ ovs_strerror(error));
}
}
}
}
\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. */
char *abs_path, *unix_path;
struct stream *stream;
int error;
+#ifdef _WIN32
+ FILE *file;
+ int port;
+
+ abs_path = strdup(path);
+ file = fopen(abs_path, "r");
+ if (!file) {
+ int error = errno;
+ ovs_error(error, "could not open %s", abs_path);
+ free(abs_path);
+ return error;
+ }
- *client = NULL;
+ error = fscanf(file, "%d", &port);
+ if (error != 1) {
+ ovs_error(errno, "failed to read port from %s", abs_path);
+ free(abs_path);
+ return EINVAL;
+ }
+ fclose(file);
+ unix_path = xasprintf("tcp:127.0.0.1:%d", port);
+#else
abs_path = abs_file_name(ovs_rundir(), path);
unix_path = xasprintf("unix:%s", abs_path);
+#endif
+
+ *client = NULL;
+
error = stream_open_block(stream_open(unix_path, &stream, DSCP_DEFAULT),
&stream);
free(unix_path);
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;
}