2 * Copyright (C) 2019 Jérémie Galarneau <jeremie.galarneau@efficios.com>
4 * SPDX-License-Identifier: LGPL-2.1-only
8 #include "lttng-ctl-helper.hpp"
10 #include <common/buffer-view.hpp>
11 #include <common/compat/poll.hpp>
12 #include <common/compat/time.hpp>
13 #include <common/dynamic-buffer.hpp>
14 #include <common/macros.hpp>
15 #include <common/optional.hpp>
16 #include <common/sessiond-comm/sessiond-comm.hpp>
18 #include <lttng/destruction-handle.h>
19 #include <lttng/location-internal.hpp>
20 #include <lttng/rotation.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
);
67 static struct lttng_destruction_handle
*lttng_destruction_handle_create(int sessiond_socket
)
70 struct lttng_destruction_handle
*handle
= zmalloc
<lttng_destruction_handle
>();
75 lttng_dynamic_buffer_init(&handle
->communication
.buffer
);
76 handle
->communication
.socket
= sessiond_socket
;
77 ret
= lttng_poll_create(&handle
->communication
.events
, 1, 0);
82 ret
= lttng_poll_add(&handle
->communication
.events
, sessiond_socket
, LPOLLIN
| LPOLLRDHUP
);
87 handle
->communication
.bytes_left_to_receive
= sizeof(struct lttcomm_lttng_msg
);
88 handle
->communication
.state
= COMMUNICATION_STATE_RECEIVE_LTTNG_MSG
;
92 lttng_destruction_handle_destroy(handle
);
96 static int handle_state_transition(struct lttng_destruction_handle
*handle
)
100 LTTNG_ASSERT(handle
->communication
.bytes_left_to_receive
== 0);
102 switch (handle
->communication
.state
) {
103 case COMMUNICATION_STATE_RECEIVE_LTTNG_MSG
:
105 const struct lttcomm_lttng_msg
*msg
=
106 (typeof(msg
)) handle
->communication
.buffer
.data
;
108 LTTNG_OPTIONAL_SET(&handle
->destruction_return_code
,
109 (enum lttng_error_code
) msg
->ret_code
);
110 if (handle
->destruction_return_code
.value
!= LTTNG_OK
) {
111 handle
->communication
.state
= COMMUNICATION_STATE_END
;
113 } else if (msg
->cmd_header_size
!=
114 sizeof(struct lttcomm_session_destroy_command_header
) ||
115 msg
->data_size
> DEFAULT_MAX_TRACE_ARCHIVE_LOCATION_PAYLOAD_SIZE
) {
116 handle
->communication
.state
= COMMUNICATION_STATE_ERROR
;
121 handle
->communication
.state
= COMMUNICATION_STATE_RECEIVE_COMMAND_HEADER
;
122 handle
->communication
.bytes_left_to_receive
= msg
->cmd_header_size
;
123 LTTNG_OPTIONAL_SET(&handle
->communication
.data_size
, msg
->data_size
);
124 ret
= lttng_dynamic_buffer_set_size(&handle
->communication
.buffer
, 0);
128 case COMMUNICATION_STATE_RECEIVE_COMMAND_HEADER
:
130 const struct lttcomm_session_destroy_command_header
*hdr
=
131 (typeof(hdr
)) handle
->communication
.buffer
.data
;
133 LTTNG_OPTIONAL_SET(&handle
->rotation_state
,
134 (enum lttng_rotation_state
) hdr
->rotation_state
);
135 switch (handle
->rotation_state
.value
) {
136 case LTTNG_ROTATION_STATE_COMPLETED
:
137 handle
->communication
.state
= COMMUNICATION_STATE_RECEIVE_PAYLOAD
;
138 handle
->communication
.bytes_left_to_receive
=
139 LTTNG_OPTIONAL_GET(handle
->communication
.data_size
);
141 case LTTNG_ROTATION_STATE_ERROR
:
142 case LTTNG_ROTATION_STATE_NO_ROTATION
:
143 handle
->communication
.state
= COMMUNICATION_STATE_END
;
146 handle
->communication
.state
= COMMUNICATION_STATE_ERROR
;
152 case COMMUNICATION_STATE_RECEIVE_PAYLOAD
:
154 ssize_t location_ret
;
155 struct lttng_trace_archive_location
*location
;
156 const struct lttng_buffer_view view
=
157 lttng_buffer_view_from_dynamic_buffer(&handle
->communication
.buffer
, 0, -1);
159 location_ret
= lttng_trace_archive_location_create_from_buffer(&view
, &location
);
160 if (location_ret
< 0) {
161 ERR("Failed to deserialize trace archive location");
162 handle
->communication
.state
= COMMUNICATION_STATE_ERROR
;
166 /* Ownership is transferred to the destruction handle. */
167 handle
->location
= location
;
168 handle
->communication
.state
= COMMUNICATION_STATE_END
;
176 /* Clear reception buffer on state transition. */
177 if (lttng_dynamic_buffer_set_size(&handle
->communication
.buffer
, 0)) {
183 static int handle_incoming_data(struct lttng_destruction_handle
*handle
)
187 const size_t original_buffer_size
= handle
->communication
.buffer
.size
;
189 /* Reserve space for reception. */
190 ret
= lttng_dynamic_buffer_set_size(&handle
->communication
.buffer
,
191 original_buffer_size
+
192 handle
->communication
.bytes_left_to_receive
);
197 comm_ret
= lttcomm_recv_unix_sock(handle
->communication
.socket
,
198 handle
->communication
.buffer
.data
+ original_buffer_size
,
199 handle
->communication
.bytes_left_to_receive
);
205 handle
->communication
.bytes_left_to_receive
-= comm_ret
;
206 if (handle
->communication
.bytes_left_to_receive
== 0) {
207 ret
= handle_state_transition(handle
);
209 ret
= lttng_dynamic_buffer_set_size(&handle
->communication
.buffer
,
210 original_buffer_size
+ comm_ret
);
216 enum lttng_destruction_handle_status
217 lttng_destruction_handle_wait_for_completion(struct lttng_destruction_handle
*handle
,
220 enum lttng_destruction_handle_status status
;
221 unsigned long time_left_ms
= 0;
222 const bool has_timeout
= timeout_ms
> 0;
223 struct timespec initial_time
;
226 status
= LTTNG_DESTRUCTION_HANDLE_STATUS_INVALID
;
230 if (handle
->communication
.state
== COMMUNICATION_STATE_ERROR
) {
231 status
= LTTNG_DESTRUCTION_HANDLE_STATUS_ERROR
;
233 } else if (handle
->communication
.state
== COMMUNICATION_STATE_END
) {
234 status
= LTTNG_DESTRUCTION_HANDLE_STATUS_COMPLETED
;
238 int ret
= lttng_clock_gettime(CLOCK_MONOTONIC
, &initial_time
);
240 status
= LTTNG_DESTRUCTION_HANDLE_STATUS_ERROR
;
243 time_left_ms
= (unsigned long) timeout_ms
;
246 while (handle
->communication
.state
!= COMMUNICATION_STATE_END
&&
247 (time_left_ms
|| !has_timeout
)) {
250 struct timespec current_time
, diff
;
251 unsigned long diff_ms
;
253 ret
= lttng_poll_wait(&handle
->communication
.events
,
254 has_timeout
? time_left_ms
: -1);
258 } else if (ret
< 0) {
259 status
= LTTNG_DESTRUCTION_HANDLE_STATUS_ERROR
;
263 /* The sessiond connection socket is the only monitored fd. */
264 revents
= LTTNG_POLL_GETEV(&handle
->communication
.events
, 0);
265 if (revents
& LPOLLIN
) {
266 ret
= handle_incoming_data(handle
);
268 handle
->communication
.state
= COMMUNICATION_STATE_ERROR
;
269 status
= LTTNG_DESTRUCTION_HANDLE_STATUS_ERROR
;
273 handle
->communication
.state
= COMMUNICATION_STATE_ERROR
;
274 status
= LTTNG_DESTRUCTION_HANDLE_STATUS_ERROR
;
281 ret
= lttng_clock_gettime(CLOCK_MONOTONIC
, ¤t_time
);
283 status
= LTTNG_DESTRUCTION_HANDLE_STATUS_ERROR
;
286 diff
= timespec_abs_diff(initial_time
, current_time
);
287 ret
= timespec_to_ms(diff
, &diff_ms
);
289 ERR("Failed to compute elapsed time while waiting for completion");
290 status
= LTTNG_DESTRUCTION_HANDLE_STATUS_ERROR
;
293 DBG("%lums elapsed while waiting for session destruction completion", diff_ms
);
294 diff_ms
= std::max(diff_ms
, 1UL);
295 diff_ms
= std::min(diff_ms
, time_left_ms
);
296 time_left_ms
-= diff_ms
;
299 status
= handle
->communication
.state
== COMMUNICATION_STATE_END
?
300 LTTNG_DESTRUCTION_HANDLE_STATUS_COMPLETED
:
301 LTTNG_DESTRUCTION_HANDLE_STATUS_TIMEOUT
;
306 enum lttng_destruction_handle_status
307 lttng_destruction_handle_get_rotation_state(const struct lttng_destruction_handle
*handle
,
308 enum lttng_rotation_state
*rotation_state
)
310 enum lttng_destruction_handle_status status
= LTTNG_DESTRUCTION_HANDLE_STATUS_OK
;
312 if (!handle
|| !rotation_state
) {
313 status
= LTTNG_DESTRUCTION_HANDLE_STATUS_INVALID
;
317 if (!handle
->rotation_state
.is_set
) {
318 status
= LTTNG_DESTRUCTION_HANDLE_STATUS_INVALID
;
321 *rotation_state
= handle
->rotation_state
.value
;
326 enum lttng_destruction_handle_status
327 lttng_destruction_handle_get_archive_location(const struct lttng_destruction_handle
*handle
,
328 const struct lttng_trace_archive_location
**location
)
330 enum lttng_destruction_handle_status status
= LTTNG_DESTRUCTION_HANDLE_STATUS_OK
;
332 if (!handle
|| !location
) {
333 status
= LTTNG_DESTRUCTION_HANDLE_STATUS_INVALID
;
337 if (!handle
->location
) {
338 status
= LTTNG_DESTRUCTION_HANDLE_STATUS_INVALID
;
341 *location
= handle
->location
;
346 enum lttng_destruction_handle_status
347 lttng_destruction_handle_get_result(const struct lttng_destruction_handle
*handle
,
348 enum lttng_error_code
*result
)
350 enum lttng_destruction_handle_status status
= LTTNG_DESTRUCTION_HANDLE_STATUS_OK
;
352 if (!handle
|| !result
) {
353 status
= LTTNG_DESTRUCTION_HANDLE_STATUS_INVALID
;
357 if (!handle
->destruction_return_code
.is_set
) {
358 status
= LTTNG_DESTRUCTION_HANDLE_STATUS_INVALID
;
361 *result
= handle
->destruction_return_code
.value
;
366 enum lttng_error_code
lttng_destroy_session_ext(const char *session_name
,
367 struct lttng_destruction_handle
**_handle
)
371 enum lttng_error_code ret_code
= LTTNG_OK
;
372 struct lttcomm_session_msg lsm
= {
373 .cmd_type
= LTTCOMM_SESSIOND_COMMAND_DESTROY_SESSION
,
379 int sessiond_socket
= -1;
380 struct lttng_destruction_handle
*handle
= nullptr;
383 ret_code
= LTTNG_ERR_INVALID
;
387 ret
= lttng_strncpy(lsm
.session
.name
, session_name
, sizeof(lsm
.session
.name
));
389 ret_code
= LTTNG_ERR_INVALID
;
393 ret
= connect_sessiond();
395 ret_code
= LTTNG_ERR_NO_SESSIOND
;
398 sessiond_socket
= ret
;
401 handle
= lttng_destruction_handle_create(sessiond_socket
);
403 ret_code
= LTTNG_ERR_NOMEM
;
407 comm_ret
= lttcomm_send_creds_unix_sock(sessiond_socket
, &lsm
, sizeof(lsm
));
409 ret_code
= LTTNG_ERR_FATAL
;
412 sessiond_socket
= -1;
414 /* Transfer the handle to the caller. */
420 if (sessiond_socket
>= 0) {
421 ret
= close(sessiond_socket
);
423 PERROR("Failed to close the LTTng session daemon connection socket");
427 lttng_destruction_handle_destroy(handle
);