2 * Copyright (C) 2019 - Jérémie Galarneau <jeremie.galarneau@efficios.com>
4 * This library is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License, version 2.1 only,
6 * as published by the Free Software Foundation.
8 * This library is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this library; if not, write to the Free Software Foundation,
15 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 #include <lttng/destruction-handle.h>
19 #include <lttng/rotation.h>
21 #include <common/optional.h>
22 #include <common/compat/poll.h>
23 #include <common/compat/time.h>
24 #include <common/macros.h>
25 #include <common/compat/poll.h>
26 #include <common/dynamic-buffer.h>
27 #include <common/buffer-view.h>
28 #include <common/sessiond-comm/sessiond-comm.h>
29 #include <lttng/location-internal.h>
30 #include "lttng-ctl-helper.h"
34 enum communication_state
{
35 COMMUNICATION_STATE_RECEIVE_LTTNG_MSG
,
36 COMMUNICATION_STATE_RECEIVE_COMMAND_HEADER
,
37 COMMUNICATION_STATE_RECEIVE_PAYLOAD
,
38 COMMUNICATION_STATE_END
,
39 COMMUNICATION_STATE_ERROR
,
42 struct lttng_destruction_handle
{
43 LTTNG_OPTIONAL(enum lttng_error_code
) destruction_return_code
;
44 LTTNG_OPTIONAL(enum lttng_rotation_state
) rotation_state
;
45 struct lttng_trace_archive_location
*location
;
48 struct lttng_poll_event events
;
49 size_t bytes_left_to_receive
;
50 enum communication_state state
;
51 struct lttng_dynamic_buffer buffer
;
52 LTTNG_OPTIONAL(size_t) data_size
;
56 void lttng_destruction_handle_destroy(struct lttng_destruction_handle
*handle
)
64 if (handle
->communication
.socket
>= 0) {
65 ret
= close(handle
->communication
.socket
);
67 PERROR("Failed to close lttng-sessiond command socket");
70 lttng_poll_clean(&handle
->communication
.events
);
71 lttng_dynamic_buffer_reset(&handle
->communication
.buffer
);
72 lttng_trace_archive_location_destroy(handle
->location
);
77 struct lttng_destruction_handle
*lttng_destruction_handle_create(
81 struct lttng_destruction_handle
*handle
= zmalloc(sizeof(*handle
));
86 lttng_dynamic_buffer_init(&handle
->communication
.buffer
);
87 handle
->communication
.socket
= sessiond_socket
;
88 ret
= lttng_poll_create(&handle
->communication
.events
, 1, 0);
93 ret
= lttng_poll_add(&handle
->communication
.events
, sessiond_socket
,
94 LPOLLIN
| LPOLLHUP
| LPOLLRDHUP
| LPOLLERR
);
99 handle
->communication
.bytes_left_to_receive
=
100 sizeof(struct lttcomm_lttng_msg
);
101 handle
->communication
.state
= COMMUNICATION_STATE_RECEIVE_LTTNG_MSG
;
105 lttng_destruction_handle_destroy(handle
);
110 int handle_state_transition(struct lttng_destruction_handle
*handle
)
114 assert(handle
->communication
.bytes_left_to_receive
== 0);
116 switch (handle
->communication
.state
) {
117 case COMMUNICATION_STATE_RECEIVE_LTTNG_MSG
:
119 const struct lttcomm_lttng_msg
*msg
=
120 (typeof(msg
)) handle
->communication
.buffer
.data
;
122 LTTNG_OPTIONAL_SET(&handle
->destruction_return_code
,
123 (enum lttng_error_code
) msg
->ret_code
);
124 if (handle
->destruction_return_code
.value
!= LTTNG_OK
) {
125 handle
->communication
.state
= COMMUNICATION_STATE_END
;
127 } else if (msg
->cmd_header_size
!= sizeof(struct lttcomm_session_destroy_command_header
) ||
128 msg
->data_size
> DEFAULT_MAX_TRACE_ARCHIVE_LOCATION_PAYLOAD_SIZE
) {
129 handle
->communication
.state
= COMMUNICATION_STATE_ERROR
;
134 handle
->communication
.state
=
135 COMMUNICATION_STATE_RECEIVE_COMMAND_HEADER
;
136 handle
->communication
.bytes_left_to_receive
=
137 msg
->cmd_header_size
;
138 LTTNG_OPTIONAL_SET(&handle
->communication
.data_size
,
140 ret
= lttng_dynamic_buffer_set_size(
141 &handle
->communication
.buffer
, 0);
145 case COMMUNICATION_STATE_RECEIVE_COMMAND_HEADER
:
147 const struct lttcomm_session_destroy_command_header
*hdr
=
148 (typeof(hdr
)) handle
->communication
.buffer
.data
;
150 LTTNG_OPTIONAL_SET(&handle
->rotation_state
,
151 (enum lttng_rotation_state
) hdr
->rotation_state
);
152 switch (handle
->rotation_state
.value
) {
153 case LTTNG_ROTATION_STATE_COMPLETED
:
154 handle
->communication
.state
=
155 COMMUNICATION_STATE_RECEIVE_PAYLOAD
;
156 handle
->communication
.bytes_left_to_receive
=
157 LTTNG_OPTIONAL_GET(handle
->communication
.data_size
);
159 case LTTNG_ROTATION_STATE_ERROR
:
160 case LTTNG_ROTATION_STATE_NO_ROTATION
:
161 handle
->communication
.state
= COMMUNICATION_STATE_END
;
164 handle
->communication
.state
= COMMUNICATION_STATE_ERROR
;
170 case COMMUNICATION_STATE_RECEIVE_PAYLOAD
:
172 ssize_t location_ret
;
173 struct lttng_trace_archive_location
*location
;
174 const struct lttng_buffer_view view
=
175 lttng_buffer_view_from_dynamic_buffer(
176 &handle
->communication
.buffer
, 0, -1);
178 location_ret
= lttng_trace_archive_location_create_from_buffer(
180 if (location_ret
< 0) {
181 ERR("Failed to deserialize trace archive location");
182 handle
->communication
.state
= COMMUNICATION_STATE_ERROR
;
186 handle
->location
= location
;
187 handle
->communication
.state
= COMMUNICATION_STATE_END
;
195 /* Clear reception buffer on state transition. */
196 if (lttng_dynamic_buffer_set_size(&handle
->communication
.buffer
, 0)) {
203 int handle_incoming_data(struct lttng_destruction_handle
*handle
)
207 const size_t original_buffer_size
= handle
->communication
.buffer
.size
;
209 /* Reserve space for reception. */
210 ret
= lttng_dynamic_buffer_set_size(&handle
->communication
.buffer
,
211 original_buffer_size
+ handle
->communication
.bytes_left_to_receive
);
216 comm_ret
= lttcomm_recv_unix_sock(handle
->communication
.socket
,
217 handle
->communication
.buffer
.data
+ original_buffer_size
,
218 handle
->communication
.bytes_left_to_receive
);
224 handle
->communication
.bytes_left_to_receive
-= comm_ret
;
225 if (handle
->communication
.bytes_left_to_receive
== 0) {
226 ret
= handle_state_transition(handle
);
228 ret
= lttng_dynamic_buffer_set_size(
229 &handle
->communication
.buffer
,
230 original_buffer_size
+ comm_ret
);
236 enum lttng_destruction_handle_status
237 lttng_destruction_handle_wait_for_completion(
238 struct lttng_destruction_handle
*handle
, int timeout_ms
)
241 enum lttng_destruction_handle_status status
;
242 unsigned long time_left_ms
= 0;
243 const bool has_timeout
= timeout_ms
> 0;
244 struct timespec initial_time
;
247 status
= LTTNG_DESTRUCTION_HANDLE_STATUS_INVALID
;
251 if (handle
->communication
.state
== COMMUNICATION_STATE_ERROR
) {
252 status
= LTTNG_DESTRUCTION_HANDLE_STATUS_ERROR
;
254 } else if (handle
->communication
.state
== COMMUNICATION_STATE_END
) {
255 status
= LTTNG_DESTRUCTION_HANDLE_STATUS_COMPLETED
;
259 ret
= lttng_clock_gettime(CLOCK_MONOTONIC
, &initial_time
);
261 status
= LTTNG_DESTRUCTION_HANDLE_STATUS_ERROR
;
264 time_left_ms
= (unsigned long) timeout_ms
;
267 while (handle
->communication
.state
!= COMMUNICATION_STATE_END
&&
268 (time_left_ms
|| !has_timeout
)) {
271 struct timespec current_time
, diff
;
272 unsigned long diff_ms
;
274 ret
= lttng_poll_wait(&handle
->communication
.events
,
275 has_timeout
? time_left_ms
: -1);
279 } else if (ret
< 0) {
280 status
= LTTNG_DESTRUCTION_HANDLE_STATUS_ERROR
;
284 /* The sessiond connection socket is the only monitored fd. */
285 revents
= LTTNG_POLL_GETEV(&handle
->communication
.events
, 0);
286 if (revents
& LPOLLIN
) {
287 ret
= handle_incoming_data(handle
);
289 handle
->communication
.state
=
290 COMMUNICATION_STATE_ERROR
;
291 status
= LTTNG_DESTRUCTION_HANDLE_STATUS_ERROR
;
295 handle
->communication
.state
= COMMUNICATION_STATE_ERROR
;
296 status
= LTTNG_DESTRUCTION_HANDLE_STATUS_ERROR
;
303 ret
= lttng_clock_gettime(CLOCK_MONOTONIC
, ¤t_time
);
305 status
= LTTNG_DESTRUCTION_HANDLE_STATUS_ERROR
;
308 diff
= timespec_abs_diff(initial_time
, current_time
);
309 ret
= timespec_to_ms(diff
, &diff_ms
);
311 ERR("Failed to compute elapsed time while waiting for completion");
312 status
= LTTNG_DESTRUCTION_HANDLE_STATUS_ERROR
;
315 DBG("%lums elapsed while waiting for session destruction completion",
317 diff_ms
= max_t(unsigned long, diff_ms
, 1);
318 diff_ms
= min_t(unsigned long, diff_ms
, time_left_ms
);
319 time_left_ms
-= diff_ms
;
322 status
= handle
->communication
.state
== COMMUNICATION_STATE_END
?
323 LTTNG_DESTRUCTION_HANDLE_STATUS_COMPLETED
:
324 LTTNG_DESTRUCTION_HANDLE_STATUS_TIMEOUT
;
329 enum lttng_destruction_handle_status
330 lttng_destruction_handle_get_rotation_state(
331 const struct lttng_destruction_handle
*handle
,
332 enum lttng_rotation_state
*rotation_state
)
334 enum lttng_destruction_handle_status status
=
335 LTTNG_DESTRUCTION_HANDLE_STATUS_OK
;
337 if (!handle
|| !rotation_state
) {
338 status
= LTTNG_DESTRUCTION_HANDLE_STATUS_INVALID
;
342 if (!handle
->rotation_state
.is_set
) {
343 status
= LTTNG_DESTRUCTION_HANDLE_STATUS_INVALID
;
346 *rotation_state
= handle
->rotation_state
.value
;
351 enum lttng_destruction_handle_status
352 lttng_destruction_handle_get_archive_location(
353 const struct lttng_destruction_handle
*handle
,
354 const struct lttng_trace_archive_location
**location
)
356 enum lttng_destruction_handle_status status
=
357 LTTNG_DESTRUCTION_HANDLE_STATUS_OK
;
359 if (!handle
|| !location
) {
360 status
= LTTNG_DESTRUCTION_HANDLE_STATUS_INVALID
;
364 if (!handle
->location
) {
365 status
= LTTNG_DESTRUCTION_HANDLE_STATUS_INVALID
;
368 *location
= handle
->location
;
373 enum lttng_destruction_handle_status
374 lttng_destruction_handle_get_result(
375 const struct lttng_destruction_handle
*handle
,
376 enum lttng_error_code
*result
)
378 enum lttng_destruction_handle_status status
=
379 LTTNG_DESTRUCTION_HANDLE_STATUS_OK
;
381 if (!handle
|| !result
) {
382 status
= LTTNG_DESTRUCTION_HANDLE_STATUS_INVALID
;
386 if (!handle
->destruction_return_code
.is_set
) {
387 status
= LTTNG_DESTRUCTION_HANDLE_STATUS_INVALID
;
390 *result
= handle
->destruction_return_code
.value
;
395 enum lttng_error_code
lttng_destroy_session_ext(const char *session_name
,
396 struct lttng_destruction_handle
**_handle
)
400 enum lttng_error_code ret_code
= LTTNG_OK
;
401 struct lttcomm_session_msg lsm
= {
402 .cmd_type
= LTTNG_DESTROY_SESSION
,
404 int sessiond_socket
= -1;
405 struct lttng_destruction_handle
*handle
= NULL
;
407 if (!session_name
|| !_handle
) {
408 ret_code
= LTTNG_ERR_INVALID
;
412 ret
= lttng_strncpy(lsm
.session
.name
, session_name
,
413 sizeof(lsm
.session
.name
));
415 ret_code
= LTTNG_ERR_INVALID
;
419 ret
= connect_sessiond();
421 ret_code
= LTTNG_ERR_NO_SESSIOND
;
424 sessiond_socket
= ret
;
427 handle
= lttng_destruction_handle_create(sessiond_socket
);
429 ret_code
= LTTNG_ERR_NOMEM
;
433 comm_ret
= lttcomm_send_creds_unix_sock(sessiond_socket
, &lsm
, sizeof(lsm
));
435 ret_code
= LTTNG_ERR_FATAL
;
438 sessiond_socket
= -1;
440 /* Transfer the handle to the caller. */
446 if (sessiond_socket
>= 0) {
447 ret
= close(sessiond_socket
);
449 PERROR("Failed to close the LTTng session daemon connection socket");
453 lttng_destruction_handle_destroy(handle
);