Basic serialization/deserialization for lttng_session
[lttng-tools.git] / src / common / session.cpp
1 /*
2 * Copyright (C) 2022 Jonathan Rajotte<jonathan.rajotte-julien@efficios.com>
3 *
4 * SPDX-License-Identifier: LGPL-2.1-only
5 */
6
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>
16 #include <memory>
17 #include <stdio.h>
18 #include <time.h>
19
20 struct session_list_element {
21 struct lttng_session *session;
22 };
23
24 static void session_list_destructor(void *ptr)
25 {
26 struct session_list_element *element = (struct session_list_element *) ptr;
27
28 free(element->session);
29 free(element);
30 }
31
32 int lttng_session_serialize(const struct lttng_session *session, lttng_payload *payload)
33 {
34 int ret;
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;
38
39 LTTNG_ASSERT(extended != nullptr);
40
41 name_len = lttng_strnlen(session->name, sizeof(session->name));
42 if (name_len == sizeof(session->name)) {
43 /* Session name is not NULL-terminated. */
44 ret = -1;
45 goto end;
46 }
47
48 /* Add null termination. */
49 name_len += 1;
50
51 path_len = lttng_strnlen(session->path, sizeof(session->path));
52 if (path_len == sizeof(session->path)) {
53 /* Session path is not NULL-terminated. */
54 ret = -1;
55 goto end;
56 }
57
58 /* Add null termination. */
59 path_len += 1;
60
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));
69 } else {
70 LTTNG_OPTIONAL_UNSET(&session_comm.creation_time);
71 }
72
73 /* Header */
74 ret = lttng_dynamic_buffer_append(&payload->buffer, &session_comm, sizeof(session_comm));
75 if (ret) {
76 goto end;
77 }
78
79 /* Session name */
80 ret = lttng_dynamic_buffer_append(&payload->buffer, session->name, name_len);
81 if (ret) {
82 goto end;
83 }
84
85 /* Session path */
86 ret = lttng_dynamic_buffer_append(&payload->buffer, session->path, path_len);
87 if (ret) {
88 goto end;
89 }
90
91 end:
92 return ret;
93 }
94
95 ssize_t lttng_session_create_from_payload(
96 struct lttng_payload_view *view, struct lttng_session **out_session)
97 {
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;
102
103 LTTNG_ASSERT(out_session);
104 LTTNG_ASSERT(view);
105
106 {
107 struct lttng_payload_view comm_view =
108 lttng_payload_view_from_view(view, offset, sizeof(*session_comm));
109
110 if (!lttng_payload_view_is_valid(&comm_view)) {
111 ret = -1;
112 goto end;
113 }
114
115 /* lttng_session_comm header */
116 session_comm = (typeof(session_comm)) comm_view.buffer.data;
117 offset += sizeof(*session_comm);
118 }
119
120 local_session = zmalloc<struct lttng_session>(
121 sizeof(struct lttng_session) + sizeof(struct lttng_session_extended));
122 if (local_session == nullptr) {
123 ret = -1;
124 goto end;
125 }
126
127 local_extended = (struct lttng_session_extended *) ((char *) local_session +
128 sizeof(lttng_session));
129 if (local_extended == nullptr) {
130 ret = -1;
131 goto end;
132 }
133
134 local_session->extended.ptr = local_extended;
135
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));
142 }
143
144 {
145 const char *name;
146 const struct lttng_buffer_view name_view = lttng_buffer_view_from_view(
147 &view->buffer, offset, session_comm->name_len);
148
149 if (!lttng_buffer_view_is_valid(&name_view)) {
150 ret = -1;
151 goto end;
152 }
153
154 name = (const char *) name_view.data;
155
156 if (!lttng_buffer_view_contains_string(&name_view, name, session_comm->name_len)) {
157 ret = -1;
158 goto end;
159 }
160
161 ret = lttng_strncpy(local_session->name, name, sizeof(local_session->name));
162 if (ret) {
163 ret = -1;
164 goto end;
165 }
166
167 offset += session_comm->name_len;
168 }
169
170 {
171 const char *path;
172 const struct lttng_buffer_view path_view = lttng_buffer_view_from_view(
173 &view->buffer, offset, session_comm->path_len);
174
175 if (!lttng_buffer_view_is_valid(&path_view)) {
176 ret = -1;
177 goto end;
178 }
179
180 path = (const char *) path_view.data;
181
182 if (!lttng_buffer_view_contains_string(&path_view, path, session_comm->path_len)) {
183 ret = -1;
184 goto end;
185 }
186
187 ret = lttng_strncpy(local_session->path, path, sizeof(local_session->path));
188 if (ret) {
189 ret = -1;
190 goto end;
191 }
192
193 offset += session_comm->path_len;
194 }
195 /* Transfer ownership to the caller. */
196 *out_session = local_session;
197 local_session = nullptr;
198
199 ret = offset;
200 end:
201 free(local_session);
202 return ret;
203 }
204
205 static enum lttng_error_code compute_flattened_size(
206 struct lttng_dynamic_pointer_array *sessions, size_t *size)
207 {
208 enum lttng_error_code ret_code;
209 size_t storage_req, session_count;
210
211 assert(size);
212 assert(sessions);
213
214 session_count = lttng_dynamic_pointer_array_get_count(sessions);
215
216 /* The basic struct lttng_session */
217 storage_req = session_count * sizeof(struct lttng_session);
218
219 /* The struct lttng_session_extended */
220 storage_req += session_count * sizeof(struct lttng_session_extended);
221
222 *size = storage_req;
223 ret_code = LTTNG_OK;
224
225 return ret_code;
226 }
227
228 static enum lttng_error_code flatten_lttng_sessions(struct lttng_dynamic_pointer_array *sessions,
229 struct lttng_session **flattened_sessions)
230 {
231 enum lttng_error_code ret_code;
232 int ret, i;
233 size_t storage_req;
234 struct lttng_dynamic_buffer local_flattened_sessions;
235 int nb_sessions;
236
237 assert(sessions);
238 assert(flattened_sessions);
239
240 lttng_dynamic_buffer_init(&local_flattened_sessions);
241 nb_sessions = lttng_dynamic_pointer_array_get_count(sessions);
242
243 ret_code = compute_flattened_size(sessions, &storage_req);
244 if (ret_code != LTTNG_OK) {
245 goto end;
246 }
247
248 /*
249 * We must ensure that "local_flattened_sessions" is never resized so as
250 * to preserve the validity of the flattened objects.
251 */
252 ret = lttng_dynamic_buffer_set_capacity(&local_flattened_sessions, storage_req);
253 if (ret) {
254 ret_code = LTTNG_ERR_NOMEM;
255 goto end;
256 }
257
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);
262
263 if (!element) {
264 ret_code = LTTNG_ERR_FATAL;
265 goto end;
266 }
267
268 ret = lttng_dynamic_buffer_append(&local_flattened_sessions, element->session,
269 sizeof(struct lttng_session));
270 if (ret) {
271 ret_code = LTTNG_ERR_NOMEM;
272 goto end;
273 }
274 }
275
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);
285
286 assert(element);
287
288 /* Insert struct lttng_session_extended. */
289 ret = lttng_dynamic_buffer_set_size(&local_flattened_sessions,
290 local_flattened_sessions.size + sizeof(*session_extended));
291 if (ret) {
292 ret_code = LTTNG_ERR_NOMEM;
293 goto end;
294 }
295 session->extended.ptr = session_extended;
296
297 memcpy(session_extended, element->session->extended.ptr,
298 sizeof(struct lttng_session_extended));
299 }
300
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);
304 ret_code = LTTNG_OK;
305 end:
306 lttng_dynamic_buffer_reset(&local_flattened_sessions);
307 return ret_code;
308 }
309
310 static enum lttng_error_code session_list_create_from_payload(struct lttng_payload_view *view,
311 unsigned int count,
312 struct lttng_dynamic_pointer_array *session_list)
313 {
314 enum lttng_error_code ret_code;
315 int ret;
316 unsigned int i;
317 int offset = 0;
318
319 assert(view);
320 assert(session_list);
321
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>();
327
328 if (!element) {
329 ret_code = LTTNG_ERR_NOMEM;
330 goto end;
331 }
332
333 /*
334 * Lifetime and management of the object is now bound to the
335 * array.
336 */
337 ret = lttng_dynamic_pointer_array_add_pointer(session_list, element);
338 if (ret) {
339 session_list_destructor(element);
340 ret_code = LTTNG_ERR_NOMEM;
341 goto end;
342 }
343
344 session_size = lttng_session_create_from_payload(&session_view, &element->session);
345 if (session_size < 0) {
346 ret_code = LTTNG_ERR_INVALID;
347 goto end;
348 }
349
350 offset += session_size;
351 }
352
353 if (view->buffer.size != offset) {
354 ret_code = LTTNG_ERR_INVALID_PROTOCOL;
355 goto end;
356 }
357
358 ret_code = LTTNG_OK;
359
360 end:
361 return ret_code;
362 }
363 enum lttng_error_code lttng_sessions_create_and_flatten_from_payload(
364 struct lttng_payload_view *payload,
365 unsigned int count,
366 struct lttng_session **sessions)
367 {
368 enum lttng_error_code ret = LTTNG_OK;
369 struct lttng_dynamic_pointer_array local_sessions;
370
371 lttng_dynamic_pointer_array_init(&local_sessions, session_list_destructor);
372
373 /* Deserialize the sessions. */
374 {
375 struct lttng_payload_view sessions_view =
376 lttng_payload_view_from_view(payload, 0, -1);
377
378 ret = session_list_create_from_payload(&sessions_view, count, &local_sessions);
379 if (ret != LTTNG_OK) {
380 goto end;
381 }
382 }
383
384 ret = flatten_lttng_sessions(&local_sessions, sessions);
385 if (ret != LTTNG_OK) {
386 goto end;
387 }
388
389 end:
390 lttng_dynamic_pointer_array_reset(&local_sessions);
391 return ret;
392 }
This page took 0.037734 seconds and 5 git commands to generate.