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
10 #include "lttng-ctl-helper.hpp"
12 #include <common/buffer-view.hpp>
13 #include <common/compat/poll.hpp>
14 #include <common/dynamic-buffer.hpp>
15 #include <common/macros.hpp>
16 #include <common/optional.hpp>
17 #include <common/sessiond-comm/sessiond-comm.hpp>
19 #include <lttng/clear-handle.h>
20 #include <lttng/clear.h>
21 #include <lttng/lttng-error.h>
26 enum communication_state
{
27 COMMUNICATION_STATE_RECEIVE_LTTNG_MSG
,
28 COMMUNICATION_STATE_RECEIVE_COMMAND_HEADER
,
29 COMMUNICATION_STATE_END
,
30 COMMUNICATION_STATE_ERROR
,
33 struct lttng_clear_handle
{
34 LTTNG_OPTIONAL(enum lttng_error_code
) clear_return_code
;
37 struct lttng_poll_event events
;
38 size_t bytes_left_to_receive
;
39 enum communication_state state
;
40 struct lttng_dynamic_buffer buffer
;
41 LTTNG_OPTIONAL(size_t) data_size
;
45 void lttng_clear_handle_destroy(struct lttng_clear_handle
*handle
)
53 if (handle
->communication
.socket
>= 0) {
54 ret
= close(handle
->communication
.socket
);
56 PERROR("Failed to close lttng-sessiond command socket");
59 lttng_poll_clean(&handle
->communication
.events
);
60 lttng_dynamic_buffer_reset(&handle
->communication
.buffer
);
64 static struct lttng_clear_handle
*lttng_clear_handle_create(int sessiond_socket
)
67 struct lttng_clear_handle
*handle
= zmalloc
<lttng_clear_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
, LPOLLIN
| LPOLLRDHUP
);
84 handle
->communication
.bytes_left_to_receive
= sizeof(struct lttcomm_lttng_msg
);
85 handle
->communication
.state
= COMMUNICATION_STATE_RECEIVE_LTTNG_MSG
;
89 lttng_clear_handle_destroy(handle
);
93 static int handle_state_transition(struct lttng_clear_handle
*handle
)
97 LTTNG_ASSERT(handle
->communication
.bytes_left_to_receive
== 0);
99 switch (handle
->communication
.state
) {
100 case COMMUNICATION_STATE_RECEIVE_LTTNG_MSG
:
102 const struct lttcomm_lttng_msg
*msg
=
103 (typeof(msg
)) handle
->communication
.buffer
.data
;
105 LTTNG_OPTIONAL_SET(&handle
->clear_return_code
,
106 (enum lttng_error_code
) msg
->ret_code
);
107 if (handle
->clear_return_code
.value
!= LTTNG_OK
) {
108 handle
->communication
.state
= COMMUNICATION_STATE_END
;
110 } else if (msg
->cmd_header_size
!= 0 || msg
->data_size
!= 0) {
111 handle
->communication
.state
= COMMUNICATION_STATE_ERROR
;
116 handle
->communication
.state
= COMMUNICATION_STATE_END
;
117 handle
->communication
.bytes_left_to_receive
= 0;
118 LTTNG_OPTIONAL_SET(&handle
->communication
.data_size
, 0);
119 ret
= lttng_dynamic_buffer_set_size(&handle
->communication
.buffer
, 0);
127 /* Clear reception buffer on state transition. */
128 if (lttng_dynamic_buffer_set_size(&handle
->communication
.buffer
, 0)) {
134 static int handle_incoming_data(struct lttng_clear_handle
*handle
)
138 const size_t original_buffer_size
= handle
->communication
.buffer
.size
;
140 /* Reserve space for reception. */
141 ret
= lttng_dynamic_buffer_set_size(&handle
->communication
.buffer
,
142 original_buffer_size
+
143 handle
->communication
.bytes_left_to_receive
);
148 comm_ret
= lttcomm_recv_unix_sock(handle
->communication
.socket
,
149 handle
->communication
.buffer
.data
+ original_buffer_size
,
150 handle
->communication
.bytes_left_to_receive
);
156 handle
->communication
.bytes_left_to_receive
-= comm_ret
;
157 if (handle
->communication
.bytes_left_to_receive
== 0) {
158 ret
= handle_state_transition(handle
);
160 ret
= lttng_dynamic_buffer_set_size(&handle
->communication
.buffer
,
161 original_buffer_size
+ comm_ret
);
167 extern enum lttng_clear_handle_status
168 lttng_clear_handle_wait_for_completion(struct lttng_clear_handle
*handle
, int timeout_ms
)
170 enum lttng_clear_handle_status status
;
171 unsigned long time_left_ms
= 0;
172 const bool has_timeout
= timeout_ms
> 0;
173 struct timespec initial_time
;
175 if (handle
->communication
.state
== COMMUNICATION_STATE_ERROR
) {
176 status
= LTTNG_CLEAR_HANDLE_STATUS_ERROR
;
178 } else if (handle
->communication
.state
== COMMUNICATION_STATE_END
) {
179 status
= LTTNG_CLEAR_HANDLE_STATUS_COMPLETED
;
183 int ret
= lttng_clock_gettime(CLOCK_MONOTONIC
, &initial_time
);
185 status
= LTTNG_CLEAR_HANDLE_STATUS_ERROR
;
188 time_left_ms
= (unsigned long) timeout_ms
;
191 while (handle
->communication
.state
!= COMMUNICATION_STATE_END
&&
192 (time_left_ms
|| !has_timeout
)) {
195 struct timespec current_time
, diff
;
196 unsigned long diff_ms
;
198 ret
= lttng_poll_wait(&handle
->communication
.events
,
199 has_timeout
? time_left_ms
: -1);
203 } else if (ret
< 0) {
204 status
= LTTNG_CLEAR_HANDLE_STATUS_ERROR
;
208 /* The sessiond connection socket is the only monitored fd. */
209 revents
= LTTNG_POLL_GETEV(&handle
->communication
.events
, 0);
210 if (revents
& LPOLLIN
) {
211 ret
= handle_incoming_data(handle
);
213 handle
->communication
.state
= COMMUNICATION_STATE_ERROR
;
214 status
= LTTNG_CLEAR_HANDLE_STATUS_ERROR
;
218 handle
->communication
.state
= COMMUNICATION_STATE_ERROR
;
219 status
= LTTNG_CLEAR_HANDLE_STATUS_ERROR
;
226 ret
= lttng_clock_gettime(CLOCK_MONOTONIC
, ¤t_time
);
228 status
= LTTNG_CLEAR_HANDLE_STATUS_ERROR
;
231 diff
= timespec_abs_diff(initial_time
, current_time
);
232 ret
= timespec_to_ms(diff
, &diff_ms
);
234 ERR("Failed to compute elapsed time while waiting for completion");
235 status
= LTTNG_CLEAR_HANDLE_STATUS_ERROR
;
238 DBG("%lums elapsed while waiting for session clear completion", diff_ms
);
239 diff_ms
= std::max(diff_ms
, 1UL);
240 diff_ms
= std::min(diff_ms
, time_left_ms
);
241 time_left_ms
-= diff_ms
;
244 status
= handle
->communication
.state
== COMMUNICATION_STATE_END
?
245 LTTNG_CLEAR_HANDLE_STATUS_COMPLETED
:
246 LTTNG_CLEAR_HANDLE_STATUS_TIMEOUT
;
251 extern enum lttng_clear_handle_status
252 lttng_clear_handle_get_result(const struct lttng_clear_handle
*handle
,
253 enum lttng_error_code
*result
)
255 enum lttng_clear_handle_status status
= LTTNG_CLEAR_HANDLE_STATUS_OK
;
257 if (!handle
->clear_return_code
.is_set
) {
258 status
= LTTNG_CLEAR_HANDLE_STATUS_INVALID
;
261 *result
= handle
->clear_return_code
.value
;
269 enum lttng_error_code
lttng_clear_session(const char *session_name
,
270 struct lttng_clear_handle
**_handle
)
272 enum lttng_error_code ret_code
= LTTNG_OK
;
273 struct lttng_clear_handle
*handle
= nullptr;
274 struct lttcomm_session_msg lsm
= {
275 .cmd_type
= LTTCOMM_SESSIOND_COMMAND_CLEAR_SESSION
,
281 int sessiond_socket
= -1;
285 if (session_name
== nullptr) {
286 ret_code
= LTTNG_ERR_INVALID
;
289 ret
= lttng_strncpy(lsm
.session
.name
, session_name
, sizeof(lsm
.session
.name
));
291 ret_code
= LTTNG_ERR_INVALID
;
294 ret
= connect_sessiond();
296 ret_code
= LTTNG_ERR_NO_SESSIOND
;
299 sessiond_socket
= ret
;
301 handle
= lttng_clear_handle_create(sessiond_socket
);
303 ret_code
= LTTNG_ERR_NOMEM
;
306 comm_ret
= lttcomm_send_creds_unix_sock(sessiond_socket
, &lsm
, sizeof(lsm
));
308 ret_code
= LTTNG_ERR_FATAL
;
311 sessiond_socket
= -1;
314 /* Transfer the handle to the caller. */
319 if (sessiond_socket
>= 0) {
320 ret
= close(sessiond_socket
);
322 PERROR("Failed to close the LTTng session daemon connection socket");
326 lttng_clear_handle_destroy(handle
);