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
= (lttng_clear_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 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
->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
)
176 enum lttng_clear_handle_status status
;
177 unsigned long time_left_ms
= 0;
178 const bool has_timeout
= timeout_ms
> 0;
179 struct timespec initial_time
;
181 if (handle
->communication
.state
== COMMUNICATION_STATE_ERROR
) {
182 status
= LTTNG_CLEAR_HANDLE_STATUS_ERROR
;
184 } else if (handle
->communication
.state
== COMMUNICATION_STATE_END
) {
185 status
= LTTNG_CLEAR_HANDLE_STATUS_COMPLETED
;
189 int ret
= lttng_clock_gettime(CLOCK_MONOTONIC
, &initial_time
);
191 status
= LTTNG_CLEAR_HANDLE_STATUS_ERROR
;
194 time_left_ms
= (unsigned long) timeout_ms
;
197 while (handle
->communication
.state
!= COMMUNICATION_STATE_END
&&
198 (time_left_ms
|| !has_timeout
)) {
201 struct timespec current_time
, diff
;
202 unsigned long diff_ms
;
204 ret
= lttng_poll_wait(&handle
->communication
.events
,
205 has_timeout
? time_left_ms
: -1);
209 } else if (ret
< 0) {
210 status
= LTTNG_CLEAR_HANDLE_STATUS_ERROR
;
214 /* The sessiond connection socket is the only monitored fd. */
215 revents
= LTTNG_POLL_GETEV(&handle
->communication
.events
, 0);
216 if (revents
& LPOLLIN
) {
217 ret
= handle_incoming_data(handle
);
219 handle
->communication
.state
=
220 COMMUNICATION_STATE_ERROR
;
221 status
= LTTNG_CLEAR_HANDLE_STATUS_ERROR
;
225 handle
->communication
.state
= COMMUNICATION_STATE_ERROR
;
226 status
= LTTNG_CLEAR_HANDLE_STATUS_ERROR
;
233 ret
= lttng_clock_gettime(CLOCK_MONOTONIC
, ¤t_time
);
235 status
= LTTNG_CLEAR_HANDLE_STATUS_ERROR
;
238 diff
= timespec_abs_diff(initial_time
, current_time
);
239 ret
= timespec_to_ms(diff
, &diff_ms
);
241 ERR("Failed to compute elapsed time while waiting for completion");
242 status
= LTTNG_CLEAR_HANDLE_STATUS_ERROR
;
245 DBG("%lums elapsed while waiting for session clear completion",
247 diff_ms
= std::max(diff_ms
, 1UL);
248 diff_ms
= std::min(diff_ms
, time_left_ms
);
249 time_left_ms
-= diff_ms
;
252 status
= handle
->communication
.state
== COMMUNICATION_STATE_END
?
253 LTTNG_CLEAR_HANDLE_STATUS_COMPLETED
:
254 LTTNG_CLEAR_HANDLE_STATUS_TIMEOUT
;
259 extern enum lttng_clear_handle_status
260 lttng_clear_handle_get_result(
261 const struct lttng_clear_handle
*handle
,
262 enum lttng_error_code
*result
)
264 enum lttng_clear_handle_status status
=
265 LTTNG_CLEAR_HANDLE_STATUS_OK
;
267 if (!handle
->clear_return_code
.is_set
) {
268 status
= LTTNG_CLEAR_HANDLE_STATUS_INVALID
;
271 *result
= handle
->clear_return_code
.value
;
279 enum lttng_error_code
lttng_clear_session(const char *session_name
,
280 struct lttng_clear_handle
**_handle
)
282 enum lttng_error_code ret_code
= LTTNG_OK
;
283 struct lttng_clear_handle
*handle
= NULL
;
284 struct lttcomm_session_msg lsm
= {
285 .cmd_type
= LTTNG_CLEAR_SESSION
,
287 int sessiond_socket
= -1;
291 if (session_name
== NULL
) {
292 ret_code
= LTTNG_ERR_INVALID
;
295 ret
= lttng_strncpy(lsm
.session
.name
, session_name
,
296 sizeof(lsm
.session
.name
));
298 ret_code
= LTTNG_ERR_INVALID
;
301 ret
= connect_sessiond();
303 ret_code
= LTTNG_ERR_NO_SESSIOND
;
306 sessiond_socket
= ret
;
308 handle
= lttng_clear_handle_create(sessiond_socket
);
310 ret_code
= LTTNG_ERR_NOMEM
;
313 comm_ret
= lttcomm_send_creds_unix_sock(sessiond_socket
, &lsm
, sizeof(lsm
));
315 ret_code
= LTTNG_ERR_FATAL
;
318 sessiond_socket
= -1;
321 /* Transfer the handle to the caller. */
326 if (sessiond_socket
>= 0) {
327 ret
= close(sessiond_socket
);
329 PERROR("Failed to close the LTTng session daemon connection socket");
333 lttng_clear_handle_destroy(handle
);