2 * Copyright (C) 2019 Jérémie Galarneau <jeremie.galarneau@efficios.com>
3 * Copyright (C) 2019 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
5 * SPDX-License-Identifier: LGPL-2.1-only
13 #include <lttng/lttng-error.h>
14 #include <lttng/clear.h>
15 #include <lttng/clear-handle.h>
16 #include <common/sessiond-comm/sessiond-comm.h>
17 #include <common/macros.h>
18 #include <common/compat/poll.h>
19 #include <common/dynamic-buffer.h>
20 #include <common/buffer-view.h>
21 #include <common/optional.h>
23 #include "lttng-ctl-helper.h"
25 enum communication_state
{
26 COMMUNICATION_STATE_RECEIVE_LTTNG_MSG
,
27 COMMUNICATION_STATE_RECEIVE_COMMAND_HEADER
,
28 COMMUNICATION_STATE_END
,
29 COMMUNICATION_STATE_ERROR
,
32 struct lttng_clear_handle
{
33 LTTNG_OPTIONAL(enum lttng_error_code
) clear_return_code
;
36 struct lttng_poll_event events
;
37 size_t bytes_left_to_receive
;
38 enum communication_state state
;
39 struct lttng_dynamic_buffer buffer
;
40 LTTNG_OPTIONAL(size_t) data_size
;
44 void lttng_clear_handle_destroy(struct lttng_clear_handle
*handle
)
52 if (handle
->communication
.socket
>= 0) {
53 ret
= close(handle
->communication
.socket
);
55 PERROR("Failed to close lttng-sessiond command socket");
58 lttng_poll_clean(&handle
->communication
.events
);
59 lttng_dynamic_buffer_reset(&handle
->communication
.buffer
);
64 struct lttng_clear_handle
*lttng_clear_handle_create(int sessiond_socket
)
67 struct lttng_clear_handle
*handle
= zmalloc(sizeof(*handle
));
72 lttng_dynamic_buffer_init(&handle
->communication
.buffer
);
73 handle
->communication
.socket
= sessiond_socket
;
74 ret
= lttng_poll_create(&handle
->communication
.events
, 1, 0);
79 ret
= lttng_poll_add(&handle
->communication
.events
, sessiond_socket
,
80 LPOLLIN
| LPOLLHUP
| LPOLLRDHUP
| LPOLLERR
);
85 handle
->communication
.bytes_left_to_receive
=
86 sizeof(struct lttcomm_lttng_msg
);
87 handle
->communication
.state
= COMMUNICATION_STATE_RECEIVE_LTTNG_MSG
;
91 lttng_clear_handle_destroy(handle
);
96 int handle_state_transition(struct lttng_clear_handle
*handle
)
100 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
->clear_return_code
,
109 (enum lttng_error_code
) msg
->ret_code
);
110 if (handle
->clear_return_code
.value
!= LTTNG_OK
) {
111 handle
->communication
.state
= COMMUNICATION_STATE_END
;
113 } else if (msg
->cmd_header_size
!= 0 || msg
->data_size
!= 0) {
114 handle
->communication
.state
= COMMUNICATION_STATE_ERROR
;
119 handle
->communication
.state
= COMMUNICATION_STATE_END
;
120 handle
->communication
.bytes_left_to_receive
= 0;
121 LTTNG_OPTIONAL_SET(&handle
->communication
.data_size
, 0);
122 ret
= lttng_dynamic_buffer_set_size(
123 &handle
->communication
.buffer
, 0);
131 /* Clear reception buffer on state transition. */
132 if (lttng_dynamic_buffer_set_size(&handle
->communication
.buffer
, 0)) {
139 int handle_incoming_data(struct lttng_clear_handle
*handle
)
143 const size_t original_buffer_size
= handle
->communication
.buffer
.size
;
145 /* Reserve space for reception. */
146 ret
= lttng_dynamic_buffer_set_size(&handle
->communication
.buffer
,
147 original_buffer_size
+ handle
->communication
.bytes_left_to_receive
);
152 comm_ret
= lttcomm_recv_unix_sock(handle
->communication
.socket
,
153 handle
->communication
.buffer
.data
+ original_buffer_size
,
154 handle
->communication
.bytes_left_to_receive
);
160 handle
->communication
.bytes_left_to_receive
-= comm_ret
;
161 if (handle
->communication
.bytes_left_to_receive
== 0) {
162 ret
= handle_state_transition(handle
);
164 ret
= lttng_dynamic_buffer_set_size(
165 &handle
->communication
.buffer
,
166 original_buffer_size
+ comm_ret
);
172 extern enum lttng_clear_handle_status
173 lttng_clear_handle_wait_for_completion(
174 struct lttng_clear_handle
*handle
, int timeout_ms
)
177 enum lttng_clear_handle_status status
;
178 unsigned long time_left_ms
= 0;
179 const bool has_timeout
= timeout_ms
> 0;
180 struct timespec initial_time
;
182 if (handle
->communication
.state
== COMMUNICATION_STATE_ERROR
) {
183 status
= LTTNG_CLEAR_HANDLE_STATUS_ERROR
;
185 } else if (handle
->communication
.state
== COMMUNICATION_STATE_END
) {
186 status
= LTTNG_CLEAR_HANDLE_STATUS_COMPLETED
;
190 ret
= lttng_clock_gettime(CLOCK_MONOTONIC
, &initial_time
);
192 status
= LTTNG_CLEAR_HANDLE_STATUS_ERROR
;
195 time_left_ms
= (unsigned long) timeout_ms
;
198 while (handle
->communication
.state
!= COMMUNICATION_STATE_END
&&
199 (time_left_ms
|| !has_timeout
)) {
202 struct timespec current_time
, diff
;
203 unsigned long diff_ms
;
205 ret
= lttng_poll_wait(&handle
->communication
.events
,
206 has_timeout
? time_left_ms
: -1);
210 } else if (ret
< 0) {
211 status
= LTTNG_CLEAR_HANDLE_STATUS_ERROR
;
215 /* The sessiond connection socket is the only monitored fd. */
216 revents
= LTTNG_POLL_GETEV(&handle
->communication
.events
, 0);
217 if (revents
& LPOLLIN
) {
218 ret
= handle_incoming_data(handle
);
220 handle
->communication
.state
=
221 COMMUNICATION_STATE_ERROR
;
222 status
= LTTNG_CLEAR_HANDLE_STATUS_ERROR
;
226 handle
->communication
.state
= COMMUNICATION_STATE_ERROR
;
227 status
= LTTNG_CLEAR_HANDLE_STATUS_ERROR
;
234 ret
= lttng_clock_gettime(CLOCK_MONOTONIC
, ¤t_time
);
236 status
= LTTNG_CLEAR_HANDLE_STATUS_ERROR
;
239 diff
= timespec_abs_diff(initial_time
, current_time
);
240 ret
= timespec_to_ms(diff
, &diff_ms
);
242 ERR("Failed to compute elapsed time while waiting for completion");
243 status
= LTTNG_CLEAR_HANDLE_STATUS_ERROR
;
246 DBG("%lums elapsed while waiting for session clear completion",
248 diff_ms
= max_t(unsigned long, diff_ms
, 1);
249 diff_ms
= min_t(unsigned long, diff_ms
, time_left_ms
);
250 time_left_ms
-= diff_ms
;
253 status
= handle
->communication
.state
== COMMUNICATION_STATE_END
?
254 LTTNG_CLEAR_HANDLE_STATUS_COMPLETED
:
255 LTTNG_CLEAR_HANDLE_STATUS_TIMEOUT
;
260 extern enum lttng_clear_handle_status
261 lttng_clear_handle_get_result(
262 const struct lttng_clear_handle
*handle
,
263 enum lttng_error_code
*result
)
265 enum lttng_clear_handle_status status
=
266 LTTNG_CLEAR_HANDLE_STATUS_OK
;
268 if (!handle
->clear_return_code
.is_set
) {
269 status
= LTTNG_CLEAR_HANDLE_STATUS_INVALID
;
272 *result
= handle
->clear_return_code
.value
;
280 enum lttng_error_code
lttng_clear_session(const char *session_name
,
281 struct lttng_clear_handle
**_handle
)
283 enum lttng_error_code ret_code
= LTTNG_OK
;
284 struct lttng_clear_handle
*handle
= NULL
;
285 struct lttcomm_session_msg lsm
= {
286 .cmd_type
= LTTNG_CLEAR_SESSION
,
288 int sessiond_socket
= -1;
292 if (session_name
== NULL
) {
293 ret_code
= LTTNG_ERR_INVALID
;
296 ret
= lttng_strncpy(lsm
.session
.name
, session_name
,
297 sizeof(lsm
.session
.name
));
299 ret_code
= LTTNG_ERR_INVALID
;
302 ret
= connect_sessiond();
304 ret_code
= LTTNG_ERR_NO_SESSIOND
;
307 sessiond_socket
= ret
;
309 handle
= lttng_clear_handle_create(sessiond_socket
);
311 ret_code
= LTTNG_ERR_NOMEM
;
314 comm_ret
= lttcomm_send_creds_unix_sock(sessiond_socket
, &lsm
, sizeof(lsm
));
316 ret_code
= LTTNG_ERR_FATAL
;
319 sessiond_socket
= -1;
322 /* Transfer the handle to the caller. */
327 if (sessiond_socket
>= 0) {
328 ret
= close(sessiond_socket
);
330 PERROR("Failed to close the LTTng session daemon connection socket");
334 lttng_clear_handle_destroy(handle
);