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
12 #include <lttng/lttng-error.h>
13 #include <lttng/clear.h>
14 #include <lttng/clear-handle.h>
15 #include <common/sessiond-comm/sessiond-comm.h>
16 #include <common/macros.h>
17 #include <common/compat/poll.h>
18 #include <common/dynamic-buffer.h>
19 #include <common/buffer-view.h>
20 #include <common/optional.h>
22 #include "lttng-ctl-helper.h"
24 enum communication_state
{
25 COMMUNICATION_STATE_RECEIVE_LTTNG_MSG
,
26 COMMUNICATION_STATE_RECEIVE_COMMAND_HEADER
,
27 COMMUNICATION_STATE_END
,
28 COMMUNICATION_STATE_ERROR
,
31 struct lttng_clear_handle
{
32 LTTNG_OPTIONAL(enum lttng_error_code
) clear_return_code
;
35 struct lttng_poll_event events
;
36 size_t bytes_left_to_receive
;
37 enum communication_state state
;
38 struct lttng_dynamic_buffer buffer
;
39 LTTNG_OPTIONAL(size_t) data_size
;
43 void lttng_clear_handle_destroy(struct lttng_clear_handle
*handle
)
51 if (handle
->communication
.socket
>= 0) {
52 ret
= close(handle
->communication
.socket
);
54 PERROR("Failed to close lttng-sessiond command socket");
57 lttng_poll_clean(&handle
->communication
.events
);
58 lttng_dynamic_buffer_reset(&handle
->communication
.buffer
);
63 struct lttng_clear_handle
*lttng_clear_handle_create(int sessiond_socket
)
66 struct lttng_clear_handle
*handle
= zmalloc(sizeof(*handle
));
71 lttng_dynamic_buffer_init(&handle
->communication
.buffer
);
72 handle
->communication
.socket
= sessiond_socket
;
73 ret
= lttng_poll_create(&handle
->communication
.events
, 1, 0);
78 ret
= lttng_poll_add(&handle
->communication
.events
, sessiond_socket
,
79 LPOLLIN
| LPOLLHUP
| LPOLLRDHUP
| LPOLLERR
);
84 handle
->communication
.bytes_left_to_receive
=
85 sizeof(struct lttcomm_lttng_msg
);
86 handle
->communication
.state
= COMMUNICATION_STATE_RECEIVE_LTTNG_MSG
;
90 lttng_clear_handle_destroy(handle
);
95 int handle_state_transition(struct lttng_clear_handle
*handle
)
99 LTTNG_ASSERT(handle
->communication
.bytes_left_to_receive
== 0);
101 switch (handle
->communication
.state
) {
102 case COMMUNICATION_STATE_RECEIVE_LTTNG_MSG
:
104 const struct lttcomm_lttng_msg
*msg
=
105 (typeof(msg
)) handle
->communication
.buffer
.data
;
107 LTTNG_OPTIONAL_SET(&handle
->clear_return_code
,
108 (enum lttng_error_code
) msg
->ret_code
);
109 if (handle
->clear_return_code
.value
!= LTTNG_OK
) {
110 handle
->communication
.state
= COMMUNICATION_STATE_END
;
112 } else if (msg
->cmd_header_size
!= 0 || msg
->data_size
!= 0) {
113 handle
->communication
.state
= COMMUNICATION_STATE_ERROR
;
118 handle
->communication
.state
= COMMUNICATION_STATE_END
;
119 handle
->communication
.bytes_left_to_receive
= 0;
120 LTTNG_OPTIONAL_SET(&handle
->communication
.data_size
, 0);
121 ret
= lttng_dynamic_buffer_set_size(
122 &handle
->communication
.buffer
, 0);
130 /* Clear reception buffer on state transition. */
131 if (lttng_dynamic_buffer_set_size(&handle
->communication
.buffer
, 0)) {
138 int handle_incoming_data(struct lttng_clear_handle
*handle
)
142 const size_t original_buffer_size
= handle
->communication
.buffer
.size
;
144 /* Reserve space for reception. */
145 ret
= lttng_dynamic_buffer_set_size(&handle
->communication
.buffer
,
146 original_buffer_size
+ handle
->communication
.bytes_left_to_receive
);
151 comm_ret
= lttcomm_recv_unix_sock(handle
->communication
.socket
,
152 handle
->communication
.buffer
.data
+ original_buffer_size
,
153 handle
->communication
.bytes_left_to_receive
);
159 handle
->communication
.bytes_left_to_receive
-= comm_ret
;
160 if (handle
->communication
.bytes_left_to_receive
== 0) {
161 ret
= handle_state_transition(handle
);
163 ret
= lttng_dynamic_buffer_set_size(
164 &handle
->communication
.buffer
,
165 original_buffer_size
+ comm_ret
);
171 extern enum lttng_clear_handle_status
172 lttng_clear_handle_wait_for_completion(
173 struct lttng_clear_handle
*handle
, int timeout_ms
)
175 enum lttng_clear_handle_status status
;
176 unsigned long time_left_ms
= 0;
177 const bool has_timeout
= timeout_ms
> 0;
178 struct timespec initial_time
;
180 if (handle
->communication
.state
== COMMUNICATION_STATE_ERROR
) {
181 status
= LTTNG_CLEAR_HANDLE_STATUS_ERROR
;
183 } else if (handle
->communication
.state
== COMMUNICATION_STATE_END
) {
184 status
= LTTNG_CLEAR_HANDLE_STATUS_COMPLETED
;
188 int ret
= lttng_clock_gettime(CLOCK_MONOTONIC
, &initial_time
);
190 status
= LTTNG_CLEAR_HANDLE_STATUS_ERROR
;
193 time_left_ms
= (unsigned long) timeout_ms
;
196 while (handle
->communication
.state
!= COMMUNICATION_STATE_END
&&
197 (time_left_ms
|| !has_timeout
)) {
200 struct timespec current_time
, diff
;
201 unsigned long diff_ms
;
203 ret
= lttng_poll_wait(&handle
->communication
.events
,
204 has_timeout
? time_left_ms
: -1);
208 } else if (ret
< 0) {
209 status
= LTTNG_CLEAR_HANDLE_STATUS_ERROR
;
213 /* The sessiond connection socket is the only monitored fd. */
214 revents
= LTTNG_POLL_GETEV(&handle
->communication
.events
, 0);
215 if (revents
& LPOLLIN
) {
216 ret
= handle_incoming_data(handle
);
218 handle
->communication
.state
=
219 COMMUNICATION_STATE_ERROR
;
220 status
= LTTNG_CLEAR_HANDLE_STATUS_ERROR
;
224 handle
->communication
.state
= COMMUNICATION_STATE_ERROR
;
225 status
= LTTNG_CLEAR_HANDLE_STATUS_ERROR
;
232 ret
= lttng_clock_gettime(CLOCK_MONOTONIC
, ¤t_time
);
234 status
= LTTNG_CLEAR_HANDLE_STATUS_ERROR
;
237 diff
= timespec_abs_diff(initial_time
, current_time
);
238 ret
= timespec_to_ms(diff
, &diff_ms
);
240 ERR("Failed to compute elapsed time while waiting for completion");
241 status
= LTTNG_CLEAR_HANDLE_STATUS_ERROR
;
244 DBG("%lums elapsed while waiting for session clear completion",
246 diff_ms
= max_t(unsigned long, diff_ms
, 1);
247 diff_ms
= min_t(unsigned long, diff_ms
, time_left_ms
);
248 time_left_ms
-= diff_ms
;
251 status
= handle
->communication
.state
== COMMUNICATION_STATE_END
?
252 LTTNG_CLEAR_HANDLE_STATUS_COMPLETED
:
253 LTTNG_CLEAR_HANDLE_STATUS_TIMEOUT
;
258 extern enum lttng_clear_handle_status
259 lttng_clear_handle_get_result(
260 const struct lttng_clear_handle
*handle
,
261 enum lttng_error_code
*result
)
263 enum lttng_clear_handle_status status
=
264 LTTNG_CLEAR_HANDLE_STATUS_OK
;
266 if (!handle
->clear_return_code
.is_set
) {
267 status
= LTTNG_CLEAR_HANDLE_STATUS_INVALID
;
270 *result
= handle
->clear_return_code
.value
;
278 enum lttng_error_code
lttng_clear_session(const char *session_name
,
279 struct lttng_clear_handle
**_handle
)
281 enum lttng_error_code ret_code
= LTTNG_OK
;
282 struct lttng_clear_handle
*handle
= NULL
;
283 struct lttcomm_session_msg lsm
= {
284 .cmd_type
= LTTNG_CLEAR_SESSION
,
286 int sessiond_socket
= -1;
290 if (session_name
== NULL
) {
291 ret_code
= LTTNG_ERR_INVALID
;
294 ret
= lttng_strncpy(lsm
.session
.name
, session_name
,
295 sizeof(lsm
.session
.name
));
297 ret_code
= LTTNG_ERR_INVALID
;
300 ret
= connect_sessiond();
302 ret_code
= LTTNG_ERR_NO_SESSIOND
;
305 sessiond_socket
= ret
;
307 handle
= lttng_clear_handle_create(sessiond_socket
);
309 ret_code
= LTTNG_ERR_NOMEM
;
312 comm_ret
= lttcomm_send_creds_unix_sock(sessiond_socket
, &lsm
, sizeof(lsm
));
314 ret_code
= LTTNG_ERR_FATAL
;
317 sessiond_socket
= -1;
320 /* Transfer the handle to the caller. */
325 if (sessiond_socket
>= 0) {
326 ret
= close(sessiond_socket
);
328 PERROR("Failed to close the LTTng session daemon connection socket");
332 lttng_clear_handle_destroy(handle
);