clang-tidy: add Chrome-inspired checks
[lttng-tools.git] / src / lib / lttng-ctl / destruction-handle.cpp
CommitLineData
3e3665b8 1/*
ab5be9fa 2 * Copyright (C) 2019 Jérémie Galarneau <jeremie.galarneau@efficios.com>
3e3665b8 3 *
ab5be9fa 4 * SPDX-License-Identifier: LGPL-2.1-only
3e3665b8 5 *
3e3665b8
JG
6 */
7
28ab034a 8#include "lttng-ctl-helper.hpp"
3e3665b8 9
28ab034a 10#include <common/buffer-view.hpp>
c9e313bc
SM
11#include <common/compat/poll.hpp>
12#include <common/compat/time.hpp>
c9e313bc 13#include <common/dynamic-buffer.hpp>
28ab034a
JG
14#include <common/macros.hpp>
15#include <common/optional.hpp>
c9e313bc 16#include <common/sessiond-comm/sessiond-comm.hpp>
28ab034a
JG
17
18#include <lttng/destruction-handle.h>
c9e313bc 19#include <lttng/location-internal.hpp>
28ab034a 20#include <lttng/rotation.h>
3e3665b8 21
4bd69c5f 22#include <algorithm>
3e3665b8
JG
23#include <stdbool.h>
24
25enum communication_state {
26 COMMUNICATION_STATE_RECEIVE_LTTNG_MSG,
27 COMMUNICATION_STATE_RECEIVE_COMMAND_HEADER,
28 COMMUNICATION_STATE_RECEIVE_PAYLOAD,
29 COMMUNICATION_STATE_END,
30 COMMUNICATION_STATE_ERROR,
31};
32
33struct lttng_destruction_handle {
34 LTTNG_OPTIONAL(enum lttng_error_code) destruction_return_code;
35 LTTNG_OPTIONAL(enum lttng_rotation_state) rotation_state;
36 struct lttng_trace_archive_location *location;
37 struct {
38 int socket;
39 struct lttng_poll_event events;
40 size_t bytes_left_to_receive;
41 enum communication_state state;
42 struct lttng_dynamic_buffer buffer;
43 LTTNG_OPTIONAL(size_t) data_size;
44 } communication;
45};
46
47void lttng_destruction_handle_destroy(struct lttng_destruction_handle *handle)
48{
49 int ret;
50
51 if (!handle) {
52 return;
53 }
54
55 if (handle->communication.socket >= 0) {
56 ret = close(handle->communication.socket);
57 if (ret) {
58 PERROR("Failed to close lttng-sessiond command socket");
59 }
96c5e4c3
JG
60 }
61 lttng_poll_clean(&handle->communication.events);
3e3665b8 62 lttng_dynamic_buffer_reset(&handle->communication.buffer);
d3740619 63 lttng_trace_archive_location_put(handle->location);
3e3665b8
JG
64 free(handle);
65}
66
28ab034a 67static struct lttng_destruction_handle *lttng_destruction_handle_create(int sessiond_socket)
3e3665b8
JG
68{
69 int ret;
64803277 70 struct lttng_destruction_handle *handle = zmalloc<lttng_destruction_handle>();
3e3665b8
JG
71
72 if (!handle) {
73 goto end;
74 }
75 lttng_dynamic_buffer_init(&handle->communication.buffer);
76 handle->communication.socket = sessiond_socket;
77 ret = lttng_poll_create(&handle->communication.events, 1, 0);
78 if (ret) {
79 goto error;
80 }
81
28ab034a 82 ret = lttng_poll_add(&handle->communication.events, sessiond_socket, LPOLLIN | LPOLLRDHUP);
96c5e4c3 83 if (ret) {
3e3665b8 84 goto error;
96c5e4c3 85 }
3e3665b8 86
28ab034a 87 handle->communication.bytes_left_to_receive = sizeof(struct lttcomm_lttng_msg);
3e3665b8
JG
88 handle->communication.state = COMMUNICATION_STATE_RECEIVE_LTTNG_MSG;
89end:
90 return handle;
91error:
92 lttng_destruction_handle_destroy(handle);
cd9adb8b 93 return nullptr;
3e3665b8
JG
94}
95
28ab034a 96static int handle_state_transition(struct lttng_destruction_handle *handle)
3e3665b8
JG
97{
98 int ret = 0;
99
a0377dfe 100 LTTNG_ASSERT(handle->communication.bytes_left_to_receive == 0);
3e3665b8
JG
101
102 switch (handle->communication.state) {
103 case COMMUNICATION_STATE_RECEIVE_LTTNG_MSG:
104 {
105 const struct lttcomm_lttng_msg *msg =
28ab034a 106 (typeof(msg)) handle->communication.buffer.data;
3e3665b8
JG
107
108 LTTNG_OPTIONAL_SET(&handle->destruction_return_code,
28ab034a 109 (enum lttng_error_code) msg->ret_code);
3e3665b8
JG
110 if (handle->destruction_return_code.value != LTTNG_OK) {
111 handle->communication.state = COMMUNICATION_STATE_END;
112 break;
28ab034a
JG
113 } else if (msg->cmd_header_size !=
114 sizeof(struct lttcomm_session_destroy_command_header) ||
115 msg->data_size > DEFAULT_MAX_TRACE_ARCHIVE_LOCATION_PAYLOAD_SIZE) {
3e3665b8
JG
116 handle->communication.state = COMMUNICATION_STATE_ERROR;
117 ret = -1;
118 break;
119 }
120
28ab034a
JG
121 handle->communication.state = COMMUNICATION_STATE_RECEIVE_COMMAND_HEADER;
122 handle->communication.bytes_left_to_receive = msg->cmd_header_size;
123 LTTNG_OPTIONAL_SET(&handle->communication.data_size, msg->data_size);
124 ret = lttng_dynamic_buffer_set_size(&handle->communication.buffer, 0);
a0377dfe 125 LTTNG_ASSERT(!ret);
3e3665b8
JG
126 break;
127 }
128 case COMMUNICATION_STATE_RECEIVE_COMMAND_HEADER:
129 {
130 const struct lttcomm_session_destroy_command_header *hdr =
28ab034a 131 (typeof(hdr)) handle->communication.buffer.data;
3e3665b8
JG
132
133 LTTNG_OPTIONAL_SET(&handle->rotation_state,
28ab034a 134 (enum lttng_rotation_state) hdr->rotation_state);
3e3665b8
JG
135 switch (handle->rotation_state.value) {
136 case LTTNG_ROTATION_STATE_COMPLETED:
28ab034a 137 handle->communication.state = COMMUNICATION_STATE_RECEIVE_PAYLOAD;
3e3665b8 138 handle->communication.bytes_left_to_receive =
28ab034a 139 LTTNG_OPTIONAL_GET(handle->communication.data_size);
3e3665b8
JG
140 break;
141 case LTTNG_ROTATION_STATE_ERROR:
142 case LTTNG_ROTATION_STATE_NO_ROTATION:
143 handle->communication.state = COMMUNICATION_STATE_END;
144 break;
145 default:
146 handle->communication.state = COMMUNICATION_STATE_ERROR;
147 ret = -1;
148 break;
149 }
150 break;
151 }
152 case COMMUNICATION_STATE_RECEIVE_PAYLOAD:
153 {
154 ssize_t location_ret;
155 struct lttng_trace_archive_location *location;
156 const struct lttng_buffer_view view =
28ab034a 157 lttng_buffer_view_from_dynamic_buffer(&handle->communication.buffer, 0, -1);
3e3665b8 158
28ab034a 159 location_ret = lttng_trace_archive_location_create_from_buffer(&view, &location);
3e3665b8
JG
160 if (location_ret < 0) {
161 ERR("Failed to deserialize trace archive location");
162 handle->communication.state = COMMUNICATION_STATE_ERROR;
163 ret = -1;
164 break;
165 } else {
d3740619 166 /* Ownership is transferred to the destruction handle. */
3e3665b8
JG
167 handle->location = location;
168 handle->communication.state = COMMUNICATION_STATE_END;
169 }
170 break;
171 }
172 default:
173 abort();
174 }
175
176 /* Clear reception buffer on state transition. */
177 if (lttng_dynamic_buffer_set_size(&handle->communication.buffer, 0)) {
178 abort();
179 }
180 return ret;
181}
182
28ab034a 183static int handle_incoming_data(struct lttng_destruction_handle *handle)
3e3665b8
JG
184{
185 int ret;
186 ssize_t comm_ret;
187 const size_t original_buffer_size = handle->communication.buffer.size;
188
189 /* Reserve space for reception. */
190 ret = lttng_dynamic_buffer_set_size(&handle->communication.buffer,
28ab034a
JG
191 original_buffer_size +
192 handle->communication.bytes_left_to_receive);
3e3665b8
JG
193 if (ret) {
194 goto end;
195 }
196
197 comm_ret = lttcomm_recv_unix_sock(handle->communication.socket,
28ab034a
JG
198 handle->communication.buffer.data + original_buffer_size,
199 handle->communication.bytes_left_to_receive);
3e3665b8
JG
200 if (comm_ret <= 0) {
201 ret = -1;
202 goto end;
203 }
204
205 handle->communication.bytes_left_to_receive -= comm_ret;
206 if (handle->communication.bytes_left_to_receive == 0) {
207 ret = handle_state_transition(handle);
208 } else {
28ab034a
JG
209 ret = lttng_dynamic_buffer_set_size(&handle->communication.buffer,
210 original_buffer_size + comm_ret);
3e3665b8
JG
211 }
212end:
213 return ret;
214}
215
216enum lttng_destruction_handle_status
28ab034a
JG
217lttng_destruction_handle_wait_for_completion(struct lttng_destruction_handle *handle,
218 int timeout_ms)
3e3665b8 219{
3e3665b8
JG
220 enum lttng_destruction_handle_status status;
221 unsigned long time_left_ms = 0;
222 const bool has_timeout = timeout_ms > 0;
96c5e4c3 223 struct timespec initial_time;
3e3665b8 224
0f7e4628
JG
225 if (!handle) {
226 status = LTTNG_DESTRUCTION_HANDLE_STATUS_INVALID;
227 goto end;
228 }
229
96c5e4c3 230 if (handle->communication.state == COMMUNICATION_STATE_ERROR) {
3e3665b8
JG
231 status = LTTNG_DESTRUCTION_HANDLE_STATUS_ERROR;
232 goto end;
233 } else if (handle->communication.state == COMMUNICATION_STATE_END) {
234 status = LTTNG_DESTRUCTION_HANDLE_STATUS_COMPLETED;
235 goto end;
236 }
96c5e4c3 237 if (has_timeout) {
bf3683d0 238 int ret = lttng_clock_gettime(CLOCK_MONOTONIC, &initial_time);
3e3665b8
JG
239 if (ret) {
240 status = LTTNG_DESTRUCTION_HANDLE_STATUS_ERROR;
241 goto end;
242 }
243 time_left_ms = (unsigned long) timeout_ms;
96c5e4c3 244 }
3e3665b8 245
96c5e4c3 246 while (handle->communication.state != COMMUNICATION_STATE_END &&
28ab034a 247 (time_left_ms || !has_timeout)) {
3e3665b8
JG
248 int ret;
249 uint32_t revents;
96c5e4c3 250 struct timespec current_time, diff;
3e3665b8
JG
251 unsigned long diff_ms;
252
96c5e4c3 253 ret = lttng_poll_wait(&handle->communication.events,
28ab034a 254 has_timeout ? time_left_ms : -1);
96c5e4c3 255 if (ret == 0) {
3e3665b8
JG
256 /* timeout */
257 break;
258 } else if (ret < 0) {
259 status = LTTNG_DESTRUCTION_HANDLE_STATUS_ERROR;
260 goto end;
261 }
262
263 /* The sessiond connection socket is the only monitored fd. */
264 revents = LTTNG_POLL_GETEV(&handle->communication.events, 0);
265 if (revents & LPOLLIN) {
266 ret = handle_incoming_data(handle);
267 if (ret) {
28ab034a 268 handle->communication.state = COMMUNICATION_STATE_ERROR;
3e3665b8
JG
269 status = LTTNG_DESTRUCTION_HANDLE_STATUS_ERROR;
270 goto end;
271 }
272 } else {
273 handle->communication.state = COMMUNICATION_STATE_ERROR;
274 status = LTTNG_DESTRUCTION_HANDLE_STATUS_ERROR;
275 goto end;
276 }
277 if (!has_timeout) {
278 continue;
279 }
280
281 ret = lttng_clock_gettime(CLOCK_MONOTONIC, &current_time);
282 if (ret) {
283 status = LTTNG_DESTRUCTION_HANDLE_STATUS_ERROR;
284 goto end;
285 }
286 diff = timespec_abs_diff(initial_time, current_time);
287 ret = timespec_to_ms(diff, &diff_ms);
288 if (ret) {
289 ERR("Failed to compute elapsed time while waiting for completion");
290 status = LTTNG_DESTRUCTION_HANDLE_STATUS_ERROR;
291 goto end;
292 }
28ab034a 293 DBG("%lums elapsed while waiting for session destruction completion", diff_ms);
4bd69c5f
SM
294 diff_ms = std::max(diff_ms, 1UL);
295 diff_ms = std::min(diff_ms, time_left_ms);
3e3665b8
JG
296 time_left_ms -= diff_ms;
297 }
298
299 status = handle->communication.state == COMMUNICATION_STATE_END ?
28ab034a
JG
300 LTTNG_DESTRUCTION_HANDLE_STATUS_COMPLETED :
301 LTTNG_DESTRUCTION_HANDLE_STATUS_TIMEOUT;
3e3665b8
JG
302end:
303 return status;
304}
305
306enum lttng_destruction_handle_status
28ab034a
JG
307lttng_destruction_handle_get_rotation_state(const struct lttng_destruction_handle *handle,
308 enum lttng_rotation_state *rotation_state)
3e3665b8 309{
28ab034a 310 enum lttng_destruction_handle_status status = LTTNG_DESTRUCTION_HANDLE_STATUS_OK;
3e3665b8 311
0f7e4628
JG
312 if (!handle || !rotation_state) {
313 status = LTTNG_DESTRUCTION_HANDLE_STATUS_INVALID;
314 goto end;
315 }
316
3e3665b8
JG
317 if (!handle->rotation_state.is_set) {
318 status = LTTNG_DESTRUCTION_HANDLE_STATUS_INVALID;
319 goto end;
320 }
321 *rotation_state = handle->rotation_state.value;
322end:
323 return status;
324}
325
326enum lttng_destruction_handle_status
28ab034a
JG
327lttng_destruction_handle_get_archive_location(const struct lttng_destruction_handle *handle,
328 const struct lttng_trace_archive_location **location)
3e3665b8 329{
28ab034a 330 enum lttng_destruction_handle_status status = LTTNG_DESTRUCTION_HANDLE_STATUS_OK;
3e3665b8 331
0f7e4628
JG
332 if (!handle || !location) {
333 status = LTTNG_DESTRUCTION_HANDLE_STATUS_INVALID;
334 goto end;
335 }
336
3e3665b8
JG
337 if (!handle->location) {
338 status = LTTNG_DESTRUCTION_HANDLE_STATUS_INVALID;
339 goto end;
340 }
341 *location = handle->location;
342end:
343 return status;
344}
345
346enum lttng_destruction_handle_status
28ab034a
JG
347lttng_destruction_handle_get_result(const struct lttng_destruction_handle *handle,
348 enum lttng_error_code *result)
3e3665b8 349{
28ab034a 350 enum lttng_destruction_handle_status status = LTTNG_DESTRUCTION_HANDLE_STATUS_OK;
3e3665b8 351
0f7e4628
JG
352 if (!handle || !result) {
353 status = LTTNG_DESTRUCTION_HANDLE_STATUS_INVALID;
354 goto end;
355 }
356
3e3665b8
JG
357 if (!handle->destruction_return_code.is_set) {
358 status = LTTNG_DESTRUCTION_HANDLE_STATUS_INVALID;
359 goto end;
360 }
361 *result = handle->destruction_return_code.value;
362end:
363 return status;
364}
365
366enum lttng_error_code lttng_destroy_session_ext(const char *session_name,
28ab034a 367 struct lttng_destruction_handle **_handle)
3e3665b8
JG
368{
369 int ret;
370 ssize_t comm_ret;
371 enum lttng_error_code ret_code = LTTNG_OK;
96c5e4c3 372 struct lttcomm_session_msg lsm = {
37a5ef39 373 .cmd_type = LTTCOMM_SESSIOND_COMMAND_DESTROY_SESSION,
1c9a0b0e
MJ
374 .session = {},
375 .domain = {},
376 .u = {},
377 .fd_count = 0,
3e3665b8
JG
378 };
379 int sessiond_socket = -1;
cd9adb8b 380 struct lttng_destruction_handle *handle = nullptr;
3e3665b8 381
1e2bb0af 382 if (!session_name) {
0f7e4628
JG
383 ret_code = LTTNG_ERR_INVALID;
384 goto error;
385 }
386
28ab034a 387 ret = lttng_strncpy(lsm.session.name, session_name, sizeof(lsm.session.name));
3e3665b8
JG
388 if (ret) {
389 ret_code = LTTNG_ERR_INVALID;
390 goto error;
391 }
392
393 ret = connect_sessiond();
394 if (ret < 0) {
395 ret_code = LTTNG_ERR_NO_SESSIOND;
396 goto error;
397 } else {
398 sessiond_socket = ret;
399 }
400
401 handle = lttng_destruction_handle_create(sessiond_socket);
402 if (!handle) {
403 ret_code = LTTNG_ERR_NOMEM;
404 goto error;
405 }
406
ee98f686 407 comm_ret = lttcomm_send_creds_unix_sock(sessiond_socket, &lsm, sizeof(lsm));
3e3665b8
JG
408 if (comm_ret < 0) {
409 ret_code = LTTNG_ERR_FATAL;
410 goto error;
411 }
412 sessiond_socket = -1;
413
414 /* Transfer the handle to the caller. */
415 if (_handle) {
416 *_handle = handle;
cd9adb8b 417 handle = nullptr;
3e3665b8
JG
418 }
419error:
420 if (sessiond_socket >= 0) {
421 ret = close(sessiond_socket);
b6d816c5
JG
422 if (ret < 0) {
423 PERROR("Failed to close the LTTng session daemon connection socket");
424 }
3e3665b8
JG
425 }
426 if (handle) {
427 lttng_destruction_handle_destroy(handle);
428 }
429 return ret_code;
430}
This page took 0.059019 seconds and 4 git commands to generate.