Extend API and remove lttng_uri from lttng.h
authorDavid Goulet <dgoulet@efficios.com>
Tue, 7 Aug 2012 19:47:19 +0000 (15:47 -0400)
committerDavid Goulet <dgoulet@efficios.com>
Tue, 14 Aug 2012 20:57:26 +0000 (16:57 -0400)
This is a big commit but actually not adding much.

First, struct lttng_uri is removed from lttng.h and replaced by calls
using string URL. The lttng_set_consumer_url is changed to "_url" taking
an handle, a control and a data string URL. You can find the definition
in proposal doc/proposals/0004-lttng-address-api.txt.

The lttng_create_session_uri is removed and the path from the original
lttng_create_session is now used to either pass a local filesystem full
path or a string URL.

Multiple fixes in uri_parse() also especially for IPv6 where address
MUST be enclosed in brackets [] in the string representation.

The help of lttng create and enable-consumer is updated and improved.

Also, the enable-consumer command can now be used without a domain
switch (-u/-k) so the destination URL is set to the global tracing
session and on both UST and kernel session if there is an existing
consumer.

Signed-off-by: David Goulet <dgoulet@efficios.com>
31 files changed:
include/lttng/lttng.h
src/bin/lttng-sessiond/consumer.c
src/bin/lttng-sessiond/consumer.h
src/bin/lttng-sessiond/kernel.c
src/bin/lttng-sessiond/kernel.h
src/bin/lttng-sessiond/main.c
src/bin/lttng-sessiond/session.c
src/bin/lttng-sessiond/session.h
src/bin/lttng-sessiond/trace-kernel.c
src/bin/lttng-sessiond/trace-kernel.h
src/bin/lttng-sessiond/trace-ust.c
src/bin/lttng-sessiond/ust-app.c
src/bin/lttng-sessiond/ust-consumer.c
src/bin/lttng/commands/create.c
src/bin/lttng/commands/enable_consumer.c
src/common/Makefile.am
src/common/consumer.c
src/common/defaults.h
src/common/sessiond-comm/sessiond-comm.c
src/common/sessiond-comm/sessiond-comm.h
src/common/uri.c
src/common/uri.h
src/common/ust-consumer/ust-consumer.c
src/common/utils.c
src/common/utils.h
src/lib/lttng-ctl/Makefile.am
src/lib/lttng-ctl/lttng-ctl.c
tests/tools/Makefile.am
tests/tools/streaming/unit_tests.c
tests/tools/test_kernel_data_trace.c
tests/tools/test_sessions.c

index 7754bcdbce6de2352ab1d0f73c8cd8ae1a9d46a3..d421ca518987fb506916fd02359ba9eef06bf63e 100644 (file)
@@ -23,7 +23,6 @@
 #define _LTTNG_H
 
 #include <limits.h>
-#include <netinet/in.h>
 #include <stdint.h>
 #include <sys/types.h>
 
@@ -141,63 +140,6 @@ enum lttng_health_component {
        LTTNG_HEALTH_ALL,
 };
 
-/* Destination type of lttng URI */
-enum lttng_dst_type {
-       LTTNG_DST_IPV4                        = 1,
-       LTTNG_DST_IPV6                        = 2,
-       LTTNG_DST_PATH                        = 3,
-};
-
-/* Type of lttng URI where it is a final destination or a hop */
-enum lttng_uri_type {
-       LTTNG_URI_DST,  /* The URI is a final destination */
-       /*
-        * Hop are not supported yet but planned for a future release.
-        *
-       LTTNG_URI_HOP,
-       */
-};
-
-/* Communication stream type of a lttng URI */
-enum lttng_stream_type {
-       LTTNG_STREAM_CONTROL,
-       LTTNG_STREAM_DATA,
-};
-
-/*
- * Protocol type of a lttng URI. The value 0 indicate that the proto_type field
- * should be ignored.
- */
-enum lttng_proto_type {
-       LTTNG_TCP                             = 1,
-       /*
-        * UDP protocol is not supported for now.
-        *
-       LTTNG_UDP                             = 2,
-       */
-};
-
-/*
- * Structure representing an URI supported by lttng.
- */
-#define LTTNG_URI_PADDING1_LEN         16
-#define LTTNG_URI_PADDING2_LEN         LTTNG_SYMBOL_NAME_LEN + 32
-struct lttng_uri {
-       enum lttng_dst_type dtype;
-       enum lttng_uri_type utype;
-       enum lttng_stream_type stype;
-       enum lttng_proto_type proto;
-       in_port_t port;
-       char padding[LTTNG_URI_PADDING1_LEN];
-       char subdir[PATH_MAX];
-       union {
-               char ipv4[INET_ADDRSTRLEN];
-               char ipv6[INET6_ADDRSTRLEN];
-               char path[PATH_MAX];
-               char padding[LTTNG_URI_PADDING2_LEN];
-       } dst;
-};
-
 /*
  * The structures should be initialized to zero before use.
  */
@@ -421,18 +363,11 @@ extern struct lttng_handle *lttng_create_handle(const char *session_name,
 extern void lttng_destroy_handle(struct lttng_handle *handle);
 
 /*
- * Create a tracing session using a name and a path where the trace will be
- * written.
- */
-extern int lttng_create_session(const char *name, const char *path);
-
-/*
- * Create a tracing sessioin using a name, URIs and a consumer enable flag.
- * The control URI is mandatory for consumer local or network.
+ * Create a tracing session using a name and an optional URL.
+ *
+ * If _url_ is NULL, no consumer is created for the session.
  */
-extern int lttng_create_session_uri(const char *name,
-               struct lttng_uri *ctrl_uri, struct lttng_uri *data_uri,
-               unsigned int enable_consumer);
+extern int lttng_create_session(const char *name, const char *url);
 
 /*
  * Destroy a tracing session.
@@ -610,14 +545,16 @@ extern void lttng_channel_set_default_attr(struct lttng_domain *domain,
                struct lttng_channel_attr *attr);
 
 /*
- * Set URI for a consumer for a session and domain.
+ * Set URL for a consumer for a session and domain.
+ *
+ * Both data and control URL must be defined. If both URLs are the same, only
+ * the control URL is used even for network streaming.
  *
- * For network streaming, both data and control stream type MUST be defined
- * with a specific URIs. Default port are 5342 and 5343 respectively for
- * control and data which uses the TCP protocol.
+ * Default port are 5342 and 5343 respectively for control and data which uses
+ * the TCP protocol.
  */
-extern int lttng_set_consumer_uri(struct lttng_handle *handle,
-               struct lttng_uri *uri);
+extern int lttng_set_consumer_url(struct lttng_handle *handle,
+               const char *control_url, const char *data_url);
 
 /*
  * Enable the consumer for a session and domain.
index 7071974a16809d963fd830cee252ca43e2758305..9ff4eceb2c84ba3469ef22a5c59b59e57ca16672 100644 (file)
 
 #include "consumer.h"
 
+/*
+ * From a consumer_data structure, allocate and add a consumer socket to the
+ * consumer output.
+ *
+ * Return 0 on success, else negative value on error
+ */
+int consumer_create_socket(struct consumer_data *data,
+               struct consumer_output *output)
+{
+       int ret = 0;
+       struct consumer_socket *socket;
+
+       assert(data);
+
+       if (output == NULL || data->cmd_sock < 0) {
+               /*
+                * Not an error. Possible there is simply not spawned consumer or it's
+                * disabled for the tracing session asking the socket.
+                */
+               goto error;
+       }
+
+       rcu_read_lock();
+       socket = consumer_find_socket(data->cmd_sock, output);
+       rcu_read_unlock();
+       if (socket == NULL) {
+               socket = consumer_allocate_socket(data->cmd_sock);
+               if (socket == NULL) {
+                       ret = -1;
+                       goto error;
+               }
+
+               socket->lock = &data->lock;
+               rcu_read_lock();
+               consumer_add_socket(socket, output);
+               rcu_read_unlock();
+       }
+
+       DBG3("Consumer socket created (fd: %d) and added to output",
+                       data->cmd_sock);
+
+error:
+       return ret;
+}
+
 /*
  * Find a consumer_socket in a consumer_output hashtable. Read side lock must
  * be acquired before calling this function and across use of the
@@ -43,7 +88,7 @@ struct consumer_socket *consumer_find_socket(int key,
        struct consumer_socket *socket = NULL;
 
        /* Negative keys are lookup failures */
-       if (key < 0) {
+       if (key < 0 || consumer == NULL) {
                return NULL;
        }
 
index ab1765c48618b4b43064707e7884820ed66111bb..68a51bb6cb6efc2424b0b2bc7427cbec2925963b 100644 (file)
@@ -144,6 +144,8 @@ int consumer_send_relayd_socket(int consumer_sock,
                enum lttng_stream_type type);
 int consumer_send_destroy_relayd(struct consumer_socket *sock,
                struct consumer_output *consumer);
+int consumer_create_socket(struct consumer_data *data,
+               struct consumer_output *output);
 
 void consumer_init_stream_comm_msg(struct lttcomm_consumer_msg *msg,
                enum lttng_consumer_command cmd,
index 9049022f478e255416e15fb691698e096d01d8ea..6fce7d84fd01644f99e30b091f61f0edc4890cc2 100644 (file)
@@ -356,13 +356,13 @@ error:
  * Create kernel metadata, open from the kernel tracer and add it to the
  * kernel session.
  */
-int kernel_open_metadata(struct ltt_kernel_session *session, char *path)
+int kernel_open_metadata(struct ltt_kernel_session *session)
 {
        int ret;
        struct ltt_kernel_metadata *lkm;
 
        /* Allocate kernel metadata */
-       lkm = trace_kernel_create_metadata(path);
+       lkm = trace_kernel_create_metadata();
        if (lkm == NULL) {
                goto error;
        }
index 0ef083073f32cb7c2baec4e99b3e1074e3a984e9..4591e48f34e0633493ec7f283d89f6f6ebecac0c 100644 (file)
@@ -42,7 +42,7 @@ int kernel_disable_channel(struct ltt_kernel_channel *chan);
 int kernel_disable_event(struct ltt_kernel_event *event);
 int kernel_enable_event(struct ltt_kernel_event *event);
 int kernel_enable_channel(struct ltt_kernel_channel *chan);
-int kernel_open_metadata(struct ltt_kernel_session *session, char *path);
+int kernel_open_metadata(struct ltt_kernel_session *session);
 int kernel_open_metadata_stream(struct ltt_kernel_session *session);
 int kernel_open_channel_stream(struct ltt_kernel_channel *channel);
 int kernel_flush_buffer(struct ltt_kernel_channel *channel);
index 6955c80b099203b23cdab6f82eb94f2c52bbc28c..1e9c0be9419f1676735e5b1fe93ec8e3ccc26169 100644 (file)
@@ -2135,8 +2135,8 @@ static int setup_relayd(struct ltt_session *session)
 
        DBG2("Setting relayd for session %s", session->name);
 
-       if (usess && usess->consumer->type == CONSUMER_DST_NET &&
-                       usess->consumer->enabled) {
+       if (usess && usess->consumer && usess->consumer->type == CONSUMER_DST_NET
+                       && usess->consumer->enabled) {
                /* For each consumer socket, send relayd sockets */
                cds_lfht_for_each_entry(usess->consumer->socks->ht, &iter.iter,
                                socket, node.node) {
@@ -2151,8 +2151,10 @@ static int setup_relayd(struct ltt_session *session)
                                goto error;
                        }
                }
-       } else if (ksess && ksess->consumer->type == CONSUMER_DST_NET &&
-                       ksess->consumer->enabled) {
+       }
+
+       if (ksess && ksess->consumer && ksess->consumer->type == CONSUMER_DST_NET
+                       && ksess->consumer->enabled) {
                cds_lfht_for_each_entry(ksess->consumer->socks->ht, &iter.iter,
                                socket, node.node) {
                        /* Code flow error */
@@ -2183,6 +2185,9 @@ static int copy_session_consumer(int domain, struct ltt_session *session)
        const char *dir_name;
        struct consumer_output *consumer;
 
+       assert(session);
+       assert(session->consumer);
+
        switch (domain) {
        case LTTNG_DOMAIN_KERNEL:
                DBG3("Copying tracing session consumer output in kernel session");
@@ -2209,12 +2214,6 @@ static int copy_session_consumer(int domain, struct ltt_session *session)
        strncat(consumer->subdir, dir_name, sizeof(consumer->subdir));
        DBG3("Copy session consumer subdir %s", consumer->subdir);
 
-       /* Add default trace directory name */
-       if (consumer->type == CONSUMER_DST_LOCAL) {
-               strncat(consumer->dst.trace_path, dir_name,
-                               sizeof(consumer->dst.trace_path));
-       }
-
        ret = LTTCOMM_OK;
 
 error:
@@ -2231,6 +2230,7 @@ static int create_ust_session(struct ltt_session *session,
        struct ltt_ust_session *lus = NULL;
 
        assert(session);
+       assert(domain);
        assert(session->consumer);
 
        switch (domain->type) {
@@ -2250,18 +2250,6 @@ static int create_ust_session(struct ltt_session *session,
                goto error;
        }
 
-       if (session->consumer->type == CONSUMER_DST_LOCAL) {
-               ret = run_as_mkdir_recursive(lus->pathname, S_IRWXU | S_IRWXG,
-                               session->uid, session->gid);
-               if (ret < 0) {
-                       if (ret != -EEXIST) {
-                               ERR("Trace directory creation error");
-                               ret = LTTCOMM_UST_SESS_FAIL;
-                               goto error;
-                       }
-               }
-       }
-
        lus->uid = session->uid;
        lus->gid = session->gid;
        session->ust_session = lus;
@@ -2295,6 +2283,9 @@ static int create_kernel_session(struct ltt_session *session)
                goto error;
        }
 
+       /* Code flow safety */
+       assert(session->kernel_session);
+
        /* Copy session output to the newly created Kernel session */
        ret = copy_session_consumer(LTTNG_DOMAIN_KERNEL, session);
        if (ret != LTTCOMM_OK) {
@@ -2302,7 +2293,8 @@ static int create_kernel_session(struct ltt_session *session)
        }
 
        /* Create directory(ies) on local filesystem. */
-       if (session->consumer->type == CONSUMER_DST_LOCAL) {
+       if (session->kernel_session->consumer->type == CONSUMER_DST_LOCAL &&
+                       strlen(session->kernel_session->consumer->dst.trace_path) > 0) {
                ret = run_as_mkdir_recursive(
                                session->kernel_session->consumer->dst.trace_path,
                                S_IRWXU | S_IRWXG, session->uid, session->gid);
@@ -2604,6 +2596,77 @@ error:
        return ret;
 }
 
+
+/*
+ * Add URI so the consumer output object. Set the correct path depending on the
+ * domain adding the default trace directory.
+ */
+static int add_uri_to_consumer(struct consumer_output *consumer,
+               struct lttng_uri *uri, int domain)
+{
+       int ret;
+       const char *default_trace_dir;
+
+       assert(uri);
+
+       if (consumer == NULL) {
+               DBG("No consumer detected. Don't add URI. Stopping.");
+               ret = LTTCOMM_NO_CONSUMER;
+               goto error;
+       }
+
+       switch (domain) {
+       case LTTNG_DOMAIN_KERNEL:
+               default_trace_dir = DEFAULT_KERNEL_TRACE_DIR;
+               break;
+       case LTTNG_DOMAIN_UST:
+               default_trace_dir = DEFAULT_UST_TRACE_DIR;
+               break;
+       default:
+               /*
+                * This case is possible is we try to add the URI to the global tracing
+                * session consumer object which in this case there is no subdir.
+                */
+               default_trace_dir = "";
+       }
+
+       switch (uri->dtype) {
+       case LTTNG_DST_IPV4:
+       case LTTNG_DST_IPV6:
+               DBG2("Setting network URI to consumer");
+
+               /* Set URI into consumer output object */
+               ret = consumer_set_network_uri(consumer, uri);
+               if (ret < 0) {
+                       ret = LTTCOMM_FATAL;
+                       goto error;
+               }
+
+               /* On a new subdir, reappend the default trace dir. */
+               if (strlen(uri->subdir) != 0) {
+                       strncat(consumer->subdir, default_trace_dir,
+                                       sizeof(consumer->subdir));
+               }
+
+               break;
+       case LTTNG_DST_PATH:
+               DBG2("Setting trace directory path from URI to %s", uri->dst.path);
+               memset(consumer->dst.trace_path, 0,
+                               sizeof(consumer->dst.trace_path));
+               strncpy(consumer->dst.trace_path, uri->dst.path,
+                               sizeof(consumer->dst.trace_path));
+               /* Append default trace dir */
+               strncat(consumer->dst.trace_path, default_trace_dir,
+                               sizeof(consumer->dst.trace_path));
+               /* Flag consumer as local. */
+               consumer->type = CONSUMER_DST_LOCAL;
+               break;
+       }
+
+error:
+       return ret;
+}
+
 /*
  * Command LTTNG_DISABLE_CHANNEL processed by the client thread.
  */
@@ -3289,8 +3352,7 @@ static int cmd_start_trace(struct ltt_session *session)
        if (ksession != NULL) {
                /* Open kernel metadata */
                if (ksession->metadata == NULL) {
-                       ret = kernel_open_metadata(ksession,
-                                       ksession->consumer->dst.trace_path);
+                       ret = kernel_open_metadata(ksession);
                        if (ret < 0) {
                                ret = LTTCOMM_KERN_META_FAIL;
                                goto error;
@@ -3422,38 +3484,102 @@ error:
 }
 
 /*
- * Command LTTNG_CREATE_SESSION_URI processed by the client thread.
+ * Command LTTNG_CREATE_SESSION processed by the client thread.
  */
-static int cmd_create_session_uri(char *name, struct lttng_uri *ctrl_uri,
-               struct lttng_uri *data_uri, unsigned int enable_consumer,
-               lttng_sock_cred *creds)
+static int cmd_create_session_uri(char *name, struct lttng_uri *uris,
+               size_t nb_uri, lttng_sock_cred *creds)
 {
-       int ret;
-       char *path = NULL;
+       int ret, have_default_name = 0;
+       char *path = NULL, datetime[16];
        struct ltt_session *session;
-       struct consumer_output *consumer;
+       struct consumer_output *consumer = NULL;
+       struct lttng_uri *ctrl_uri, *data_uri = NULL;
+       time_t rawtime;
+       struct tm *timeinfo;
+
+       assert(name);
+
+       /* Flag if we have a default session. */
+       if (strncmp(name, DEFAULT_SESSION_NAME,
+                               strlen(DEFAULT_SESSION_NAME)) == 0) {
+               have_default_name = 1;
+       } else {
+               /* Get date and time for session path */
+               time(&rawtime);
+               timeinfo = localtime(&rawtime);
+               strftime(datetime, sizeof(datetime), "%Y%m%d-%H%M%S", timeinfo);
+       }
 
-       /* Verify if the session already exist */
+       /*
+        * Verify if the session already exist
+        *
+        * XXX: There is no need for the session lock list here since the caller
+        * (process_client_msg) is holding it. We might want to change that so a
+        * single command does not lock the entire session list.
+        */
        session = session_find_by_name(name);
        if (session != NULL) {
                ret = LTTCOMM_EXIST_SESS;
-               goto error;
+               goto consumer_error;
        }
 
-       /* TODO: validate URIs */
-
-       /* Create default consumer output */
+       /* Create default consumer output for the session not yet created. */
        consumer = consumer_create_output(CONSUMER_DST_LOCAL);
        if (consumer == NULL) {
                ret = LTTCOMM_FATAL;
+               goto consumer_error;
+       }
+
+       /* Add session name and data to the consumer subdir */
+       if (have_default_name) {
+               ret = snprintf(consumer->subdir, sizeof(consumer->subdir), "/%s",
+                               name);
+       } else {
+               ret = snprintf(consumer->subdir, sizeof(consumer->subdir), "/%s-%s",
+                               name, datetime);
+       }
+       if (ret < 0) {
+               PERROR("snprintf consumer subdir");
                goto error;
        }
-       strncpy(consumer->subdir, ctrl_uri->subdir, sizeof(consumer->subdir));
-       DBG2("Consumer subdir set to %s", consumer->subdir);
+       DBG2("Consumer subdir set to '%s'", consumer->subdir);
+
+       /*
+        * This means that the lttng_create_session call was called with the _path_
+        * argument set to NULL.
+        */
+       if (uris == NULL) {
+               /*
+                * At this point, we'll skip the consumer URI setup and create a
+                * session with a NULL path which will flag the session to NOT spawn a
+                * consumer.
+                */
+               DBG("Create session %s with NO uri, skipping consumer setup", name);
+               goto skip_consumer;
+       }
+
+       /* TODO: validate URIs */
+
+       ctrl_uri = &uris[0];
+       if (nb_uri > 1) {
+               data_uri = &uris[1];
+       }
+
+       /* Set subdirectory from the ctrl_uri received. */
+       if (strlen(ctrl_uri->subdir) > 0) {
+               strncpy(consumer->subdir, ctrl_uri->subdir, sizeof(consumer->subdir));
+               DBG2("Consumer subdir copy from ctrl_uri '%s'", consumer->subdir);
+       }
 
        switch (ctrl_uri->dtype) {
        case LTTNG_DST_IPV4:
        case LTTNG_DST_IPV6:
+               /*
+                * We MUST have a data_uri set at this point or else there is a code
+                * flow error. The caller should check that.
+                */
+               assert(data_uri);
+
                /* Set control URI into consumer output object */
                ret = consumer_set_network_uri(consumer, ctrl_uri);
                if (ret < 0) {
@@ -3479,53 +3605,50 @@ static int cmd_create_session_uri(char *name, struct lttng_uri *ctrl_uri,
                break;
        }
 
-       /* Set if the consumer is enabled or not */
-       consumer->enabled = enable_consumer;
+       consumer->enabled = 1;
 
+skip_consumer:
+       /* Create tracing session in the registry */
        ret = session_create(name, path, LTTNG_SOCK_GET_UID_CRED(creds),
                        LTTNG_SOCK_GET_GID_CRED(creds));
        if (ret != LTTCOMM_OK) {
-               goto consumer_error;
+               goto error;
        }
 
-       /* Get the newly created session pointer back */
+       /*
+        * Get the newly created session pointer back
+        *
+        * XXX: There is no need for the session lock list here since the caller
+        * (process_client_msg) is holding it. We might want to change that so a
+        * single command does not lock the entire session list.
+        */
        session = session_find_by_name(name);
        assert(session);
 
        /* Assign consumer to session */
        session->consumer = consumer;
 
-       return LTTCOMM_OK;
-
-consumer_error:
-       consumer_destroy_output(consumer);
-error:
-       return ret;
-}
-
-/*
- * Command LTTNG_CREATE_SESSION processed by the client thread.
- */
-static int cmd_create_session(char *name, char *path, lttng_sock_cred *creds)
-{
-       int ret;
-       struct lttng_uri uri;
-
-       /* Zeroed temporary URI */
-       memset(&uri, 0, sizeof(uri));
-
-       uri.dtype = LTTNG_DST_PATH;
-       uri.utype = LTTNG_URI_DST;
-       strncpy(uri.dst.path, path, sizeof(uri.dst.path));
-
-       /* TODO: Strip date-time from path and put it in uri's subdir */
-
-       ret = cmd_create_session_uri(name, &uri, NULL, 1, creds);
-       if (ret != LTTCOMM_OK) {
-               goto error;
+       /* Set correct path to session */
+       if (have_default_name) {
+               /* We have the default session so the date-time is already appended */
+               ret = snprintf(session->path, sizeof(session->path), "%s/%s",
+                               path, name);
+       } else {
+               ret = snprintf(session->path, sizeof(session->path), "%s/%s-%s",
+                               path, name, datetime);
+       }
+       if (ret < 0) {
+               PERROR("snprintf session path");
+               goto session_error;
        }
 
+       return LTTCOMM_OK;
+
+session_error:
+       session_destroy(session);
 error:
+       consumer_destroy_output(consumer);
+consumer_error:
        return ret;
 }
 
@@ -3787,12 +3910,16 @@ error:
  * Command LTTNG_SET_CONSUMER_URI processed by the client thread.
  */
 static int cmd_set_consumer_uri(int domain, struct ltt_session *session,
-               struct lttng_uri *uri)
+               size_t nb_uri, struct lttng_uri *uris)
 {
-       int ret;
+       int ret, i;
        struct ltt_kernel_session *ksess = session->kernel_session;
        struct ltt_ust_session *usess = session->ust_session;
-       struct consumer_output *consumer;
+       struct consumer_output *consumer = NULL;
+
+       assert(session);
+       assert(uris);
+       assert(nb_uri > 0);
 
        /* Can't enable consumer after session started. */
        if (session->enabled) {
@@ -3800,14 +3927,29 @@ static int cmd_set_consumer_uri(int domain, struct ltt_session *session,
                goto error;
        }
 
+       if (!session->start_consumer) {
+               ret = LTTCOMM_NO_CONSUMER;
+               goto error;
+       }
+
+       /*
+        * This case switch makes sure the domain session has a temporary consumer
+        * so the URL can be set.
+        */
        switch (domain) {
+       case 0:
+               /* Code flow error. A session MUST always have a consumer object */
+               assert(session->consumer);
+               /*
+                * The URL will be added to the tracing session consumer instead of a
+                * specific domain consumer.
+                */
+               consumer = session->consumer;
+               break;
        case LTTNG_DOMAIN_KERNEL:
-       {
-               struct lttng_ht_iter iter;
-               struct consumer_socket *socket;
-
                /* Code flow error if we don't have a kernel session here. */
                assert(ksess);
+               assert(ksess->consumer);
 
                /* Create consumer output if none exists */
                consumer = ksess->tmp_consumer;
@@ -3817,58 +3959,10 @@ static int cmd_set_consumer_uri(int domain, struct ltt_session *session,
                                ret = LTTCOMM_FATAL;
                                goto error;
                        }
-                       /* Reassign new pointer */
                        ksess->tmp_consumer = consumer;
                }
 
-               switch (uri->dtype) {
-               case LTTNG_DST_IPV4:
-               case LTTNG_DST_IPV6:
-                       DBG2("Setting network URI for kernel session %s", session->name);
-
-                       /* Set URI into consumer output object */
-                       ret = consumer_set_network_uri(consumer, uri);
-                       if (ret < 0) {
-                               ret = LTTCOMM_FATAL;
-                               goto error;
-                       }
-
-                       /* On a new subdir, reappend the default trace dir. */
-                       if (strlen(uri->subdir) != 0) {
-                               strncat(consumer->subdir, DEFAULT_KERNEL_TRACE_DIR,
-                                               sizeof(consumer->subdir));
-                       }
-
-                       cds_lfht_for_each_entry(consumer->socks->ht, &iter.iter,
-                                       socket, node.node) {
-                               /* Code flow error */
-                               assert(socket->fd >= 0);
-
-                               pthread_mutex_lock(socket->lock);
-                               ret = send_socket_relayd_consumer(domain, session, uri, consumer,
-                                               socket->fd);
-                               pthread_mutex_unlock(socket->lock);
-                               if (ret != LTTCOMM_OK) {
-                                       goto error;
-                               }
-                       }
-
-                       break;
-               case LTTNG_DST_PATH:
-                       DBG2("Setting trace directory path from URI to %s", uri->dst.path);
-                       memset(consumer->dst.trace_path, 0,
-                                       sizeof(consumer->dst.trace_path));
-                       strncpy(consumer->dst.trace_path, uri->dst.path,
-                                       sizeof(consumer->dst.trace_path));
-                       /* Append default kernel trace dir */
-                       strncat(consumer->dst.trace_path, DEFAULT_KERNEL_TRACE_DIR,
-                                       sizeof(consumer->dst.trace_path));
-                       break;
-               }
-
-               /* All good! */
                break;
-       }
        case LTTNG_DOMAIN_UST:
                /* Code flow error if we don't have a kernel session here. */
                assert(usess);
@@ -3881,70 +3975,41 @@ static int cmd_set_consumer_uri(int domain, struct ltt_session *session,
                                ret = LTTCOMM_FATAL;
                                goto error;
                        }
-                       /* Reassign new pointer */
                        usess->tmp_consumer = consumer;
                }
 
-               switch (uri->dtype) {
-               case LTTNG_DST_IPV4:
-               case LTTNG_DST_IPV6:
-               {
-                       struct consumer_socket *socket;
+               break;
+       }
 
-                       DBG2("Setting network URI for UST session %s", session->name);
+       for (i = 0; i < nb_uri; i++) {
+               struct consumer_socket *socket;
+               struct lttng_ht_iter iter;
 
-                       /* Set URI into consumer object */
-                       ret = consumer_set_network_uri(consumer, uri);
-                       if (ret < 0) {
-                               ret = LTTCOMM_FATAL;
-                               goto error;
-                       }
+               ret = add_uri_to_consumer(consumer, &uris[i], domain);
+               if (ret < 0) {
+                       goto error;
+               }
 
-                       /* On a new subdir, reappend the default trace dir. */
-                       if (strlen(uri->subdir) != 0) {
-                               strncat(consumer->subdir, DEFAULT_UST_TRACE_DIR,
-                                               sizeof(consumer->subdir));
-                       }
+               /* Don't send relayd socket if URI is NOT remote */
+               if (uris[i].dtype == LTTNG_DST_PATH) {
+                       continue;
+               }
 
-                       rcu_read_lock();
-                       socket = consumer_find_socket(uatomic_read(&ust_consumerd64_fd),
-                                       consumer);
-                       if (socket != NULL) {
-                               pthread_mutex_lock(socket->lock);
-                               ret = send_socket_relayd_consumer(domain, session, uri,
-                                               consumer, socket->fd);
-                               pthread_mutex_unlock(socket->lock);
-                               if (ret != LTTCOMM_OK) {
-                                       goto error;
-                               }
-                       }
+               /* Try to send relayd URI to the consumer if exist. */
+               cds_lfht_for_each_entry(consumer->socks->ht, &iter.iter,
+                               socket, node.node) {
 
-                       socket = consumer_find_socket(uatomic_read(&ust_consumerd32_fd),
-                                       consumer);
-                       if (socket != NULL) {
-                               pthread_mutex_lock(socket->lock);
-                               ret = send_socket_relayd_consumer(domain, session, uri,
-                                               consumer, socket->fd);
-                               pthread_mutex_unlock(socket->lock);
-                               if (ret != LTTCOMM_OK) {
-                                       goto error;
-                               }
+                       /* A socket in the HT should never have a negative fd */
+                       assert(socket->fd >= 0);
+
+                       pthread_mutex_lock(socket->lock);
+                       ret = send_socket_relayd_consumer(domain, session, &uris[i],
+                                       consumer, socket->fd);
+                       pthread_mutex_unlock(socket->lock);
+                       if (ret != LTTCOMM_OK) {
+                               goto error;
                        }
-                       rcu_read_unlock();
-                       break;
                }
-               case LTTNG_DST_PATH:
-                       DBG2("Setting trace directory path from URI to %s", uri->dst.path);
-                       memset(consumer->dst.trace_path, 0,
-                                       sizeof(consumer->dst.trace_path));
-                       strncpy(consumer->dst.trace_path, uri->dst.path,
-                                       sizeof(consumer->dst.trace_path));
-                       /* Append default UST trace dir */
-                       strncat(consumer->dst.trace_path, DEFAULT_UST_TRACE_DIR,
-                                       sizeof(consumer->dst.trace_path));
-                       break;
-               }
-               break;
        }
 
        /* All good! */
@@ -3964,13 +4029,24 @@ static int cmd_disable_consumer(int domain, struct ltt_session *session)
        struct ltt_ust_session *usess = session->ust_session;
        struct consumer_output *consumer;
 
+       assert(session);
+
        if (session->enabled) {
                /* Can't disable consumer on an already started session */
                ret = LTTCOMM_TRACE_ALREADY_STARTED;
                goto error;
        }
 
+       if (!session->start_consumer) {
+               ret = LTTCOMM_NO_CONSUMER;
+               goto error;
+       }
+
        switch (domain) {
+       case 0:
+               DBG("Disable tracing session %s consumer", session->name);
+               consumer = session->consumer;
+               break;
        case LTTNG_DOMAIN_KERNEL:
                /* Code flow error if we don't have a kernel session here. */
                assert(ksess);
@@ -3992,11 +4068,13 @@ static int cmd_disable_consumer(int domain, struct ltt_session *session)
                goto error;
        }
 
-       assert(consumer);
-       consumer->enabled = 0;
-
-       /* Success at this point */
-       ret = LTTCOMM_OK;
+       if (consumer) {
+               consumer->enabled = 0;
+               /* Success at this point */
+               ret = LTTCOMM_OK;
+       } else {
+               ret = LTTCOMM_NO_CONSUMER;
+       }
 
 error:
        return ret;
@@ -4010,7 +4088,9 @@ static int cmd_enable_consumer(int domain, struct ltt_session *session)
        int ret;
        struct ltt_kernel_session *ksess = session->kernel_session;
        struct ltt_ust_session *usess = session->ust_session;
-       struct consumer_output *tmp_out;
+       struct consumer_output *consumer = NULL;
+
+       assert(session);
 
        /* Can't enable consumer after session started. */
        if (session->enabled) {
@@ -4018,7 +4098,16 @@ static int cmd_enable_consumer(int domain, struct ltt_session *session)
                goto error;
        }
 
+       if (!session->start_consumer) {
+               ret = LTTCOMM_NO_CONSUMER;
+               goto error;
+       }
+
        switch (domain) {
+       case 0:
+               assert(session->consumer);
+               consumer = session->consumer;
+               break;
        case LTTNG_DOMAIN_KERNEL:
                /* Code flow error if we don't have a kernel session here. */
                assert(ksess);
@@ -4033,20 +4122,21 @@ static int cmd_enable_consumer(int domain, struct ltt_session *session)
                        goto error;
                }
 
-               tmp_out = ksess->tmp_consumer;
-               if (tmp_out == NULL) {
+               consumer = ksess->tmp_consumer;
+               if (consumer == NULL) {
+                       ret = LTTCOMM_OK;
                        /* No temp. consumer output exists. Using the current one. */
                        DBG3("No temporary consumer. Using default");
-                       ret = LTTCOMM_OK;
+                       consumer = ksess->consumer;
                        goto error;
                }
 
-               switch (tmp_out->type) {
+               switch (consumer->type) {
                case CONSUMER_DST_LOCAL:
                        DBG2("Consumer output is local. Creating directory(ies)");
 
                        /* Create directory(ies) */
-                       ret = run_as_mkdir_recursive(tmp_out->dst.trace_path,
+                       ret = run_as_mkdir_recursive(consumer->dst.trace_path,
                                        S_IRWXU | S_IRWXG, session->uid, session->gid);
                        if (ret < 0) {
                                if (ret != -EEXIST) {
@@ -4059,13 +4149,13 @@ static int cmd_enable_consumer(int domain, struct ltt_session *session)
                case CONSUMER_DST_NET:
                        DBG2("Consumer output is network. Validating URIs");
                        /* Validate if we have both control and data path set. */
-                       if (!tmp_out->dst.net.control_isset) {
-                               ret = LTTCOMM_URI_CTRL_MISS;
+                       if (!consumer->dst.net.control_isset) {
+                               ret = LTTCOMM_URL_CTRL_MISS;
                                goto error;
                        }
 
-                       if (!tmp_out->dst.net.data_isset) {
-                               ret = LTTCOMM_URI_DATA_MISS;
+                       if (!consumer->dst.net.data_isset) {
+                               ret = LTTCOMM_URL_DATA_MISS;
                                goto error;
                        }
 
@@ -4091,7 +4181,7 @@ static int cmd_enable_consumer(int domain, struct ltt_session *session)
                 * is valid.
                 */
                consumer_destroy_output(ksess->consumer);
-               ksess->consumer = tmp_out;
+               ksess->consumer = consumer;
                ksess->tmp_consumer = NULL;
 
                break;
@@ -4109,20 +4199,21 @@ static int cmd_enable_consumer(int domain, struct ltt_session *session)
                        goto error;
                }
 
-               tmp_out = usess->tmp_consumer;
-               if (tmp_out == NULL) {
+               consumer = usess->tmp_consumer;
+               if (consumer == NULL) {
+                       ret = LTTCOMM_OK;
                        /* No temp. consumer output exists. Using the current one. */
                        DBG3("No temporary consumer. Using default");
-                       ret = LTTCOMM_OK;
+                       consumer = usess->consumer;
                        goto error;
                }
 
-               switch (tmp_out->type) {
+               switch (consumer->type) {
                case CONSUMER_DST_LOCAL:
                        DBG2("Consumer output is local. Creating directory(ies)");
 
                        /* Create directory(ies) */
-                       ret = run_as_mkdir_recursive(tmp_out->dst.trace_path,
+                       ret = run_as_mkdir_recursive(consumer->dst.trace_path,
                                        S_IRWXU | S_IRWXG, session->uid, session->gid);
                        if (ret < 0) {
                                if (ret != -EEXIST) {
@@ -4135,13 +4226,13 @@ static int cmd_enable_consumer(int domain, struct ltt_session *session)
                case CONSUMER_DST_NET:
                        DBG2("Consumer output is network. Validating URIs");
                        /* Validate if we have both control and data path set. */
-                       if (!tmp_out->dst.net.control_isset) {
-                               ret = LTTCOMM_URI_CTRL_MISS;
+                       if (!consumer->dst.net.control_isset) {
+                               ret = LTTCOMM_URL_CTRL_MISS;
                                goto error;
                        }
 
-                       if (!tmp_out->dst.net.data_isset) {
-                               ret = LTTCOMM_URI_DATA_MISS;
+                       if (!consumer->dst.net.data_isset) {
+                               ret = LTTCOMM_URL_DATA_MISS;
                                goto error;
                        }
 
@@ -4152,7 +4243,7 @@ static int cmd_enable_consumer(int domain, struct ltt_session *session)
                                goto error;
                        }
 
-                       if (tmp_out->net_seq_index == -1) {
+                       if (consumer->net_seq_index == -1) {
                                ret = LTTCOMM_ENABLE_CONSUMER_FAIL;
                                DBG2("Network index is not set on the consumer");
                                goto error;
@@ -4173,14 +4264,21 @@ static int cmd_enable_consumer(int domain, struct ltt_session *session)
                 * is valid.
                 */
                consumer_destroy_output(usess->consumer);
-               usess->consumer = tmp_out;
+               usess->consumer = consumer;
                usess->tmp_consumer = NULL;
 
                break;
        }
 
-       /* Success at this point */
-       ret = LTTCOMM_OK;
+       /* Enable it */
+       if (consumer) {
+               consumer->enabled = 1;
+               /* Success at this point */
+               ret = LTTCOMM_OK;
+       } else {
+               /* Should not really happend... */
+               ret = LTTCOMM_NO_CONSUMER;
+       }
 
 error:
        return ret;
@@ -4208,7 +4306,6 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int sock,
 
        switch (cmd_ctx->lsm->cmd_type) {
        case LTTNG_CREATE_SESSION:
-       case LTTNG_CREATE_SESSION_URI:
        case LTTNG_DESTROY_SESSION:
        case LTTNG_LIST_SESSIONS:
        case LTTNG_LIST_DOMAINS:
@@ -4255,7 +4352,6 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int sock,
        /* Commands that DO NOT need a session. */
        switch (cmd_ctx->lsm->cmd_type) {
        case LTTNG_CREATE_SESSION:
-       case LTTNG_CREATE_SESSION_URI:
        case LTTNG_CALIBRATE:
        case LTTNG_LIST_SESSIONS:
        case LTTNG_LIST_TRACEPOINTS:
@@ -4289,6 +4385,7 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int sock,
        if (!need_domain) {
                goto skip_domain;
        }
+
        /*
         * Check domain type for specific "pre-action".
         */
@@ -4316,8 +4413,6 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int sock,
 
                /* Need a session for kernel command */
                if (need_tracing_session) {
-                       struct consumer_socket *socket;
-
                        if (cmd_ctx->session->kernel_session == NULL) {
                                ret = create_kernel_session(cmd_ctx->session);
                                if (ret < 0) {
@@ -4329,7 +4424,8 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int sock,
                        /* Start the kernel consumer daemon */
                        pthread_mutex_lock(&kconsumer_data.pid_mutex);
                        if (kconsumer_data.pid == 0 &&
-                                       cmd_ctx->lsm->cmd_type != LTTNG_REGISTER_CONSUMER) {
+                                       cmd_ctx->lsm->cmd_type != LTTNG_REGISTER_CONSUMER &&
+                                       cmd_ctx->session->start_consumer) {
                                pthread_mutex_unlock(&kconsumer_data.pid_mutex);
                                ret = start_consumerd(&kconsumer_data);
                                if (ret < 0) {
@@ -4341,24 +4437,14 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int sock,
                                pthread_mutex_unlock(&kconsumer_data.pid_mutex);
                        }
 
-                       /* Set kernel consumer socket fd */
-                       if (kconsumer_data.cmd_sock >= 0) {
-                               rcu_read_lock();
-                               socket = consumer_find_socket(kconsumer_data.cmd_sock,
-                                               cmd_ctx->session->kernel_session->consumer);
-                               rcu_read_unlock();
-                               if (socket == NULL) {
-                                       socket = consumer_allocate_socket(kconsumer_data.cmd_sock);
-                                       if (socket == NULL) {
-                                               goto error;
-                                       }
-
-                                       socket->lock = &kconsumer_data.lock;
-                                       rcu_read_lock();
-                                       consumer_add_socket(socket,
-                                                       cmd_ctx->session->kernel_session->consumer);
-                                       rcu_read_unlock();
-                               }
+                       /*
+                        * The consumer was just spawned so we need to add the socket to
+                        * the consumer output of the session if exist.
+                        */
+                       ret = consumer_create_socket(&kconsumer_data,
+                                       cmd_ctx->session->kernel_session->consumer);
+                       if (ret < 0) {
+                               goto error;
                        }
                }
 
@@ -4372,8 +4458,7 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int sock,
                }
 
                if (need_tracing_session) {
-                       struct consumer_socket *socket;
-
+                       /* Create UST session if none exist. */
                        if (cmd_ctx->session->ust_session == NULL) {
                                ret = create_ust_session(cmd_ctx->session,
                                                &cmd_ctx->lsm->domain);
@@ -4387,7 +4472,8 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int sock,
                        pthread_mutex_lock(&ustconsumer64_data.pid_mutex);
                        if (consumerd64_bin[0] != '\0' &&
                                        ustconsumer64_data.pid == 0 &&
-                                       cmd_ctx->lsm->cmd_type != LTTNG_REGISTER_CONSUMER) {
+                                       cmd_ctx->lsm->cmd_type != LTTNG_REGISTER_CONSUMER &&
+                                       cmd_ctx->session->start_consumer) {
                                pthread_mutex_unlock(&ustconsumer64_data.pid_mutex);
                                ret = start_consumerd(&ustconsumer64_data);
                                if (ret < 0) {
@@ -4406,30 +4492,17 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int sock,
                         * Setup socket for consumer 64 bit. No need for atomic access
                         * since it was set above and can ONLY be set in this thread.
                         */
-                       if (ust_consumerd64_fd >= 0) {
-                               rcu_read_lock();
-                               socket = consumer_find_socket(uatomic_read(&ust_consumerd64_fd),
-                                               cmd_ctx->session->ust_session->consumer);
-                               rcu_read_unlock();
-                               if (socket == NULL) {
-                                       socket = consumer_allocate_socket(ust_consumerd64_fd);
-                                       if (socket == NULL) {
-                                               goto error;
-                                       }
-                                       socket->lock = &ustconsumer32_data.lock;
-
-                                       rcu_read_lock();
-                                       consumer_add_socket(socket,
-                                                       cmd_ctx->session->ust_session->consumer);
-                                       rcu_read_unlock();
-                               }
-                               DBG3("UST consumer 64 bit socket set to %d", socket->fd);
+                       ret = consumer_create_socket(&ustconsumer64_data,
+                                       cmd_ctx->session->ust_session->consumer);
+                       if (ret < 0) {
+                               goto error;
                        }
 
                        /* 32-bit */
                        if (consumerd32_bin[0] != '\0' &&
                                        ustconsumer32_data.pid == 0 &&
-                                       cmd_ctx->lsm->cmd_type != LTTNG_REGISTER_CONSUMER) {
+                                       cmd_ctx->lsm->cmd_type != LTTNG_REGISTER_CONSUMER &&
+                                       cmd_ctx->session->start_consumer) {
                                pthread_mutex_unlock(&ustconsumer32_data.pid_mutex);
                                ret = start_consumerd(&ustconsumer32_data);
                                if (ret < 0) {
@@ -4448,24 +4521,10 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int sock,
                         * Setup socket for consumer 64 bit. No need for atomic access
                         * since it was set above and can ONLY be set in this thread.
                         */
-                       if (ust_consumerd32_fd >= 0) {
-                               rcu_read_lock();
-                               socket = consumer_find_socket(uatomic_read(&ust_consumerd64_fd),
-                                               cmd_ctx->session->ust_session->consumer);
-                               rcu_read_unlock();
-                               if (socket == NULL) {
-                                       socket = consumer_allocate_socket(ust_consumerd32_fd);
-                                       if (socket == NULL) {
-                                               goto error;
-                                       }
-                                       socket->lock = &ustconsumer32_data.lock;
-
-                                       rcu_read_lock();
-                                       consumer_add_socket(socket,
-                                                       cmd_ctx->session->ust_session->consumer);
-                                       rcu_read_unlock();
-                               }
-                               DBG3("UST consumer 32 bit socket set to %d", socket->fd);
+                       ret = consumer_create_socket(&ustconsumer32_data,
+                                       cmd_ctx->session->ust_session->consumer);
+                       if (ret < 0) {
+                               goto error;
                        }
                }
                break;
@@ -4551,7 +4610,26 @@ skip_domain:
        }
        case LTTNG_ENABLE_CONSUMER:
        {
+               /*
+                * XXX: 0 means that this URI should be applied on the session. Should
+                * be a DOMAIN enuam.
+                */
                ret = cmd_enable_consumer(cmd_ctx->lsm->domain.type, cmd_ctx->session);
+               if (ret != LTTCOMM_OK) {
+                       goto error;
+               }
+
+               if (cmd_ctx->lsm->domain.type == 0) {
+                       /* Add the URI for the UST session if a consumer is present. */
+                       if (cmd_ctx->session->ust_session &&
+                                       cmd_ctx->session->ust_session->consumer) {
+                               ret = cmd_enable_consumer(LTTNG_DOMAIN_UST, cmd_ctx->session);
+                       } else if (cmd_ctx->session->kernel_session &&
+                                       cmd_ctx->session->kernel_session->consumer) {
+                               ret = cmd_enable_consumer(LTTNG_DOMAIN_KERNEL,
+                                               cmd_ctx->session);
+                       }
+               }
                break;
        }
        case LTTNG_ENABLE_EVENT:
@@ -4605,7 +4683,8 @@ skip_domain:
                struct lttng_event_field *fields;
                ssize_t nb_fields;
 
-               nb_fields = cmd_list_tracepoint_fields(cmd_ctx->lsm->domain.type, &fields);
+               nb_fields = cmd_list_tracepoint_fields(cmd_ctx->lsm->domain.type,
+                               &fields);
                if (nb_fields < 0) {
                        ret = -nb_fields;
                        goto error;
@@ -4615,7 +4694,8 @@ skip_domain:
                 * Setup lttng message with payload size set to the event list size in
                 * bytes and then copy list into the llm payload.
                 */
-               ret = setup_lttng_msg(cmd_ctx, sizeof(struct lttng_event_field) * nb_fields);
+               ret = setup_lttng_msg(cmd_ctx,
+                               sizeof(struct lttng_event_field) * nb_fields);
                if (ret < 0) {
                        free(fields);
                        goto setup_error;
@@ -4632,8 +4712,56 @@ skip_domain:
        }
        case LTTNG_SET_CONSUMER_URI:
        {
+               size_t nb_uri, len;
+               struct lttng_uri *uris;
+
+               nb_uri = cmd_ctx->lsm->u.uri.size;
+               len = nb_uri * sizeof(struct lttng_uri);
+
+               if (nb_uri == 0) {
+                       ret = LTTCOMM_INVALID;
+                       goto error;
+               }
+
+               uris = zmalloc(len);
+               if (uris == NULL) {
+                       ret = LTTCOMM_FATAL;
+                       goto error;
+               }
+
+               /* Receive variable len data */
+               DBG("Receiving %lu URI(s) from client ...", nb_uri);
+               ret = lttcomm_recv_unix_sock(sock, uris, len);
+               if (ret <= 0) {
+                       DBG("No URIs received from client... continuing");
+                       *sock_error = 1;
+                       ret = LTTCOMM_SESSION_FAIL;
+                       goto error;
+               }
+
                ret = cmd_set_consumer_uri(cmd_ctx->lsm->domain.type, cmd_ctx->session,
-                               &cmd_ctx->lsm->u.uri);
+                               nb_uri, uris);
+               if (ret != LTTCOMM_OK) {
+                       goto error;
+               }
+
+               /*
+                * XXX: 0 means that this URI should be applied on the session. Should
+                * be a DOMAIN enuam.
+                */
+               if (cmd_ctx->lsm->domain.type == 0) {
+                       /* Add the URI for the UST session if a consumer is present. */
+                       if (cmd_ctx->session->ust_session &&
+                                       cmd_ctx->session->ust_session->consumer) {
+                               ret = cmd_set_consumer_uri(LTTNG_DOMAIN_UST, cmd_ctx->session,
+                                               nb_uri, uris);
+                       } else if (cmd_ctx->session->kernel_session &&
+                                       cmd_ctx->session->kernel_session->consumer) {
+                               ret = cmd_set_consumer_uri(LTTNG_DOMAIN_KERNEL,
+                                               cmd_ctx->session, nb_uri, uris);
+                       }
+               }
+
                break;
        }
        case LTTNG_START_TRACE:
@@ -4648,26 +4776,47 @@ skip_domain:
        }
        case LTTNG_CREATE_SESSION:
        {
-               ret = cmd_create_session(cmd_ctx->lsm->session.name,
-                               cmd_ctx->lsm->session.path, &cmd_ctx->creds);
-               break;
-       }
-       case LTTNG_CREATE_SESSION_URI:
-       {
-               ret = cmd_create_session_uri(cmd_ctx->lsm->session.name,
-                               &cmd_ctx->lsm->u.create_uri.ctrl_uri,
-                               &cmd_ctx->lsm->u.create_uri.data_uri,
-                               cmd_ctx->lsm->u.create_uri.enable_consumer, &cmd_ctx->creds);
+               size_t nb_uri, len;
+               struct lttng_uri *uris = NULL;
+
+               nb_uri = cmd_ctx->lsm->u.uri.size;
+               len = nb_uri * sizeof(struct lttng_uri);
+
+               if (nb_uri > 0) {
+                       uris = zmalloc(len);
+                       if (uris == NULL) {
+                               ret = LTTCOMM_FATAL;
+                               goto error;
+                       }
+
+                       /* Receive variable len data */
+                       DBG("Waiting for %lu URIs from client ...", nb_uri);
+                       ret = lttcomm_recv_unix_sock(sock, uris, len);
+                       if (ret <= 0) {
+                               DBG("No URIs received from client... continuing");
+                               *sock_error = 1;
+                               ret = LTTCOMM_SESSION_FAIL;
+                               goto error;
+                       }
+
+                       if (nb_uri == 1 && uris[0].dtype != LTTNG_DST_PATH) {
+                               DBG("Creating session with ONE network URI is a bad call");
+                               ret = LTTCOMM_SESSION_FAIL;
+                               goto error;
+                       }
+               }
+
+               ret = cmd_create_session_uri(cmd_ctx->lsm->session.name, uris, nb_uri,
+                       &cmd_ctx->creds);
+
                break;
        }
        case LTTNG_DESTROY_SESSION:
        {
                ret = cmd_destroy_session(cmd_ctx->session,
                                cmd_ctx->lsm->session.name);
-               /*
-                * Set session to NULL so we do not unlock it after
-                * free.
-                */
+
+               /* Set session to NULL so we do not unlock it after free. */
                cmd_ctx->session = NULL;
                break;
        }
index 2181c0dd58fc5b4ccb33f9a5c4ae10fe7bda2ff0..e445363ea03d214d90a4f4ded762ad9593d818b1 100644 (file)
@@ -188,10 +188,11 @@ int session_create(char *name, char *path, uid_t uid, gid_t gid)
                        ret = LTTCOMM_FATAL;
                        goto error_asprintf;
                }
+               new_session->start_consumer = 1;
        } else {
-               ERR("No session path given");
-               ret = LTTCOMM_FATAL;
-               goto error;
+               /* No path indicates that there is no use for a consumer. */
+               new_session->start_consumer = 0;
+               new_session->path[0] = '\0';
        }
 
        /* Init kernel session */
@@ -204,7 +205,7 @@ int session_create(char *name, char *path, uid_t uid, gid_t gid)
        new_session->uid = uid;
        new_session->gid = gid;
 
-       /* Mkdir if we have a valid path length */
+       /* Mkdir if we have a valid path and length */
        if (strlen(new_session->path) > 0) {
                ret = run_as_mkdir_recursive(new_session->path, S_IRWXU | S_IRWXG,
                                new_session->uid, new_session->gid);
@@ -222,9 +223,13 @@ int session_create(char *name, char *path, uid_t uid, gid_t gid)
        new_session->id = add_session_list(new_session);
        session_unlock_list();
 
-       DBG("Tracing session %s created in %s with ID %u by UID %d GID %d",
-               name, path, new_session->id,
-               new_session->uid, new_session->gid);
+       /*
+        * Consumer is let to NULL since the create_session_uri command will set it
+        * up and, if valid, assign it to the session.
+        */
+
+       DBG("Tracing session %s created in %s with ID %u by UID %d GID %d", name,
+                       path, new_session->id, new_session->uid, new_session->gid);
 
        return LTTCOMM_OK;
 
index 167ea9c058afa2fac651e1fedc886e7009526aca..b90e8f4677f8530227825e3671639cf1b3bf0547 100644 (file)
@@ -82,6 +82,9 @@ struct ltt_session {
         * copied into those sessions.
         */
        struct consumer_output *consumer;
+
+       /* Indicates whether or not we have to spawn consumer(s) */
+       unsigned int start_consumer;
 };
 
 /* Prototypes */
index c0239d4bb8230aacd8901b3881c41c1498577cc3..7748b891faef7b35add6d9c6e8e2da2e52f24f96 100644 (file)
@@ -86,13 +86,13 @@ error:
 struct ltt_kernel_session *trace_kernel_create_session(char *path)
 {
        int ret;
-       struct ltt_kernel_session *lks;
+       struct ltt_kernel_session *lks = NULL;
 
        /* Allocate a new ltt kernel session */
        lks = zmalloc(sizeof(struct ltt_kernel_session));
        if (lks == NULL) {
                PERROR("create kernel session zmalloc");
-               goto error;
+               goto alloc_error;
        }
 
        /* Init data structure */
@@ -103,7 +103,6 @@ struct ltt_kernel_session *trace_kernel_create_session(char *path)
        lks->metadata = NULL;
        CDS_INIT_LIST_HEAD(&lks->channel_list.head);
 
-       /* Create default consumer output object */
        lks->consumer = consumer_create_output(CONSUMER_DST_LOCAL);
        if (lks->consumer == NULL) {
                goto error;
@@ -117,23 +116,29 @@ struct ltt_kernel_session *trace_kernel_create_session(char *path)
         */
        lks->tmp_consumer = NULL;
 
-       /* Use the default consumer output which is the tracing session path. */
-       ret = snprintf(lks->consumer->dst.trace_path, PATH_MAX, "%s/kernel", path);
-       if (ret < 0) {
-               PERROR("snprintf consumer trace path");
-               goto error;
-       }
+       if (path && strlen(path) > 0) {
+               /* Use the default consumer output which is the tracing session path. */
+               ret = snprintf(lks->consumer->dst.trace_path, PATH_MAX,
+                               "%s" DEFAULT_KERNEL_TRACE_DIR, path);
+               if (ret < 0) {
+                       PERROR("snprintf consumer trace path");
+                       goto error;
+               }
 
-       /* Set session path */
-       ret = asprintf(&lks->trace_path, "%s/kernel", path);
-       if (ret < 0) {
-               PERROR("asprintf kernel traces path");
-               goto error;
+               /* Set session path */
+               ret = asprintf(&lks->trace_path, "%s" DEFAULT_KERNEL_TRACE_DIR, path);
+               if (ret < 0) {
+                       PERROR("asprintf kernel traces path");
+                       goto error;
+               }
        }
 
        return lks;
 
 error:
+       free(lks);
+
+alloc_error:
        return NULL;
 }
 
@@ -253,7 +258,7 @@ error:
  *
  * Return pointer to structure or NULL.
  */
-struct ltt_kernel_metadata *trace_kernel_create_metadata(char *path)
+struct ltt_kernel_metadata *trace_kernel_create_metadata(void)
 {
        struct ltt_kernel_metadata *lkm;
        struct lttng_channel *chan;
index d34b83c8cb19ca7da84168db7511b5a76391964b..f04d9e7b50e710fadf27c5e4bc5ac9a198499918 100644 (file)
@@ -122,7 +122,7 @@ struct ltt_kernel_channel *trace_kernel_get_channel_by_name(
 struct ltt_kernel_session *trace_kernel_create_session(char *path);
 struct ltt_kernel_channel *trace_kernel_create_channel(struct lttng_channel *chan, char *path);
 struct ltt_kernel_event *trace_kernel_create_event(struct lttng_event *ev);
-struct ltt_kernel_metadata *trace_kernel_create_metadata(char *path);
+struct ltt_kernel_metadata *trace_kernel_create_metadata(void);
 struct ltt_kernel_stream *trace_kernel_create_stream(const char *name,
                unsigned int count);
 
index 4001ec87bdd8359f6224a1915e84c62f9c22486a..d1e8b8dae117a4369d35681a0e6d7462b0f136c3 100644 (file)
@@ -111,7 +111,7 @@ struct ltt_ust_session *trace_ust_create_session(char *path,
 
        lus->consumer = consumer_create_output(CONSUMER_DST_LOCAL);
        if (lus->consumer == NULL) {
-               goto error;
+               goto error_free_session;
        }
 
        /*
@@ -123,17 +123,21 @@ struct ltt_ust_session *trace_ust_create_session(char *path,
        lus->tmp_consumer = NULL;
 
        /* Use the default consumer output which is the tracing session path. */
-       ret = snprintf(lus->consumer->dst.trace_path, PATH_MAX, "%s/ust", path);
-       if (ret < 0) {
-               PERROR("snprintf UST consumer trace path");
-               goto error;
-       }
+       if (path && strlen(path) > 0) {
+               ret = snprintf(lus->consumer->dst.trace_path, PATH_MAX,
+                               "%s" DEFAULT_UST_TRACE_DIR, path);
+               if (ret < 0) {
+                       PERROR("snprintf UST consumer trace path");
+                       goto error;
+               }
 
-       /* Set session path */
-       ret = snprintf(lus->pathname, PATH_MAX, "%s/ust", path);
-       if (ret < 0) {
-               PERROR("snprintf kernel traces path");
-               goto error_free_session;
+               /* Set session path */
+               ret = snprintf(lus->pathname, PATH_MAX, "%s" DEFAULT_UST_TRACE_DIR,
+                               path);
+               if (ret < 0) {
+                       PERROR("snprintf kernel traces path");
+                       goto error_free_session;
+               }
        }
 
        DBG2("UST trace session create successful");
index 087846df1c45f086298c51baf7996fbc53583a7f..e5d8b5707dea19b10810a89ecae52191b189fc15 100644 (file)
@@ -2177,6 +2177,20 @@ int ust_app_start_trace(struct ltt_ust_session *usess, struct ust_app *app)
                goto skip_setup;
        }
 
+       /* Create directories if consumer is LOCAL and has a path defined. */
+       if (usess->consumer->type == CONSUMER_DST_LOCAL &&
+                       strlen(usess->consumer->dst.trace_path) > 0) {
+               ret = run_as_mkdir_recursive(usess->consumer->dst.trace_path,
+                               S_IRWXU | S_IRWXG, usess->uid, usess->gid);
+               if (ret < 0) {
+                       if (ret != -EEXIST) {
+                               ERR("Trace directory creation error");
+                               ret = -1;
+                               goto error_rcu_unlock;
+                       }
+               }
+       }
+
        /* Indicate that the session has been started once */
        ua_sess->started = 1;
 
index b7e0d359261dbdec4a686a893dbb3a0416ea04ac..aabe49403fbc1215d423986cb7dfa71301da2a47 100644 (file)
@@ -136,8 +136,8 @@ static int send_channel_streams(int sock,
        /* Get the right path name destination */
        if (consumer->type == CONSUMER_DST_LOCAL) {
                /* Set application path to the destination path */
-               ret = snprintf(tmp_path, sizeof(tmp_path), "%s/%s",
-                               consumer->dst.trace_path, usess->path);
+               ret = snprintf(tmp_path, sizeof(tmp_path), "%s/%s/%s",
+                               consumer->dst.trace_path, consumer->subdir, usess->path);
                if (ret < 0) {
                        PERROR("snprintf stream path");
                        goto error;
@@ -225,8 +225,8 @@ static int send_metadata(int sock, struct ust_app_session *usess,
        /* Get correct path name destination */
        if (consumer->type == CONSUMER_DST_LOCAL) {
                /* Set application path to the destination path */
-               ret = snprintf(tmp_path, sizeof(tmp_path), "%s/%s",
-                               consumer->dst.trace_path, usess->path);
+               ret = snprintf(tmp_path, sizeof(tmp_path), "%s/%s/%s",
+                               consumer->dst.trace_path, consumer->subdir, usess->path);
                if (ret < 0) {
                        PERROR("snprintf stream path");
                        goto error;
@@ -289,8 +289,12 @@ int ust_consumer_send_session(struct ust_app_session *usess,
        struct ust_app_channel *ua_chan;
 
        assert(usess);
-       assert(consumer);
-       assert(sock);
+
+       if (consumer == NULL || sock == NULL) {
+               /* There is no consumer so just ignoring the command. */
+               DBG("UST consumer does not exist. Not sending streams");
+               return 0;
+       }
 
        DBG("Sending metadata stream fd to consumer on %d", sock->fd);
 
index 354a68dcfbc461ab09ff86cb64f672b3bc8f0ae8..3e7074e02bc0e35f611fb2e9347342159a7234d2 100644 (file)
@@ -16,6 +16,7 @@
  */
 
 #define _GNU_SOURCE
+#include <assert.h>
 #include <popt.h>
 #include <stdio.h>
 #include <stdlib.h>
 
 static char *opt_output_path;
 static char *opt_session_name;
-static char *opt_uris;
-static char *opt_ctrl_uris;
-static char *opt_data_uris;
-static int opt_no_consumer = 1;
+static char *opt_url;
+static char *opt_ctrl_url;
+static char *opt_data_url;
+static int opt_no_consumer;
+static int opt_disable_consumer;
 
 enum {
        OPT_HELP = 1,
@@ -50,10 +52,11 @@ static struct poptOption long_options[] = {
        {"help", 'h', POPT_ARG_NONE, NULL, OPT_HELP, NULL, NULL},
        {"output", 'o', POPT_ARG_STRING, &opt_output_path, 0, NULL, NULL},
        {"list-options", 0, POPT_ARG_NONE, NULL, OPT_LIST_OPTIONS, NULL, NULL},
-       {"set-uri",        'U', POPT_ARG_STRING, &opt_uris, 0, 0, 0},
-       {"ctrl-uri",       'C', POPT_ARG_STRING, &opt_ctrl_uris, 0, 0, 0},
-       {"data-uri",       'D', POPT_ARG_STRING, &opt_data_uris, 0, 0, 0},
-       {"no-consumer",      0, POPT_ARG_NONE, &opt_no_consumer, 0, 0, 0},
+       {"set-uri",        'U', POPT_ARG_STRING, &opt_url, 0, 0, 0},
+       {"ctrl-uri",       'C', POPT_ARG_STRING, &opt_ctrl_url, 0, 0, 0},
+       {"data-uri",       'D', POPT_ARG_STRING, &opt_data_url, 0, 0, 0},
+       {"no-consumer",      0, POPT_ARG_VAL, &opt_no_consumer, 1, 0, 0},
+       {"disable-consumer", 0, POPT_ARG_VAL, &opt_disable_consumer, 1, 0, 0},
        {0, 0, 0, 0, 0, 0, 0}
 };
 
@@ -62,85 +65,175 @@ static struct poptOption long_options[] = {
  */
 static void usage(FILE *ofp)
 {
-       fprintf(ofp, "usage: lttng create [options] [NAME]\n");
+       fprintf(ofp, "usage: lttng create [NAME] [OPTIONS] \n");
        fprintf(ofp, "\n");
-       fprintf(ofp, "  The default NAME is 'auto-yyyymmdd-hhmmss'\n");
+       fprintf(ofp, "Without a given NAME, the default is 'auto-<yyyymmdd>-<hhmmss>'\n");
+       fprintf(ofp, "\n");
+       fprintf(ofp, "Options:\n");
        fprintf(ofp, "  -h, --help           Show this help\n");
        fprintf(ofp, "      --list-options   Simple listing of options\n");
        fprintf(ofp, "  -o, --output PATH    Specify output path for traces\n");
-       fprintf(ofp, "  -U, --set-uri=URI    Set URI for the enable-consumer destination.\n");
+       fprintf(ofp, "\n");
+       fprintf(ofp, "Extended Options:\n");
+       fprintf(ofp, "\n");
+       fprintf(ofp, "Using these options, each API call can be controlled individually.\n");
+       fprintf(ofp, "\n");
+       fprintf(ofp, "  -U, --set-url=URL    Set URL destination of the trace data.\n");
        fprintf(ofp, "                       It is persistent for the session lifetime.\n");
-       fprintf(ofp, "                       Redo the command to change it.\n");
-       fprintf(ofp, "                       This will set both data and control URI for network.\n");
-       fprintf(ofp, "  -C, --ctrl-uri=URI   Set control path URI.\n");
-       fprintf(ofp, "  -D, --data-uri=URI   Set data path URI.\n");
-       fprintf(ofp, "      --no-consumer    Disable consumer for entire tracing session.\n");
+       fprintf(ofp, "                       This will set both data and control URL.\n");
+       fprintf(ofp, "                       You can change it with the enable-consumer cmd\n");
+       fprintf(ofp, "  -C, --ctrl-url=URL   Set control path URL. (Must use -D also)\n");
+       fprintf(ofp, "  -D, --data-url=URL   Set data path URL. (Must use -C also)\n");
+       fprintf(ofp, "      --no-consumer    Don't activate a consumer for this session.\n");
+       fprintf(ofp, "      --disable-consumer\n");
+       fprintf(ofp, "                       Disable consumer for this session.\n");
+       fprintf(ofp, "\n");
+       fprintf(ofp, "Please refer to the man page (lttng(1)) for more information on network\n");
+       fprintf(ofp, "streaming mechanisms and explanation of the control and data port\n");
+       fprintf(ofp, "You must have a running remote lttng-relayd for network streaming\n");
+       fprintf(ofp, "\n");
+       fprintf(ofp, "URL format is has followed:\n");
+       fprintf(ofp, "\n");
+       fprintf(ofp, "  proto://[HOST|IP][:PORT1[:PORT2]][/TRACE_PATH]\n");
+       fprintf(ofp, "\n");
+       fprintf(ofp, "  Supported protocols are (proto):\n");
+       fprintf(ofp, "  > file://...\n");
+       fprintf(ofp, "    Local filesystem full path.\n");
+       fprintf(ofp, "\n");
+       fprintf(ofp, "  > net[4|6]://...\n");
+       fprintf(ofp, "    This will use the default network transport layer which is\n");
+       fprintf(ofp, "    TCP for both control (PORT1) and data port (PORT2).\n");
+       fprintf(ofp, "    The default ports are respectively 5342 and 5343.\n");
+       fprintf(ofp, "\n");
+       fprintf(ofp, "  > tcp[4|6]://...\n");
+       fprintf(ofp, "    Can only be used with -C and -D together\n");
+       fprintf(ofp, "\n");
+       fprintf(ofp, "NOTE: IPv6 address MUST be enclosed in brackets '[]' (rfc2732)\n");
+       fprintf(ofp, "\n");
+       fprintf(ofp, "Examples:\n");
+       fprintf(ofp, "    # lttng create -U net://192.168.1.42\n");
+       fprintf(ofp, "    Uses TCP and default ports for the given destination.\n");
+       fprintf(ofp, "    # lttng create -U net6://[fe80::f66d:4ff:fe53:d220]\n");
+       fprintf(ofp, "    Uses TCP, default ports and IPv6.\n");
+       fprintf(ofp, "    # lttng create s1 -U net://myhost.com:3229\n");
+       fprintf(ofp, "    Set the consumer to the remote HOST on port 3229 for control.\n");
        fprintf(ofp, "\n");
 }
 
 /*
- * Parse URI from string to lttng_uri object array.
+ * For a session name, set the consumer URLs.
  */
-static ssize_t parse_uri_from_str(const char *str_uri, struct lttng_uri **uris)
+static int set_consumer_url(const char *session_name, const char *ctrl_url,
+               const char *data_url)
 {
-       int i;
-       ssize_t size;
-       struct lttng_uri *uri;
+       int ret;
+       struct lttng_handle *handle;
+       struct lttng_domain dom;
+
+       assert(session_name);
+
+       /*
+        * Set handle with the session name and the domain set to 0. This means to
+        * the session daemon that the next action applies on the tracing session
+        * rather then the domain specific session.
+        */
+       memset(&dom, 0, sizeof(dom));
+
+       handle = lttng_create_handle(session_name, &dom);
+       if (handle == NULL) {
+               ret = CMD_FATAL;
+               goto error;
+       }
 
-       if (*uris != NULL) {
-               free(*uris);
+       ret = lttng_set_consumer_url(handle, ctrl_url, data_url);
+       if (ret < 0) {
+               goto error;
        }
 
-       size = uri_parse(str_uri, uris);
-       if (size < 1) {
-               ERR("Bad URI %s. Either the hostname or IP is invalid", str_uri);
-               size = -1;
+       if (ctrl_url) {
+               MSG("Control URL %s set for session %s", ctrl_url, session_name);
        }
 
-       for (i = 0; i < size; i++) {
-               uri = (struct lttng_uri *) &uris[i];
-               /* Set default port if none was given */
-               if (uri->port == 0) {
-                       if (uri->stype == LTTNG_STREAM_CONTROL) {
-                               uri->port = DEFAULT_NETWORK_CONTROL_PORT;
-                       } else if (uri->stype == LTTNG_STREAM_DATA) {
-                               uri->port = DEFAULT_NETWORK_DATA_PORT;
-                       }
-               }
+       if (data_url) {
+               MSG("Data URL %s set for session %s", data_url, session_name);
+       }
+
+error:
+       lttng_destroy_handle(handle);
+       return ret;
+}
+
+/*
+ * For a session name, enable the consumer.
+ */
+static int enable_consumer(const char *session_name)
+{
+       int ret;
+       struct lttng_handle *handle;
+       struct lttng_domain dom;
+
+       assert(session_name);
+
+       /*
+        * Set handle with the session name and the domain set to 0. This means to
+        * the session daemon that the next action applies on the tracing session
+        * rather then the domain specific session.
+        *
+        * XXX: This '0' value should be a domain enum value.
+        */
+       memset(&dom, 0, sizeof(dom));
+
+       handle = lttng_create_handle(session_name, 0);
+       if (handle == NULL) {
+               ret = CMD_FATAL;
+               goto error;
        }
 
-       return size;
+       ret = lttng_enable_consumer(handle);
+       if (ret < 0) {
+               goto error;
+       }
+
+       MSG("Consumer enabled for session %s", session_name);
+
+error:
+       lttng_destroy_handle(handle);
+       return ret;
 }
 
 /*
- * Print URI message.
+ * For a session name, disable the consumer.
  */
-static void print_uri_msg(struct lttng_uri *uri)
+static int disable_consumer(const char *session_name)
 {
-       char *dst;
-
-       switch (uri->dtype) {
-       case LTTNG_DST_IPV4:
-               dst = uri->dst.ipv4;
-               break;
-       case LTTNG_DST_IPV6:
-               dst = uri->dst.ipv6;
-               break;
-       case LTTNG_DST_PATH:
-               dst = uri->dst.path;
-               MSG("Consumer destination set to %s", dst);
-               goto end;
-       default:
-               DBG("Unknown URI destination");
-               goto end;
+       int ret;
+       struct lttng_handle *handle;
+
+       assert(session_name);
+
+       /*
+        * Set handle with the session name and the domain set to 0. This means to
+        * the session daemon that the next action applies on the tracing session
+        * rather then the domain specific session.
+        *
+        * XXX: This '0' value should be a domain enum value.
+        */
+       handle = lttng_create_handle(session_name, 0);
+       if (handle == NULL) {
+               ret = CMD_FATAL;
+               goto error;
        }
 
-       MSG("Consumer %s stream set to %s with the %s protocol on port %d",
-                       uri->stype == LTTNG_STREAM_CONTROL ? "control" : "data",
-                       dst, uri->proto == LTTNG_TCP ? "TCP" : "UNK", uri->port);
+       ret = lttng_disable_consumer(handle);
+       if (ret < 0) {
+               goto error;
+       }
+       free(handle);
 
-end:
-       return;
+       MSG("Consumer disabled for session %s", session_name);
+
+error:
+       return ret;
 }
 
 /*
@@ -149,15 +242,13 @@ end:
  *
  *  Returns one of the CMD_* result constants.
  */
-static int create_session()
+static int create_session(void)
 {
-       int ret, have_name = 0, i;
-       char datetime[16];
+       int ret;
        char *session_name, *traces_path = NULL, *alloc_path = NULL;
+       char *alloc_url = NULL, *url = NULL, datetime[16];
        time_t rawtime;
-       ssize_t size;
        struct tm *timeinfo;
-       struct lttng_uri *uris = NULL, *ctrl_uri = NULL, *data_uri = NULL;
 
        /* Get date and time for automatic session name/path */
        time(&rawtime);
@@ -166,102 +257,39 @@ static int create_session()
 
        /* Auto session name creation */
        if (opt_session_name == NULL) {
-               ret = asprintf(&session_name, "auto-%s", datetime);
+               ret = asprintf(&session_name, DEFAULT_SESSION_NAME "%s", datetime);
                if (ret < 0) {
-                       perror("asprintf session name");
+                       PERROR("asprintf session name");
                        goto error;
                }
                DBG("Auto session name set to %s", session_name);
        } else {
                session_name = opt_session_name;
-               have_name = 1;
        }
 
-       if (opt_output_path != NULL) {
+       if (opt_no_consumer) {
+               url = NULL;
+       } else if (opt_output_path != NULL) {
                traces_path = utils_expand_path(opt_output_path);
                if (traces_path == NULL) {
                        ret = CMD_ERROR;
                        goto error;
                }
 
-               ret = asprintf(&alloc_path, "file://%s", traces_path);
+               /* Create URL string from the local filesytem path */
+               ret = asprintf(&alloc_url, "file://%s", traces_path);
                if (ret < 0) {
-                       PERROR("asprintf expand path");
-                       ret = CMD_FATAL;
-                       goto error;
-               }
-
-               ret = uri_parse(alloc_path, &ctrl_uri);
-               if (ret < 1) {
+                       PERROR("asprintf url path");
                        ret = CMD_FATAL;
                        goto error;
                }
-       } else if (opt_uris) { /* Handling URIs (-U opt) */
-               size = parse_uri_from_str(opt_uris, &uris);
-               if (size < 1) {
-                       ret = CMD_ERROR;
-                       goto error;
-               } else if (size == 1 && uris[0].dtype != LTTNG_DST_PATH) {
-                       ERR("Only net:// and file:// are supported. "
-                                       "Use -C and -D for more fine grained control");
-                       ret = CMD_ERROR;
-                       goto error;
-               } else if (size == 2) {
-                       uris[0].stype = LTTNG_STREAM_CONTROL;
-                       uris[1].stype = LTTNG_STREAM_DATA;
-
-                       for (i = 0; i < size; i++) {
-                               /* Set default port if none was given */
-                               if (uris[i].port == 0) {
-                                       if (uris[i].stype == LTTNG_STREAM_CONTROL) {
-                                               uris[i].port = DEFAULT_NETWORK_CONTROL_PORT;
-                                       } else {
-                                               uris[i].port = DEFAULT_NETWORK_DATA_PORT;
-                                       }
-                               }
-                       }
-
-                       ctrl_uri = &uris[0];
-                       print_uri_msg(ctrl_uri);
-                       data_uri = &uris[1];
-                       print_uri_msg(data_uri);
-               } else {
-                       ctrl_uri = &uris[0];
-                       print_uri_msg(ctrl_uri);
-               }
-       } else if (opt_ctrl_uris || opt_data_uris) {
-               /* Setting up control URI (-C opt) */
-               if (opt_ctrl_uris) {
-                       size = parse_uri_from_str(opt_ctrl_uris, &uris);
-                       if (size < 1) {
-                               ret = CMD_ERROR;
-                               goto error;
-                       }
-                       ctrl_uri = &uris[0];
-                       ctrl_uri->stype = LTTNG_STREAM_CONTROL;
-                       /* Set default port if none specified */
-                       if (ctrl_uri->port == 0) {
-                               ctrl_uri->port = DEFAULT_NETWORK_CONTROL_PORT;
-                       }
-                       print_uri_msg(ctrl_uri);
-               }
-
-               /* Setting up data URI (-D opt) */
-               if (opt_data_uris) {
-                       size = parse_uri_from_str(opt_data_uris, &uris);
-                       if (size < 1) {
-                               ret = CMD_ERROR;
-                               goto error;
-                       }
-                       data_uri = &uris[0];
-                       data_uri->stype = LTTNG_STREAM_DATA;
-                       /* Set default port if none specified */
-                       if (data_uri->port == 0) {
-                               data_uri->port = DEFAULT_NETWORK_DATA_PORT;
-                       }
-                       print_uri_msg(data_uri);
-               }
-       } else {
+               /* URL to use in the lttng_create_session() call */
+               url = alloc_url;
+               MSG("Trace(s) output set to %s", traces_path);
+       } else if (opt_url) { /* Handling URL (-U opt) */
+               url = opt_url;
+               MSG("Trace(s) output set to %s", url);
+       } else if (opt_ctrl_url == NULL && opt_data_url == NULL) {
                /* Auto output path */
                alloc_path = config_get_default_path();
                if (alloc_path == NULL) {
@@ -272,44 +300,19 @@ static int create_session()
                }
                alloc_path = strdup(alloc_path);
 
-               if (have_name) {
-                       ret = asprintf(&traces_path, "file://%s/" DEFAULT_TRACE_DIR_NAME
-                                       "/%s-%s", alloc_path, session_name, datetime);
-               } else {
-                       ret = asprintf(&traces_path, "file://%s/" DEFAULT_TRACE_DIR_NAME
-                                       "/%s", alloc_path, session_name);
-               }
+               ret = asprintf(&alloc_url, "file://%s/" DEFAULT_TRACE_DIR_NAME,
+                               alloc_path);
                if (ret < 0) {
                        PERROR("asprintf trace dir name");
                        ret = CMD_FATAL;
                        goto error;
                }
 
-               ret = uri_parse(traces_path, &ctrl_uri);
-               if (ret < 1) {
-                       ret = CMD_FATAL;
-                       goto error;
-               }
+               url = alloc_url;
+               MSG("Trace(s) output set to %s", alloc_url + strlen("file://"));
        }
 
-       /* If there is no subdir specified and the URI are network */
-       if (strlen(ctrl_uri->subdir) == 0) {
-               if (have_name) {
-                       ret = snprintf(ctrl_uri->subdir, sizeof(ctrl_uri->subdir), "%s-%s",
-                                       session_name, datetime);
-               } else {
-                       ret = snprintf(ctrl_uri->subdir, sizeof(ctrl_uri->subdir), "%s",
-                                       session_name);
-               }
-               if (ret < 0) {
-                       PERROR("snprintf subdir");
-                       goto error;
-               }
-               DBG("Subdir update to %s", ctrl_uri->subdir);
-       }
-
-       ret = lttng_create_session_uri(session_name, ctrl_uri, data_uri,
-                       opt_no_consumer);
+       ret = lttng_create_session(session_name, url);
        if (ret < 0) {
                /* Don't set ret so lttng can interpret the sessiond error. */
                switch (-ret) {
@@ -320,6 +323,32 @@ static int create_session()
                goto error;
        }
 
+       if (opt_session_name == NULL) {
+               MSG("Session created with default name %s", session_name);
+       } else {
+               MSG("Session %s created.", session_name);
+       }
+
+       if (opt_ctrl_url || opt_data_url) {
+               /* Setting up control URI (-C or/and -D opt) */
+               ret = set_consumer_url(session_name, opt_ctrl_url, opt_data_url);
+               if (ret < 0) {
+                       goto error;
+               }
+
+               ret = enable_consumer(session_name);
+               if (ret < 0) {
+                       goto error;
+               }
+       }
+
+       if (opt_disable_consumer && !opt_no_consumer) {
+               ret = disable_consumer(session_name);
+               if (ret < 0) {
+                       goto error;
+               }
+       }
+
        /* Init lttng session config */
        ret = config_init(session_name);
        if (ret < 0) {
@@ -327,11 +356,6 @@ static int create_session()
                goto error;
        }
 
-       MSG("Session %s created.", session_name);
-       if (ctrl_uri->dtype == LTTNG_DST_PATH) {
-               MSG("Traces will be written in %s" , ctrl_uri->dst.path);
-       }
-
        ret = CMD_SUCCESS;
 
 error:
@@ -339,13 +363,17 @@ error:
                free(session_name);
        }
 
-       if (alloc_path) {
-               free(alloc_path);
+       if (alloc_url) {
+               free(alloc_url);
        }
 
        if (traces_path) {
                free(traces_path);
        }
+
+       if (ret < 0) {
+               ERR("%s", lttng_strerror(ret));
+       }
        return ret;
 }
 
index 67594529f0eef81966532aea4020a2102d8000b8..0a61362220b80138dde5ee4a192ddb29639f0662 100644 (file)
@@ -36,10 +36,10 @@ static int opt_kernel;
 static int opt_userspace;
 static int opt_enable;
 static char *opt_session_name;
-static char *opt_uris;
-static char *opt_ctrl_uris;
-static char *opt_data_uris;
-static char *opt_uris_arg;
+static char *opt_url;
+static char *opt_ctrl_url;
+static char *opt_data_url;
+static char *opt_url_arg;
 
 static struct lttng_handle *handle;
 
@@ -55,9 +55,9 @@ static struct poptOption long_options[] = {
        {"session",        's', POPT_ARG_STRING, &opt_session_name, 0, 0, 0},
        {"kernel",         'k', POPT_ARG_VAL, &opt_kernel, 1, 0, 0},
        {"userspace",      'u', POPT_ARG_VAL, &opt_userspace, 1, 0, 0},
-       {"set-uri",        'U', POPT_ARG_STRING, &opt_uris, 0, 0, 0},
-       {"ctrl-uri",       'C', POPT_ARG_STRING, &opt_ctrl_uris, 0, 0, 0},
-       {"data-uri",       'D', POPT_ARG_STRING, &opt_data_uris, 0, 0, 0},
+       {"set-uri",        'U', POPT_ARG_STRING, &opt_url, 0, 0, 0},
+       {"ctrl-uri",       'C', POPT_ARG_STRING, &opt_ctrl_url, 0, 0, 0},
+       {"data-uri",       'D', POPT_ARG_STRING, &opt_data_url, 0, 0, 0},
        {"enable",         'e', POPT_ARG_VAL, &opt_enable, 1, 0, 0},
        {0, 0, 0, 0, 0, 0, 0}
 };
@@ -67,154 +67,60 @@ static struct poptOption long_options[] = {
  */
 static void usage(FILE *ofp)
 {
-       fprintf(ofp, "usage: lttng enable-consumer [-u|-k] [URI] [OPTIONS]\n");
+       fprintf(ofp, "usage: lttng enable-consumer [-u|-k] [URL] [OPTIONS]\n");
        fprintf(ofp, "\n");
-       fprintf(ofp, "The default behavior is to enable a consumer to the current URI.\n");
-       fprintf(ofp, "The default URI is the local filesystem at the path of the session.\n");
+       fprintf(ofp, "The default behavior is to enable a consumer to the current URL.\n");
+       fprintf(ofp, "The default URL is the local filesystem at the path of the session.\n");
        fprintf(ofp, "\n");
        fprintf(ofp, "The enable-consumer feature supports both local and network transport.\n");
        fprintf(ofp, "You must have a running lttng-relayd for network transmission.\n");
        fprintf(ofp, "\n");
-       fprintf(ofp, "You can optionally specify two URIs for respectively the\n");
-       fprintf(ofp, "control and data channel. URI supported:\n");
-       fprintf(ofp, "  > file://PATH\n");
-       fprintf(ofp, "    Local file full system path.\n");
-       fprintf(ofp, "\n");
-       fprintf(ofp, "  > net://DST[:CTRL_PORT[:DATA_PORT]] and net6://...\n");
-       fprintf(ofp, "    This will use the default network transport layer which is\n");
-       fprintf(ofp, "    TCP for both control and data port. The default ports are\n");
-       fprintf(ofp, "    respectively 5342 and 5343.\n");
-       fprintf(ofp, "    Example:\n");
-       fprintf(ofp, "    # lttng enable-consumer net://192.168.1.42 -k\n");
-       fprintf(ofp, "    Uses TCP and default ports for the given destination.\n");
-       fprintf(ofp, "\n");
-       fprintf(ofp, "  > tcp://DST:PORT and tcp6://DST:PORT\n");
-       fprintf(ofp, "\n");
        fprintf(ofp, "Options:\n");
        fprintf(ofp, "  -h, --help           Show this help\n");
        fprintf(ofp, "      --list-options   Simple listing of options\n");
        fprintf(ofp, "  -s, --session=NAME   Apply to session name\n");
        fprintf(ofp, "  -k, --kernel         Apply to the kernel tracer\n");
        fprintf(ofp, "  -u, --userspace      Apply to the user-space tracer\n");
-       //fprintf(ofp, "  -U, --set-uri=URI1[,URI2,...]\n");
        fprintf(ofp, "\n");
        fprintf(ofp, "Extended Options:\n");
        fprintf(ofp, "\n");
-       fprintf(ofp, "Using these options, each API call is controlled individually.\n");
+       fprintf(ofp, "Using these options, each API call can be controlled individually.\n");
        fprintf(ofp, "For instance, -C does not enable the consumer automatically.\n");
        fprintf(ofp, "\n");
-       fprintf(ofp, "  -U, --set-uri=URI    Set URI for the enable-consumer destination.\n");
+       fprintf(ofp, "  -U, --set-uri=URL    Set URL for the enable-consumer destination.\n");
        fprintf(ofp, "                       It is persistent for the session lifetime.\n");
        fprintf(ofp, "                       Redo the command to change it.\n");
-       fprintf(ofp, "                       This will set both data and control URI for network.\n");
-       //fprintf(ofp, "  -C, --ctrl-uri=URI1[,URI2,...]\n");
-       fprintf(ofp, "  -C, --ctrl-uri=URI   Set control path URI.\n");
-       //fprintf(ofp, "  -D, --data-uri=URI1[,URI2,...]\n");
-       fprintf(ofp, "  -D, --data-uri=URI   Set data path URI.\n");
+       fprintf(ofp, "                       This will set both data and control URL for network.\n");
+       fprintf(ofp, "  -C, --ctrl-url=URL   Set control path URL. (Must use -D also)\n");
+       fprintf(ofp, "  -D, --data-url=URL   Set data path URL. (Must use -C also)\n");
        fprintf(ofp, "  -e, --enable         Enable consumer\n");
        fprintf(ofp, "\n");
-}
-
-/*
- * Print URI message.
- */
-static void print_uri_msg(struct lttng_uri *uri)
-{
-       char *dst;
-
-       switch (uri->dtype) {
-       case LTTNG_DST_IPV4:
-               dst = uri->dst.ipv4;
-               break;
-       case LTTNG_DST_IPV6:
-               dst = uri->dst.ipv6;
-               break;
-       case LTTNG_DST_PATH:
-               dst = uri->dst.path;
-               MSG("Consumer destination set to %s", dst);
-               goto end;
-       default:
-               DBG("Unknown URI destination");
-               goto end;
-       }
-
-       MSG("Consumer %s stream set to %s with the %s protocol on port %d",
-                       uri->stype == LTTNG_STREAM_CONTROL ? "control" : "data",
-                       dst, uri->proto == LTTNG_TCP ? "TCP" : "UNK", uri->port);
-
-end:
-       return;
-}
-
-/*
- * Setting URIs taking from the command line arguments. There is some
- * manipulations and special cases using the default args.
- */
-static int set_consumer_arg_uris(struct lttng_uri *uri, size_t size)
-{
-       int ret, i;
-
-       if (size == 2) {
-               /* URIs are the control and data stream respectively for net:// */
-               uri[0].stype = LTTNG_STREAM_CONTROL;
-               uri[1].stype = LTTNG_STREAM_DATA;
-
-               for (i = 0; i < size; i++) {
-                       ret = lttng_set_consumer_uri(handle, &uri[i]);
-                       if (ret < 0) {
-                               ERR("Setting %s stream URI: %s",
-                                               uri[i].stype == LTTNG_STREAM_DATA ? "data" : "control",
-                                               lttng_strerror(ret));
-                               goto error;
-                       }
-                       /* Set default port if none was given */
-                       if (uri[i].port == 0) {
-                               if (uri[i].stype == LTTNG_STREAM_CONTROL) {
-                                       uri[i].port = DEFAULT_NETWORK_CONTROL_PORT;
-                               } else {
-                                       uri[i].port = DEFAULT_NETWORK_DATA_PORT;
-                               }
-                       }
-                       print_uri_msg(&uri[i]);
-               }
-       } else if (size == 1 && uri[0].dtype == LTTNG_DST_PATH) {
-               /* Set URI if it's file:// */
-               ret = lttng_set_consumer_uri(handle, &uri[0]);
-               if (ret < 0) {
-                       ERR("Failed to set URI %s: %s", opt_uris_arg,
-                                       lttng_strerror(ret));
-                       goto error;
-               }
-               print_uri_msg(&uri[0]);
-       } else {
-               ERR("Only net:// and file:// are supported. "
-                               "Use -D or -U for more fine grained control");
-               ret = CMD_ERROR;
-               goto error;
-       }
-
-error:
-       return ret;
-}
-
-/*
- * Parse URI from string to lttng_uri object array.
- */
-static ssize_t parse_uri_from_str(const char *str_uri, struct lttng_uri **uris)
-{
-       ssize_t size;
-
-       if (*uris != NULL) {
-               free(*uris);
-       }
-
-       size = uri_parse(str_uri, uris);
-       if (size < 1) {
-               ERR("Bad URI %s. Either the hostname or IP is invalid", str_uri);
-               size = -1;
-       }
-
-       return size;
+       fprintf(ofp, "\n");
+       fprintf(ofp, "Please refer to the man page (lttng(1)) for more information on network\n");
+       fprintf(ofp, "streaming mechanisms and explanation of the control and data port\n");
+       fprintf(ofp, "\n");
+       fprintf(ofp, "URL format is has followed:\n");
+       fprintf(ofp, "\n");
+       fprintf(ofp, "  proto://[HOST|IP][:PORT1[:PORT2]][/TRACE_PATH]\n");
+       fprintf(ofp, "\n");
+       fprintf(ofp, "  Supported protocols are (proto):\n");
+       fprintf(ofp, "  > file://...\n");
+       fprintf(ofp, "    Local filesystem full path.\n");
+       fprintf(ofp, "\n");
+       fprintf(ofp, "  > net[4|6]://...\n");
+       fprintf(ofp, "    This will use the default network transport layer which is\n");
+       fprintf(ofp, "    TCP for both control (PORT1) and data port (PORT2).\n");
+       fprintf(ofp, "    The default ports are respectively 5342 and 5343.\n");
+       fprintf(ofp, "\n");
+       fprintf(ofp, "  > tcp[4|6]://...\n");
+       fprintf(ofp, "    Can only be used with -C and -D together\n");
+       fprintf(ofp, "\n");
+       fprintf(ofp, "NOTE: IPv6 address MUST be enclosed in brackets '[]' (rfc2732)\n");
+       fprintf(ofp, "\n");
+       fprintf(ofp, "Examples:\n");
+       fprintf(ofp, "    # lttng enable-consumer -u net://192.168.1.42\n");
+       fprintf(ofp, "    Uses TCP and default ports for user space tracing (-u).\n");
+       fprintf(ofp, "\n");
 }
 
 /*
@@ -224,9 +130,7 @@ static int enable_consumer(char *session_name)
 {
        int ret = CMD_SUCCESS;
        int run_enable_cmd = 1;
-       ssize_t size;
        struct lttng_domain dom;
-       struct lttng_uri *uri = NULL;
 
        memset(&dom, 0, sizeof(dom));
 
@@ -236,9 +140,14 @@ static int enable_consumer(char *session_name)
        } else if (opt_userspace) {
                dom.type = LTTNG_DOMAIN_UST;
        } else {
-               ERR("Please specify a tracer (-k/--kernel or -u/--userspace)");
-               ret = CMD_ERROR;
-               goto error;
+               /*
+                * Set handle with domain set to 0. This means to the session daemon
+                * that the next action applies on the tracing session rather then the
+                * domain specific session.
+                *
+                * XXX: This '0' value should be a domain enum value.
+                */
+               dom.type = 0;
        }
 
        handle = lttng_create_handle(session_name, &dom);
@@ -248,88 +157,49 @@ static int enable_consumer(char *session_name)
        }
 
        /* Handle trailing arguments */
-       if (opt_uris_arg) {
-               size = parse_uri_from_str(opt_uris_arg, &uri);
-               if (size < 1) {
-                       ret = CMD_ERROR;
+       if (opt_url_arg) {
+               ret = lttng_set_consumer_url(handle, opt_url_arg, NULL);
+               if (ret < 0) {
+                       ERR("%s", lttng_strerror(ret));
                        goto error;
                }
 
-               ret = set_consumer_arg_uris(uri, size);
-               if (ret < 0) {
-                       goto free_uri;
-               }
+               MSG("URL %s set for session %s.", opt_url_arg, session_name);
        }
 
-       /* Handling URIs (-U opt) */
-       if (opt_uris) {
-               size = parse_uri_from_str(opt_uris, &uri);
-               if (size < 1) {
-                       ret = CMD_ERROR;
-                       goto error;
-               }
-
-               ret = set_consumer_arg_uris(uri, size);
+       /* Handling URLs (-U opt) */
+       if (opt_url) {
+               ret = lttng_set_consumer_url(handle, opt_url, NULL);
                if (ret < 0) {
-                       goto free_uri;
+                       ERR("%s", lttng_strerror(ret));
+                       goto error;
                }
 
                /* opt_enable will tell us to run or not the enable_consumer cmd. */
                run_enable_cmd = 0;
-       }
-
-       /* Setting up control URI (-C opt) */
-       if (opt_ctrl_uris) {
-               size = parse_uri_from_str(opt_ctrl_uris, &uri);
-               if (size < 1) {
-                       ret = CMD_ERROR;
-                       goto error;
-               }
 
-               /* Set default port if none specified */
-               if (uri[0].port == 0) {
-                       uri[0].port = DEFAULT_NETWORK_CONTROL_PORT;
-               }
-
-               uri[0].stype = LTTNG_STREAM_CONTROL;
+               MSG("URL %s set for session %s.", opt_url, session_name);
+       }
 
-               ret = lttng_set_consumer_uri(handle, &uri[0]);
+       /* Setting up control URL (-C or/and -D opt) */
+       if (opt_ctrl_url || opt_data_url) {
+               ret = lttng_set_consumer_url(handle, opt_ctrl_url, opt_data_url);
                if (ret < 0) {
-                       ERR("Failed to set control URI %s: %s", opt_ctrl_uris,
-                                       lttng_strerror(ret));
-                       goto free_uri;
+                       ERR("%s", lttng_strerror(ret));
+                       goto error;
                }
-               print_uri_msg(&uri[0]);
 
                /* opt_enable will tell us to run or not the enable_consumer cmd. */
                run_enable_cmd = 0;
-       }
 
-       /* Setting up data URI (-D opt) */
-       if (opt_data_uris) {
-               size = parse_uri_from_str(opt_data_uris, &uri);
-               if (size < 1) {
-                       ret = CMD_ERROR;
-                       goto error;
+               if (opt_ctrl_url) {
+                       MSG("Control URL %s set for session %s.", opt_ctrl_url,
+                                       session_name);
                }
 
-               /* Set default port if none specified */
-               if (uri[0].port == 0) {
-                       uri[0].port = DEFAULT_NETWORK_DATA_PORT;
+               if (opt_data_url) {
+                       MSG("Data URL %s set for session %s.", opt_data_url, session_name);
                }
-
-               uri[0].stype = LTTNG_STREAM_DATA;
-
-               ret = lttng_set_consumer_uri(handle, &uri[0]);
-               if (ret < 0) {
-                       ERR("Failed to set data URI %s: %s", opt_data_uris,
-                                       lttng_strerror(ret));
-                       goto free_uri;
-               }
-               print_uri_msg(&uri[0]);
-
-               /* opt_enable will tell us to run or not the enable_consumer cmd. */
-               run_enable_cmd = 0;
        }
 
        /* Enable consumer (-e opt) */
@@ -341,15 +211,12 @@ static int enable_consumer(char *session_name)
                        if (ret == -LTTCOMM_ENABLE_CONSUMER_FAIL) {
                                ERR("Perhaps the session was previously started?");
                        }
-                       goto free_uri;
+                       goto error;
                }
 
                MSG("Consumer enabled successfully");
        }
 
-free_uri:
-       free(uri);
-
 error:
        lttng_destroy_handle(handle);
        return ret;
@@ -384,8 +251,8 @@ int cmd_enable_consumer(int argc, const char **argv)
                }
        }
 
-       opt_uris_arg = (char *) poptGetArg(pc);
-       DBG("URIs: %s", opt_uris_arg);
+       opt_url_arg = (char *) poptGetArg(pc);
+       DBG("URLs: %s", opt_url_arg);
 
        /* Get session name */
        if (!opt_session_name) {
index 131fda8e5925ee51579828d30659a6664b0d0e16..84bed094fd94f16365cb0d5b8d5a96824f25ce86 100644 (file)
@@ -9,8 +9,7 @@ noinst_HEADERS = lttng-kernel.h defaults.h macros.h error.h futex.h uri.h utils.
 # Common library
 noinst_LTLIBRARIES = libcommon.la
 
-libcommon_la_SOURCES = runas.c runas.h common.h futex.c futex.h uri.c uri.h \
-                       utils.c utils.h
+libcommon_la_SOURCES = utils.c utils.h runas.c runas.h common.h futex.c futex.h uri.c uri.h
 
 # Consumer library
 noinst_LTLIBRARIES += libconsumer.la
index 0e33bea72e96b4c6a7c35fd82ec9e1cfb9bb82da..deebd2e2b353cd1cc4365f5ede45e78203e9653e 100644 (file)
@@ -278,8 +278,12 @@ void consumer_del_stream(struct lttng_consumer_stream *stream)
                                stream->relayd_stream_id,
                                stream->next_net_seq_num - 1);
                if (ret < 0) {
-                       ERR("Unable to close stream on the relayd. Continuing");
-                       /* Continue here. There is nothing we can do for the relayd.*/
+                       DBG("Unable to close stream on the relayd. Continuing");
+                       /*
+                        * Continue here. There is nothing we can do for the relayd.
+                        * Chances are that the relayd has closed the socket so we just
+                        * continue cleaning up.
+                        */
                }
 
                /* Both conditions are met, we destroy the relayd. */
index 5ab63d050712e5c5f8641dd4b90f37a74dac1c82..0303c02ae80cee9a42548b8b012b8a19591eb3ae 100644 (file)
 #define DEFAULT_KERNEL_TRACE_DIR                "/kernel"
 #define DEFAULT_UST_TRACE_DIR                   "/ust"
 
+/*
+ * Default session name for the lttng command line. This default value will
+ * get the date and time appended (%Y%m%d-%H%M%S) to it.
+ */
+#define DEFAULT_SESSION_NAME                    "auto-"
+
 /* Default consumer paths */
 #define DEFAULT_CONSUMERD_RUNDIR                "%s"
 
index 432cf4cfff746e014cd66b1af465338076b4a0c2..aee9458b44660d1a728b726eee79379277f69230 100644 (file)
@@ -138,14 +138,15 @@ static const char *lttcomm_readable_code[] = {
        [ LTTCOMM_ERR_INDEX(LTTCOMM_NO_USTCONSUMERD) ] = "No UST consumer detected",
        [ LTTCOMM_ERR_INDEX(LTTCOMM_NO_KERNCONSUMERD) ] = "No kernel consumer detected",
        [ LTTCOMM_ERR_INDEX(LTTCOMM_EVENT_EXIST_LOGLEVEL) ] = "Event already enabled with different loglevel",
-       [ LTTCOMM_ERR_INDEX(LTTCOMM_URI_DATA_MISS) ] = "Missing data path URI",
-       [ LTTCOMM_ERR_INDEX(LTTCOMM_URI_CTRL_MISS) ] = "Missing control data path URI",
+       [ LTTCOMM_ERR_INDEX(LTTCOMM_URL_DATA_MISS) ] = "Missing data path URL",
+       [ LTTCOMM_ERR_INDEX(LTTCOMM_URL_CTRL_MISS) ] = "Missing control data path URL",
        [ LTTCOMM_ERR_INDEX(LTTCOMM_ENABLE_CONSUMER_FAIL) ] = "Enabling consumer failed",
        [ LTTCOMM_ERR_INDEX(LTTCOMM_RELAYD_SESSION_FAIL) ] = "Unable to create session on lttng-relayd",
        [ LTTCOMM_ERR_INDEX(LTTCOMM_RELAYD_VERSION_FAIL) ] = "Relay daemon not compatible",
        [ LTTCOMM_ERR_INDEX(LTTCOMM_FILTER_INVAL) ] = "Invalid filter bytecode",
        [ LTTCOMM_ERR_INDEX(LTTCOMM_FILTER_NOMEM) ] = "Not enough memory for filter bytecode",
        [ LTTCOMM_ERR_INDEX(LTTCOMM_FILTER_EXIST) ] = "Filter already exist",
+       [ LTTCOMM_ERR_INDEX(LTTCOMM_NO_CONSUMER) ] = "Consumer not found for tracing session",
 };
 
 /*
index 8d1400cdb98c8a51a1b789e4192dfc37fb902c3b..e544bf5458870e880a40c20fdab61c71c51bca69 100644 (file)
@@ -29,6 +29,7 @@
 #include <limits.h>
 #include <lttng/lttng.h>
 #include <common/compat/socket.h>
+#include <common/uri.h>
 
 #include <arpa/inet.h>
 #include <netinet/in.h>
@@ -61,7 +62,6 @@ enum lttcomm_sessiond_command {
        LTTNG_ENABLE_ALL_EVENT,
        /* Session daemon command */
        LTTNG_CREATE_SESSION,
-       LTTNG_CREATE_SESSION_URI,
        LTTNG_DESTROY_SESSION,
        LTTNG_LIST_CHANNELS,
        LTTNG_LIST_DOMAINS,
@@ -185,14 +185,15 @@ enum lttcomm_return_code {
        LTTCOMM_NO_USTCONSUMERD,        /* No UST consumer detected */
        LTTCOMM_NO_KERNCONSUMERD,       /* No Kernel consumer detected */
        LTTCOMM_EVENT_EXIST_LOGLEVEL,   /* Event already enabled with different loglevel */
-       LTTCOMM_URI_DATA_MISS,          /* Missing network data URI */
-       LTTCOMM_URI_CTRL_MISS,          /* Missing network control URI */
+       LTTCOMM_URL_DATA_MISS,          /* Missing network data URL */
+       LTTCOMM_URL_CTRL_MISS,          /* Missing network control URL */
        LTTCOMM_ENABLE_CONSUMER_FAIL,   /* Enabling consumer failed */
        LTTCOMM_RELAYD_SESSION_FAIL,    /* lttng-relayd create session failed */
        LTTCOMM_RELAYD_VERSION_FAIL,    /* lttng-relayd not compatible */
        LTTCOMM_FILTER_INVAL,           /* Invalid filter bytecode */
        LTTCOMM_FILTER_NOMEM,           /* Lack of memory for filter bytecode */
        LTTCOMM_FILTER_EXIST,           /* Filter already exist */
+       LTTCOMM_NO_CONSUMER,            /* No consumer exist for the tracing session */
 
        /* MUST be last element */
        LTTCOMM_NR,                                             /* Last element */
@@ -280,13 +281,11 @@ struct lttcomm_session_msg {
                        char channel_name[NAME_MAX];
                } list;
                struct lttng_calibrate calibrate;
-               /* Used by the set_consumer_uri call */
-               struct lttng_uri uri;
+               /* Used by the set_consumer_url and used by create_session also call */
                struct {
-                       uint32_t enable_consumer;
-                       struct lttng_uri ctrl_uri;
-                       struct lttng_uri data_uri;
-               } create_uri;
+                       /* Number of lttng_uri following */
+                       uint32_t size;
+               } uri;
                struct {
                        char channel_name[NAME_MAX];
                        char event_name[NAME_MAX];
index 6ca46474f06086666b68d22fa1871b51bebfdc9f..3581e307d33a0dfa5bdcb5932b0e5fb648b30114 100644 (file)
@@ -24,6 +24,7 @@
 
 #include <common/common.h>
 #include <common/defaults.h>
+#include <common/utils.h>
 
 #include "uri.h"
 
@@ -32,7 +33,8 @@ enum uri_proto_code {
 };
 
 struct uri_proto {
-       char *name;
+       const char *name;
+       const char *leading_string;
        enum uri_proto_code code;
        enum lttng_proto_type type;
        enum lttng_dst_type dtype;
@@ -40,29 +42,46 @@ struct uri_proto {
 
 /* Supported protocols */
 static const struct uri_proto proto_uri[] = {
-       { .name = "file", .code = P_FILE, .type = 0, .dtype = LTTNG_DST_PATH},
-       { .name = "net", .code = P_NET, .type = LTTNG_TCP, .dtype = LTTNG_DST_IPV4 },
-       { .name = "net6", .code = P_NET6, .type = LTTNG_TCP, .dtype = LTTNG_DST_IPV6 },
-       { .name = "tcp", .code = P_TCP, .type = LTTNG_TCP, .dtype = LTTNG_DST_IPV4 },
-       { .name = "tcp6", .code = P_TCP6, .type = LTTNG_TCP, .dtype = LTTNG_DST_IPV6 },
-       { .name = NULL }
+       { .name = "file", .leading_string = "file://", .code = P_FILE, .type = 0, .dtype = LTTNG_DST_PATH },
+       { .name = "net", .leading_string = "net://", .code = P_NET, .type = LTTNG_TCP, .dtype = LTTNG_DST_IPV4 },
+       { .name = "net6", .leading_string = "net6://", .code = P_NET6, .type = LTTNG_TCP, .dtype = LTTNG_DST_IPV6 },
+       { .name = "tcp", .leading_string = "tcp://", .code = P_TCP, .type = LTTNG_TCP, .dtype = LTTNG_DST_IPV4 },
+       { .name = "tcp6", .leading_string = "tcp6://", .code = P_TCP6, .type = LTTNG_TCP, .dtype = LTTNG_DST_IPV6 },
+       /* Invalid proto marking the end of the array. */
+       { NULL, NULL, 0, 0, 0 }
 };
 
+/*
+ * Return pointer to the character in s matching one of the characters in
+ * accept. If nothing is found, return pointer to the end of string (eos).
+ */
+const inline char *strpbrk_or_eos(const char *s, const char *accept)
+{
+       char *p = strpbrk(s, accept);
+       if (p == NULL) {
+               p = strchr(s, '\0');
+       }
+
+       return p;
+}
+
+
 /*
  * Validate if proto is a supported protocol from proto_uri array.
  */
-static const struct uri_proto *validate_protocol(char *proto)
+static const struct uri_proto *get_uri_proto(const char *uri_str)
 {
-       const struct uri_proto *supported;
+       const struct uri_proto *supported = NULL;
 
        /* Safety net */
-       if (proto == NULL) {
+       if (uri_str == NULL) {
                goto end;
        }
 
        for (supported = &proto_uri[0];
-                       supported->name != NULL; ++supported) {
-               if (strncmp(proto, supported->name, strlen(proto)) == 0) {
+                       supported->leading_string != NULL; ++supported) {
+               if (strncasecmp(uri_str, supported->leading_string,
+                                       strlen(supported->leading_string)) == 0) {
                        goto end;
                }
        }
@@ -101,6 +120,8 @@ static int set_ip_address(const char *addr, int af, char *dst, size_t size)
                memcpy(dst, addr, size);
        }
 
+       DBG2("IP address resolved to %s", dst);
+
        return 0;
 
 error:
@@ -152,18 +173,26 @@ struct lttng_uri *uri_create(void)
  * make sure the correct type (stype) is set on the return URI(s). The default
  * port must also be set by the caller if the returned URI has its port set to
  * zero.
+ *
+ * NOTE: A good part of the following code was inspired from the "wget" source
+ * tree from the src/url.c file and url_parse() function. Also, the
+ * strpbrk_or_eos() function found above is also inspired by the same code.
+ * This code was originally licensed GPLv2 so we acknolwedge the Free Software
+ * Foundation here for the work and to make sure we are compliant with it.
  */
 ssize_t uri_parse(const char *str_uri, struct lttng_uri **uris)
 {
-       int ret;
-       size_t str_offset = 0;
+       int ret, i = 0;
        /* Size of the uris array. Default is 1 */
        ssize_t size = 1;
-       char net[6], dst[LTTNG_MAX_DNNAME + 1], subdir[PATH_MAX];
+       char subdir[PATH_MAX];
        unsigned int ctrl_port = 0;
        unsigned int data_port = 0;
-       struct lttng_uri *uri;
+       struct lttng_uri *tmp_uris;
+       char *addr_f = NULL;
        const struct uri_proto *proto;
+       const char *purl, *addr_e, *addr_b, *subdir_b = NULL;
+       const char *seps = ":/\0";
 
        /*
         * The first part is the protocol portion of a maximum of 5 bytes for now.
@@ -173,110 +202,208 @@ ssize_t uri_parse(const char *str_uri, struct lttng_uri **uris)
         * protocol, two ports CAN be specified.
         */
 
-       ret = sscanf(str_uri, "%5[^:]://", net);
-       if (ret < 1) {
-               ERR("URI parse bad protocol %s", str_uri);
-               goto error;
-       }
-
        DBG3("URI string: %s", str_uri);
 
-       proto = validate_protocol(net);
+       proto = get_uri_proto(str_uri);
        if (proto == NULL) {
-               ERR("URI parse unknown protocol %s", net);
-               ret = -1;
+               ERR("URI parse unknown protocol %s", str_uri);
                goto error;
        }
 
+       purl = str_uri;
+
        if (proto->code == P_NET || proto->code == P_NET6) {
-               /* Special case for net:// which requires two URI object */
+               /* Special case for net:// which requires two URI objects */
                size = 2;
        }
 
+       /* Allocate URI array */
+       tmp_uris = zmalloc(sizeof(struct lttng_uri) * size);
+       if (tmp_uris == NULL) {
+               PERROR("zmalloc uri");
+               goto error;
+       }
+
        memset(subdir, 0, sizeof(subdir));
-       str_offset += strlen(net);
-
-       /* Parse the rest of the URI */
-       if (sscanf(str_uri + str_offset, "://%255[^:]:%u:%u/%s", dst, &ctrl_port,
-                       &data_port, subdir) == 4) {
-               /* All set */
-       } else if (sscanf(str_uri + str_offset, "://%255[^:]:%u:%u", dst,
-                               &ctrl_port, &data_port) == 3) {
-       } else if (sscanf(str_uri + str_offset, "://%255[^:]:%u/%s", dst,
-                               &ctrl_port, subdir) == 3) {
-       } else if (sscanf(str_uri + str_offset, "://%255[^:]:%u", dst,
-                               &ctrl_port) == 2) {
-       } else if (sscanf(str_uri + str_offset, "://%255[^/]/%s", dst,
-                               subdir) == 2) {
-       } else {
-               ret = sscanf(str_uri + str_offset, "://%255[^:]", dst);
-               if (ret < 0) {
-                       ERR("Bad URI");
-                       goto error;
+       purl += strlen(proto->leading_string);
+
+       /* Copy known value to the first URI. */
+       tmp_uris[0].dtype = proto->dtype;
+       tmp_uris[0].proto = proto->type;
+
+       if (proto->code == P_FILE) {
+               if (*purl != '/') {
+                       ERR("Missing destination full path.");
+                       goto free_error;
                }
+
+               strncpy(tmp_uris[0].dst.path, purl, sizeof(tmp_uris[0].dst.path));
+               tmp_uris[0].dst.path[sizeof(tmp_uris[0].dst.path) - 1] = '\0';
+               DBG3("URI file destination: %s", purl);
+               goto end;
        }
 
-       /* We have enough valid information to create URI(s) object */
+       /* Assume we are at the beginning of an address or host of some sort. */
+       addr_b = purl;
 
-       /* Allocate URI array */
-       uri = zmalloc(sizeof(struct lttng_uri) * size);
-       if (uri == NULL) {
-               PERROR("zmalloc uri");
-               goto error;
+       /*
+        * Handle IPv6 address inside square brackets as mention by RFC 2732. IPv6
+        * address that does not start AND end with brackets will be rejected even
+        * if valid.
+        *
+        * proto://[<addr>]...
+        *         ^
+        */
+       if (*purl == '[') {
+               /* Address begins after '[' */
+               addr_b = purl + 1;
+               addr_e = strchr(addr_b, ']');
+               if (addr_e == NULL || addr_b == addr_e) {
+                       ERR("Broken IPv6 address %s", addr_b);
+                       goto free_error;
+               }
+
+               /* Moving parsed URL pointer after the final bracket ']' */
+               purl = addr_e + 1;
+
+               /*
+                * The closing bracket must be followed by a seperator or NULL char.
+                */
+               if (strchr(seps, *purl) == NULL) {
+                       ERR("Unknown symbol after IPv6 address: %s", purl);
+                       goto free_error;
+               }
+       } else {
+               purl = strpbrk_or_eos(purl, seps);
+               addr_e = purl;
+       }
+
+       /* Check if we at least have a char for the addr or hostname. */
+       if (addr_b == addr_e) {
+               ERR("No address or hostname detected.");
+               goto free_error;
+       }
+
+       addr_f = utils_strdupdelim(addr_b, addr_e);
+       if (addr_f == NULL) {
+               goto free_error;
        }
 
+       /*
+        * Detect PORT after address. The net/net6 protocol allows up to two port
+        * so we can define the control and data port.
+        */
+       while (*purl == ':') {
+               int port;
+               const char *port_b, *port_e;
+               char *port_f;
+
+               /* Update pass counter */
+               i++;
+
+               /*
+                * Maximum of two ports is possible if P_NET/NET6. Bigger than that,
+                * two much stuff.
+                */
+               if ((i == 2 && (proto->code != P_NET && proto->code != P_NET6))
+                               || i > 2) {
+                       break;
+               }
+
+               /*
+                * Move parsed URL to port value.
+                * proto://addr_host:PORT1:PORT2/foo/bar
+                *                   ^
+                */
+               ++purl;
+               port_b = purl;
+               purl = strpbrk_or_eos(purl, seps);
+               port_e = purl;
+
+               if (port_b != port_e) {
+                       port_f = utils_strdupdelim(port_b, port_e);
+                       if (port_f == NULL) {
+                               goto free_error;
+                       }
+
+                       port = atoi(port_f);
+                       if (port > 0xffff || port <= 0x0) {
+                               ERR("Invalid port number %d", port);
+                               free(port_f);
+                               goto free_error;
+                       }
+                       free(port_f);
+
+                       if (i == 1) {
+                               ctrl_port = port;
+                       } else {
+                               data_port = port;
+                       }
+               }
+       };
+
+       /* Check for a valid subdir or trailing garbage */
+       if (*purl == '/') {
+               /*
+                * Move to subdir value.
+                * proto://addr_host:PORT1:PORT2/foo/bar
+                *                               ^
+                */
+               ++purl;
+               subdir_b = purl;
+       } else if (*purl != '\0') {
+               ERR("Trailing characters not recognized: %s", purl);
+               goto free_error;
+       }
+
+       /* We have enough valid information to create URI(s) object */
+
        /* Copy generic information */
-       uri[0].dtype = proto->dtype;
-       uri[0].proto = proto->type;
-       uri[0].port = ctrl_port;
-       strncpy(uri[0].subdir, subdir, sizeof(uri[0].subdir));
+       tmp_uris[0].port = ctrl_port;
 
-       DBG3("URI dtype: %d, proto: %d, host: %s, subdir: %s, ctrl: %d, data: %d",
-                       proto->dtype, proto->type, dst, subdir, ctrl_port, data_port);
+       /* Copy subdirectory if one. */
+       if (subdir_b) {
+               strncpy(tmp_uris[0].subdir, subdir_b, sizeof(tmp_uris[0].subdir));
+               tmp_uris[0].subdir[sizeof(tmp_uris[0].subdir) - 1] = '\0';
+       }
 
        switch (proto->code) {
-       case P_FILE:
-               memcpy(uri[0].dst.path, dst, sizeof(uri[0].dst.path));
-               /* Reset port for the file:// URI */
-               uri[0].port = 0;
-               DBG3("URI file destination: %s", dst);
-               break;
        case P_NET:
-               ret = set_ip_address(dst, AF_INET, uri[0].dst.ipv4,
-                               sizeof(uri[0].dst.ipv4));
+               ret = set_ip_address(addr_f, AF_INET, tmp_uris[0].dst.ipv4,
+                               sizeof(tmp_uris[0].dst.ipv4));
                if (ret < 0) {
                        goto free_error;
                }
 
-               memcpy(uri[1].dst.ipv4, uri[0].dst.ipv4, sizeof(uri[1].dst.ipv4));
+               memcpy(tmp_uris[1].dst.ipv4, tmp_uris[0].dst.ipv4, sizeof(tmp_uris[1].dst.ipv4));
 
-               uri[1].dtype = proto->dtype;
-               uri[1].proto = proto->type;
-               uri[1].port = data_port;
+               tmp_uris[1].dtype = proto->dtype;
+               tmp_uris[1].proto = proto->type;
+               tmp_uris[1].port = data_port;
                break;
        case P_NET6:
-               ret = set_ip_address(dst, AF_INET6, uri[0].dst.ipv6,
-                               sizeof(uri[0].dst.ipv6));
+               ret = set_ip_address(addr_f, AF_INET6, tmp_uris[0].dst.ipv6,
+                               sizeof(tmp_uris[0].dst.ipv6));
                if (ret < 0) {
                        goto free_error;
                }
 
-               memcpy(uri[1].dst.ipv6, uri[0].dst.ipv6, sizeof(uri[1].dst.ipv6));
+               memcpy(tmp_uris[1].dst.ipv6, tmp_uris[0].dst.ipv6, sizeof(tmp_uris[1].dst.ipv6));
 
-               uri[1].dtype = proto->dtype;
-               uri[1].proto = proto->type;
-               uri[1].port = data_port;
+               tmp_uris[1].dtype = proto->dtype;
+               tmp_uris[1].proto = proto->type;
+               tmp_uris[1].port = data_port;
                break;
        case P_TCP:
-               ret = set_ip_address(dst, AF_INET, uri[0].dst.ipv4,
-                               sizeof(uri[0].dst.ipv4));
+               ret = set_ip_address(addr_f, AF_INET, tmp_uris[0].dst.ipv4,
+                               sizeof(tmp_uris[0].dst.ipv4));
                if (ret < 0) {
                        goto free_error;
                }
                break;
        case P_TCP6:
-               ret = set_ip_address(dst, AF_INET6, uri[0].dst.ipv6,
-                               sizeof(uri[0].dst.ipv6));
+               ret = set_ip_address(addr_f, AF_INET6, tmp_uris[0].dst.ipv6,
+                               sizeof(tmp_uris[0].dst.ipv6));
                if (ret < 0) {
                        goto free_error;
                }
@@ -285,12 +412,19 @@ ssize_t uri_parse(const char *str_uri, struct lttng_uri **uris)
                goto free_error;
        }
 
-       *uris = uri;
+end:
+       DBG3("URI dtype: %d, proto: %d, host: %s, subdir: %s, ctrl: %d, data: %d",
+                       proto->dtype, proto->type, (addr_f == NULL) ? "" : addr_f,
+                       (subdir_b == NULL) ? "" : subdir_b, ctrl_port, data_port);
+
+       free(addr_f);
 
+       *uris = tmp_uris;
        return size;
 
 free_error:
-       free(uri);
+       free(addr_f);
+       free(tmp_uris);
 error:
        return -1;
 }
index 959b9a66c7b6f3f61b8b0fa6d2d4f65d5fed8d7b..d768e8724670d80759c8002a60b2c4acb81efde8 100644 (file)
  * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 
-#ifndef _LTT_URI_H
-#define _LTT_URI_H
+#ifndef URI_H
+#define URI_H
 
+#include <netinet/in.h>
 #include <lttng/lttng.h>
 
+/* Destination type of lttng URI */
+enum lttng_dst_type {
+       LTTNG_DST_IPV4                        = 1,
+       LTTNG_DST_IPV6                        = 2,
+       LTTNG_DST_PATH                        = 3,
+};
+
+/* Type of lttng URI where it is a final destination or a hop */
+enum lttng_uri_type {
+       LTTNG_URI_DST,  /* The URI is a final destination */
+       /*
+        * Hops are not supported yet but planned for a future release.
+        *
+        LTTNG_URI_HOP,
+        */
+};
+
+/* Communication stream type of a lttng URI */
+enum lttng_stream_type {
+       LTTNG_STREAM_CONTROL,
+       LTTNG_STREAM_DATA,
+};
+
+/*
+ * Protocol type of a lttng URI. The value 0 indicate that the proto_type field
+ * should be ignored.
+ */
+enum lttng_proto_type {
+       LTTNG_TCP                             = 1,
+       /*
+        * UDP protocol is not supported for now.
+        *
+        LTTNG_UDP                             = 2,
+        */
+};
+
+/*
+ * Structure representing an URI supported by lttng.
+ */
+struct lttng_uri {
+       enum lttng_dst_type dtype;
+       enum lttng_uri_type utype;
+       enum lttng_stream_type stype;
+       enum lttng_proto_type proto;
+       in_port_t port;
+       char subdir[PATH_MAX];
+       union {
+               char ipv4[INET_ADDRSTRLEN];
+               char ipv6[INET6_ADDRSTRLEN];
+               char path[PATH_MAX];
+       } dst;
+};
+
 int uri_compare(struct lttng_uri *uri1, struct lttng_uri *uri2);
 void uri_free(struct lttng_uri *uri);
 ssize_t uri_parse(const char *str_uri, struct lttng_uri **uris);
index 1fed58bdc8d5be33179bf5b70e346e09b842c5d0..c92d59d027c0e28c3914094257df5b22d97e59de 100644 (file)
@@ -483,7 +483,7 @@ int lttng_ustconsumer_read_subbuffer(struct lttng_consumer_stream *stream,
                 * display the error but continue processing to try
                 * to release the subbuffer
                 */
-               ERR("Error writing to tracefile");
+               ERR("Error writing to tracefile (expected: %ld, got: %ld)", ret, len);
        }
        err = ustctl_put_next_subbuf(handle, buf);
        assert(err == 0);
index bc9b2db3fcc0caf379464b271d22b570f115d9e0..0494b23bdcd0bd356f45c0f4f8c5bf8a0f99c871 100644 (file)
@@ -154,3 +154,23 @@ void utils_close_pipe(int *src)
                }
        }
 }
+
+/*
+ * Create a new string using two strings range.
+ */
+char *utils_strdupdelim(const char *begin, const char *end)
+{
+       char *str;
+
+       str = zmalloc(end - begin + 1);
+       if (str == NULL) {
+               PERROR("zmalloc strdupdelim");
+               goto error;
+       }
+
+       memcpy(str, begin, end - begin);
+       str[end - begin] = '\0';
+
+error:
+       return str;
+}
index 87d090245bf12d4b6be9cf281a9662caed8ab43e..d47d448895952b609a529cdb15709279db830c73 100644 (file)
@@ -22,5 +22,6 @@ char *utils_expand_path(const char *path);
 int utils_create_pipe(int *dst);
 int utils_create_pipe_cloexec(int *dst);
 void utils_close_pipe(int *src);
+char *utils_strdupdelim(const char *begin, const char *end);
 
 #endif /* _COMMON_UTILS_H */
index a5f6851ca9534cbdbb631c31325322ea2ccb443f..e00a880263adba798a93474b387b9f2cbd4f29b8 100644 (file)
@@ -23,4 +23,6 @@ filter_grammar_test_SOURCES = filter-grammar-test.c
 filter_grammar_test_LDADD = liblttng-ctl.la
 
 liblttng_ctl_la_LIBADD = \
-               $(top_builddir)/src/common/sessiond-comm/libsessiond-comm.la
+               $(top_builddir)/src/common/sessiond-comm/libsessiond-comm.la \
+               $(top_builddir)/src/common/libcommon.la \
+               $(top_builddir)/src/common/hashtable/libhashtable.la
index ba0c4c8269a301d31c0183c02592f0d77e363b8e..064f739aa329d939ceefd116e5cb09f387ef7a20 100644 (file)
@@ -31,6 +31,7 @@
 #include <common/common.h>
 #include <common/defaults.h>
 #include <common/sessiond-comm/sessiond-comm.h>
+#include <common/uri.h>
 #include <lttng/lttng.h>
 
 #include "filter-ast.h"
@@ -74,6 +75,134 @@ static int connected;
 int lttng_opt_quiet;
 int lttng_opt_verbose;
 
+static void set_default_url_attr(struct lttng_uri *uri,
+               enum lttng_stream_type stype)
+{
+       uri->stype = stype;
+       if (uri->dtype != LTTNG_DST_PATH && uri->port == 0) {
+               uri->port = (stype == LTTNG_STREAM_CONTROL) ?
+                       DEFAULT_NETWORK_CONTROL_PORT : DEFAULT_NETWORK_DATA_PORT;
+       }
+}
+
+/*
+ * Parse a string URL and creates URI(s) returning the size of the populated
+ * array.
+ */
+static ssize_t parse_str_urls_to_uri(const char *ctrl_url, const char *data_url,
+               struct lttng_uri **uris)
+{
+       int ret;
+       unsigned int equal = 1, idx = 0;
+       /* Add the "file://" size to the URL maximum size */
+       char url[PATH_MAX + 7];
+       ssize_t size_ctrl = 0, size_data = 0, size;
+       struct lttng_uri *ctrl_uris = NULL, *data_uris = NULL;
+       struct lttng_uri *tmp_uris = NULL;
+
+       /* No URL(s) is allowed. This means that the consumer will be disabled. */
+       if (ctrl_url == NULL && data_url == NULL) {
+               return 0;
+       }
+
+       /* Check if URLs are equal and if so, only use the control URL */
+       if (ctrl_url && data_url) {
+               equal = !strcmp(ctrl_url, data_url);
+       }
+
+       /*
+        * Since we allow the str_url to be a full local filesystem path, we are
+        * going to create a valid file:// URL if it's the case.
+        *
+        * Check if first character is a '/' or else reject the URL.
+        */
+       if (ctrl_url && ctrl_url[0] == '/') {
+               ret = snprintf(url, sizeof(url), "file://%s", ctrl_url);
+               if (ret < 0) {
+                       PERROR("snprintf file url");
+                       goto parse_error;
+               }
+               ctrl_url = url;
+       }
+
+       /* Parse the control URL if there is one */
+       if (ctrl_url) {
+               size_ctrl = uri_parse(ctrl_url, &ctrl_uris);
+               if (size_ctrl < 1) {
+                       ERR("Unable to parse the URL %s", ctrl_url);
+                       goto parse_error;
+               }
+
+               /* At this point, we know there is at least one URI in the array */
+               set_default_url_attr(&ctrl_uris[0], LTTNG_STREAM_CONTROL);
+
+               if (ctrl_uris[0].dtype == LTTNG_DST_PATH && data_url) {
+                       ERR("Can not have a data URL when destination is file://");
+                       goto error;
+               }
+
+               /* URL are not equal but the control URL uses a net:// protocol */
+               if (size_ctrl == 2) {
+                       if (!equal) {
+                               ERR("Control URL uses the net:// protocol and the data URL is "
+                                               "different. Not allowed.");
+                               goto error;
+                       } else {
+                               set_default_url_attr(&ctrl_uris[1], LTTNG_STREAM_DATA);
+                               /*
+                                * The data_url and ctrl_url are equal and the ctrl_url
+                                * contains a net:// protocol so we just skip the data part.
+                                */
+                               data_url = NULL;
+                       }
+               }
+       }
+
+       if (data_url) {
+               /* We have to parse the data URL in this case */
+               size_data = uri_parse(data_url, &data_uris);
+               if (size_data < 1) {
+                       ERR("Unable to parse the URL %s", data_url);
+                       goto error;
+               } else if (size_data == 2) {
+                       ERR("Data URL can not be set with the net[4|6]:// protocol");
+                       goto error;
+               }
+
+               set_default_url_attr(&data_uris[0], LTTNG_STREAM_DATA);
+       }
+
+       /* Compute total size */
+       size = size_ctrl + size_data;
+
+       tmp_uris = zmalloc(sizeof(struct lttng_uri) * size);
+       if (tmp_uris == NULL) {
+               PERROR("zmalloc uris");
+               goto error;
+       }
+
+       if (ctrl_uris) {
+               /* It's possible the control URIs array contains more than one URI */
+               memcpy(tmp_uris, ctrl_uris, sizeof(struct lttng_uri) * size_ctrl);
+               ++idx;
+       }
+
+       if (data_uris) {
+               memcpy(&tmp_uris[idx], data_uris, sizeof(struct lttng_uri));
+       }
+
+       *uris = tmp_uris;
+
+       return size;
+
+error:
+       free(ctrl_uris);
+       free(data_uris);
+       free(tmp_uris);
+parse_error:
+       return -1;
+}
+
 /*
  * Copy string from src to dst and enforce null terminated byte.
  */
@@ -108,7 +237,6 @@ static void copy_lttng_domain(struct lttng_domain *dst, struct lttng_domain *src
                        break;
                default:
                        memset(dst, 0, sizeof(struct lttng_domain));
-                       dst->type = LTTNG_DOMAIN_KERNEL;
                        break;
                }
        }
@@ -129,6 +257,8 @@ static int send_session_msg(struct lttcomm_session_msg *lsm)
                goto end;
        }
 
+       DBG("LSM cmd type : %d", lsm->cmd_type);
+
        ret = lttcomm_send_creds_unix_sock(sessiond_socket, lsm,
                        sizeof(struct lttcomm_session_msg));
 
@@ -150,6 +280,7 @@ static int send_session_varlen(void *data, size_t len)
                ret = -ENOTCONN;
                goto end;
        }
+
        if (!data || !len) {
                ret = 0;
                goto end;
@@ -363,9 +494,7 @@ static int disconnect_sessiond(void)
  * Return size of data (only payload, not header) or a negative error code.
  */
 static int ask_sessiond_varlen(struct lttcomm_session_msg *lsm,
-               void *vardata,
-               size_t varlen,
-               void **buf)
+               void *vardata, size_t varlen, void **buf)
 {
        int ret;
        size_t size;
@@ -921,51 +1050,35 @@ const char *lttng_strerror(int code)
 }
 
 /*
- *  Create a brand new session using name and path.
- *  Returns size of returned session payload data or a negative error code.
- */
-int lttng_create_session(const char *name, const char *path)
-{
-       struct lttcomm_session_msg lsm;
-
-       lsm.cmd_type = LTTNG_CREATE_SESSION;
-       copy_string(lsm.session.name, name, sizeof(lsm.session.name));
-       copy_string(lsm.session.path, path, sizeof(lsm.session.path));
-
-       return ask_sessiond(&lsm, NULL);
-}
-
-/*
- * Create a new tracing session using a name, URIs and a consumer enable flag.
+ * Create a brand new session using name and url for destination.
+ *
+ * Returns LTTCOMM_OK on success or a negative error code.
  */
-int lttng_create_session_uri(const char *name, struct lttng_uri *ctrl_uri,
-               struct lttng_uri *data_uri, unsigned int enable_consumer)
+int lttng_create_session(const char *name, const char *url)
 {
+       ssize_t size;
        struct lttcomm_session_msg lsm;
+       struct lttng_uri *uris = NULL;
 
-       /* Name and ctrl_uri are mandatory */
-       if (name == NULL || ctrl_uri == NULL) {
+       if (name == NULL) {
                return -1;
        }
 
-       lsm.cmd_type = LTTNG_CREATE_SESSION_URI;
+       memset(&lsm, 0, sizeof(lsm));
 
+       lsm.cmd_type = LTTNG_CREATE_SESSION;
        copy_string(lsm.session.name, name, sizeof(lsm.session.name));
-       /* Anything bigger than zero, the consumer(s) will be enabled */
-       lsm.u.create_uri.enable_consumer = enable_consumer;
-       memcpy(&lsm.u.create_uri.ctrl_uri, ctrl_uri,
-                       sizeof(lsm.u.create_uri.ctrl_uri));
-       if (data_uri) {
-               /*
-                * The only possible scenario where data_uri is NULL is for a local
-                * consumer where the output is at a specified path name on the
-                * filesystem.
-                */
-               memcpy(&lsm.u.create_uri.data_uri, data_uri,
-                               sizeof(lsm.u.create_uri.data_uri));
+
+       /* There should never be a data URL */
+       size = parse_str_urls_to_uri(url, NULL, &uris);
+       if (size < 0) {
+               return LTTCOMM_INVALID;
        }
 
-       return ask_sessiond(&lsm, NULL);
+       lsm.u.uri.size = size;
+
+       return ask_sessiond_varlen(&lsm, uris, sizeof(struct lttng_uri) * size,
+                       NULL);
 }
 
 /*
@@ -1213,27 +1326,38 @@ int lttng_session_daemon_alive(void)
 }
 
 /*
- * Set URI for a consumer for a session and domain.
+ * Set URL for a consumer for a session and domain.
  *
  * Return 0 on success, else a negative value.
  */
-int lttng_set_consumer_uri(struct lttng_handle *handle, struct lttng_uri *uri)
+int lttng_set_consumer_url(struct lttng_handle *handle,
+               const char *control_url, const char *data_url)
 {
+       ssize_t size;
        struct lttcomm_session_msg lsm;
+       struct lttng_uri *uris = NULL;
 
-       if (handle == NULL || uri == NULL) {
+       if (handle == NULL || (control_url == NULL && data_url == NULL)) {
                return -1;
        }
 
+       memset(&lsm, 0, sizeof(lsm));
+
        lsm.cmd_type = LTTNG_SET_CONSUMER_URI;
 
        copy_string(lsm.session.name, handle->session_name,
                        sizeof(lsm.session.name));
        copy_lttng_domain(&lsm.domain, &handle->domain);
 
-       memcpy(&lsm.u.uri, uri, sizeof(lsm.u.uri));
+       size = parse_str_urls_to_uri(control_url, data_url, &uris);
+       if (size < 0) {
+               return LTTCOMM_INVALID;
+       }
+
+       lsm.u.uri.size = size;
 
-       return ask_sessiond(&lsm, NULL);
+       return ask_sessiond_varlen(&lsm, uris, sizeof(struct lttng_uri) * size,
+                       NULL);
 }
 
 /*
index 5cad1fb058ea7523d4b0513067b21764a0808a7d..f4cfe57b9ffa2f332b46038563fd7d084b4c9aaf 100644 (file)
@@ -11,7 +11,8 @@ UTILS=../utils.h
 SESSIONS=$(top_srcdir)/src/bin/lttng-sessiond/session.c
 KERN_DATA_TRACE=$(top_srcdir)/src/bin/lttng-sessiond/trace-kernel.c \
                                $(top_srcdir)/src/bin/lttng-sessiond/consumer.c \
-                               $(top_srcdir)/src/common/uri.c
+                               $(top_srcdir)/src/common/uri.c \
+                               $(top_srcdir)/src/common/utils.c
 COMMON=$(top_builddir)/src/common/libcommon.la
 HASHTABLE=$(top_builddir)/src/common/hashtable/libhashtable.la
 SESSIOND_COMM=$(top_builddir)/src/common/sessiond-comm/libsessiond-comm.la
@@ -28,7 +29,8 @@ if HAVE_LIBLTTNG_UST_CTL
 noinst_PROGRAMS += test_ust_data_trace
 UST_DATA_TRACE=$(top_srcdir)/src/bin/lttng-sessiond/trace-ust.c \
                           $(top_srcdir)/src/bin/lttng-sessiond/consumer.c \
-                          $(top_srcdir)/src/common/uri.c
+                          $(top_srcdir)/src/common/uri.c \
+                          $(top_srcdir)/src/common/utils.c
 # UST trace data unit tests
 test_ust_data_trace_SOURCES = test_ust_data_trace.c $(UTILS) $(UST_DATA_TRACE)
 test_ust_data_trace_LDADD = $(COMMON) $(HASHTABLE) $(SESSIOND_COMM)
index 6fea139c30f61415920575cbc0ef8f3aa10fda40..915e7d1adc74f7ff25d6717bb6624b5b79218f94 100644 (file)
@@ -37,7 +37,7 @@
 
 /* For lttngerr.h */
 int lttng_opt_quiet = 1;
-int lttng_opt_verbose = 0;
+int lttng_opt_verbose = 3;
 
 /*
  * Test string URI and if uri_parse works well.
@@ -138,7 +138,7 @@ int test_uri(void)
        assert(strcmp(uri[0].dst.ipv4, "42.42.42.42") == 0);
        PRINT_OK();
 
-       s_uri1 = "tcp6://fe80::f66d:4ff:fe53:d220/my/test/path";
+       s_uri1 = "tcp6://[fe80::f66d:4ff:fe53:d220]/my/test/path";
        fprintf(stdout, " [+] URI set to %s ", s_uri1);
        size = uri_parse(s_uri1, &uri);
        assert(size == 1);
@@ -174,12 +174,6 @@ int test_uri(void)
        assert(size == -1);
        PRINT_OK();
 
-       s_uri1 = "net://localhost/";
-       fprintf(stdout, " [+] Bad URI set to %s ", s_uri1);
-       size = uri_parse(s_uri1, &uri);
-       assert(size == -1);
-       PRINT_OK();
-
        return 0;
 }
 
index 8bd62875a17124caa9b12ce0cd44f48b2547f510..c49d7ce549795000753b029e3256b4aeaafd2f0d 100644 (file)
@@ -89,7 +89,7 @@ static void create_kernel_metadata(void)
        assert(kern != NULL);
 
        printf("Create kernel metadata: ");
-       kern->metadata = trace_kernel_create_metadata(PATH1);
+       kern->metadata = trace_kernel_create_metadata();
        assert(kern->metadata != NULL);
        PRINT_OK();
 
index fc3fbc1ebd98053094050b9694e3d4942a099cbc..cd8003dda5b17342e98c614232ec062989d3e9ff 100644 (file)
@@ -196,12 +196,6 @@ static int fuzzing_create_args(void)
                return -1;
        }
 
-       ret = create_one_session(SESSION1, NULL);
-       if (ret > 0) {
-               printf("Session created with %s, (null)\n", SESSION1);
-               return -1;
-       }
-
        /* Session list must be 0 */
        assert(!session_list_count());
 
This page took 0.07477 seconds and 4 git commands to generate.