X-Git-Url: https://git.lttng.org/?p=lttng-tools.git;a=blobdiff_plain;f=src%2Fbin%2Flttng-sessiond%2Fsession.c;h=16431ca15ca19d3cd3260ee99e6a4c5163232d35;hp=07031a30a5c5bc6cf603b84847aac2a866919ede;hb=731c1b1217bdbb47501426a6a0a2220ce4bc442c;hpb=731848356e38d33b32fc6346ac30fba3a46a8673 diff --git a/src/bin/lttng-sessiond/session.c b/src/bin/lttng-sessiond/session.c index 07031a30a..16431ca15 100644 --- a/src/bin/lttng-sessiond/session.c +++ b/src/bin/lttng-sessiond/session.c @@ -15,7 +15,7 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#define _GNU_SOURCE +#define _LGPL_SOURCE #include #include #include @@ -23,11 +23,15 @@ #include #include #include +#include +#include #include #include #include "session.h" +#include "utils.h" +#include "trace-ust.h" /* * NOTES: @@ -49,6 +53,45 @@ static struct ltt_session_list ltt_session_list = { .next_uuid = 0, }; +/* These characters are forbidden in a session name. Used by validate_name. */ +static const char *forbidden_name_chars = "/"; + +/* Global hash table to keep the sessions, indexed by id. */ +static struct lttng_ht *ltt_sessions_ht_by_id = NULL; + +/* + * Validate the session name for forbidden characters. + * + * Return 0 on success else -1 meaning a forbidden char. has been found. + */ +static int validate_name(const char *name) +{ + int ret; + char *tok, *tmp_name; + + assert(name); + + tmp_name = strdup(name); + if (!tmp_name) { + /* ENOMEM here. */ + ret = -1; + goto error; + } + + tok = strpbrk(tmp_name, forbidden_name_chars); + if (tok) { + DBG("Session name %s contains a forbidden character", name); + /* Forbidden character has been found. */ + ret = -1; + goto error; + } + ret = 0; + +error: + free(tmp_name); + return ret; +} + /* * Add a ltt_session structure to the global list. * @@ -91,6 +134,14 @@ void session_lock_list(void) pthread_mutex_lock(<t_session_list.lock); } +/* + * Try to acquire session list lock + */ +int session_trylock_list(void) +{ + return pthread_mutex_trylock(<t_session_list.lock); +} + /* * Release session list lock */ @@ -99,6 +150,175 @@ void session_unlock_list(void) pthread_mutex_unlock(<t_session_list.lock); } +/* + * Get the session's consumer destination type. + * + * The caller must hold the session lock. + */ +enum consumer_dst_type session_get_consumer_destination_type( + const struct ltt_session *session) +{ + /* + * The output information is duplicated in both of those session types. + * Hence, it doesn't matter from which it is retrieved. However, it is + * possible for only one of them to be set. + */ + return session->kernel_session ? + session->kernel_session->consumer->type : + session->ust_session->consumer->type; +} + +/* + * Get the session's consumer network hostname. + * The caller must ensure that the destination is of type "net". + * + * The caller must hold the session lock. + */ +const char *session_get_net_consumer_hostname(const struct ltt_session *session) +{ + const char *hostname = NULL; + const struct consumer_output *output; + + output = session->kernel_session ? + session->kernel_session->consumer : + session->ust_session->consumer; + + /* + * hostname is assumed to be the same for both control and data + * connections. + */ + switch (output->dst.net.control.dtype) { + case LTTNG_DST_IPV4: + hostname = output->dst.net.control.dst.ipv4; + break; + case LTTNG_DST_IPV6: + hostname = output->dst.net.control.dst.ipv6; + break; + default: + abort(); + } + return hostname; +} + +/* + * Get the session's consumer network control and data ports. + * The caller must ensure that the destination is of type "net". + * + * The caller must hold the session lock. + */ +void session_get_net_consumer_ports(const struct ltt_session *session, + uint16_t *control_port, uint16_t *data_port) +{ + const struct consumer_output *output; + + output = session->kernel_session ? + session->kernel_session->consumer : + session->ust_session->consumer; + *control_port = output->dst.net.control.port; + *data_port = output->dst.net.data.port; +} + +/* + * Allocate the ltt_sessions_ht_by_id HT. + * + * The session list lock must be held. + */ +int ltt_sessions_ht_alloc(void) +{ + int ret = 0; + + DBG("Allocating ltt_sessions_ht_by_id"); + ltt_sessions_ht_by_id = lttng_ht_new(0, LTTNG_HT_TYPE_U64); + if (!ltt_sessions_ht_by_id) { + ret = -1; + ERR("Failed to allocate ltt_sessions_ht_by_id"); + goto end; + } +end: + return ret; +} + +/* + * Destroy the ltt_sessions_ht_by_id HT. + * + * The session list lock must be held. + */ +static void ltt_sessions_ht_destroy(void) +{ + if (!ltt_sessions_ht_by_id) { + return; + } + ht_cleanup_push(ltt_sessions_ht_by_id); + ltt_sessions_ht_by_id = NULL; +} + +/* + * Add a ltt_session to the ltt_sessions_ht_by_id. + * If unallocated, the ltt_sessions_ht_by_id HT is allocated. + * The session list lock must be held. + */ +static void add_session_ht(struct ltt_session *ls) +{ + int ret; + + assert(ls); + + if (!ltt_sessions_ht_by_id) { + ret = ltt_sessions_ht_alloc(); + if (ret) { + ERR("Error allocating the sessions HT"); + goto end; + } + } + lttng_ht_node_init_u64(&ls->node, ls->id); + lttng_ht_add_unique_u64(ltt_sessions_ht_by_id, &ls->node); + +end: + return; +} + +/* + * Test if ltt_sessions_ht_by_id is empty. + * Return 1 if empty, 0 if not empty. + * The session list lock must be held. + */ +static int ltt_sessions_ht_empty(void) +{ + int ret; + + if (!ltt_sessions_ht_by_id) { + ret = 1; + goto end; + } + + ret = lttng_ht_get_count(ltt_sessions_ht_by_id) ? 0 : 1; +end: + return ret; +} + +/* + * Remove a ltt_session from the ltt_sessions_ht_by_id. + * If empty, the ltt_sessions_ht_by_id HT is freed. + * The session list lock must be held. + */ +static void del_session_ht(struct ltt_session *ls) +{ + struct lttng_ht_iter iter; + int ret; + + assert(ls); + assert(ltt_sessions_ht_by_id); + + iter.iter.node = &ls->node.node; + ret = lttng_ht_del(ltt_sessions_ht_by_id, &iter); + assert(!ret); + + if (ltt_sessions_ht_empty()) { + DBG("Empty ltt_sessions_ht_by_id, destroying it"); + ltt_sessions_ht_destroy(); + } +} + /* * Acquire session lock */ @@ -121,10 +341,10 @@ void session_unlock(struct ltt_session *session) /* * Return a ltt_session structure ptr that matches name. If no session found, - * NULL is returned. This must be called with the session lock held using + * NULL is returned. This must be called with the session list lock held using * session_lock_list and session_unlock_list. */ -struct ltt_session *session_find_by_name(char *name) +struct ltt_session *session_find_by_name(const char *name) { struct ltt_session *iter; @@ -144,6 +364,36 @@ found: return iter; } +/* + * Return an ltt_session that matches the id. If no session is found, + * NULL is returned. This must be called with rcu_read_lock and + * session list lock held (to guarantee the lifetime of the session). + */ +struct ltt_session *session_find_by_id(uint64_t id) +{ + struct lttng_ht_node_u64 *node; + struct lttng_ht_iter iter; + struct ltt_session *ls; + + if (!ltt_sessions_ht_by_id) { + goto end; + } + + lttng_ht_lookup(ltt_sessions_ht_by_id, &id, &iter); + node = lttng_ht_iter_get_node_u64(&iter); + if (node == NULL) { + goto end; + } + ls = caa_container_of(node, struct ltt_session, node); + + DBG3("Session %" PRIu64 " found by id.", id); + return ls; + +end: + DBG3("Session %" PRIu64 " NOT found by id", id); + return NULL; +} + /* * Delete session from the session list and free the memory. * @@ -155,11 +405,12 @@ int session_destroy(struct ltt_session *session) /* Safety check */ assert(session); - DBG("Destroying session %s", session->name); + DBG("Destroying session %s (id %" PRIu64 ")", session->name, session->id); del_session_list(session); pthread_mutex_destroy(&session->lock); + del_session_ht(session); - consumer_destroy_output(session->consumer); + consumer_output_put(session->consumer); snapshot_destroy(&session->snapshot); free(session); @@ -194,6 +445,12 @@ int session_create(char *name, uid_t uid, gid_t gid) goto error; } + ret = validate_name(name); + if (ret < 0) { + ret = LTTNG_ERR_SESSION_INVALID_CHAR; + goto error; + } + ret = gethostname(new_session->hostname, sizeof(new_session->hostname)); if (ret < 0) { if (errno == ENAMETOOLONG) { @@ -220,16 +477,28 @@ int session_create(char *name, uid_t uid, gid_t gid) goto error; } + new_session->rotate_pending = false; + new_session->rotation_state = LTTNG_ROTATION_STATE_NO_ROTATION; + new_session->rotate_pending_relay = false; + new_session->rotate_relay_pending_timer_enabled = false; + new_session->rotate_timer = false; + /* Add new session to the session list */ session_lock_list(); new_session->id = add_session_list(new_session); + /* + * Add the new session to the ltt_sessions_ht_by_id. + * No ownership is taken by the hash table; it is merely + * a wrapper around the session list used for faster access + * by session id. + */ + add_session_ht(new_session); session_unlock_list(); /* * 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 with ID %" PRIu64 " by UID %d GID %d", name, new_session->id, new_session->uid, new_session->gid);