2 * Copyright (C) 2019 Jérémie Galarneau <jeremie.galarneau@efficios.com>
4 * SPDX-License-Identifier: LGPL-2.1-only
8 #include <lttng/destruction-handle.h>
9 #include <lttng/rotation.h>
11 #include <common/optional.h>
12 #include <common/compat/poll.h>
13 #include <common/compat/time.h>
14 #include <common/macros.h>
15 #include <common/compat/poll.h>
16 #include <common/dynamic-buffer.h>
17 #include <common/buffer-view.h>
18 #include <common/sessiond-comm/sessiond-comm.h>
19 #include <lttng/location-internal.h>
20 #include "lttng-ctl-helper.h"
25 enum communication_state
{
26 COMMUNICATION_STATE_RECEIVE_LTTNG_MSG
,
27 COMMUNICATION_STATE_RECEIVE_COMMAND_HEADER
,
28 COMMUNICATION_STATE_RECEIVE_PAYLOAD
,
29 COMMUNICATION_STATE_END
,
30 COMMUNICATION_STATE_ERROR
,
33 struct lttng_destruction_handle
{
34 LTTNG_OPTIONAL(enum lttng_error_code
) destruction_return_code
;
35 LTTNG_OPTIONAL(enum lttng_rotation_state
) rotation_state
;
36 struct lttng_trace_archive_location
*location
;
39 struct lttng_poll_event events
;
40 size_t bytes_left_to_receive
;
41 enum communication_state state
;
42 struct lttng_dynamic_buffer buffer
;
43 LTTNG_OPTIONAL(size_t) data_size
;
47 void lttng_destruction_handle_destroy(struct lttng_destruction_handle
*handle
)
55 if (handle
->communication
.socket
>= 0) {
56 ret
= close(handle
->communication
.socket
);
58 PERROR("Failed to close lttng-sessiond command socket");
61 lttng_poll_clean(&handle
->communication
.events
);
62 lttng_dynamic_buffer_reset(&handle
->communication
.buffer
);
63 lttng_trace_archive_location_put(handle
->location
);
68 struct lttng_destruction_handle
*lttng_destruction_handle_create(
72 struct lttng_destruction_handle
*handle
= (lttng_destruction_handle
*) zmalloc(sizeof(*handle
));
77 lttng_dynamic_buffer_init(&handle
->communication
.buffer
);
78 handle
->communication
.socket
= sessiond_socket
;
79 ret
= lttng_poll_create(&handle
->communication
.events
, 1, 0);
84 ret
= lttng_poll_add(&handle
->communication
.events
, sessiond_socket
,
85 LPOLLIN
| LPOLLHUP
| LPOLLRDHUP
| LPOLLERR
);
90 handle
->communication
.bytes_left_to_receive
=
91 sizeof(struct lttcomm_lttng_msg
);
92 handle
->communication
.state
= COMMUNICATION_STATE_RECEIVE_LTTNG_MSG
;
96 lttng_destruction_handle_destroy(handle
);
101 int handle_state_transition(struct lttng_destruction_handle
*handle
)
105 LTTNG_ASSERT(handle
->communication
.bytes_left_to_receive
== 0);
107 switch (handle
->communication
.state
) {
108 case COMMUNICATION_STATE_RECEIVE_LTTNG_MSG
:
110 const struct lttcomm_lttng_msg
*msg
=
111 (typeof(msg
)) handle
->communication
.buffer
.data
;
113 LTTNG_OPTIONAL_SET(&handle
->destruction_return_code
,
114 (enum lttng_error_code
) msg
->ret_code
);
115 if (handle
->destruction_return_code
.value
!= LTTNG_OK
) {
116 handle
->communication
.state
= COMMUNICATION_STATE_END
;
118 } else if (msg
->cmd_header_size
!= sizeof(struct lttcomm_session_destroy_command_header
) ||
119 msg
->data_size
> DEFAULT_MAX_TRACE_ARCHIVE_LOCATION_PAYLOAD_SIZE
) {
120 handle
->communication
.state
= COMMUNICATION_STATE_ERROR
;
125 handle
->communication
.state
=
126 COMMUNICATION_STATE_RECEIVE_COMMAND_HEADER
;
127 handle
->communication
.bytes_left_to_receive
=
128 msg
->cmd_header_size
;
129 LTTNG_OPTIONAL_SET(&handle
->communication
.data_size
,
131 ret
= lttng_dynamic_buffer_set_size(
132 &handle
->communication
.buffer
, 0);
136 case COMMUNICATION_STATE_RECEIVE_COMMAND_HEADER
:
138 const struct lttcomm_session_destroy_command_header
*hdr
=
139 (typeof(hdr
)) handle
->communication
.buffer
.data
;
141 LTTNG_OPTIONAL_SET(&handle
->rotation_state
,
142 (enum lttng_rotation_state
) hdr
->rotation_state
);
143 switch (handle
->rotation_state
.value
) {
144 case LTTNG_ROTATION_STATE_COMPLETED
:
145 handle
->communication
.state
=
146 COMMUNICATION_STATE_RECEIVE_PAYLOAD
;
147 handle
->communication
.bytes_left_to_receive
=
148 LTTNG_OPTIONAL_GET(handle
->communication
.data_size
);
150 case LTTNG_ROTATION_STATE_ERROR
:
151 case LTTNG_ROTATION_STATE_NO_ROTATION
:
152 handle
->communication
.state
= COMMUNICATION_STATE_END
;
155 handle
->communication
.state
= COMMUNICATION_STATE_ERROR
;
161 case COMMUNICATION_STATE_RECEIVE_PAYLOAD
:
163 ssize_t location_ret
;
164 struct lttng_trace_archive_location
*location
;
165 const struct lttng_buffer_view view
=
166 lttng_buffer_view_from_dynamic_buffer(
167 &handle
->communication
.buffer
, 0, -1);
169 location_ret
= lttng_trace_archive_location_create_from_buffer(
171 if (location_ret
< 0) {
172 ERR("Failed to deserialize trace archive location");
173 handle
->communication
.state
= COMMUNICATION_STATE_ERROR
;
177 /* Ownership is transferred to the destruction handle. */
178 handle
->location
= location
;
179 handle
->communication
.state
= COMMUNICATION_STATE_END
;
187 /* Clear reception buffer on state transition. */
188 if (lttng_dynamic_buffer_set_size(&handle
->communication
.buffer
, 0)) {
195 int handle_incoming_data(struct lttng_destruction_handle
*handle
)
199 const size_t original_buffer_size
= handle
->communication
.buffer
.size
;
201 /* Reserve space for reception. */
202 ret
= lttng_dynamic_buffer_set_size(&handle
->communication
.buffer
,
203 original_buffer_size
+ handle
->communication
.bytes_left_to_receive
);
208 comm_ret
= lttcomm_recv_unix_sock(handle
->communication
.socket
,
209 handle
->communication
.buffer
.data
+ original_buffer_size
,
210 handle
->communication
.bytes_left_to_receive
);
216 handle
->communication
.bytes_left_to_receive
-= comm_ret
;
217 if (handle
->communication
.bytes_left_to_receive
== 0) {
218 ret
= handle_state_transition(handle
);
220 ret
= lttng_dynamic_buffer_set_size(
221 &handle
->communication
.buffer
,
222 original_buffer_size
+ comm_ret
);
228 enum lttng_destruction_handle_status
229 lttng_destruction_handle_wait_for_completion(
230 struct lttng_destruction_handle
*handle
, int timeout_ms
)
232 enum lttng_destruction_handle_status status
;
233 unsigned long time_left_ms
= 0;
234 const bool has_timeout
= timeout_ms
> 0;
235 struct timespec initial_time
;
238 status
= LTTNG_DESTRUCTION_HANDLE_STATUS_INVALID
;
242 if (handle
->communication
.state
== COMMUNICATION_STATE_ERROR
) {
243 status
= LTTNG_DESTRUCTION_HANDLE_STATUS_ERROR
;
245 } else if (handle
->communication
.state
== COMMUNICATION_STATE_END
) {
246 status
= LTTNG_DESTRUCTION_HANDLE_STATUS_COMPLETED
;
250 int ret
= lttng_clock_gettime(CLOCK_MONOTONIC
, &initial_time
);
252 status
= LTTNG_DESTRUCTION_HANDLE_STATUS_ERROR
;
255 time_left_ms
= (unsigned long) timeout_ms
;
258 while (handle
->communication
.state
!= COMMUNICATION_STATE_END
&&
259 (time_left_ms
|| !has_timeout
)) {
262 struct timespec current_time
, diff
;
263 unsigned long diff_ms
;
265 ret
= lttng_poll_wait(&handle
->communication
.events
,
266 has_timeout
? time_left_ms
: -1);
270 } else if (ret
< 0) {
271 status
= LTTNG_DESTRUCTION_HANDLE_STATUS_ERROR
;
275 /* The sessiond connection socket is the only monitored fd. */
276 revents
= LTTNG_POLL_GETEV(&handle
->communication
.events
, 0);
277 if (revents
& LPOLLIN
) {
278 ret
= handle_incoming_data(handle
);
280 handle
->communication
.state
=
281 COMMUNICATION_STATE_ERROR
;
282 status
= LTTNG_DESTRUCTION_HANDLE_STATUS_ERROR
;
286 handle
->communication
.state
= COMMUNICATION_STATE_ERROR
;
287 status
= LTTNG_DESTRUCTION_HANDLE_STATUS_ERROR
;
294 ret
= lttng_clock_gettime(CLOCK_MONOTONIC
, ¤t_time
);
296 status
= LTTNG_DESTRUCTION_HANDLE_STATUS_ERROR
;
299 diff
= timespec_abs_diff(initial_time
, current_time
);
300 ret
= timespec_to_ms(diff
, &diff_ms
);
302 ERR("Failed to compute elapsed time while waiting for completion");
303 status
= LTTNG_DESTRUCTION_HANDLE_STATUS_ERROR
;
306 DBG("%lums elapsed while waiting for session destruction completion",
308 diff_ms
= std::max(diff_ms
, 1UL);
309 diff_ms
= std::min(diff_ms
, time_left_ms
);
310 time_left_ms
-= diff_ms
;
313 status
= handle
->communication
.state
== COMMUNICATION_STATE_END
?
314 LTTNG_DESTRUCTION_HANDLE_STATUS_COMPLETED
:
315 LTTNG_DESTRUCTION_HANDLE_STATUS_TIMEOUT
;
320 enum lttng_destruction_handle_status
321 lttng_destruction_handle_get_rotation_state(
322 const struct lttng_destruction_handle
*handle
,
323 enum lttng_rotation_state
*rotation_state
)
325 enum lttng_destruction_handle_status status
=
326 LTTNG_DESTRUCTION_HANDLE_STATUS_OK
;
328 if (!handle
|| !rotation_state
) {
329 status
= LTTNG_DESTRUCTION_HANDLE_STATUS_INVALID
;
333 if (!handle
->rotation_state
.is_set
) {
334 status
= LTTNG_DESTRUCTION_HANDLE_STATUS_INVALID
;
337 *rotation_state
= handle
->rotation_state
.value
;
342 enum lttng_destruction_handle_status
343 lttng_destruction_handle_get_archive_location(
344 const struct lttng_destruction_handle
*handle
,
345 const struct lttng_trace_archive_location
**location
)
347 enum lttng_destruction_handle_status status
=
348 LTTNG_DESTRUCTION_HANDLE_STATUS_OK
;
350 if (!handle
|| !location
) {
351 status
= LTTNG_DESTRUCTION_HANDLE_STATUS_INVALID
;
355 if (!handle
->location
) {
356 status
= LTTNG_DESTRUCTION_HANDLE_STATUS_INVALID
;
359 *location
= handle
->location
;
364 enum lttng_destruction_handle_status
365 lttng_destruction_handle_get_result(
366 const struct lttng_destruction_handle
*handle
,
367 enum lttng_error_code
*result
)
369 enum lttng_destruction_handle_status status
=
370 LTTNG_DESTRUCTION_HANDLE_STATUS_OK
;
372 if (!handle
|| !result
) {
373 status
= LTTNG_DESTRUCTION_HANDLE_STATUS_INVALID
;
377 if (!handle
->destruction_return_code
.is_set
) {
378 status
= LTTNG_DESTRUCTION_HANDLE_STATUS_INVALID
;
381 *result
= handle
->destruction_return_code
.value
;
386 enum lttng_error_code
lttng_destroy_session_ext(const char *session_name
,
387 struct lttng_destruction_handle
**_handle
)
391 enum lttng_error_code ret_code
= LTTNG_OK
;
392 struct lttcomm_session_msg lsm
= {
393 .cmd_type
= LTTNG_DESTROY_SESSION
,
399 int sessiond_socket
= -1;
400 struct lttng_destruction_handle
*handle
= NULL
;
403 ret_code
= LTTNG_ERR_INVALID
;
407 ret
= lttng_strncpy(lsm
.session
.name
, session_name
,
408 sizeof(lsm
.session
.name
));
410 ret_code
= LTTNG_ERR_INVALID
;
414 ret
= connect_sessiond();
416 ret_code
= LTTNG_ERR_NO_SESSIOND
;
419 sessiond_socket
= ret
;
422 handle
= lttng_destruction_handle_create(sessiond_socket
);
424 ret_code
= LTTNG_ERR_NOMEM
;
428 comm_ret
= lttcomm_send_creds_unix_sock(sessiond_socket
, &lsm
, sizeof(lsm
));
430 ret_code
= LTTNG_ERR_FATAL
;
433 sessiond_socket
= -1;
435 /* Transfer the handle to the caller. */
441 if (sessiond_socket
>= 0) {
442 ret
= close(sessiond_socket
);
444 PERROR("Failed to close the LTTng session daemon connection socket");
448 lttng_destruction_handle_destroy(handle
);