Fix: liblttng-ctl comm: lttng_channel is not packed
[lttng-tools.git] / src / common / channel.cpp
CommitLineData
999af9c1
JR
1/*
2 * Copyright (C) 2021 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
3 *
4 * SPDX-License-Identifier: LGPL-2.1-only
5 *
6 */
7
8#include <common/macros.h>
9#include <lttng/channel.h>
10#include <lttng/constant.h>
11#include <lttng/channel-internal.h>
12#include <lttng/userspace-probe-internal.h>
13#include <common/dynamic-buffer.h>
14#include <common/error.h>
15#include <assert.h>
16#include <string.h>
17#include <common/sessiond-comm/sessiond-comm.h>
18#include <common/dynamic-array.h>
19#include <common/buffer-view.h>
20
21static enum lttng_error_code flatten_lttng_channels(
22 struct lttng_dynamic_pointer_array *channels,
23 struct lttng_channel **flattened_channels);
24
25static enum lttng_error_code channel_list_create_from_buffer(
26 const struct lttng_buffer_view *buffer,
27 uint32_t count,
28 struct lttng_dynamic_pointer_array *channel_list);
29
30static void channel_list_destructor(void *ptr)
31{
32 struct lttng_channel *element = (struct lttng_channel *) ptr;
33
34 lttng_channel_destroy(element);
35}
36
37struct lttng_channel *lttng_channel_copy(const struct lttng_channel *src)
38{
39 struct lttng_channel_extended *extended = nullptr;
40 struct lttng_channel *channel = nullptr, *ret = nullptr;
41
42 channel = (struct lttng_channel *) zmalloc(sizeof(*channel));
43 if (!channel) {
44 goto end;
45 }
46
47 *channel = *src;
48
49 if (src->attr.extended.ptr) {
50 extended = (struct lttng_channel_extended *) zmalloc(
51 sizeof(*extended));
52 if (!extended) {
53 goto end;
54 }
55 memcpy(extended, src->attr.extended.ptr, sizeof(*extended));
56 channel->attr.extended.ptr = extended;
57 extended = nullptr;
58 }
59
60 ret = channel;
61 channel = nullptr;
62end:
63 free(channel);
64 free(extended);
65 return ret;
66}
67
68/*
69 * The channel object is NOT populated.
70 */
71struct lttng_channel *lttng_channel_create_internal(void)
72{
73 struct lttng_channel *local_channel = nullptr, *ret = nullptr;
74 struct lttng_channel_extended *extended = nullptr;
75
76 local_channel = (struct lttng_channel *) zmalloc(
77 sizeof(struct lttng_channel));
78 if (!local_channel) {
79 goto end;
80 }
81
82 /* Extended struct */
83 extended = (struct lttng_channel_extended *) zmalloc(
84 sizeof(*extended));
85 if (!extended) {
86 goto end;
87 }
88
89 local_channel->attr.extended.ptr = extended;
90 extended = nullptr;
91
92 ret = local_channel;
93 local_channel = nullptr;
94end:
95 free(extended);
96 free(local_channel);
97 return ret;
98}
99
100ssize_t lttng_channel_create_from_buffer(const struct lttng_buffer_view *view,
101 struct lttng_channel **channel)
102{
103 ssize_t ret, offset = 0;
104 struct lttng_channel *local_channel = nullptr;
105 const struct lttng_channel_comm *channel_comm;
106 struct lttng_channel_extended *extended = nullptr;
107
108 assert(channel);
109
110 if (!view || !channel) {
111 ret = -1;
112 goto end;
113 }
114
115 /*
116 * Create an 'internal' channel since `lttng_create_channel` requires a
117 * domain and we cannot infer the domain from the payload.
118 */
119 local_channel = lttng_channel_create_internal();
120 if (!local_channel) {
121 ret = -1;
122 goto end;
123 }
124
125 extended = (typeof(extended)) local_channel->attr.extended.ptr;
126
127 /* lttng_trigger_comm header */
128 {
129 const struct lttng_buffer_view comm_view =
130 lttng_buffer_view_from_view(view, offset,
131 sizeof(*channel_comm));
132
133 if (!lttng_buffer_view_is_valid(&comm_view)) {
134 ret = -1;
135 goto end;
136 }
137
138 channel_comm = (const struct lttng_channel_comm *)
139 comm_view.data;
140 offset += sizeof(*channel_comm);
141 }
142
143 {
144 const char *name;
145 const struct lttng_buffer_view name_view =
146 lttng_buffer_view_from_view(view, offset,
147 channel_comm->name_len);
148
149 if (channel_comm->name_len > LTTNG_SYMBOL_NAME_LEN - 1) {
150 ret = -1;
151 goto end;
152 }
153
154 name = name_view.data;
155 if (!lttng_buffer_view_contains_string(
156 &name_view, name, channel_comm->name_len)) {
157 ret = -1;
158 goto end;
159 }
160
161 strcpy(local_channel->name, name);
162 offset += channel_comm->name_len;
163 }
164
165 /* Populate the channel */
166 local_channel->enabled = channel_comm->enabled;
167
168 /* attr */
169 local_channel->attr.overwrite = channel_comm->overwrite;
170 local_channel->attr.subbuf_size = channel_comm->subbuf_size;
171 local_channel->attr.num_subbuf = channel_comm->num_subbuf;
172 local_channel->attr.switch_timer_interval =
173 channel_comm->switch_timer_interval;
174 local_channel->attr.read_timer_interval =
175 channel_comm->read_timer_interval;
176 local_channel->attr.output = (enum lttng_event_output) channel_comm->output;
177 local_channel->attr.tracefile_size = channel_comm->tracefile_size;
178 local_channel->attr.tracefile_count = channel_comm->tracefile_count;
179 local_channel->attr.live_timer_interval =
180 channel_comm->live_timer_interval;
181
182 extended->discarded_events = channel_comm->discarded_events;
183 extended->lost_packets = channel_comm->lost_packets;
184 extended->monitor_timer_interval = channel_comm->monitor_timer_interval;
185 extended->blocking_timeout = channel_comm->blocking_timeout;
186
187 *channel = local_channel;
188 local_channel = nullptr;
189
190 ret = offset;
191end:
192 lttng_channel_destroy(local_channel);
193 return ret;
194}
195
196int lttng_channel_serialize(
197 struct lttng_channel *channel, struct lttng_dynamic_buffer *buf)
198{
199 int ret;
200 size_t name_len;
201 struct lttng_channel_comm channel_comm = { 0 };
202 struct lttng_channel_extended *extended;
203
204 assert(channel);
205 assert(buf);
206
207 extended = (struct lttng_channel_extended *) channel->attr.extended.ptr;
208
209 name_len = lttng_strnlen(channel->name, LTTNG_SYMBOL_NAME_LEN);
210 if (name_len == LTTNG_SYMBOL_NAME_LEN) {
211 /* channel name is not nullptr-terminated. */
212 ret = -1;
213 goto end;
214 }
215
216 /* Include string termination. */
217 name_len += 1;
218
219 /* Base field */
220 channel_comm.name_len = (uint32_t) name_len;
221 channel_comm.enabled = channel->enabled;
222
223 /* attr */
224 channel_comm.overwrite = channel->attr.overwrite;
225 channel_comm.subbuf_size = channel->attr.subbuf_size;
226 channel_comm.num_subbuf = channel->attr.num_subbuf;
227 channel_comm.switch_timer_interval =
228 channel->attr.switch_timer_interval;
229 channel_comm.read_timer_interval = channel->attr.read_timer_interval;
230 channel_comm.output = channel->attr.output;
231 channel_comm.tracefile_size = channel->attr.tracefile_size;
232 channel_comm.tracefile_count = channel->attr.tracefile_count;
233 channel_comm.live_timer_interval = channel->attr.live_timer_interval;
234
235 /* Extended struct */
236 channel_comm.discarded_events = extended->discarded_events;
237 channel_comm.lost_packets = extended->lost_packets;
238 channel_comm.monitor_timer_interval = extended->monitor_timer_interval;
239 channel_comm.blocking_timeout = extended->blocking_timeout;
240
241 /* Header */
242 ret = lttng_dynamic_buffer_append(
243 buf, &channel_comm, sizeof(channel_comm));
244 if (ret) {
245 goto end;
246 }
247
248 /* channel name */
249 ret = lttng_dynamic_buffer_append(buf, channel->name, name_len);
250 if (ret) {
251 goto end;
252 }
253end:
254 return ret;
255}
256
257void lttng_channel_set_default_extended_attr(struct lttng_domain *domain,
258 struct lttng_channel_extended *extended_attr)
259{
260 assert(domain);
261 assert(extended_attr);
262
263 memset(extended_attr, 0, sizeof(*extended_attr));
264
265 switch (domain->type) {
266 case LTTNG_DOMAIN_KERNEL:
267 extended_attr->monitor_timer_interval =
268 DEFAULT_KERNEL_CHANNEL_MONITOR_TIMER;
269 extended_attr->blocking_timeout =
270 DEFAULT_KERNEL_CHANNEL_BLOCKING_TIMEOUT;
271 break;
272 case LTTNG_DOMAIN_UST:
273 switch (domain->buf_type) {
274 case LTTNG_BUFFER_PER_UID:
275 extended_attr->monitor_timer_interval =
276 DEFAULT_UST_UID_CHANNEL_MONITOR_TIMER;
277 extended_attr->blocking_timeout =
278 DEFAULT_UST_UID_CHANNEL_BLOCKING_TIMEOUT;
279 break;
280 case LTTNG_BUFFER_PER_PID:
281 default:
282 if (extended_attr) {
283 extended_attr->monitor_timer_interval =
284 DEFAULT_UST_PID_CHANNEL_MONITOR_TIMER;
285 extended_attr->blocking_timeout =
286 DEFAULT_UST_PID_CHANNEL_BLOCKING_TIMEOUT;
287 }
288 break;
289 }
290 default:
291 /* Default behavior: leave set to 0. */
292 break;
293 }
294}
295
296static enum lttng_error_code channel_list_create_from_buffer(
297 const struct lttng_buffer_view *view,
298 unsigned int count,
299 struct lttng_dynamic_pointer_array *channel_list)
300{
301 enum lttng_error_code ret_code;
302 int ret, i;
303 int offset = 0;
304
305 assert(view);
306 assert(channel_list);
307
308 for (i = 0; i < count; i++) {
309 ssize_t channel_size;
310 struct lttng_channel *channel = nullptr;
311 const struct lttng_buffer_view channel_view =
312 lttng_buffer_view_from_view(view, offset, -1);
313
314 channel_size = lttng_channel_create_from_buffer(
315 &channel_view, &channel);
316 if (channel_size < 0) {
317 ret_code = LTTNG_ERR_INVALID;
318 goto end;
319 }
320
321 /* Lifetime and management of the object is now bound to the array. */
322 ret = lttng_dynamic_pointer_array_add_pointer(channel_list, channel);
323 if (ret) {
324 lttng_channel_destroy(channel);
325 ret_code = LTTNG_ERR_NOMEM;
326 goto end;
327 }
328 offset += channel_size;
329 }
330
331 if (view->size != offset) {
332 ret_code = LTTNG_ERR_INVALID;
333 goto end;
334 }
335
336 ret_code = LTTNG_OK;
337
338end:
339 return ret_code;
340}
341
342static enum lttng_error_code flatten_lttng_channels(struct lttng_dynamic_pointer_array *channels,
343 struct lttng_channel **flattened_channels)
344{
345 enum lttng_error_code ret_code;
346 int ret, i;
347 size_t storage_req = 0;
348 struct lttng_dynamic_buffer local_flattened_channels;
349 int nb_channels;
350
351 assert(channels);
352 assert(flattened_channels);
353
354 lttng_dynamic_buffer_init(&local_flattened_channels);
355 nb_channels = lttng_dynamic_pointer_array_get_count(channels);
356
357 storage_req += sizeof(struct lttng_channel) * nb_channels;
358 storage_req += sizeof(struct lttng_channel_extended) * nb_channels;
359
360 /*
361 * We must ensure that "local_flattened_channels" is never resized so as
362 * to preserve the validity of the flattened objects.
363 */
364 ret = lttng_dynamic_buffer_set_capacity(
365 &local_flattened_channels, storage_req);
366 if (ret) {
367 ret_code = LTTNG_ERR_NOMEM;
368 goto end;
369 }
370
371 /* Start by laying the struct lttng_channel */
372 for (i = 0; i < nb_channels; i++) {
373 const auto *element = (const struct lttng_channel *)
374 lttng_dynamic_pointer_array_get_pointer(
375 channels, i);
376
377 if (!element) {
378 ret_code = LTTNG_ERR_FATAL;
379 goto end;
380 }
381
382 ret = lttng_dynamic_buffer_append(&local_flattened_channels,
383 element, sizeof(struct lttng_channel));
384 if (ret) {
385 ret_code = LTTNG_ERR_NOMEM;
386 goto end;
387 }
388 }
389
390 /* Flatten the extended data */
391 for (i = 0; i < nb_channels; i++) {
392 const auto *element = (const struct lttng_channel *)
393 lttng_dynamic_pointer_array_get_pointer(
394 channels, i);
395 /*
396 * Sample the location of the flattened channel we are about
397 * to modify.
398 */
399 auto *channel = (struct lttng_channel *)
400 (local_flattened_channels.data + (sizeof(struct lttng_channel) * i));
401 /*
402 * Sample the location of the extended attributes we are about
403 * to add.
404 */
405 const auto *channel_extended = (struct lttng_channel_extended *)
406 (local_flattened_channels.data + local_flattened_channels.size);
407
408 if (!element) {
409 ret_code = LTTNG_ERR_FATAL;
410 goto end;
411 }
412
413 ret = lttng_dynamic_buffer_append(&local_flattened_channels,
414 element->attr.extended.ptr,
415 sizeof(struct lttng_channel_extended));
416 if (ret) {
417 ret_code = LTTNG_ERR_NOMEM;
418 goto end;
419 }
420
421 /*
422 * Update the flattened lttng_channel object with its flattened
423 * extended object location.
424 */
425 channel->attr.extended.ptr = (void *) channel_extended;
426 }
427
428 /* Don't reset local_flattened_channels buffer as we return its content. */
429 *flattened_channels = (struct lttng_channel *) local_flattened_channels.data;
430 lttng_dynamic_buffer_init(&local_flattened_channels);
431 ret_code = LTTNG_OK;
432end:
433 lttng_dynamic_buffer_reset(&local_flattened_channels);
434 return ret_code;
435}
436
437enum lttng_error_code lttng_channels_create_and_flatten_from_buffer(
438 const struct lttng_buffer_view *view,
439 uint32_t count,
440 struct lttng_channel **channels)
441{
442 enum lttng_error_code ret_code;
443 struct lttng_dynamic_pointer_array local_channels;
444
445 lttng_dynamic_pointer_array_init(&local_channels, channel_list_destructor);
446
447 /* Deserialize the channels */
448 {
449 const struct lttng_buffer_view channels_view =
450 lttng_buffer_view_from_view(view, 0, -1);
451
452 ret_code = channel_list_create_from_buffer(
453 &channels_view, count, &local_channels);
454 if (ret_code != LTTNG_OK) {
455 goto end;
456 }
457 }
458
459 ret_code = flatten_lttng_channels(&local_channels, channels);
460
461end:
462 lttng_dynamic_pointer_array_reset(&local_channels);
463 return ret_code;
464}
This page took 0.038976 seconds and 4 git commands to generate.