e05482f15622995673aa71aabe3abc92a0b0d779
[lttng-tools.git] / src / bin / lttng-relayd / session.cpp
1 /*
2 * Copyright (C) 2013 Julien Desfossez <jdesfossez@efficios.com>
3 * Copyright (C) 2013 David Goulet <dgoulet@efficios.com>
4 * Copyright (C) 2015 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
5 *
6 * SPDX-License-Identifier: GPL-2.0-only
7 *
8 */
9
10 #define _LGPL_SOURCE
11 #include "ctf-trace.hpp"
12 #include "lttng-relayd.hpp"
13 #include "session.hpp"
14 #include "sessiond-trace-chunks.hpp"
15 #include "stream.hpp"
16 #include "utils.hpp"
17
18 #include <common/common.hpp>
19 #include <common/compat/path.hpp>
20 #include <common/defaults.hpp>
21 #include <common/fd-tracker/utils.hpp>
22 #include <common/time.hpp>
23 #include <common/urcu.hpp>
24 #include <common/utils.hpp>
25 #include <common/uuid.hpp>
26
27 #include <sys/stat.h>
28 #include <urcu/rculist.h>
29
30 /* Global session id used in the session creation. */
31 static uint64_t last_relay_session_id;
32 static pthread_mutex_t last_relay_session_id_lock = PTHREAD_MUTEX_INITIALIZER;
33
34 static int init_session_output_path_group_by_host(struct relay_session *session)
35 {
36 /*
37 * session_directory:
38 *
39 * if base_path is \0'
40 * hostname/session_name
41 * else
42 * hostname/base_path
43 */
44 char *session_directory = nullptr;
45 int ret = 0;
46
47 if (session->output_path[0] != '\0') {
48 goto end;
49 }
50 /*
51 * If base path is set, it overrides the session name for the
52 * session relative base path. No timestamp is appended if the
53 * base path is overridden.
54 *
55 * If the session name already contains the creation time (e.g.
56 * auto-<timestamp>, don't append yet another timestamp after
57 * the session name in the generated path.
58 *
59 * Otherwise, generate the path with session_name-<timestamp>.
60 */
61 if (session->base_path[0] != '\0') {
62 ret = asprintf(&session_directory, "%s/%s", session->hostname, session->base_path);
63 } else if (session->session_name_contains_creation_time) {
64 ret = asprintf(
65 &session_directory, "%s/%s", session->hostname, session->session_name);
66 } else {
67 char session_creation_datetime[DATETIME_STR_LEN];
68
69 ret = time_to_datetime_str(LTTNG_OPTIONAL_GET(session->creation_time),
70 session_creation_datetime,
71 sizeof(session_creation_datetime));
72 if (ret) {
73 ERR("Failed to format session creation timestamp while initializing session output directory handle");
74 ret = -1;
75 goto end;
76 }
77
78 ret = asprintf(&session_directory,
79 "%s/%s-%s",
80 session->hostname,
81 session->session_name,
82 session_creation_datetime);
83 }
84 if (ret < 0) {
85 PERROR("Failed to format session directory name");
86 goto end;
87 }
88
89 if (strlen(session_directory) >= LTTNG_PATH_MAX) {
90 ERR("Session output directory exceeds maximal length");
91 ret = -1;
92 goto end;
93 }
94 strcpy(session->output_path, session_directory);
95 ret = 0;
96
97 end:
98 free(session_directory);
99 return ret;
100 }
101
102 static int init_session_output_path_group_by_session(struct relay_session *session)
103 {
104 /*
105 * session_directory:
106 *
107 * session_name/hostname-creation_time/base_path
108 *
109 * For session name including the datetime, use it as the complete name
110 * since. Do not perform modification on it since the datetime is an
111 * integral part of the name and how a user identify a session.
112 */
113 int ret = 0;
114 char *session_directory = nullptr;
115 char creation_datetime[DATETIME_STR_LEN];
116
117 if (session->output_path[0] != '\0') {
118 /* output_path as been generated already */
119 goto end;
120 }
121
122 ret = time_to_datetime_str(LTTNG_OPTIONAL_GET(session->creation_time),
123 creation_datetime,
124 sizeof(creation_datetime));
125 if (ret) {
126 ERR("Failed to format session creation timestamp while initializing session output directory handle");
127 ret = -1;
128 goto end;
129 }
130
131 ret = asprintf(&session_directory,
132 "%s/%s-%s%s%s",
133 session->session_name,
134 session->hostname,
135 creation_datetime,
136 session->base_path[0] != '\0' ? "/" : "",
137 session->base_path);
138 if (ret < 0) {
139 PERROR("Failed to format session directory name");
140 goto end;
141 }
142
143 if (strlen(session_directory) >= LTTNG_PATH_MAX) {
144 ERR("Session output directory exceeds maximal length");
145 ret = -1;
146 goto end;
147 }
148
149 strcpy(session->output_path, session_directory);
150 ret = 0;
151
152 end:
153 free(session_directory);
154 return ret;
155 }
156
157 static int init_session_output_path(struct relay_session *session)
158 {
159 int ret;
160
161 switch (opt_group_output_by) {
162 case RELAYD_GROUP_OUTPUT_BY_HOST:
163 ret = init_session_output_path_group_by_host(session);
164 break;
165 case RELAYD_GROUP_OUTPUT_BY_SESSION:
166 ret = init_session_output_path_group_by_session(session);
167 break;
168 case RELAYD_GROUP_OUTPUT_BY_UNKNOWN:
169 default:
170 abort();
171 break;
172 }
173
174 return ret;
175 }
176
177 static struct lttng_directory_handle *
178 session_create_output_directory_handle(struct relay_session *session)
179 {
180 int ret;
181 /*
182 * relayd_output_path/session_directory
183 * e.g. /home/user/lttng-traces/hostname/session_name
184 */
185 char *full_session_path = nullptr;
186 struct lttng_directory_handle *handle = nullptr;
187
188 pthread_mutex_lock(&session->lock);
189 full_session_path = create_output_path(session->output_path);
190 if (!full_session_path) {
191 goto end;
192 }
193
194 ret = utils_mkdir_recursive(full_session_path, S_IRWXU | S_IRWXG, -1, -1);
195 if (ret) {
196 ERR("Failed to create session output path \"%s\"", full_session_path);
197 goto end;
198 }
199
200 handle = fd_tracker_create_directory_handle(the_fd_tracker, full_session_path);
201 end:
202 pthread_mutex_unlock(&session->lock);
203 free(full_session_path);
204 return handle;
205 }
206
207 static int session_set_anonymous_chunk(struct relay_session *session)
208 {
209 int ret = 0;
210 struct lttng_trace_chunk *chunk = nullptr;
211 enum lttng_trace_chunk_status status;
212 struct lttng_directory_handle *output_directory;
213
214 output_directory = session_create_output_directory_handle(session);
215 if (!output_directory) {
216 goto end;
217 }
218
219 chunk = lttng_trace_chunk_create_anonymous();
220 if (!chunk) {
221 goto end;
222 }
223
224 lttng_trace_chunk_set_fd_tracker(chunk, the_fd_tracker);
225 status = lttng_trace_chunk_set_credentials_current_user(chunk);
226 if (status != LTTNG_TRACE_CHUNK_STATUS_OK) {
227 ret = -1;
228 goto end;
229 }
230
231 status = lttng_trace_chunk_set_as_owner(chunk, output_directory);
232 if (status != LTTNG_TRACE_CHUNK_STATUS_OK) {
233 ret = -1;
234 goto end;
235 }
236
237 session->current_trace_chunk = chunk;
238 chunk = nullptr;
239 end:
240 lttng_trace_chunk_put(chunk);
241 lttng_directory_handle_put(output_directory);
242 return ret;
243 }
244
245 /*
246 * Check if a name is safe to use in a path.
247 *
248 * A name that is deemed "path-safe":
249 * - Does not contains a path separator (/ or \, platform dependant),
250 * - Does not start with a '.' (hidden file/folder),
251 * - Is not empty.
252 */
253 static bool is_name_path_safe(const char *name)
254 {
255 const size_t name_len = strlen(name);
256
257 /* Not empty. */
258 if (name_len == 0) {
259 WARN("An empty name is not allowed to be used in a path");
260 return false;
261 }
262 /* Does not start with '.'. */
263 if (name[0] == '.') {
264 WARN("Name \"%s\" is not allowed to be used in a path since it starts with '.'",
265 name);
266 return false;
267 }
268 /* Does not contain a path-separator. */
269 if (strchr(name, LTTNG_PATH_SEPARATOR)) {
270 WARN("Name \"%s\" is not allowed to be used in a path since it contains a path separator",
271 name);
272 return false;
273 }
274
275 return true;
276 }
277
278 /*
279 * Create a new session by assigning a new session ID.
280 *
281 * Return allocated session or else NULL.
282 */
283 struct relay_session *session_create(const char *session_name,
284 const char *hostname,
285 const char *base_path,
286 uint32_t live_timer,
287 bool snapshot,
288 const lttng_uuid& sessiond_uuid,
289 const uint64_t *id_sessiond,
290 const uint64_t *current_chunk_id,
291 const time_t *creation_time,
292 uint32_t major,
293 uint32_t minor,
294 bool session_name_contains_creation_time)
295 {
296 int ret;
297 struct relay_session *session = nullptr;
298
299 LTTNG_ASSERT(session_name);
300 LTTNG_ASSERT(hostname);
301 LTTNG_ASSERT(base_path);
302
303 if (!is_name_path_safe(session_name)) {
304 ERR("Refusing to create session as the provided session name is not path-safe");
305 goto error;
306 }
307 if (!is_name_path_safe(hostname)) {
308 ERR("Refusing to create session as the provided hostname is not path-safe");
309 goto error;
310 }
311 if (strstr(base_path, "../")) {
312 ERR("Invalid session base path walks up the path hierarchy: \"%s\"", base_path);
313 goto error;
314 }
315
316 session = zmalloc<relay_session>();
317 if (!session) {
318 PERROR("Failed to allocate session");
319 goto error;
320 }
321
322 pthread_mutex_lock(&last_relay_session_id_lock);
323 session->id = ++last_relay_session_id;
324 pthread_mutex_unlock(&last_relay_session_id_lock);
325
326 lttng_ht_node_init_u64(&session->session_n, session->id);
327 urcu_ref_init(&session->ref);
328 CDS_INIT_LIST_HEAD(&session->recv_list);
329 pthread_mutex_init(&session->lock, nullptr);
330 pthread_mutex_init(&session->recv_list_lock, nullptr);
331
332 if (lttng_strncpy(session->session_name, session_name, sizeof(session->session_name))) {
333 WARN("Session name exceeds maximal allowed length");
334 goto error;
335 }
336 if (lttng_strncpy(session->hostname, hostname, sizeof(session->hostname))) {
337 WARN("Hostname exceeds maximal allowed length");
338 goto error;
339 }
340 if (lttng_strncpy(session->base_path, base_path, sizeof(session->base_path))) {
341 WARN("Base path exceeds maximal allowed length");
342 goto error;
343 }
344 if (creation_time) {
345 LTTNG_OPTIONAL_SET(&session->creation_time, *creation_time);
346 } else {
347 LTTNG_OPTIONAL_SET(&session->creation_time, time(nullptr));
348 if (session->creation_time.value == (time_t) -1) {
349 PERROR("Failed to sample session creation time");
350 goto error;
351 }
352 }
353 session->session_name_contains_creation_time = session_name_contains_creation_time;
354
355 session->ctf_traces_ht = lttng_ht_new(0, LTTNG_HT_TYPE_STRING);
356 if (!session->ctf_traces_ht) {
357 goto error;
358 }
359
360 session->major = major;
361 session->minor = minor;
362
363 session->live_timer = live_timer;
364 session->snapshot = snapshot;
365 session->sessiond_uuid = sessiond_uuid;
366
367 if (id_sessiond) {
368 LTTNG_OPTIONAL_SET(&session->id_sessiond, *id_sessiond);
369 }
370
371 if (major == 2 && minor >= 11) {
372 /* Only applies for 2.11+ peers using trace chunks. */
373 ret = init_session_output_path(session);
374 if (ret) {
375 goto error;
376 }
377 }
378
379 ret = sessiond_trace_chunk_registry_session_created(sessiond_trace_chunk_registry,
380 sessiond_uuid);
381 if (ret) {
382 goto error;
383 }
384
385 if (id_sessiond && current_chunk_id) {
386 enum lttng_trace_chunk_status chunk_status;
387 struct lttng_directory_handle *session_output_directory;
388
389 session->current_trace_chunk =
390 sessiond_trace_chunk_registry_get_chunk(sessiond_trace_chunk_registry,
391 session->sessiond_uuid,
392 session->id_sessiond.value,
393 *current_chunk_id);
394 if (!session->current_trace_chunk) {
395 char uuid_str[LTTNG_UUID_STR_LEN];
396
397 lttng_uuid_to_str(sessiond_uuid, uuid_str);
398 ERR("Could not find trace chunk: sessiond = {%s}, sessiond session id = %" PRIu64
399 ", trace chunk id = %" PRIu64,
400 uuid_str,
401 *id_sessiond,
402 *current_chunk_id);
403 goto error;
404 }
405
406 chunk_status = lttng_trace_chunk_get_session_output_directory_handle(
407 session->current_trace_chunk, &session_output_directory);
408 if (chunk_status != LTTNG_TRACE_CHUNK_STATUS_OK) {
409 goto error;
410 }
411
412 LTTNG_ASSERT(session_output_directory);
413 session->output_directory = session_output_directory;
414 } else if (!id_sessiond) {
415 /*
416 * Pre-2.11 peers will not announce trace chunks. An
417 * anonymous trace chunk which will remain set for the
418 * duration of the session is created.
419 */
420 ret = session_set_anonymous_chunk(session);
421 if (ret) {
422 goto error;
423 }
424 } else {
425 session->output_directory = session_create_output_directory_handle(session);
426 if (!session->output_directory) {
427 goto error;
428 }
429 }
430
431 lttng_ht_add_unique_u64(sessions_ht, &session->session_n);
432 return session;
433
434 error:
435 session_put(session);
436 return nullptr;
437 }
438
439 /* Should be called with RCU read-side lock held. */
440 bool session_get(struct relay_session *session)
441 {
442 return urcu_ref_get_unless_zero(&session->ref);
443 }
444
445 /*
446 * Lookup a session within the session hash table using the session id
447 * as key. A session reference is taken when a session is returned.
448 * session_put() must be called on that session.
449 *
450 * Return session or NULL if not found.
451 */
452 struct relay_session *session_get_by_id(uint64_t id)
453 {
454 struct relay_session *session = nullptr;
455 struct lttng_ht_node_u64 *node;
456 struct lttng_ht_iter iter;
457
458 const lttng::urcu::read_lock_guard read_lock;
459 lttng_ht_lookup(sessions_ht, &id, &iter);
460 node = lttng_ht_iter_get_node<lttng_ht_node_u64>(&iter);
461 if (!node) {
462 DBG("Session find by ID %" PRIu64 " id NOT found", id);
463 goto end;
464 }
465 session = lttng::utils::container_of(node, &relay_session::session_n);
466 DBG("Session find by ID %" PRIu64 " id found", id);
467 if (!session_get(session)) {
468 session = nullptr;
469 }
470 end:
471 return session;
472 }
473
474 /*
475 * Check if any of the relay sessions originating from the same
476 * session daemon session have the 'ongoing_rotation' state set.
477 *
478 * The caller must hold the lock of session.
479 */
480 bool session_has_ongoing_rotation(const struct relay_session *session)
481 {
482 bool ongoing_rotation = false;
483
484 ASSERT_LOCKED(session->lock);
485
486 if (!session->id_sessiond.is_set) {
487 /*
488 * The peer that created this session is too old to
489 * support rotations; we can assume no rotations are ongoing.
490 */
491 goto end;
492 }
493
494 if (session->ongoing_rotation) {
495 ongoing_rotation = true;
496 goto end;
497 }
498
499 /*
500 * Sample the 'ongoing_rotation' status of all relay sessions that
501 * originate from the same session daemon session.
502 */
503 for (auto *iterated_session :
504 lttng::urcu::lfht_iteration_adapter<relay_session,
505 decltype(relay_session::session_n),
506 &relay_session::session_n>(*sessions_ht->ht)) {
507 if (!session_get(iterated_session)) {
508 continue;
509 }
510
511 if (session == iterated_session) {
512 /* Skip this session. */
513 goto next_session_no_unlock;
514 }
515
516 pthread_mutex_lock(&iterated_session->lock);
517
518 if (!iterated_session->id_sessiond.is_set) {
519 /*
520 * Session belongs to a peer that doesn't support
521 * rotations.
522 */
523 goto next_session;
524 }
525
526 if (session->sessiond_uuid != iterated_session->sessiond_uuid) {
527 /* Sessions do not originate from the same sessiond. */
528 goto next_session;
529 }
530
531 if (LTTNG_OPTIONAL_GET(session->id_sessiond) !=
532 LTTNG_OPTIONAL_GET(iterated_session->id_sessiond)) {
533 /*
534 * Sessions do not originate from the same sessiond
535 * session.
536 */
537 goto next_session;
538 }
539
540 ongoing_rotation = iterated_session->ongoing_rotation;
541
542 next_session:
543 pthread_mutex_unlock(&iterated_session->lock);
544 next_session_no_unlock:
545 session_put(iterated_session);
546
547 if (ongoing_rotation) {
548 break;
549 }
550 }
551
552 end:
553 return ongoing_rotation;
554 }
555
556 static void rcu_destroy_session(struct rcu_head *rcu_head)
557 {
558 auto *session = lttng::utils::container_of(rcu_head, &relay_session::rcu_node);
559 /*
560 * Since each trace has a reference on the session, it means
561 * that if we are at the point where we teardown the session, no
562 * trace belonging to that session exist at this point.
563 * Calling lttng_ht_destroy in call_rcu worker thread so we
564 * don't hold the RCU read-side lock while calling it.
565 */
566 lttng_ht_destroy(session->ctf_traces_ht);
567 free(session);
568 }
569
570 /*
571 * Delete session from the given hash table.
572 *
573 * Return lttng ht del error code being 0 on success and 1 on failure.
574 */
575 static int session_delete(struct relay_session *session)
576 {
577 struct lttng_ht_iter iter;
578
579 iter.iter.node = &session->session_n.node;
580 return lttng_ht_del(sessions_ht, &iter);
581 }
582
583 static void destroy_session(struct relay_session *session)
584 {
585 int ret;
586
587 ret = session_delete(session);
588 LTTNG_ASSERT(!ret);
589 lttng_trace_chunk_put(session->current_trace_chunk);
590 session->current_trace_chunk = nullptr;
591 lttng_trace_chunk_put(session->pending_closure_trace_chunk);
592 session->pending_closure_trace_chunk = nullptr;
593 ret = sessiond_trace_chunk_registry_session_destroyed(sessiond_trace_chunk_registry,
594 session->sessiond_uuid);
595 LTTNG_ASSERT(!ret);
596 lttng_directory_handle_put(session->output_directory);
597 session->output_directory = nullptr;
598 call_rcu(&session->rcu_node, rcu_destroy_session);
599 }
600
601 static void session_release(struct urcu_ref *ref)
602 {
603 struct relay_session *session = lttng::utils::container_of(ref, &relay_session::ref);
604
605 destroy_session(session);
606 }
607
608 void session_put(struct relay_session *session)
609 {
610 if (!session) {
611 return;
612 }
613 const lttng::urcu::read_lock_guard read_lock;
614 urcu_ref_put(&session->ref, session_release);
615 }
616
617 int session_close(struct relay_session *session)
618 {
619 int ret = 0;
620
621 pthread_mutex_lock(&session->lock);
622 DBG("closing session %" PRIu64 ": is conn already closed %d",
623 session->id,
624 session->connection_closed);
625 session->connection_closed = true;
626 pthread_mutex_unlock(&session->lock);
627
628 for (auto *trace :
629 lttng::urcu::lfht_iteration_adapter<ctf_trace,
630 decltype(ctf_trace::node),
631 &ctf_trace::node>(*session->ctf_traces_ht->ht)) {
632 ret = ctf_trace_close(trace);
633 if (ret) {
634 goto end;
635 }
636 }
637
638 for (auto *stream :
639 lttng::urcu::rcu_list_iteration_adapter<relay_stream, &relay_stream::recv_node>(
640 session->recv_list)) {
641 /* Close streams which have not been published yet. */
642 try_stream_close(stream);
643 }
644
645 end:
646 if (ret) {
647 return ret;
648 }
649
650 /* Put self-reference from create. */
651 session_put(session);
652 return ret;
653 }
654
655 int session_abort(struct relay_session *session)
656 {
657 const int ret = 0;
658
659 if (!session) {
660 return 0;
661 }
662
663 pthread_mutex_lock(&session->lock);
664 DBG("aborting session %" PRIu64, session->id);
665 session->aborted = true;
666 pthread_mutex_unlock(&session->lock);
667 return ret;
668 }
669
670 void print_sessions()
671 {
672 if (!sessions_ht) {
673 return;
674 }
675
676 for (auto *session :
677 lttng::urcu::lfht_iteration_adapter<relay_session,
678 decltype(relay_session::session_n),
679 &relay_session::session_n>(*sessions_ht->ht)) {
680 if (!session_get(session)) {
681 continue;
682 }
683 DBG("session %p refcount %ld session %" PRIu64,
684 session,
685 session->ref.refcount,
686 session->id);
687 session_put(session);
688 }
689 }
This page took 0.043098 seconds and 5 git commands to generate.