2 * Copyright (C) 2019 - Jérémie Galarneau <jeremie.galarneau@efficios.com>
3 * Copyright (C) 2019 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
5 * This library is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU Lesser General Public License, version 2.1 only,
7 * as published by the Free Software Foundation.
9 * This library is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
14 * You should have received a copy of the GNU Lesser General Public License
15 * along with this library; if not, write to the Free Software Foundation,
16 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 #include <lttng/lttng-error.h>
24 #include <lttng/clear.h>
25 #include <lttng/clear-handle.h>
26 #include <common/sessiond-comm/sessiond-comm.h>
27 #include <common/macros.h>
28 #include <common/compat/poll.h>
29 #include <common/dynamic-buffer.h>
30 #include <common/buffer-view.h>
31 #include <common/optional.h>
33 #include "lttng-ctl-helper.h"
35 enum communication_state
{
36 COMMUNICATION_STATE_RECEIVE_LTTNG_MSG
,
37 COMMUNICATION_STATE_RECEIVE_COMMAND_HEADER
,
38 COMMUNICATION_STATE_END
,
39 COMMUNICATION_STATE_ERROR
,
42 struct lttng_clear_handle
{
43 LTTNG_OPTIONAL(enum lttng_error_code
) clear_return_code
;
46 struct lttng_poll_event events
;
47 size_t bytes_left_to_receive
;
48 enum communication_state state
;
49 struct lttng_dynamic_buffer buffer
;
50 LTTNG_OPTIONAL(size_t) data_size
;
54 void lttng_clear_handle_destroy(struct lttng_clear_handle
*handle
)
62 if (handle
->communication
.socket
>= 0) {
63 ret
= close(handle
->communication
.socket
);
65 PERROR("Failed to close lttng-sessiond command socket");
68 lttng_poll_clean(&handle
->communication
.events
);
69 lttng_dynamic_buffer_reset(&handle
->communication
.buffer
);
74 struct lttng_clear_handle
*lttng_clear_handle_create(int sessiond_socket
)
77 struct lttng_clear_handle
*handle
= zmalloc(sizeof(*handle
));
82 lttng_dynamic_buffer_init(&handle
->communication
.buffer
);
83 handle
->communication
.socket
= sessiond_socket
;
84 ret
= lttng_poll_create(&handle
->communication
.events
, 1, 0);
89 ret
= lttng_poll_add(&handle
->communication
.events
, sessiond_socket
,
90 LPOLLIN
| LPOLLHUP
| LPOLLRDHUP
| LPOLLERR
);
95 handle
->communication
.bytes_left_to_receive
=
96 sizeof(struct lttcomm_lttng_msg
);
97 handle
->communication
.state
= COMMUNICATION_STATE_RECEIVE_LTTNG_MSG
;
101 lttng_clear_handle_destroy(handle
);
106 int handle_state_transition(struct lttng_clear_handle
*handle
)
110 assert(handle
->communication
.bytes_left_to_receive
== 0);
112 switch (handle
->communication
.state
) {
113 case COMMUNICATION_STATE_RECEIVE_LTTNG_MSG
:
115 const struct lttcomm_lttng_msg
*msg
=
116 (typeof(msg
)) handle
->communication
.buffer
.data
;
118 LTTNG_OPTIONAL_SET(&handle
->clear_return_code
,
119 (enum lttng_error_code
) msg
->ret_code
);
120 if (handle
->clear_return_code
.value
!= LTTNG_OK
) {
121 handle
->communication
.state
= COMMUNICATION_STATE_END
;
123 } else if (msg
->cmd_header_size
!= 0 || msg
->data_size
!= 0) {
124 handle
->communication
.state
= COMMUNICATION_STATE_ERROR
;
129 handle
->communication
.state
= COMMUNICATION_STATE_END
;
130 handle
->communication
.bytes_left_to_receive
= 0;
131 LTTNG_OPTIONAL_SET(&handle
->communication
.data_size
, 0);
132 ret
= lttng_dynamic_buffer_set_size(
133 &handle
->communication
.buffer
, 0);
141 /* Clear reception buffer on state transition. */
142 if (lttng_dynamic_buffer_set_size(&handle
->communication
.buffer
, 0)) {
149 int handle_incoming_data(struct lttng_clear_handle
*handle
)
153 const size_t original_buffer_size
= handle
->communication
.buffer
.size
;
155 /* Reserve space for reception. */
156 ret
= lttng_dynamic_buffer_set_size(&handle
->communication
.buffer
,
157 original_buffer_size
+ handle
->communication
.bytes_left_to_receive
);
162 comm_ret
= lttcomm_recv_unix_sock(handle
->communication
.socket
,
163 handle
->communication
.buffer
.data
+ original_buffer_size
,
164 handle
->communication
.bytes_left_to_receive
);
170 handle
->communication
.bytes_left_to_receive
-= comm_ret
;
171 if (handle
->communication
.bytes_left_to_receive
== 0) {
172 ret
= handle_state_transition(handle
);
174 ret
= lttng_dynamic_buffer_set_size(
175 &handle
->communication
.buffer
,
176 original_buffer_size
+ comm_ret
);
182 extern enum lttng_clear_handle_status
183 lttng_clear_handle_wait_for_completion(
184 struct lttng_clear_handle
*handle
, int timeout_ms
)
187 enum lttng_clear_handle_status status
;
188 unsigned long time_left_ms
= 0;
189 const bool has_timeout
= timeout_ms
> 0;
190 struct timespec initial_time
;
192 if (handle
->communication
.state
== COMMUNICATION_STATE_ERROR
) {
193 status
= LTTNG_CLEAR_HANDLE_STATUS_ERROR
;
195 } else if (handle
->communication
.state
== COMMUNICATION_STATE_END
) {
196 status
= LTTNG_CLEAR_HANDLE_STATUS_COMPLETED
;
200 ret
= lttng_clock_gettime(CLOCK_MONOTONIC
, &initial_time
);
202 status
= LTTNG_CLEAR_HANDLE_STATUS_ERROR
;
205 time_left_ms
= (unsigned long) timeout_ms
;
208 while (handle
->communication
.state
!= COMMUNICATION_STATE_END
&&
209 (time_left_ms
|| !has_timeout
)) {
212 struct timespec current_time
, diff
;
213 unsigned long diff_ms
;
215 ret
= lttng_poll_wait(&handle
->communication
.events
,
216 has_timeout
? time_left_ms
: -1);
220 } else if (ret
< 0) {
221 status
= LTTNG_CLEAR_HANDLE_STATUS_ERROR
;
225 /* The sessiond connection socket is the only monitored fd. */
226 revents
= LTTNG_POLL_GETEV(&handle
->communication
.events
, 0);
227 if (revents
& LPOLLIN
) {
228 ret
= handle_incoming_data(handle
);
230 handle
->communication
.state
=
231 COMMUNICATION_STATE_ERROR
;
232 status
= LTTNG_CLEAR_HANDLE_STATUS_ERROR
;
236 handle
->communication
.state
= COMMUNICATION_STATE_ERROR
;
237 status
= LTTNG_CLEAR_HANDLE_STATUS_ERROR
;
244 ret
= lttng_clock_gettime(CLOCK_MONOTONIC
, ¤t_time
);
246 status
= LTTNG_CLEAR_HANDLE_STATUS_ERROR
;
249 diff
= timespec_abs_diff(initial_time
, current_time
);
250 ret
= timespec_to_ms(diff
, &diff_ms
);
252 ERR("Failed to compute elapsed time while waiting for completion");
253 status
= LTTNG_CLEAR_HANDLE_STATUS_ERROR
;
256 DBG("%lums elapsed while waiting for session clear completion",
258 diff_ms
= max_t(unsigned long, diff_ms
, 1);
259 diff_ms
= min_t(unsigned long, diff_ms
, time_left_ms
);
260 time_left_ms
-= diff_ms
;
263 status
= handle
->communication
.state
== COMMUNICATION_STATE_END
?
264 LTTNG_CLEAR_HANDLE_STATUS_COMPLETED
:
265 LTTNG_CLEAR_HANDLE_STATUS_TIMEOUT
;
270 extern enum lttng_clear_handle_status
271 lttng_clear_handle_get_result(
272 const struct lttng_clear_handle
*handle
,
273 enum lttng_error_code
*result
)
275 enum lttng_clear_handle_status status
=
276 LTTNG_CLEAR_HANDLE_STATUS_OK
;
278 if (!handle
->clear_return_code
.is_set
) {
279 status
= LTTNG_CLEAR_HANDLE_STATUS_INVALID
;
282 *result
= handle
->clear_return_code
.value
;
290 enum lttng_error_code
lttng_clear_session(const char *session_name
,
291 struct lttng_clear_handle
**_handle
)
293 enum lttng_error_code ret_code
= LTTNG_OK
;
294 struct lttng_clear_handle
*handle
= NULL
;
295 struct lttcomm_session_msg lsm
= {
296 .cmd_type
= LTTNG_CLEAR_SESSION
,
298 int sessiond_socket
= -1;
302 if (session_name
== NULL
) {
303 ret_code
= LTTNG_ERR_INVALID
;
306 ret
= lttng_strncpy(lsm
.session
.name
, session_name
,
307 sizeof(lsm
.session
.name
));
309 ret_code
= LTTNG_ERR_INVALID
;
312 ret
= connect_sessiond();
314 ret_code
= LTTNG_ERR_NO_SESSIOND
;
317 sessiond_socket
= ret
;
319 handle
= lttng_clear_handle_create(sessiond_socket
);
321 ret_code
= LTTNG_ERR_NOMEM
;
324 comm_ret
= lttcomm_send_creds_unix_sock(sessiond_socket
, &lsm
, sizeof(lsm
));
326 ret_code
= LTTNG_ERR_FATAL
;
329 sessiond_socket
= -1;
332 /* Transfer the handle to the caller. */
337 if (sessiond_socket
>= 0) {
338 ret
= close(sessiond_socket
);
340 PERROR("Failed to close the LTTng session daemon connection socket");
344 lttng_clear_handle_destroy(handle
);