configure: add '-Wredundant-decls' to warning flags
[lttng-tools.git] / src / lib / lttng-ctl / clear.cpp
CommitLineData
f2c1f0d4 1/*
ab5be9fa
MJ
2 * Copyright (C) 2019 Jérémie Galarneau <jeremie.galarneau@efficios.com>
3 * Copyright (C) 2019 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
f2c1f0d4 4 *
ab5be9fa 5 * SPDX-License-Identifier: LGPL-2.1-only
f2c1f0d4 6 *
f2c1f0d4
MD
7 */
8
9#define _LGPL_SOURCE
4bd69c5f 10#include <algorithm>
f2c1f0d4
MD
11#include <string.h>
12
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>
22
23#include "lttng-ctl-helper.h"
24
25enum communication_state {
26 COMMUNICATION_STATE_RECEIVE_LTTNG_MSG,
27 COMMUNICATION_STATE_RECEIVE_COMMAND_HEADER,
28 COMMUNICATION_STATE_END,
29 COMMUNICATION_STATE_ERROR,
30};
31
32struct lttng_clear_handle {
33 LTTNG_OPTIONAL(enum lttng_error_code) clear_return_code;
34 struct {
35 int socket;
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;
41 } communication;
42};
43
44void lttng_clear_handle_destroy(struct lttng_clear_handle *handle)
45{
46 int ret;
47
48 if (!handle) {
49 return;
50 }
51
52 if (handle->communication.socket >= 0) {
53 ret = close(handle->communication.socket);
54 if (ret) {
55 PERROR("Failed to close lttng-sessiond command socket");
56 }
e429da85
JG
57 }
58 lttng_poll_clean(&handle->communication.events);
f2c1f0d4
MD
59 lttng_dynamic_buffer_reset(&handle->communication.buffer);
60 free(handle);
61}
62
63static
64struct lttng_clear_handle *lttng_clear_handle_create(int sessiond_socket)
65{
66 int ret;
4bd69c5f 67 struct lttng_clear_handle *handle = (lttng_clear_handle *) zmalloc(sizeof(*handle));
f2c1f0d4
MD
68
69 if (!handle) {
70 goto end;
71 }
72 lttng_dynamic_buffer_init(&handle->communication.buffer);
73 handle->communication.socket = sessiond_socket;
74 ret = lttng_poll_create(&handle->communication.events, 1, 0);
75 if (ret) {
76 goto error;
77 }
78
79 ret = lttng_poll_add(&handle->communication.events, sessiond_socket,
80 LPOLLIN | LPOLLHUP | LPOLLRDHUP | LPOLLERR);
e429da85 81 if (ret) {
f2c1f0d4 82 goto error;
e429da85 83 }
f2c1f0d4
MD
84
85 handle->communication.bytes_left_to_receive =
86 sizeof(struct lttcomm_lttng_msg);
87 handle->communication.state = COMMUNICATION_STATE_RECEIVE_LTTNG_MSG;
88end:
89 return handle;
90error:
91 lttng_clear_handle_destroy(handle);
92 return NULL;
93}
94
95static
96int handle_state_transition(struct lttng_clear_handle *handle)
97{
98 int ret = 0;
99
a0377dfe 100 LTTNG_ASSERT(handle->communication.bytes_left_to_receive == 0);
f2c1f0d4
MD
101
102 switch (handle->communication.state) {
103 case COMMUNICATION_STATE_RECEIVE_LTTNG_MSG:
104 {
105 const struct lttcomm_lttng_msg *msg =
106 (typeof(msg)) handle->communication.buffer.data;
107
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;
112 break;
113 } else if (msg->cmd_header_size != 0 || msg->data_size != 0) {
114 handle->communication.state = COMMUNICATION_STATE_ERROR;
115 ret = -1;
116 break;
117 }
118
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);
a0377dfe 124 LTTNG_ASSERT(!ret);
f2c1f0d4
MD
125 break;
126 }
127 default:
128 abort();
129 }
130
131 /* Clear reception buffer on state transition. */
132 if (lttng_dynamic_buffer_set_size(&handle->communication.buffer, 0)) {
133 abort();
134 }
135 return ret;
136}
137
138static
139int handle_incoming_data(struct lttng_clear_handle *handle)
140{
141 int ret;
142 ssize_t comm_ret;
143 const size_t original_buffer_size = handle->communication.buffer.size;
144
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);
148 if (ret) {
149 goto end;
150 }
151
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);
155 if (comm_ret <= 0) {
156 ret = -1;
157 goto end;
158 }
159
160 handle->communication.bytes_left_to_receive -= comm_ret;
161 if (handle->communication.bytes_left_to_receive == 0) {
162 ret = handle_state_transition(handle);
163 } else {
164 ret = lttng_dynamic_buffer_set_size(
165 &handle->communication.buffer,
166 original_buffer_size + comm_ret);
167 }
168end:
169 return ret;
170}
171
172extern enum lttng_clear_handle_status
173 lttng_clear_handle_wait_for_completion(
174 struct lttng_clear_handle *handle, int timeout_ms)
175{
f2c1f0d4
MD
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;
180
e429da85 181 if (handle->communication.state == COMMUNICATION_STATE_ERROR) {
f2c1f0d4
MD
182 status = LTTNG_CLEAR_HANDLE_STATUS_ERROR;
183 goto end;
184 } else if (handle->communication.state == COMMUNICATION_STATE_END) {
185 status = LTTNG_CLEAR_HANDLE_STATUS_COMPLETED;
186 goto end;
187 }
e429da85 188 if (has_timeout) {
bf3683d0 189 int ret = lttng_clock_gettime(CLOCK_MONOTONIC, &initial_time);
f2c1f0d4
MD
190 if (ret) {
191 status = LTTNG_CLEAR_HANDLE_STATUS_ERROR;
192 goto end;
193 }
194 time_left_ms = (unsigned long) timeout_ms;
e429da85 195 }
f2c1f0d4 196
e429da85 197 while (handle->communication.state != COMMUNICATION_STATE_END &&
f2c1f0d4
MD
198 (time_left_ms || !has_timeout)) {
199 int ret;
200 uint32_t revents;
e429da85 201 struct timespec current_time, diff;
f2c1f0d4
MD
202 unsigned long diff_ms;
203
e429da85 204 ret = lttng_poll_wait(&handle->communication.events,
f2c1f0d4 205 has_timeout ? time_left_ms : -1);
e429da85 206 if (ret == 0) {
f2c1f0d4
MD
207 /* timeout */
208 break;
209 } else if (ret < 0) {
210 status = LTTNG_CLEAR_HANDLE_STATUS_ERROR;
211 goto end;
212 }
213
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);
218 if (ret) {
219 handle->communication.state =
220 COMMUNICATION_STATE_ERROR;
221 status = LTTNG_CLEAR_HANDLE_STATUS_ERROR;
222 goto end;
223 }
224 } else {
225 handle->communication.state = COMMUNICATION_STATE_ERROR;
226 status = LTTNG_CLEAR_HANDLE_STATUS_ERROR;
227 goto end;
228 }
229 if (!has_timeout) {
230 continue;
231 }
232
233 ret = lttng_clock_gettime(CLOCK_MONOTONIC, &current_time);
234 if (ret) {
235 status = LTTNG_CLEAR_HANDLE_STATUS_ERROR;
236 goto end;
237 }
238 diff = timespec_abs_diff(initial_time, current_time);
239 ret = timespec_to_ms(diff, &diff_ms);
240 if (ret) {
241 ERR("Failed to compute elapsed time while waiting for completion");
242 status = LTTNG_CLEAR_HANDLE_STATUS_ERROR;
243 goto end;
244 }
245 DBG("%lums elapsed while waiting for session clear completion",
246 diff_ms);
4bd69c5f
SM
247 diff_ms = std::max(diff_ms, 1UL);
248 diff_ms = std::min(diff_ms, time_left_ms);
f2c1f0d4
MD
249 time_left_ms -= diff_ms;
250 }
251
252 status = handle->communication.state == COMMUNICATION_STATE_END ?
253 LTTNG_CLEAR_HANDLE_STATUS_COMPLETED :
254 LTTNG_CLEAR_HANDLE_STATUS_TIMEOUT;
255end:
256 return status;
257}
258
259extern enum lttng_clear_handle_status
260 lttng_clear_handle_get_result(
261 const struct lttng_clear_handle *handle,
262 enum lttng_error_code *result)
263{
264 enum lttng_clear_handle_status status =
265 LTTNG_CLEAR_HANDLE_STATUS_OK;
266
267 if (!handle->clear_return_code.is_set) {
268 status = LTTNG_CLEAR_HANDLE_STATUS_INVALID;
269 goto end;
270 }
271 *result = handle->clear_return_code.value;
272end:
273 return status;
274}
275
276/*
277 * Clear the session
278 */
279enum lttng_error_code lttng_clear_session(const char *session_name,
280 struct lttng_clear_handle **_handle)
281{
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,
286 };
287 int sessiond_socket = -1;
288 ssize_t comm_ret;
289 int ret;
290
291 if (session_name == NULL) {
292 ret_code = LTTNG_ERR_INVALID;
293 goto error;
294 }
295 ret = lttng_strncpy(lsm.session.name, session_name,
296 sizeof(lsm.session.name));
297 if (ret) {
298 ret_code = LTTNG_ERR_INVALID;
299 goto error;
300 }
301 ret = connect_sessiond();
302 if (ret < 0) {
303 ret_code = LTTNG_ERR_NO_SESSIOND;
304 goto error;
305 } else {
306 sessiond_socket = ret;
307 }
308 handle = lttng_clear_handle_create(sessiond_socket);
309 if (!handle) {
310 ret_code = LTTNG_ERR_NOMEM;
311 goto error;
312 }
313 comm_ret = lttcomm_send_creds_unix_sock(sessiond_socket, &lsm, sizeof(lsm));
314 if (comm_ret < 0) {
315 ret_code = LTTNG_ERR_FATAL;
316 goto error;
317 }
318 sessiond_socket = -1;
319
320error:
321 /* Transfer the handle to the caller. */
322 if (_handle) {
323 *_handle = handle;
324 handle = NULL;
325 }
326 if (sessiond_socket >= 0) {
327 ret = close(sessiond_socket);
328 if (ret < 0) {
329 PERROR("Failed to close the LTTng session daemon connection socket");
330 }
331 }
332 if (handle) {
333 lttng_clear_handle_destroy(handle);
334 }
335 return ret_code;
336}
This page took 0.080863 seconds and 4 git commands to generate.