2 * Copyright (C) 2022 Jonathan Rajotte<jonathan.rajotte-julien@efficios.com>
4 * SPDX-License-Identifier: LGPL-2.1-only
7 #include <common/defaults.hpp>
8 #include <common/error.hpp>
9 #include <common/macros.hpp>
10 #include <common/optional.hpp>
11 #include <common/payload-view.hpp>
12 #include <common/payload.hpp>
13 #include <common/uri.hpp>
14 #include <lttng/session-internal.hpp>
15 #include <lttng/session.h>
20 struct session_list_element
{
21 struct lttng_session
*session
;
24 static void session_list_destructor(void *ptr
)
26 struct session_list_element
*element
= (struct session_list_element
*) ptr
;
28 free(element
->session
);
32 int lttng_session_serialize(const struct lttng_session
*session
, lttng_payload
*payload
)
35 size_t name_len
, path_len
;
36 struct lttng_session_comm session_comm
= {};
37 struct lttng_session_extended
*extended
= (typeof(extended
)) session
->extended
.ptr
;
39 LTTNG_ASSERT(extended
!= nullptr);
41 name_len
= lttng_strnlen(session
->name
, sizeof(session
->name
));
42 if (name_len
== sizeof(session
->name
)) {
43 /* Session name is not NULL-terminated. */
48 /* Add null termination. */
51 path_len
= lttng_strnlen(session
->path
, sizeof(session
->path
));
52 if (path_len
== sizeof(session
->path
)) {
53 /* Session path is not NULL-terminated. */
58 /* Add null termination. */
61 session_comm
.name_len
= (uint32_t) name_len
;
62 session_comm
.path_len
= (uint32_t) path_len
;
63 session_comm
.enabled
= (uint8_t) session
->enabled
;
64 session_comm
.snapshot_mode
= session
->snapshot_mode
;
65 session_comm
.live_timer_interval
= session
->live_timer_interval
;
66 if (extended
->creation_time
.is_set
) {
67 LTTNG_OPTIONAL_SET(&session_comm
.creation_time
,
68 LTTNG_OPTIONAL_GET(extended
->creation_time
));
70 LTTNG_OPTIONAL_UNSET(&session_comm
.creation_time
);
74 ret
= lttng_dynamic_buffer_append(&payload
->buffer
, &session_comm
, sizeof(session_comm
));
80 ret
= lttng_dynamic_buffer_append(&payload
->buffer
, session
->name
, name_len
);
86 ret
= lttng_dynamic_buffer_append(&payload
->buffer
, session
->path
, path_len
);
95 ssize_t
lttng_session_create_from_payload(
96 struct lttng_payload_view
*view
, struct lttng_session
**out_session
)
98 ssize_t ret
, offset
= 0;
99 struct lttng_session
*local_session
= nullptr;
100 struct lttng_session_extended
*local_extended
= nullptr;
101 const struct lttng_session_comm
*session_comm
;
103 LTTNG_ASSERT(out_session
);
107 struct lttng_payload_view comm_view
=
108 lttng_payload_view_from_view(view
, offset
, sizeof(*session_comm
));
110 if (!lttng_payload_view_is_valid(&comm_view
)) {
115 /* lttng_session_comm header */
116 session_comm
= (typeof(session_comm
)) comm_view
.buffer
.data
;
117 offset
+= sizeof(*session_comm
);
120 local_session
= zmalloc
<struct lttng_session
>(
121 sizeof(struct lttng_session
) + sizeof(struct lttng_session_extended
));
122 if (local_session
== nullptr) {
127 local_extended
= (struct lttng_session_extended
*) ((char *) local_session
+
128 sizeof(lttng_session
));
129 if (local_extended
== nullptr) {
134 local_session
->extended
.ptr
= local_extended
;
136 local_session
->enabled
= session_comm
->enabled
;
137 local_session
->live_timer_interval
= session_comm
->live_timer_interval
;
138 local_session
->snapshot_mode
= session_comm
->snapshot_mode
;
139 if (session_comm
->creation_time
.is_set
) {
140 LTTNG_OPTIONAL_SET(&local_extended
->creation_time
,
141 LTTNG_OPTIONAL_GET(session_comm
->creation_time
));
146 const struct lttng_buffer_view name_view
= lttng_buffer_view_from_view(
147 &view
->buffer
, offset
, session_comm
->name_len
);
149 if (!lttng_buffer_view_is_valid(&name_view
)) {
154 name
= (const char *) name_view
.data
;
156 if (!lttng_buffer_view_contains_string(&name_view
, name
, session_comm
->name_len
)) {
161 ret
= lttng_strncpy(local_session
->name
, name
, sizeof(local_session
->name
));
167 offset
+= session_comm
->name_len
;
172 const struct lttng_buffer_view path_view
= lttng_buffer_view_from_view(
173 &view
->buffer
, offset
, session_comm
->path_len
);
175 if (!lttng_buffer_view_is_valid(&path_view
)) {
180 path
= (const char *) path_view
.data
;
182 if (!lttng_buffer_view_contains_string(&path_view
, path
, session_comm
->path_len
)) {
187 ret
= lttng_strncpy(local_session
->path
, path
, sizeof(local_session
->path
));
193 offset
+= session_comm
->path_len
;
195 /* Transfer ownership to the caller. */
196 *out_session
= local_session
;
197 local_session
= nullptr;
205 static enum lttng_error_code
compute_flattened_size(
206 struct lttng_dynamic_pointer_array
*sessions
, size_t *size
)
208 enum lttng_error_code ret_code
;
209 size_t storage_req
, session_count
;
214 session_count
= lttng_dynamic_pointer_array_get_count(sessions
);
216 /* The basic struct lttng_session */
217 storage_req
= session_count
* sizeof(struct lttng_session
);
219 /* The struct lttng_session_extended */
220 storage_req
+= session_count
* sizeof(struct lttng_session_extended
);
228 static enum lttng_error_code
flatten_lttng_sessions(struct lttng_dynamic_pointer_array
*sessions
,
229 struct lttng_session
**flattened_sessions
)
231 enum lttng_error_code ret_code
;
234 struct lttng_dynamic_buffer local_flattened_sessions
;
238 assert(flattened_sessions
);
240 lttng_dynamic_buffer_init(&local_flattened_sessions
);
241 nb_sessions
= lttng_dynamic_pointer_array_get_count(sessions
);
243 ret_code
= compute_flattened_size(sessions
, &storage_req
);
244 if (ret_code
!= LTTNG_OK
) {
249 * We must ensure that "local_flattened_sessions" is never resized so as
250 * to preserve the validity of the flattened objects.
252 ret
= lttng_dynamic_buffer_set_capacity(&local_flattened_sessions
, storage_req
);
254 ret_code
= LTTNG_ERR_NOMEM
;
258 /* Start by laying the struct lttng_session */
259 for (i
= 0; i
< nb_sessions
; i
++) {
260 const struct session_list_element
*element
= (const struct session_list_element
*)
261 lttng_dynamic_pointer_array_get_pointer(sessions
, i
);
264 ret_code
= LTTNG_ERR_FATAL
;
268 ret
= lttng_dynamic_buffer_append(&local_flattened_sessions
, element
->session
,
269 sizeof(struct lttng_session
));
271 ret_code
= LTTNG_ERR_NOMEM
;
276 for (i
= 0; i
< nb_sessions
; i
++) {
277 const struct session_list_element
*element
= (const struct session_list_element
*)
278 lttng_dynamic_pointer_array_get_pointer(sessions
, i
);
279 struct lttng_session
*session
=
280 (struct lttng_session
*) (local_flattened_sessions
.data
+
281 (sizeof(struct lttng_session
) * i
));
282 struct lttng_session_extended
*session_extended
=
283 (struct lttng_session_extended
*) (local_flattened_sessions
.data
+
284 local_flattened_sessions
.size
);
288 /* Insert struct lttng_session_extended. */
289 ret
= lttng_dynamic_buffer_set_size(&local_flattened_sessions
,
290 local_flattened_sessions
.size
+ sizeof(*session_extended
));
292 ret_code
= LTTNG_ERR_NOMEM
;
295 session
->extended
.ptr
= session_extended
;
297 memcpy(session_extended
, element
->session
->extended
.ptr
,
298 sizeof(struct lttng_session_extended
));
301 /* Don't reset local_flattened_sessions buffer as we return its content. */
302 *flattened_sessions
= (struct lttng_session
*) local_flattened_sessions
.data
;
303 lttng_dynamic_buffer_init(&local_flattened_sessions
);
306 lttng_dynamic_buffer_reset(&local_flattened_sessions
);
310 static enum lttng_error_code
session_list_create_from_payload(struct lttng_payload_view
*view
,
312 struct lttng_dynamic_pointer_array
*session_list
)
314 enum lttng_error_code ret_code
;
320 assert(session_list
);
322 for (i
= 0; i
< count
; i
++) {
323 ssize_t session_size
;
324 struct lttng_payload_view session_view
=
325 lttng_payload_view_from_view(view
, offset
, -1);
326 struct session_list_element
*element
= zmalloc
<session_list_element
>();
329 ret_code
= LTTNG_ERR_NOMEM
;
334 * Lifetime and management of the object is now bound to the
337 ret
= lttng_dynamic_pointer_array_add_pointer(session_list
, element
);
339 session_list_destructor(element
);
340 ret_code
= LTTNG_ERR_NOMEM
;
344 session_size
= lttng_session_create_from_payload(&session_view
, &element
->session
);
345 if (session_size
< 0) {
346 ret_code
= LTTNG_ERR_INVALID
;
350 offset
+= session_size
;
353 if (view
->buffer
.size
!= offset
) {
354 ret_code
= LTTNG_ERR_INVALID_PROTOCOL
;
363 enum lttng_error_code
lttng_sessions_create_and_flatten_from_payload(
364 struct lttng_payload_view
*payload
,
366 struct lttng_session
**sessions
)
368 enum lttng_error_code ret
= LTTNG_OK
;
369 struct lttng_dynamic_pointer_array local_sessions
;
371 lttng_dynamic_pointer_array_init(&local_sessions
, session_list_destructor
);
373 /* Deserialize the sessions. */
375 struct lttng_payload_view sessions_view
=
376 lttng_payload_view_from_view(payload
, 0, -1);
378 ret
= session_list_create_from_payload(&sessions_view
, count
, &local_sessions
);
379 if (ret
!= LTTNG_OK
) {
384 ret
= flatten_lttng_sessions(&local_sessions
, sessions
);
385 if (ret
!= LTTNG_OK
) {
390 lttng_dynamic_pointer_array_reset(&local_sessions
);