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
;
246 if (handle
->communication
.state
== COMMUNICATION_STATE_ERROR
) {
247 status
= LTTNG_DESTRUCTION_HANDLE_STATUS_ERROR
;
249 } else if (handle
->communication
.state
== COMMUNICATION_STATE_END
) {
250 status
= LTTNG_DESTRUCTION_HANDLE_STATUS_COMPLETED
;
254 ret
= lttng_clock_gettime(CLOCK_MONOTONIC
, &initial_time
);
256 status
= LTTNG_DESTRUCTION_HANDLE_STATUS_ERROR
;
259 time_left_ms
= (unsigned long) timeout_ms
;
262 while (handle
->communication
.state
!= COMMUNICATION_STATE_END
&&
263 (time_left_ms
|| !has_timeout
)) {
266 struct timespec current_time
, diff
;
267 unsigned long diff_ms
;
269 ret
= lttng_poll_wait(&handle
->communication
.events
,
270 has_timeout
? time_left_ms
: -1);
274 } else if (ret
< 0) {
275 status
= LTTNG_DESTRUCTION_HANDLE_STATUS_ERROR
;
279 /* The sessiond connection socket is the only monitored fd. */
280 revents
= LTTNG_POLL_GETEV(&handle
->communication
.events
, 0);
281 if (revents
& LPOLLIN
) {
282 ret
= handle_incoming_data(handle
);
284 handle
->communication
.state
=
285 COMMUNICATION_STATE_ERROR
;
286 status
= LTTNG_DESTRUCTION_HANDLE_STATUS_ERROR
;
290 handle
->communication
.state
= COMMUNICATION_STATE_ERROR
;
291 status
= LTTNG_DESTRUCTION_HANDLE_STATUS_ERROR
;
298 ret
= lttng_clock_gettime(CLOCK_MONOTONIC
, ¤t_time
);
300 status
= LTTNG_DESTRUCTION_HANDLE_STATUS_ERROR
;
303 diff
= timespec_abs_diff(initial_time
, current_time
);
304 ret
= timespec_to_ms(diff
, &diff_ms
);
306 ERR("Failed to compute elapsed time while waiting for completion");
307 status
= LTTNG_DESTRUCTION_HANDLE_STATUS_ERROR
;
310 DBG("%lums elapsed while waiting for session destruction completion",
312 diff_ms
= max_t(unsigned long, diff_ms
, 1);
313 diff_ms
= min_t(unsigned long, diff_ms
, time_left_ms
);
314 time_left_ms
-= diff_ms
;
317 status
= handle
->communication
.state
== COMMUNICATION_STATE_END
?
318 LTTNG_DESTRUCTION_HANDLE_STATUS_COMPLETED
:
319 LTTNG_DESTRUCTION_HANDLE_STATUS_TIMEOUT
;
324 enum lttng_destruction_handle_status
325 lttng_destruction_handle_get_rotation_state(
326 const struct lttng_destruction_handle
*handle
,
327 enum lttng_rotation_state
*rotation_state
)
329 enum lttng_destruction_handle_status status
=
330 LTTNG_DESTRUCTION_HANDLE_STATUS_OK
;
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
;
353 *location
= handle
->location
;
358 enum lttng_destruction_handle_status
359 lttng_destruction_handle_get_result(
360 const struct lttng_destruction_handle
*handle
,
361 enum lttng_error_code
*result
)
363 enum lttng_destruction_handle_status status
=
364 LTTNG_DESTRUCTION_HANDLE_STATUS_OK
;
366 if (!handle
->destruction_return_code
.is_set
) {
367 status
= LTTNG_DESTRUCTION_HANDLE_STATUS_INVALID
;
370 *result
= handle
->destruction_return_code
.value
;
375 enum lttng_error_code
lttng_destroy_session_ext(const char *session_name
,
376 struct lttng_destruction_handle
**_handle
)
380 enum lttng_error_code ret_code
= LTTNG_OK
;
381 struct lttcomm_session_msg lsm
= {
382 .cmd_type
= LTTNG_DESTROY_SESSION
,
384 int sessiond_socket
= -1;
385 struct lttng_destruction_handle
*handle
= NULL
;
387 ret
= lttng_strncpy(lsm
.session
.name
, session_name
,
388 sizeof(lsm
.session
.name
));
390 ret_code
= LTTNG_ERR_INVALID
;
394 ret
= connect_sessiond();
396 ret_code
= LTTNG_ERR_NO_SESSIOND
;
399 sessiond_socket
= ret
;
402 handle
= lttng_destruction_handle_create(sessiond_socket
);
404 ret_code
= LTTNG_ERR_NOMEM
;
408 comm_ret
= lttcomm_send_unix_sock(sessiond_socket
, &lsm
, sizeof(lsm
));
410 ret_code
= LTTNG_ERR_FATAL
;
413 sessiond_socket
= -1;
415 /* Transfer the handle to the caller. */
421 if (sessiond_socket
>= 0) {
422 ret
= close(sessiond_socket
);
423 PERROR("Failed to close the LTTng session daemon connection socket");
426 lttng_destruction_handle_destroy(handle
);