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"
24 enum communication_state
{
25 COMMUNICATION_STATE_RECEIVE_LTTNG_MSG
,
26 COMMUNICATION_STATE_RECEIVE_COMMAND_HEADER
,
27 COMMUNICATION_STATE_RECEIVE_PAYLOAD
,
28 COMMUNICATION_STATE_END
,
29 COMMUNICATION_STATE_ERROR
,
32 struct lttng_destruction_handle
{
33 LTTNG_OPTIONAL(enum lttng_error_code
) destruction_return_code
;
34 LTTNG_OPTIONAL(enum lttng_rotation_state
) rotation_state
;
35 struct lttng_trace_archive_location
*location
;
38 struct lttng_poll_event events
;
39 size_t bytes_left_to_receive
;
40 enum communication_state state
;
41 struct lttng_dynamic_buffer buffer
;
42 LTTNG_OPTIONAL(size_t) data_size
;
46 void lttng_destruction_handle_destroy(struct lttng_destruction_handle
*handle
)
54 if (handle
->communication
.socket
>= 0) {
55 ret
= close(handle
->communication
.socket
);
57 PERROR("Failed to close lttng-sessiond command socket");
60 lttng_poll_clean(&handle
->communication
.events
);
61 lttng_dynamic_buffer_reset(&handle
->communication
.buffer
);
62 lttng_trace_archive_location_destroy(handle
->location
);
67 struct lttng_destruction_handle
*lttng_destruction_handle_create(
71 struct lttng_destruction_handle
*handle
= zmalloc(sizeof(*handle
));
76 lttng_dynamic_buffer_init(&handle
->communication
.buffer
);
77 handle
->communication
.socket
= sessiond_socket
;
78 ret
= lttng_poll_create(&handle
->communication
.events
, 1, 0);
83 ret
= lttng_poll_add(&handle
->communication
.events
, sessiond_socket
,
84 LPOLLIN
| LPOLLHUP
| LPOLLRDHUP
| LPOLLERR
);
89 handle
->communication
.bytes_left_to_receive
=
90 sizeof(struct lttcomm_lttng_msg
);
91 handle
->communication
.state
= COMMUNICATION_STATE_RECEIVE_LTTNG_MSG
;
95 lttng_destruction_handle_destroy(handle
);
100 int handle_state_transition(struct lttng_destruction_handle
*handle
)
104 assert(handle
->communication
.bytes_left_to_receive
== 0);
106 switch (handle
->communication
.state
) {
107 case COMMUNICATION_STATE_RECEIVE_LTTNG_MSG
:
109 const struct lttcomm_lttng_msg
*msg
=
110 (typeof(msg
)) handle
->communication
.buffer
.data
;
112 LTTNG_OPTIONAL_SET(&handle
->destruction_return_code
,
113 (enum lttng_error_code
) msg
->ret_code
);
114 if (handle
->destruction_return_code
.value
!= LTTNG_OK
) {
115 handle
->communication
.state
= COMMUNICATION_STATE_END
;
117 } else if (msg
->cmd_header_size
!= sizeof(struct lttcomm_session_destroy_command_header
) ||
118 msg
->data_size
> DEFAULT_MAX_TRACE_ARCHIVE_LOCATION_PAYLOAD_SIZE
) {
119 handle
->communication
.state
= COMMUNICATION_STATE_ERROR
;
124 handle
->communication
.state
=
125 COMMUNICATION_STATE_RECEIVE_COMMAND_HEADER
;
126 handle
->communication
.bytes_left_to_receive
=
127 msg
->cmd_header_size
;
128 LTTNG_OPTIONAL_SET(&handle
->communication
.data_size
,
130 ret
= lttng_dynamic_buffer_set_size(
131 &handle
->communication
.buffer
, 0);
135 case COMMUNICATION_STATE_RECEIVE_COMMAND_HEADER
:
137 const struct lttcomm_session_destroy_command_header
*hdr
=
138 (typeof(hdr
)) handle
->communication
.buffer
.data
;
140 LTTNG_OPTIONAL_SET(&handle
->rotation_state
,
141 (enum lttng_rotation_state
) hdr
->rotation_state
);
142 switch (handle
->rotation_state
.value
) {
143 case LTTNG_ROTATION_STATE_COMPLETED
:
144 handle
->communication
.state
=
145 COMMUNICATION_STATE_RECEIVE_PAYLOAD
;
146 handle
->communication
.bytes_left_to_receive
=
147 LTTNG_OPTIONAL_GET(handle
->communication
.data_size
);
149 case LTTNG_ROTATION_STATE_ERROR
:
150 case LTTNG_ROTATION_STATE_NO_ROTATION
:
151 handle
->communication
.state
= COMMUNICATION_STATE_END
;
154 handle
->communication
.state
= COMMUNICATION_STATE_ERROR
;
160 case COMMUNICATION_STATE_RECEIVE_PAYLOAD
:
162 ssize_t location_ret
;
163 struct lttng_trace_archive_location
*location
;
164 const struct lttng_buffer_view view
=
165 lttng_buffer_view_from_dynamic_buffer(
166 &handle
->communication
.buffer
, 0, -1);
168 location_ret
= lttng_trace_archive_location_create_from_buffer(
170 if (location_ret
< 0) {
171 ERR("Failed to deserialize trace archive location");
172 handle
->communication
.state
= COMMUNICATION_STATE_ERROR
;
176 handle
->location
= location
;
177 handle
->communication
.state
= COMMUNICATION_STATE_END
;
185 /* Clear reception buffer on state transition. */
186 if (lttng_dynamic_buffer_set_size(&handle
->communication
.buffer
, 0)) {
193 int handle_incoming_data(struct lttng_destruction_handle
*handle
)
197 const size_t original_buffer_size
= handle
->communication
.buffer
.size
;
199 /* Reserve space for reception. */
200 ret
= lttng_dynamic_buffer_set_size(&handle
->communication
.buffer
,
201 original_buffer_size
+ handle
->communication
.bytes_left_to_receive
);
206 comm_ret
= lttcomm_recv_unix_sock(handle
->communication
.socket
,
207 handle
->communication
.buffer
.data
+ original_buffer_size
,
208 handle
->communication
.bytes_left_to_receive
);
214 handle
->communication
.bytes_left_to_receive
-= comm_ret
;
215 if (handle
->communication
.bytes_left_to_receive
== 0) {
216 ret
= handle_state_transition(handle
);
218 ret
= lttng_dynamic_buffer_set_size(
219 &handle
->communication
.buffer
,
220 original_buffer_size
+ comm_ret
);
226 enum lttng_destruction_handle_status
227 lttng_destruction_handle_wait_for_completion(
228 struct lttng_destruction_handle
*handle
, int timeout_ms
)
231 enum lttng_destruction_handle_status status
;
232 unsigned long time_left_ms
= 0;
233 const bool has_timeout
= timeout_ms
> 0;
234 struct timespec initial_time
;
237 status
= LTTNG_DESTRUCTION_HANDLE_STATUS_INVALID
;
241 if (handle
->communication
.state
== COMMUNICATION_STATE_ERROR
) {
242 status
= LTTNG_DESTRUCTION_HANDLE_STATUS_ERROR
;
244 } else if (handle
->communication
.state
== COMMUNICATION_STATE_END
) {
245 status
= LTTNG_DESTRUCTION_HANDLE_STATUS_COMPLETED
;
249 ret
= lttng_clock_gettime(CLOCK_MONOTONIC
, &initial_time
);
251 status
= LTTNG_DESTRUCTION_HANDLE_STATUS_ERROR
;
254 time_left_ms
= (unsigned long) timeout_ms
;
257 while (handle
->communication
.state
!= COMMUNICATION_STATE_END
&&
258 (time_left_ms
|| !has_timeout
)) {
261 struct timespec current_time
, diff
;
262 unsigned long diff_ms
;
264 ret
= lttng_poll_wait(&handle
->communication
.events
,
265 has_timeout
? time_left_ms
: -1);
269 } else if (ret
< 0) {
270 status
= LTTNG_DESTRUCTION_HANDLE_STATUS_ERROR
;
274 /* The sessiond connection socket is the only monitored fd. */
275 revents
= LTTNG_POLL_GETEV(&handle
->communication
.events
, 0);
276 if (revents
& LPOLLIN
) {
277 ret
= handle_incoming_data(handle
);
279 handle
->communication
.state
=
280 COMMUNICATION_STATE_ERROR
;
281 status
= LTTNG_DESTRUCTION_HANDLE_STATUS_ERROR
;
285 handle
->communication
.state
= COMMUNICATION_STATE_ERROR
;
286 status
= LTTNG_DESTRUCTION_HANDLE_STATUS_ERROR
;
293 ret
= lttng_clock_gettime(CLOCK_MONOTONIC
, ¤t_time
);
295 status
= LTTNG_DESTRUCTION_HANDLE_STATUS_ERROR
;
298 diff
= timespec_abs_diff(initial_time
, current_time
);
299 ret
= timespec_to_ms(diff
, &diff_ms
);
301 ERR("Failed to compute elapsed time while waiting for completion");
302 status
= LTTNG_DESTRUCTION_HANDLE_STATUS_ERROR
;
305 DBG("%lums elapsed while waiting for session destruction completion",
307 diff_ms
= max_t(unsigned long, diff_ms
, 1);
308 diff_ms
= min_t(unsigned long, diff_ms
, time_left_ms
);
309 time_left_ms
-= diff_ms
;
312 status
= handle
->communication
.state
== COMMUNICATION_STATE_END
?
313 LTTNG_DESTRUCTION_HANDLE_STATUS_COMPLETED
:
314 LTTNG_DESTRUCTION_HANDLE_STATUS_TIMEOUT
;
319 enum lttng_destruction_handle_status
320 lttng_destruction_handle_get_rotation_state(
321 const struct lttng_destruction_handle
*handle
,
322 enum lttng_rotation_state
*rotation_state
)
324 enum lttng_destruction_handle_status status
=
325 LTTNG_DESTRUCTION_HANDLE_STATUS_OK
;
327 if (!handle
|| !rotation_state
) {
328 status
= LTTNG_DESTRUCTION_HANDLE_STATUS_INVALID
;
332 if (!handle
->rotation_state
.is_set
) {
333 status
= LTTNG_DESTRUCTION_HANDLE_STATUS_INVALID
;
336 *rotation_state
= handle
->rotation_state
.value
;
341 enum lttng_destruction_handle_status
342 lttng_destruction_handle_get_archive_location(
343 const struct lttng_destruction_handle
*handle
,
344 const struct lttng_trace_archive_location
**location
)
346 enum lttng_destruction_handle_status status
=
347 LTTNG_DESTRUCTION_HANDLE_STATUS_OK
;
349 if (!handle
|| !location
) {
350 status
= LTTNG_DESTRUCTION_HANDLE_STATUS_INVALID
;
354 if (!handle
->location
) {
355 status
= LTTNG_DESTRUCTION_HANDLE_STATUS_INVALID
;
358 *location
= handle
->location
;
363 enum lttng_destruction_handle_status
364 lttng_destruction_handle_get_result(
365 const struct lttng_destruction_handle
*handle
,
366 enum lttng_error_code
*result
)
368 enum lttng_destruction_handle_status status
=
369 LTTNG_DESTRUCTION_HANDLE_STATUS_OK
;
371 if (!handle
|| !result
) {
372 status
= LTTNG_DESTRUCTION_HANDLE_STATUS_INVALID
;
376 if (!handle
->destruction_return_code
.is_set
) {
377 status
= LTTNG_DESTRUCTION_HANDLE_STATUS_INVALID
;
380 *result
= handle
->destruction_return_code
.value
;
385 enum lttng_error_code
lttng_destroy_session_ext(const char *session_name
,
386 struct lttng_destruction_handle
**_handle
)
390 enum lttng_error_code ret_code
= LTTNG_OK
;
391 struct lttcomm_session_msg lsm
= {
392 .cmd_type
= LTTNG_DESTROY_SESSION
,
394 int sessiond_socket
= -1;
395 struct lttng_destruction_handle
*handle
= NULL
;
398 ret_code
= LTTNG_ERR_INVALID
;
402 ret
= lttng_strncpy(lsm
.session
.name
, session_name
,
403 sizeof(lsm
.session
.name
));
405 ret_code
= LTTNG_ERR_INVALID
;
409 ret
= connect_sessiond();
411 ret_code
= LTTNG_ERR_NO_SESSIOND
;
414 sessiond_socket
= ret
;
417 handle
= lttng_destruction_handle_create(sessiond_socket
);
419 ret_code
= LTTNG_ERR_NOMEM
;
423 comm_ret
= lttcomm_send_creds_unix_sock(sessiond_socket
, &lsm
, sizeof(lsm
));
425 ret_code
= LTTNG_ERR_FATAL
;
428 sessiond_socket
= -1;
430 /* Transfer the handle to the caller. */
436 if (sessiond_socket
>= 0) {
437 ret
= close(sessiond_socket
);
439 PERROR("Failed to close the LTTng session daemon connection socket");
443 lttng_destruction_handle_destroy(handle
);