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>
#define _LTTNG_H
#include <limits.h>
-#include <netinet/in.h>
#include <stdint.h>
#include <sys/types.h>
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.
*/
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.
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.
#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
struct consumer_socket *socket = NULL;
/* Negative keys are lookup failures */
- if (key < 0) {
+ if (key < 0 || consumer == NULL) {
return NULL;
}
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,
* 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;
}
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);
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) {
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 */
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");
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:
struct ltt_ust_session *lus = NULL;
assert(session);
+ assert(domain);
assert(session->consumer);
switch (domain->type) {
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;
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) {
}
/* 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);
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.
*/
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;
}
/*
- * 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) {
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;
}
* 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) {
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;
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);
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! */
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);
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;
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) {
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);
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) {
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;
}
* is valid.
*/
consumer_destroy_output(ksess->consumer);
- ksess->consumer = tmp_out;
+ ksess->consumer = consumer;
ksess->tmp_consumer = NULL;
break;
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) {
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;
}
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;
* 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;
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:
/* 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:
if (!need_domain) {
goto skip_domain;
}
+
/*
* Check domain type for specific "pre-action".
*/
/* 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) {
/* 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) {
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;
}
}
}
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);
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) {
* 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) {
* 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;
}
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:
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;
* 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;
}
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:
}
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;
}
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 */
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);
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;
* copied into those sessions.
*/
struct consumer_output *consumer;
+
+ /* Indicates whether or not we have to spawn consumer(s) */
+ unsigned int start_consumer;
};
/* Prototypes */
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 */
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;
*/
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;
}
*
* 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;
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);
lus->consumer = consumer_create_output(CONSUMER_DST_LOCAL);
if (lus->consumer == NULL) {
- goto error;
+ goto error_free_session;
}
/*
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");
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;
/* 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;
/* 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;
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);
*/
#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,
{"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}
};
*/
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;
}
/*
*
* 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);
/* 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) {
}
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) {
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) {
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:
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;
}
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;
{"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}
};
*/
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");
}
/*
{
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));
} 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);
}
/* 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) */
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;
}
}
- 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) {
# 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
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. */
#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"
[ 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",
};
/*
#include <limits.h>
#include <lttng/lttng.h>
#include <common/compat/socket.h>
+#include <common/uri.h>
#include <arpa/inet.h>
#include <netinet/in.h>
LTTNG_ENABLE_ALL_EVENT,
/* Session daemon command */
LTTNG_CREATE_SESSION,
- LTTNG_CREATE_SESSION_URI,
LTTNG_DESTROY_SESSION,
LTTNG_LIST_CHANNELS,
LTTNG_LIST_DOMAINS,
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 */
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];
#include <common/common.h>
#include <common/defaults.h>
+#include <common/utils.h>
#include "uri.h"
};
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;
/* 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;
}
}
memcpy(dst, addr, size);
}
+ DBG2("IP address resolved to %s", dst);
+
return 0;
error:
* 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.
* 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;
}
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;
}
* 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);
* 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);
}
}
}
+
+/*
+ * 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;
+}
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 */
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
#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"
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.
*/
break;
default:
memset(dst, 0, sizeof(struct lttng_domain));
- dst->type = LTTNG_DOMAIN_KERNEL;
break;
}
}
goto end;
}
+ DBG("LSM cmd type : %d", lsm->cmd_type);
+
ret = lttcomm_send_creds_unix_sock(sessiond_socket, lsm,
sizeof(struct lttcomm_session_msg));
ret = -ENOTCONN;
goto end;
}
+
if (!data || !len) {
ret = 0;
goto end;
* 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;
}
/*
- * 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);
}
/*
}
/*
- * 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);
}
/*
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
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)
/* 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.
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);
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;
}
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();
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());