Commit | Line | Data |
---|---|---|
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 | ||
25 | enum 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 | ||
33 | struct 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 | ||
47 | void 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 | 67 | static 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; |
89 | end: | |
90 | return handle; | |
91 | error: | |
92 | lttng_destruction_handle_destroy(handle); | |
cd9adb8b | 93 | return nullptr; |
3e3665b8 JG |
94 | } |
95 | ||
28ab034a | 96 | static 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 | 183 | static 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 | } |
212 | end: | |
213 | return ret; | |
214 | } | |
215 | ||
216 | enum lttng_destruction_handle_status | |
28ab034a JG |
217 | lttng_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, ¤t_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 |
302 | end: |
303 | return status; | |
304 | } | |
305 | ||
306 | enum lttng_destruction_handle_status | |
28ab034a JG |
307 | lttng_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; | |
322 | end: | |
323 | return status; | |
324 | } | |
325 | ||
326 | enum lttng_destruction_handle_status | |
28ab034a JG |
327 | lttng_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; | |
342 | end: | |
343 | return status; | |
344 | } | |
345 | ||
346 | enum lttng_destruction_handle_status | |
28ab034a JG |
347 | lttng_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; | |
362 | end: | |
363 | return status; | |
364 | } | |
365 | ||
366 | enum 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 | } |
419 | error: | |
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 | } |