Commit | Line | Data |
---|---|---|
7cdc2bab | 1 | /* |
0235b0db | 2 | * SPDX-License-Identifier: MIT |
7cdc2bab | 3 | * |
0235b0db MJ |
4 | * Copyright 2019 Francis Deslauriers <francis.deslauriers@efficios.com> |
5 | * Copyright 2016 Mathieu Desnoyers <mathieu.desnoyers@efficios.com> | |
7cdc2bab MD |
6 | */ |
7 | ||
2ece7dd0 | 8 | #define BT_COMP_LOG_SELF_COMP (viewer_connection->self_comp) |
c01594de | 9 | #define BT_LOG_OUTPUT_LEVEL (viewer_connection->log_level) |
350ad6c1 | 10 | #define BT_LOG_TAG "PLUGIN/SRC.CTF.LTTNG-LIVE/VIEWER" |
d9c39b0a | 11 | #include "logging/comp-logging.h" |
020bc26f | 12 | |
3c22a242 FD |
13 | #include <fcntl.h> |
14 | #include <stdbool.h> | |
7cdc2bab | 15 | #include <stdint.h> |
3c22a242 | 16 | #include <stdio.h> |
7cdc2bab | 17 | #include <stdlib.h> |
3c22a242 | 18 | #include <sys/types.h> |
7cdc2bab | 19 | #include <unistd.h> |
3c22a242 | 20 | |
7cdc2bab | 21 | #include <glib.h> |
7cdc2bab | 22 | |
578e048b MJ |
23 | #include "compat/socket.h" |
24 | #include "compat/endian.h" | |
25 | #include "compat/compiler.h" | |
26 | #include "common/common.h" | |
3fadfbc0 | 27 | #include <babeltrace2/babeltrace.h> |
7cdc2bab | 28 | |
087cd0f5 SM |
29 | #include "lttng-live.hpp" |
30 | #include "viewer-connection.hpp" | |
31 | #include "lttng-viewer-abi.hpp" | |
32 | #include "data-stream.hpp" | |
33 | #include "metadata.hpp" | |
7cdc2bab | 34 | |
f79c2d7a FD |
35 | #define viewer_handle_send_recv_status(_self_comp, _self_comp_class, \ |
36 | _status, _action, _msg_str) \ | |
37 | do { \ | |
38 | switch (_status) { \ | |
39 | case LTTNG_LIVE_VIEWER_STATUS_INTERRUPTED: \ | |
40 | break; \ | |
41 | case LTTNG_LIVE_VIEWER_STATUS_ERROR: \ | |
42 | BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(_self_comp, \ | |
43 | _self_comp_class, "Error " _action " " _msg_str); \ | |
44 | break; \ | |
45 | default: \ | |
46 | bt_common_abort(); \ | |
47 | } \ | |
48 | } while (0) | |
49 | ||
50 | #define viewer_handle_send_status(_self_comp, _self_comp_class, _status, _msg_str) \ | |
51 | viewer_handle_send_recv_status(_self_comp, _self_comp_class, _status, \ | |
52 | "sending", _msg_str) | |
53 | ||
54 | #define viewer_handle_recv_status(_self_comp, _self_comp_class, _status, _msg_str) \ | |
55 | viewer_handle_send_recv_status(_self_comp, _self_comp_class, _status, \ | |
56 | "receiving", _msg_str) | |
57 | ||
58 | #define LTTNG_LIVE_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE_ERRNO(_self_comp, \ | |
59 | _self_comp_class, _msg, _fmt, ...) \ | |
60 | do { \ | |
61 | BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(_self_comp, _self_comp_class, \ | |
62 | _msg ": %s" _fmt, bt_socket_errormsg(), ##__VA_ARGS__); \ | |
63 | } while (0) | |
64 | ||
f93afbf9 FD |
65 | static |
66 | const char *lttng_viewer_command_string(enum lttng_viewer_command cmd) | |
67 | { | |
68 | switch (cmd){ | |
69 | case LTTNG_VIEWER_CONNECT: | |
70 | return "CONNECT"; | |
71 | case LTTNG_VIEWER_LIST_SESSIONS: | |
72 | return "LIST_SESSIONS"; | |
73 | case LTTNG_VIEWER_ATTACH_SESSION: | |
74 | return "ATTACH_SESSION"; | |
75 | case LTTNG_VIEWER_GET_NEXT_INDEX: | |
76 | return "GET_NEXT_INDEX"; | |
77 | case LTTNG_VIEWER_GET_PACKET: | |
78 | return "GET_PACKET"; | |
79 | case LTTNG_VIEWER_GET_METADATA: | |
80 | return "GET_METADATA"; | |
81 | case LTTNG_VIEWER_GET_NEW_STREAMS: | |
82 | return "GET_NEW_STREAMS"; | |
83 | case LTTNG_VIEWER_CREATE_SESSION: | |
84 | return "CREATE_SESSION"; | |
85 | case LTTNG_VIEWER_DETACH_SESSION: | |
86 | return "DETACH_SESSION"; | |
87 | } | |
88 | ||
89 | bt_common_abort(); | |
90 | } | |
91 | ||
92 | static | |
93 | const char *lttng_viewer_next_index_return_code_string( | |
94 | enum lttng_viewer_next_index_return_code code) | |
95 | { | |
96 | switch (code) { | |
97 | case LTTNG_VIEWER_INDEX_OK: | |
98 | return "INDEX_OK"; | |
99 | case LTTNG_VIEWER_INDEX_RETRY: | |
100 | return "INDEX_RETRY"; | |
101 | case LTTNG_VIEWER_INDEX_HUP: | |
102 | return "INDEX_HUP"; | |
103 | case LTTNG_VIEWER_INDEX_ERR: | |
104 | return "INDEX_ERR"; | |
105 | case LTTNG_VIEWER_INDEX_INACTIVE: | |
106 | return "INDEX_INACTIVE"; | |
107 | case LTTNG_VIEWER_INDEX_EOF: | |
108 | return "INDEX_EOF"; | |
109 | } | |
110 | ||
111 | bt_common_abort(); | |
112 | } | |
113 | ||
087cd0f5 SM |
114 | static |
115 | const char *lttng_viewer_next_index_return_code_string(uint32_t code) | |
116 | { | |
117 | return lttng_viewer_next_index_return_code_string( | |
118 | (lttng_viewer_next_index_return_code) code); | |
119 | } | |
120 | ||
f93afbf9 FD |
121 | static |
122 | const char *lttng_viewer_get_packet_return_code_string( | |
123 | enum lttng_viewer_get_packet_return_code code) | |
124 | { | |
125 | switch (code) { | |
126 | case LTTNG_VIEWER_GET_PACKET_OK: | |
127 | return "GET_PACKET_OK"; | |
128 | case LTTNG_VIEWER_GET_PACKET_RETRY: | |
129 | return "GET_PACKET_RETRY"; | |
130 | case LTTNG_VIEWER_GET_PACKET_ERR: | |
131 | return "GET_PACKET_ERR"; | |
132 | case LTTNG_VIEWER_GET_PACKET_EOF: | |
133 | return "GET_PACKET_EOF"; | |
134 | } | |
135 | ||
136 | bt_common_abort(); | |
137 | }; | |
138 | ||
087cd0f5 SM |
139 | static |
140 | const char *lttng_viewer_get_packet_return_code_string(uint32_t code) | |
141 | { | |
142 | return lttng_viewer_get_packet_return_code_string( | |
143 | (lttng_viewer_get_packet_return_code) code); | |
144 | } | |
145 | ||
f93afbf9 FD |
146 | static |
147 | const char *lttng_viewer_seek_string(enum lttng_viewer_seek seek) | |
148 | { | |
149 | switch (seek) { | |
150 | case LTTNG_VIEWER_SEEK_BEGINNING: | |
151 | return "SEEK_BEGINNING"; | |
152 | case LTTNG_VIEWER_SEEK_LAST: | |
153 | return "SEEK_LAST"; | |
154 | } | |
155 | ||
156 | bt_common_abort(); | |
157 | } | |
158 | ||
f79c2d7a FD |
159 | static inline |
160 | enum lttng_live_iterator_status viewer_status_to_live_iterator_status( | |
161 | enum lttng_live_viewer_status viewer_status) | |
162 | { | |
163 | switch (viewer_status) { | |
164 | case LTTNG_LIVE_VIEWER_STATUS_OK: | |
165 | return LTTNG_LIVE_ITERATOR_STATUS_OK; | |
166 | case LTTNG_LIVE_VIEWER_STATUS_INTERRUPTED: | |
167 | return LTTNG_LIVE_ITERATOR_STATUS_AGAIN; | |
168 | case LTTNG_LIVE_VIEWER_STATUS_ERROR: | |
169 | return LTTNG_LIVE_ITERATOR_STATUS_ERROR; | |
f79c2d7a | 170 | } |
f93afbf9 FD |
171 | |
172 | bt_common_abort(); | |
f79c2d7a FD |
173 | } |
174 | ||
175 | static inline | |
176 | enum ctf_msg_iter_medium_status viewer_status_to_ctf_msg_iter_medium_status( | |
177 | enum lttng_live_viewer_status viewer_status) | |
178 | { | |
179 | switch (viewer_status) { | |
180 | case LTTNG_LIVE_VIEWER_STATUS_OK: | |
181 | return CTF_MSG_ITER_MEDIUM_STATUS_OK; | |
182 | case LTTNG_LIVE_VIEWER_STATUS_INTERRUPTED: | |
183 | return CTF_MSG_ITER_MEDIUM_STATUS_AGAIN; | |
184 | case LTTNG_LIVE_VIEWER_STATUS_ERROR: | |
185 | return CTF_MSG_ITER_MEDIUM_STATUS_ERROR; | |
f79c2d7a | 186 | } |
f93afbf9 FD |
187 | |
188 | bt_common_abort(); | |
f79c2d7a FD |
189 | } |
190 | ||
b197ca37 FD |
191 | static inline |
192 | void viewer_connection_close_socket( | |
193 | struct live_viewer_connection *viewer_connection) | |
194 | { | |
195 | bt_self_component_class *self_comp_class = | |
196 | viewer_connection->self_comp_class; | |
197 | bt_self_component *self_comp = | |
198 | viewer_connection->self_comp; | |
199 | int ret = bt_socket_close(viewer_connection->control_sock); | |
200 | if (ret == -1) { | |
201 | BT_COMP_OR_COMP_CLASS_LOGW_ERRNO( | |
202 | self_comp, self_comp_class, | |
203 | "Error closing viewer connection socket: ", "."); | |
204 | } | |
205 | ||
206 | viewer_connection->control_sock = BT_INVALID_SOCKET; | |
207 | } | |
208 | ||
f79c2d7a FD |
209 | /* |
210 | * This function receives a message from the Relay daemon. | |
211 | * If it received the entire message, it returns _OK, | |
212 | * If it's interrupted, it returns _INTERRUPTED, | |
213 | * otherwise, it returns _ERROR. | |
214 | */ | |
14f28187 | 215 | static |
f79c2d7a FD |
216 | enum lttng_live_viewer_status lttng_live_recv( |
217 | struct live_viewer_connection *viewer_connection, | |
4c66436f | 218 | void *buf, size_t len) |
7cdc2bab | 219 | { |
f79c2d7a FD |
220 | ssize_t received; |
221 | bt_self_component_class *self_comp_class = | |
222 | viewer_connection->self_comp_class; | |
223 | bt_self_component *self_comp = | |
224 | viewer_connection->self_comp; | |
225 | size_t total_received = 0, to_receive = len; | |
14f28187 FD |
226 | struct lttng_live_msg_iter *lttng_live_msg_iter = |
227 | viewer_connection->lttng_live_msg_iter; | |
f79c2d7a | 228 | enum lttng_live_viewer_status status; |
1cb3cdd7 | 229 | BT_SOCKET sock = viewer_connection->control_sock; |
7cdc2bab | 230 | |
f79c2d7a FD |
231 | /* |
232 | * Receive a message from the Relay. | |
233 | */ | |
7cdc2bab | 234 | do { |
087cd0f5 | 235 | received = bt_socket_recv(sock, (char *) buf + total_received, to_receive, 0); |
f79c2d7a FD |
236 | if (received == BT_SOCKET_ERROR) { |
237 | if (bt_socket_interrupted()) { | |
238 | if (lttng_live_graph_is_canceled(lttng_live_msg_iter)) { | |
239 | /* | |
240 | * This interruption was due to a | |
241 | * SIGINT and the graph is being torn | |
242 | * down. | |
243 | */ | |
244 | status = LTTNG_LIVE_VIEWER_STATUS_INTERRUPTED; | |
245 | lttng_live_msg_iter->was_interrupted = true; | |
246 | goto end; | |
247 | } else { | |
248 | /* | |
249 | * A signal was received, but the graph | |
250 | * is not being torn down. Carry on. | |
251 | */ | |
252 | continue; | |
253 | } | |
4c66436f | 254 | } else { |
f79c2d7a | 255 | /* |
b197ca37 FD |
256 | * For any other types of socket error, close |
257 | * the socket and return an error. | |
f79c2d7a FD |
258 | */ |
259 | LTTNG_LIVE_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE_ERRNO( | |
260 | self_comp, self_comp_class, | |
261 | "Error receiving from Relay", "."); | |
b197ca37 FD |
262 | |
263 | viewer_connection_close_socket(viewer_connection); | |
f79c2d7a FD |
264 | status = LTTNG_LIVE_VIEWER_STATUS_ERROR; |
265 | goto end; | |
4c66436f | 266 | } |
f79c2d7a FD |
267 | } else if (received == 0) { |
268 | /* | |
269 | * The recv() call returned 0. This means the | |
270 | * connection was orderly shutdown from the other peer. | |
271 | * If that happens when we are trying to receive | |
272 | * a message from it, it means something when wrong. | |
b197ca37 | 273 | * Close the socket and return an error. |
f79c2d7a | 274 | */ |
f79c2d7a FD |
275 | BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp, |
276 | self_comp_class, "Remote side has closed connection"); | |
b197ca37 FD |
277 | viewer_connection_close_socket(viewer_connection); |
278 | status = LTTNG_LIVE_VIEWER_STATUS_ERROR; | |
f79c2d7a | 279 | goto end; |
4c66436f | 280 | } |
710d900e | 281 | |
f79c2d7a FD |
282 | BT_ASSERT(received <= to_receive); |
283 | total_received += received; | |
284 | to_receive -= received; | |
710d900e | 285 | |
f79c2d7a FD |
286 | } while (to_receive > 0); |
287 | ||
288 | BT_ASSERT(total_received == len); | |
289 | status = LTTNG_LIVE_VIEWER_STATUS_OK; | |
290 | ||
291 | end: | |
292 | return status; | |
7cdc2bab MD |
293 | } |
294 | ||
f79c2d7a FD |
295 | /* |
296 | * This function sends a message to the Relay daemon. | |
297 | * If it send the message, it returns _OK, | |
298 | * If it's interrupted, it returns _INTERRUPTED, | |
299 | * otherwise, it returns _ERROR. | |
300 | */ | |
14f28187 | 301 | static |
f79c2d7a FD |
302 | enum lttng_live_viewer_status lttng_live_send( |
303 | struct live_viewer_connection *viewer_connection, | |
4c66436f | 304 | const void *buf, size_t len) |
7cdc2bab | 305 | { |
f79c2d7a FD |
306 | enum lttng_live_viewer_status status; |
307 | bt_self_component_class *self_comp_class = | |
308 | viewer_connection->self_comp_class; | |
309 | bt_self_component *self_comp = | |
310 | viewer_connection->self_comp; | |
14f28187 FD |
311 | struct lttng_live_msg_iter *lttng_live_msg_iter = |
312 | viewer_connection->lttng_live_msg_iter; | |
1cb3cdd7 | 313 | BT_SOCKET sock = viewer_connection->control_sock; |
f79c2d7a FD |
314 | size_t to_send = len; |
315 | ssize_t total_sent = 0; | |
316 | ||
317 | do { | |
087cd0f5 | 318 | ssize_t sent = bt_socket_send_nosigpipe(sock, (char *) buf + total_sent, |
f79c2d7a FD |
319 | to_send); |
320 | if (sent == BT_SOCKET_ERROR) { | |
321 | if (bt_socket_interrupted()) { | |
322 | if (lttng_live_graph_is_canceled(lttng_live_msg_iter)) { | |
323 | /* | |
324 | * This interruption was a SIGINT and | |
325 | * the graph is being teared down. | |
326 | */ | |
327 | status = LTTNG_LIVE_VIEWER_STATUS_INTERRUPTED; | |
328 | lttng_live_msg_iter->was_interrupted = true; | |
329 | goto end; | |
330 | } else { | |
331 | /* | |
332 | * A signal was received, but the graph | |
333 | * is not being teared down. Carry on. | |
334 | */ | |
335 | continue; | |
336 | } | |
4c66436f | 337 | } else { |
f79c2d7a | 338 | /* |
b197ca37 FD |
339 | * For any other types of socket error, close |
340 | * the socket and return an error. | |
f79c2d7a FD |
341 | */ |
342 | LTTNG_LIVE_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE_ERRNO( | |
343 | self_comp, self_comp_class, | |
344 | "Error sending to Relay", "."); | |
b197ca37 FD |
345 | |
346 | viewer_connection_close_socket(viewer_connection); | |
f79c2d7a FD |
347 | status = LTTNG_LIVE_VIEWER_STATUS_ERROR; |
348 | goto end; | |
4c66436f | 349 | } |
4c66436f | 350 | } |
f79c2d7a FD |
351 | |
352 | BT_ASSERT(sent <= to_send); | |
353 | total_sent += sent; | |
354 | to_send -= sent; | |
355 | ||
356 | } while (to_send > 0); | |
357 | ||
358 | BT_ASSERT(total_sent == len); | |
359 | status = LTTNG_LIVE_VIEWER_STATUS_OK; | |
360 | ||
361 | end: | |
362 | return status; | |
7cdc2bab MD |
363 | } |
364 | ||
14f28187 FD |
365 | static |
366 | int parse_url(struct live_viewer_connection *viewer_connection) | |
7cdc2bab | 367 | { |
94b828f3 | 368 | char error_buf[256] = { 0 }; |
1419db2b FD |
369 | bt_self_component *self_comp = viewer_connection->self_comp; |
370 | bt_self_component_class *self_comp_class = viewer_connection->self_comp_class; | |
94b828f3 MD |
371 | struct bt_common_lttng_live_url_parts lttng_live_url_parts = { 0 }; |
372 | int ret = -1; | |
7cdc2bab | 373 | const char *path = viewer_connection->url->str; |
7cdc2bab MD |
374 | |
375 | if (!path) { | |
376 | goto end; | |
377 | } | |
7cdc2bab | 378 | |
0f1979c3 FD |
379 | lttng_live_url_parts = bt_common_parse_lttng_live_url(path, error_buf, |
380 | sizeof(error_buf)); | |
94b828f3 | 381 | if (!lttng_live_url_parts.proto) { |
1419db2b FD |
382 | BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp, |
383 | self_comp_class,"Invalid LTTng live URL format: %s", | |
384 | error_buf); | |
7cdc2bab MD |
385 | goto end; |
386 | } | |
ecb4ba8a FD |
387 | viewer_connection->proto = lttng_live_url_parts.proto; |
388 | lttng_live_url_parts.proto = NULL; | |
7cdc2bab | 389 | |
0f1979c3 | 390 | viewer_connection->relay_hostname = lttng_live_url_parts.hostname; |
94b828f3 MD |
391 | lttng_live_url_parts.hostname = NULL; |
392 | ||
393 | if (lttng_live_url_parts.port >= 0) { | |
394 | viewer_connection->port = lttng_live_url_parts.port; | |
395 | } else { | |
7cdc2bab MD |
396 | viewer_connection->port = LTTNG_DEFAULT_NETWORK_VIEWER_PORT; |
397 | } | |
398 | ||
0f1979c3 | 399 | viewer_connection->target_hostname = lttng_live_url_parts.target_hostname; |
94b828f3 MD |
400 | lttng_live_url_parts.target_hostname = NULL; |
401 | ||
402 | if (lttng_live_url_parts.session_name) { | |
0f1979c3 | 403 | viewer_connection->session_name = lttng_live_url_parts.session_name; |
94b828f3 | 404 | lttng_live_url_parts.session_name = NULL; |
7cdc2bab MD |
405 | } |
406 | ||
7cdc2bab MD |
407 | ret = 0; |
408 | ||
409 | end: | |
94b828f3 | 410 | bt_common_destroy_lttng_live_url_parts(<tng_live_url_parts); |
7cdc2bab MD |
411 | return ret; |
412 | } | |
413 | ||
14f28187 | 414 | static |
f79c2d7a FD |
415 | enum lttng_live_viewer_status lttng_live_handshake( |
416 | struct live_viewer_connection *viewer_connection) | |
7cdc2bab MD |
417 | { |
418 | struct lttng_viewer_cmd cmd; | |
419 | struct lttng_viewer_connect connect; | |
f79c2d7a | 420 | enum lttng_live_viewer_status status; |
1419db2b FD |
421 | bt_self_component_class *self_comp_class = viewer_connection->self_comp_class; |
422 | bt_self_component *self_comp = viewer_connection->self_comp; | |
bdcbd52e JR |
423 | const size_t cmd_buf_len = sizeof(cmd) + sizeof(connect); |
424 | char cmd_buf[cmd_buf_len]; | |
7cdc2bab | 425 | |
ecb4ba8a | 426 | BT_COMP_OR_COMP_CLASS_LOGD(self_comp, self_comp_class, |
f93afbf9 FD |
427 | "Handshaking with the relay daemon: cmd=%s, major-version=%u, minor-version=%u", |
428 | lttng_viewer_command_string(LTTNG_VIEWER_CONNECT), LTTNG_LIVE_MAJOR, | |
429 | LTTNG_LIVE_MINOR); | |
ecb4ba8a | 430 | |
7cdc2bab MD |
431 | cmd.cmd = htobe32(LTTNG_VIEWER_CONNECT); |
432 | cmd.data_size = htobe64((uint64_t) sizeof(connect)); | |
433 | cmd.cmd_version = htobe32(0); | |
434 | ||
435 | connect.viewer_session_id = -1ULL; /* will be set on recv */ | |
436 | connect.major = htobe32(LTTNG_LIVE_MAJOR); | |
437 | connect.minor = htobe32(LTTNG_LIVE_MINOR); | |
438 | connect.type = htobe32(LTTNG_VIEWER_CLIENT_COMMAND); | |
439 | ||
bdcbd52e JR |
440 | /* |
441 | * Merge the cmd and connection request to prevent a write-write | |
442 | * sequence on the TCP socket. Otherwise, a delayed ACK will prevent the | |
443 | * second write to be performed quickly in presence of Nagle's algorithm | |
444 | */ | |
445 | memcpy(cmd_buf, &cmd, sizeof(cmd)); | |
446 | memcpy(cmd_buf + sizeof(cmd), &connect, sizeof(connect)); | |
7cdc2bab | 447 | |
f79c2d7a FD |
448 | status = lttng_live_send(viewer_connection, &cmd_buf, cmd_buf_len); |
449 | if (status != LTTNG_LIVE_VIEWER_STATUS_OK) { | |
450 | viewer_handle_send_status(self_comp, self_comp_class, | |
451 | status, "viewer connect command"); | |
452 | goto end; | |
7cdc2bab | 453 | } |
f79c2d7a FD |
454 | |
455 | status = lttng_live_recv(viewer_connection, &connect, sizeof(connect)); | |
456 | if (status != LTTNG_LIVE_VIEWER_STATUS_OK) { | |
457 | viewer_handle_recv_status(self_comp, self_comp_class, | |
458 | status, "viewer connect reply"); | |
459 | goto end; | |
7cdc2bab | 460 | } |
7cdc2bab | 461 | |
ecb4ba8a FD |
462 | BT_COMP_OR_COMP_CLASS_LOGI(self_comp, self_comp_class, |
463 | "Received viewer session ID : %" PRIu64, | |
464 | (uint64_t) be64toh(connect.viewer_session_id)); | |
465 | BT_COMP_OR_COMP_CLASS_LOGI(self_comp, self_comp_class, | |
466 | "Relayd version : %u.%u", be32toh(connect.major), | |
467 | be32toh(connect.minor)); | |
7cdc2bab MD |
468 | |
469 | if (LTTNG_LIVE_MAJOR != be32toh(connect.major)) { | |
1419db2b FD |
470 | BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp, |
471 | self_comp_class, "Incompatible lttng-relayd protocol"); | |
f79c2d7a FD |
472 | status = LTTNG_LIVE_VIEWER_STATUS_ERROR; |
473 | goto end; | |
7cdc2bab MD |
474 | } |
475 | /* Use the smallest protocol version implemented. */ | |
476 | if (LTTNG_LIVE_MINOR > be32toh(connect.minor)) { | |
477 | viewer_connection->minor = be32toh(connect.minor); | |
478 | } else { | |
479 | viewer_connection->minor = LTTNG_LIVE_MINOR; | |
480 | } | |
481 | viewer_connection->major = LTTNG_LIVE_MAJOR; | |
7cdc2bab | 482 | |
f79c2d7a FD |
483 | status = LTTNG_LIVE_VIEWER_STATUS_OK; |
484 | ||
485 | goto end; | |
486 | ||
487 | end: | |
488 | return status; | |
7cdc2bab MD |
489 | } |
490 | ||
14f28187 | 491 | static |
f79c2d7a | 492 | enum lttng_live_viewer_status lttng_live_connect_viewer( |
36e94ad6 | 493 | struct live_viewer_connection *viewer_connection) |
7cdc2bab MD |
494 | { |
495 | struct hostent *host; | |
496 | struct sockaddr_in server_addr; | |
f79c2d7a | 497 | enum lttng_live_viewer_status status; |
1419db2b FD |
498 | bt_self_component_class *self_comp_class = viewer_connection->self_comp_class; |
499 | bt_self_component *self_comp = viewer_connection->self_comp; | |
7cdc2bab MD |
500 | |
501 | if (parse_url(viewer_connection)) { | |
1419db2b FD |
502 | BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp, |
503 | self_comp_class, "Failed to parse URL"); | |
f79c2d7a | 504 | status = LTTNG_LIVE_VIEWER_STATUS_ERROR; |
7cdc2bab MD |
505 | goto error; |
506 | } | |
507 | ||
ecb4ba8a FD |
508 | BT_COMP_OR_COMP_CLASS_LOGD(self_comp, self_comp_class, |
509 | "Connecting to hostname : %s, port : %d, " | |
510 | "target hostname : %s, session name : %s, proto : %s", | |
511 | viewer_connection->relay_hostname->str, | |
512 | viewer_connection->port, | |
513 | !viewer_connection->target_hostname ? | |
514 | "<none>" : viewer_connection->target_hostname->str, | |
515 | !viewer_connection->session_name ? | |
516 | "<none>" : viewer_connection->session_name->str, | |
517 | viewer_connection->proto->str); | |
518 | ||
94b828f3 | 519 | host = gethostbyname(viewer_connection->relay_hostname->str); |
7cdc2bab | 520 | if (!host) { |
1419db2b FD |
521 | BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp, |
522 | self_comp_class, "Cannot lookup hostname: hostname=\"%s\"", | |
94b828f3 | 523 | viewer_connection->relay_hostname->str); |
f79c2d7a | 524 | status = LTTNG_LIVE_VIEWER_STATUS_ERROR; |
7cdc2bab MD |
525 | goto error; |
526 | } | |
527 | ||
1cb3cdd7 | 528 | if ((viewer_connection->control_sock = socket(AF_INET, SOCK_STREAM, 0)) == BT_INVALID_SOCKET) { |
1419db2b FD |
529 | BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp, |
530 | self_comp_class, "Socket creation failed: %s", bt_socket_errormsg()); | |
f79c2d7a | 531 | status = LTTNG_LIVE_VIEWER_STATUS_ERROR; |
7cdc2bab MD |
532 | goto error; |
533 | } | |
534 | ||
535 | server_addr.sin_family = AF_INET; | |
536 | server_addr.sin_port = htons(viewer_connection->port); | |
537 | server_addr.sin_addr = *((struct in_addr *) host->h_addr); | |
538 | memset(&(server_addr.sin_zero), 0, 8); | |
539 | ||
540 | if (connect(viewer_connection->control_sock, (struct sockaddr *) &server_addr, | |
1cb3cdd7 | 541 | sizeof(struct sockaddr)) == BT_SOCKET_ERROR) { |
1419db2b FD |
542 | BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp, |
543 | self_comp_class, "Connection failed: %s", | |
544 | bt_socket_errormsg()); | |
f79c2d7a | 545 | status = LTTNG_LIVE_VIEWER_STATUS_ERROR; |
7cdc2bab MD |
546 | goto error; |
547 | } | |
f79c2d7a FD |
548 | |
549 | status = lttng_live_handshake(viewer_connection); | |
550 | ||
551 | /* | |
552 | * Only print error and append cause in case of error. not in case of | |
553 | * interruption. | |
554 | */ | |
555 | if (status == LTTNG_LIVE_VIEWER_STATUS_ERROR) { | |
1419db2b FD |
556 | BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp, |
557 | self_comp_class, "Viewer handshake failed"); | |
7cdc2bab | 558 | goto error; |
f79c2d7a FD |
559 | } else if (status == LTTNG_LIVE_VIEWER_STATUS_INTERRUPTED) { |
560 | goto end; | |
7cdc2bab MD |
561 | } |
562 | ||
f79c2d7a | 563 | goto end; |
7cdc2bab MD |
564 | |
565 | error: | |
1cb3cdd7 MJ |
566 | if (viewer_connection->control_sock != BT_INVALID_SOCKET) { |
567 | if (bt_socket_close(viewer_connection->control_sock) == BT_SOCKET_ERROR) { | |
ecb4ba8a FD |
568 | BT_COMP_OR_COMP_CLASS_LOGW(self_comp, self_comp_class, |
569 | "Error closing socket: %s.", bt_socket_errormsg()); | |
7cdc2bab MD |
570 | } |
571 | } | |
1cb3cdd7 | 572 | viewer_connection->control_sock = BT_INVALID_SOCKET; |
f79c2d7a FD |
573 | end: |
574 | return status; | |
7cdc2bab MD |
575 | } |
576 | ||
14f28187 FD |
577 | static |
578 | void lttng_live_disconnect_viewer( | |
579 | struct live_viewer_connection *viewer_connection) | |
7cdc2bab | 580 | { |
ecb4ba8a FD |
581 | bt_self_component_class *self_comp_class = viewer_connection->self_comp_class; |
582 | bt_self_component *self_comp = viewer_connection->self_comp; | |
583 | ||
1cb3cdd7 | 584 | if (viewer_connection->control_sock == BT_INVALID_SOCKET) { |
7cdc2bab MD |
585 | return; |
586 | } | |
1cb3cdd7 | 587 | if (bt_socket_close(viewer_connection->control_sock) == BT_SOCKET_ERROR) { |
ecb4ba8a FD |
588 | BT_COMP_OR_COMP_CLASS_LOGW(self_comp, self_comp_class, |
589 | "Error closing socket: %s", bt_socket_errormsg()); | |
1cb3cdd7 | 590 | viewer_connection->control_sock = BT_INVALID_SOCKET; |
7cdc2bab MD |
591 | } |
592 | } | |
593 | ||
7cdc2bab | 594 | static |
14f28187 | 595 | int list_update_session(bt_value *results, |
7cdc2bab | 596 | const struct lttng_viewer_session *session, |
c01594de | 597 | bool *_found, struct live_viewer_connection *viewer_connection) |
7cdc2bab | 598 | { |
1419db2b FD |
599 | bt_self_component_class *self_comp_class = viewer_connection->self_comp_class; |
600 | bt_self_component *self_comp = viewer_connection->self_comp; | |
f80e9ec1 FD |
601 | int ret = 0; |
602 | uint64_t i, len; | |
b19ff26f PP |
603 | bt_value *map = NULL; |
604 | bt_value *hostname = NULL; | |
605 | bt_value *session_name = NULL; | |
606 | bt_value *btval = NULL; | |
7cdc2bab MD |
607 | bool found = false; |
608 | ||
393729a6 | 609 | len = bt_value_array_get_length(results); |
7cdc2bab MD |
610 | for (i = 0; i < len; i++) { |
611 | const char *hostname_str = NULL; | |
612 | const char *session_name_str = NULL; | |
613 | ||
f80e9ec1 | 614 | map = bt_value_array_borrow_element_by_index(results, i); |
14f28187 | 615 | hostname = bt_value_map_borrow_entry_value(map, "target-hostname"); |
7cdc2bab | 616 | if (!hostname) { |
1419db2b FD |
617 | BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp, |
618 | self_comp_class, | |
619 | "Error borrowing \"target-hostname\" entry."); | |
14f28187 | 620 | ret = -1; |
7cdc2bab MD |
621 | goto end; |
622 | } | |
14f28187 | 623 | session_name = bt_value_map_borrow_entry_value(map, "session-name"); |
7cdc2bab | 624 | if (!session_name) { |
1419db2b FD |
625 | BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp, |
626 | self_comp_class, | |
627 | "Error borrowing \"session-name\" entry."); | |
14f28187 | 628 | ret = -1; |
7cdc2bab MD |
629 | goto end; |
630 | } | |
601b0d3c PP |
631 | hostname_str = bt_value_string_get(hostname); |
632 | session_name_str = bt_value_string_get(session_name); | |
7cdc2bab | 633 | |
2242b43d PP |
634 | if (strcmp(session->hostname, hostname_str) == 0 |
635 | && strcmp(session->session_name, session_name_str) == 0) { | |
7cdc2bab MD |
636 | int64_t val; |
637 | uint32_t streams = be32toh(session->streams); | |
638 | uint32_t clients = be32toh(session->clients); | |
639 | ||
640 | found = true; | |
641 | ||
14f28187 | 642 | btval = bt_value_map_borrow_entry_value(map, "stream-count"); |
7cdc2bab | 643 | if (!btval) { |
1419db2b FD |
644 | BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( |
645 | self_comp, self_comp_class, | |
646 | "Error borrowing \"stream-count\" entry."); | |
14f28187 | 647 | ret = -1; |
7cdc2bab MD |
648 | goto end; |
649 | } | |
a91cb83e | 650 | val = bt_value_integer_unsigned_get(btval); |
7cdc2bab MD |
651 | /* sum */ |
652 | val += streams; | |
a91cb83e | 653 | bt_value_integer_unsigned_set(btval, val); |
7cdc2bab | 654 | |
14f28187 | 655 | btval = bt_value_map_borrow_entry_value(map, "client-count"); |
7cdc2bab | 656 | if (!btval) { |
1419db2b FD |
657 | BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( |
658 | self_comp, self_comp_class, | |
659 | "Error borrowing \"client-count\" entry."); | |
14f28187 | 660 | ret = -1; |
7cdc2bab MD |
661 | goto end; |
662 | } | |
a91cb83e | 663 | val = bt_value_integer_unsigned_get(btval); |
7cdc2bab | 664 | /* max */ |
91d81473 | 665 | val = bt_max_t(int64_t, clients, val); |
a91cb83e | 666 | bt_value_integer_unsigned_set(btval, val); |
7cdc2bab MD |
667 | } |
668 | ||
7cdc2bab MD |
669 | if (found) { |
670 | break; | |
671 | } | |
672 | } | |
673 | end: | |
7cdc2bab MD |
674 | *_found = found; |
675 | return ret; | |
676 | } | |
677 | ||
678 | static | |
14f28187 | 679 | int list_append_session(bt_value *results, |
7cdc2bab | 680 | GString *base_url, |
c01594de PP |
681 | const struct lttng_viewer_session *session, |
682 | struct live_viewer_connection *viewer_connection) | |
7cdc2bab | 683 | { |
14f28187 | 684 | int ret = 0; |
1419db2b | 685 | bt_self_component_class *self_comp_class = viewer_connection->self_comp_class; |
d24d5663 PP |
686 | bt_value_map_insert_entry_status insert_status; |
687 | bt_value_array_append_element_status append_status; | |
b19ff26f | 688 | bt_value *map = NULL; |
7cdc2bab MD |
689 | GString *url = NULL; |
690 | bool found = false; | |
691 | ||
692 | /* | |
693 | * If the session already exists, add the stream count to it, | |
694 | * and do max of client counts. | |
695 | */ | |
c01594de | 696 | ret = list_update_session(results, session, &found, viewer_connection); |
14f28187 | 697 | if (ret || found) { |
7cdc2bab MD |
698 | goto end; |
699 | } | |
700 | ||
14f28187 | 701 | map = bt_value_map_create(); |
7cdc2bab | 702 | if (!map) { |
1419db2b FD |
703 | BT_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp_class, |
704 | "Error creating map value."); | |
14f28187 | 705 | ret = -1; |
7cdc2bab MD |
706 | goto end; |
707 | } | |
708 | ||
709 | if (base_url->len < 1) { | |
1419db2b FD |
710 | BT_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp_class, |
711 | "Error: base_url length smaller than 1."); | |
14f28187 | 712 | ret = -1; |
7cdc2bab MD |
713 | goto end; |
714 | } | |
715 | /* | |
716 | * key = "url", | |
717 | * value = <string>, | |
718 | */ | |
719 | url = g_string_new(base_url->str); | |
720 | g_string_append(url, "/host/"); | |
721 | g_string_append(url, session->hostname); | |
722 | g_string_append_c(url, '/'); | |
723 | g_string_append(url, session->session_name); | |
724 | ||
d24d5663 PP |
725 | insert_status = bt_value_map_insert_string_entry(map, "url", url->str); |
726 | if (insert_status != BT_VALUE_MAP_INSERT_ENTRY_STATUS_OK) { | |
1419db2b FD |
727 | BT_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp_class, |
728 | "Error inserting \"url\" entry."); | |
14f28187 | 729 | ret = -1; |
7cdc2bab MD |
730 | goto end; |
731 | } | |
732 | ||
733 | /* | |
734 | * key = "target-hostname", | |
735 | * value = <string>, | |
736 | */ | |
d24d5663 | 737 | insert_status = bt_value_map_insert_string_entry(map, "target-hostname", |
7cdc2bab | 738 | session->hostname); |
d24d5663 | 739 | if (insert_status != BT_VALUE_MAP_INSERT_ENTRY_STATUS_OK) { |
1419db2b FD |
740 | BT_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp_class, |
741 | "Error inserting \"target-hostname\" entry."); | |
14f28187 | 742 | ret = -1; |
7cdc2bab MD |
743 | goto end; |
744 | } | |
745 | ||
746 | /* | |
747 | * key = "session-name", | |
748 | * value = <string>, | |
749 | */ | |
d24d5663 | 750 | insert_status = bt_value_map_insert_string_entry(map, "session-name", |
7cdc2bab | 751 | session->session_name); |
d24d5663 | 752 | if (insert_status != BT_VALUE_MAP_INSERT_ENTRY_STATUS_OK) { |
1419db2b FD |
753 | BT_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp_class, |
754 | "Error inserting \"session-name\" entry."); | |
14f28187 | 755 | ret = -1; |
7cdc2bab MD |
756 | goto end; |
757 | } | |
758 | ||
759 | /* | |
760 | * key = "timer-us", | |
761 | * value = <integer>, | |
762 | */ | |
763 | { | |
764 | uint32_t live_timer = be32toh(session->live_timer); | |
765 | ||
a91cb83e | 766 | insert_status = bt_value_map_insert_unsigned_integer_entry( |
fdd3a2da | 767 | map, "timer-us", live_timer); |
d24d5663 | 768 | if (insert_status != BT_VALUE_MAP_INSERT_ENTRY_STATUS_OK) { |
1419db2b FD |
769 | BT_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp_class, |
770 | "Error inserting \"timer-us\" entry."); | |
14f28187 | 771 | ret = -1; |
7cdc2bab MD |
772 | goto end; |
773 | } | |
774 | } | |
775 | ||
776 | /* | |
777 | * key = "stream-count", | |
778 | * value = <integer>, | |
779 | */ | |
780 | { | |
781 | uint32_t streams = be32toh(session->streams); | |
782 | ||
a91cb83e | 783 | insert_status = bt_value_map_insert_unsigned_integer_entry(map, |
fdd3a2da | 784 | "stream-count", streams); |
d24d5663 | 785 | if (insert_status != BT_VALUE_MAP_INSERT_ENTRY_STATUS_OK) { |
1419db2b FD |
786 | BT_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp_class, |
787 | "Error inserting \"stream-count\" entry."); | |
14f28187 | 788 | ret = -1; |
7cdc2bab MD |
789 | goto end; |
790 | } | |
791 | } | |
792 | ||
7cdc2bab MD |
793 | /* |
794 | * key = "client-count", | |
795 | * value = <integer>, | |
796 | */ | |
797 | { | |
798 | uint32_t clients = be32toh(session->clients); | |
799 | ||
a91cb83e | 800 | insert_status = bt_value_map_insert_unsigned_integer_entry(map, |
fdd3a2da | 801 | "client-count", clients); |
d24d5663 | 802 | if (insert_status != BT_VALUE_MAP_INSERT_ENTRY_STATUS_OK) { |
1419db2b FD |
803 | BT_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp_class, |
804 | "Error inserting \"client-count\" entry."); | |
14f28187 | 805 | ret = -1; |
7cdc2bab MD |
806 | goto end; |
807 | } | |
808 | } | |
809 | ||
d24d5663 PP |
810 | append_status = bt_value_array_append_element(results, map); |
811 | if (append_status != BT_VALUE_ARRAY_APPEND_ELEMENT_STATUS_OK) { | |
1419db2b FD |
812 | BT_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp_class, |
813 | "Error appending map to results."); | |
14f28187 FD |
814 | ret = -1; |
815 | } | |
816 | ||
7cdc2bab MD |
817 | end: |
818 | if (url) { | |
14f28187 | 819 | g_string_free(url, true); |
7cdc2bab | 820 | } |
c5b9b441 | 821 | BT_VALUE_PUT_REF_AND_RESET(map); |
7cdc2bab MD |
822 | return ret; |
823 | } | |
824 | ||
825 | /* | |
826 | * Data structure returned: | |
827 | * | |
828 | * { | |
829 | * <array> = { | |
830 | * [n] = { | |
831 | * <map> = { | |
832 | * { | |
833 | * key = "url", | |
834 | * value = <string>, | |
835 | * }, | |
836 | * { | |
837 | * key = "target-hostname", | |
838 | * value = <string>, | |
839 | * }, | |
840 | * { | |
841 | * key = "session-name", | |
842 | * value = <string>, | |
843 | * }, | |
844 | * { | |
845 | * key = "timer-us", | |
846 | * value = <integer>, | |
847 | * }, | |
848 | * { | |
849 | * key = "stream-count", | |
850 | * value = <integer>, | |
851 | * }, | |
852 | * { | |
853 | * key = "client-count", | |
854 | * value = <integer>, | |
855 | * }, | |
856 | * }, | |
857 | * } | |
858 | * } | |
859 | */ | |
860 | ||
861 | BT_HIDDEN | |
d24d5663 | 862 | bt_component_class_query_method_status live_viewer_connection_list_sessions( |
14f28187 FD |
863 | struct live_viewer_connection *viewer_connection, |
864 | const bt_value **user_result) | |
7cdc2bab | 865 | { |
1419db2b | 866 | bt_self_component_class *self_comp_class = viewer_connection->self_comp_class; |
d24d5663 PP |
867 | bt_component_class_query_method_status status = |
868 | BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_OK; | |
14f28187 | 869 | bt_value *result = NULL; |
f79c2d7a | 870 | enum lttng_live_viewer_status viewer_status; |
7cdc2bab MD |
871 | struct lttng_viewer_cmd cmd; |
872 | struct lttng_viewer_list_sessions list; | |
873 | uint32_t i, sessions_count; | |
7cdc2bab | 874 | |
14f28187 FD |
875 | result = bt_value_array_create(); |
876 | if (!result) { | |
1419db2b FD |
877 | BT_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp_class, |
878 | "Error creating array"); | |
d24d5663 | 879 | status = BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_MEMORY_ERROR; |
7cdc2bab MD |
880 | goto error; |
881 | } | |
882 | ||
f93afbf9 FD |
883 | BT_LOGD("Requesting list of sessions: cmd=%s", |
884 | lttng_viewer_command_string(LTTNG_VIEWER_LIST_SESSIONS)); | |
885 | ||
7cdc2bab MD |
886 | cmd.cmd = htobe32(LTTNG_VIEWER_LIST_SESSIONS); |
887 | cmd.data_size = htobe64((uint64_t) 0); | |
888 | cmd.cmd_version = htobe32(0); | |
889 | ||
f79c2d7a FD |
890 | viewer_status = lttng_live_send(viewer_connection, &cmd, sizeof(cmd)); |
891 | if (viewer_status == LTTNG_LIVE_VIEWER_STATUS_ERROR) { | |
1419db2b | 892 | BT_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp_class, |
f79c2d7a | 893 | "Error sending list sessions command"); |
d24d5663 | 894 | status = BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_ERROR; |
7cdc2bab | 895 | goto error; |
f79c2d7a FD |
896 | } else if (viewer_status == LTTNG_LIVE_VIEWER_STATUS_INTERRUPTED) { |
897 | status = BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_AGAIN; | |
898 | goto error; | |
7cdc2bab | 899 | } |
7cdc2bab | 900 | |
f79c2d7a FD |
901 | viewer_status = lttng_live_recv(viewer_connection, &list, sizeof(list)); |
902 | if (viewer_status == LTTNG_LIVE_VIEWER_STATUS_ERROR) { | |
1419db2b | 903 | BT_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp_class, |
f79c2d7a | 904 | "Error receiving session list"); |
d24d5663 | 905 | status = BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_ERROR; |
7cdc2bab | 906 | goto error; |
f79c2d7a FD |
907 | } else if (viewer_status == LTTNG_LIVE_VIEWER_STATUS_INTERRUPTED) { |
908 | status = BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_AGAIN; | |
7cdc2bab MD |
909 | goto error; |
910 | } | |
7cdc2bab MD |
911 | |
912 | sessions_count = be32toh(list.sessions_count); | |
913 | for (i = 0; i < sessions_count; i++) { | |
914 | struct lttng_viewer_session lsession; | |
915 | ||
f79c2d7a | 916 | viewer_status = lttng_live_recv(viewer_connection, &lsession, |
14f28187 | 917 | sizeof(lsession)); |
f79c2d7a | 918 | if (viewer_status == LTTNG_LIVE_VIEWER_STATUS_ERROR) { |
1419db2b | 919 | BT_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp_class, |
f79c2d7a | 920 | "Error receiving session:"); |
d24d5663 | 921 | status = BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_ERROR; |
7cdc2bab | 922 | goto error; |
f79c2d7a FD |
923 | } else if (viewer_status == LTTNG_LIVE_VIEWER_STATUS_INTERRUPTED) { |
924 | status = BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_AGAIN; | |
7cdc2bab MD |
925 | goto error; |
926 | } | |
f79c2d7a | 927 | |
7cdc2bab MD |
928 | lsession.hostname[LTTNG_VIEWER_HOST_NAME_MAX - 1] = '\0'; |
929 | lsession.session_name[LTTNG_VIEWER_NAME_MAX - 1] = '\0'; | |
14f28187 | 930 | if (list_append_session(result, viewer_connection->url, |
c01594de | 931 | &lsession, viewer_connection)) { |
1419db2b FD |
932 | BT_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp_class, |
933 | "Error appending session"); | |
d24d5663 | 934 | status = BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_ERROR; |
7cdc2bab MD |
935 | goto error; |
936 | } | |
937 | } | |
14f28187 FD |
938 | |
939 | *user_result = result; | |
7cdc2bab MD |
940 | goto end; |
941 | error: | |
14f28187 | 942 | BT_VALUE_PUT_REF_AND_RESET(result); |
7cdc2bab | 943 | end: |
14f28187 | 944 | return status; |
7cdc2bab MD |
945 | } |
946 | ||
947 | static | |
f79c2d7a FD |
948 | enum lttng_live_viewer_status lttng_live_query_session_ids( |
949 | struct lttng_live_msg_iter *lttng_live_msg_iter) | |
7cdc2bab MD |
950 | { |
951 | struct lttng_viewer_cmd cmd; | |
952 | struct lttng_viewer_list_sessions list; | |
953 | struct lttng_viewer_session lsession; | |
954 | uint32_t i, sessions_count; | |
7cdc2bab | 955 | uint64_t session_id; |
f79c2d7a | 956 | enum lttng_live_viewer_status status; |
14f28187 | 957 | struct live_viewer_connection *viewer_connection = |
1419db2b FD |
958 | lttng_live_msg_iter->viewer_connection; |
959 | bt_self_component *self_comp = viewer_connection->self_comp; | |
f79c2d7a FD |
960 | bt_self_component_class *self_comp_class = |
961 | viewer_connection->self_comp_class; | |
7cdc2bab | 962 | |
f93afbf9 FD |
963 | BT_COMP_LOGD("Asking the relay daemon for the list of sessions: cmd=%s", |
964 | lttng_viewer_command_string(LTTNG_VIEWER_LIST_SESSIONS)); | |
ecb4ba8a | 965 | |
7cdc2bab MD |
966 | cmd.cmd = htobe32(LTTNG_VIEWER_LIST_SESSIONS); |
967 | cmd.data_size = htobe64((uint64_t) 0); | |
968 | cmd.cmd_version = htobe32(0); | |
969 | ||
f79c2d7a FD |
970 | status = lttng_live_send(viewer_connection, &cmd, sizeof(cmd)); |
971 | if (status != LTTNG_LIVE_VIEWER_STATUS_OK) { | |
972 | viewer_handle_send_status(self_comp, self_comp_class, | |
973 | status, "list sessions command"); | |
974 | goto end; | |
7cdc2bab | 975 | } |
7cdc2bab | 976 | |
f79c2d7a FD |
977 | status = lttng_live_recv(viewer_connection, &list, sizeof(list)); |
978 | if (status != LTTNG_LIVE_VIEWER_STATUS_OK) { | |
979 | viewer_handle_recv_status(self_comp, self_comp_class, | |
980 | status, "session list reply"); | |
981 | goto end; | |
7cdc2bab | 982 | } |
7cdc2bab MD |
983 | |
984 | sessions_count = be32toh(list.sessions_count); | |
985 | for (i = 0; i < sessions_count; i++) { | |
f79c2d7a FD |
986 | status = lttng_live_recv(viewer_connection, &lsession, |
987 | sizeof(lsession)); | |
988 | if (status != LTTNG_LIVE_VIEWER_STATUS_OK) { | |
989 | viewer_handle_recv_status(self_comp, self_comp_class, | |
990 | status, "session reply"); | |
991 | goto end; | |
7cdc2bab | 992 | } |
7cdc2bab MD |
993 | lsession.hostname[LTTNG_VIEWER_HOST_NAME_MAX - 1] = '\0'; |
994 | lsession.session_name[LTTNG_VIEWER_NAME_MAX - 1] = '\0'; | |
995 | session_id = be64toh(lsession.id); | |
996 | ||
ecb4ba8a FD |
997 | BT_COMP_LOGI("Adding session to internal list: " |
998 | "session-id=%" PRIu64 ", hostname=\"%s\", session-name=\"%s\"", | |
06994c71 MD |
999 | session_id, lsession.hostname, lsession.session_name); |
1000 | ||
7cdc2bab | 1001 | if ((strncmp(lsession.session_name, |
94b828f3 | 1002 | viewer_connection->session_name->str, |
1cb3cdd7 | 1003 | LTTNG_VIEWER_NAME_MAX) == 0) && (strncmp(lsession.hostname, |
94b828f3 | 1004 | viewer_connection->target_hostname->str, |
1cb3cdd7 | 1005 | LTTNG_VIEWER_HOST_NAME_MAX) == 0)) { |
ecb4ba8a | 1006 | |
14f28187 | 1007 | if (lttng_live_add_session(lttng_live_msg_iter, session_id, |
06994c71 MD |
1008 | lsession.hostname, |
1009 | lsession.session_name)) { | |
1419db2b FD |
1010 | BT_COMP_LOGE_APPEND_CAUSE(self_comp, |
1011 | "Failed to add live session"); | |
f79c2d7a FD |
1012 | status = LTTNG_LIVE_VIEWER_STATUS_ERROR; |
1013 | goto end; | |
7cdc2bab MD |
1014 | } |
1015 | } | |
1016 | } | |
1017 | ||
f79c2d7a | 1018 | status = LTTNG_LIVE_VIEWER_STATUS_OK; |
7cdc2bab | 1019 | |
f79c2d7a FD |
1020 | end: |
1021 | return status; | |
7cdc2bab MD |
1022 | } |
1023 | ||
1024 | BT_HIDDEN | |
f79c2d7a | 1025 | enum lttng_live_viewer_status lttng_live_create_viewer_session( |
14f28187 | 1026 | struct lttng_live_msg_iter *lttng_live_msg_iter) |
7cdc2bab MD |
1027 | { |
1028 | struct lttng_viewer_cmd cmd; | |
1029 | struct lttng_viewer_create_session_response resp; | |
f79c2d7a | 1030 | enum lttng_live_viewer_status status; |
14f28187 | 1031 | struct live_viewer_connection *viewer_connection = |
1419db2b FD |
1032 | lttng_live_msg_iter->viewer_connection; |
1033 | bt_self_component *self_comp = viewer_connection->self_comp; | |
f79c2d7a FD |
1034 | bt_self_component_class *self_comp_class = |
1035 | viewer_connection->self_comp_class; | |
7cdc2bab | 1036 | |
ecb4ba8a | 1037 | BT_COMP_OR_COMP_CLASS_LOGD(self_comp, self_comp_class, |
f93afbf9 FD |
1038 | "Creating a viewer session: cmd=%s", |
1039 | lttng_viewer_command_string(LTTNG_VIEWER_CREATE_SESSION)); | |
ecb4ba8a | 1040 | |
7cdc2bab MD |
1041 | cmd.cmd = htobe32(LTTNG_VIEWER_CREATE_SESSION); |
1042 | cmd.data_size = htobe64((uint64_t) 0); | |
1043 | cmd.cmd_version = htobe32(0); | |
1044 | ||
f79c2d7a FD |
1045 | status = lttng_live_send(viewer_connection, &cmd, sizeof(cmd)); |
1046 | if (status != LTTNG_LIVE_VIEWER_STATUS_OK) { | |
1047 | viewer_handle_send_status(self_comp, self_comp_class, | |
1048 | status, "create session command"); | |
1049 | goto end; | |
7cdc2bab | 1050 | } |
7cdc2bab | 1051 | |
f79c2d7a FD |
1052 | status = lttng_live_recv(viewer_connection, &resp, sizeof(resp)); |
1053 | if (status != LTTNG_LIVE_VIEWER_STATUS_OK) { | |
1054 | viewer_handle_recv_status(self_comp, self_comp_class, | |
1055 | status, "create session reply"); | |
1056 | goto end; | |
7cdc2bab | 1057 | } |
7cdc2bab MD |
1058 | |
1059 | if (be32toh(resp.status) != LTTNG_VIEWER_CREATE_SESSION_OK) { | |
1419db2b FD |
1060 | BT_COMP_LOGE_APPEND_CAUSE(self_comp, |
1061 | "Error creating viewer session"); | |
f79c2d7a FD |
1062 | status = LTTNG_LIVE_VIEWER_STATUS_ERROR; |
1063 | goto end; | |
7cdc2bab | 1064 | } |
f79c2d7a FD |
1065 | |
1066 | status = lttng_live_query_session_ids(lttng_live_msg_iter); | |
1067 | if (status == LTTNG_LIVE_VIEWER_STATUS_ERROR) { | |
1419db2b FD |
1068 | BT_COMP_LOGE_APPEND_CAUSE(self_comp, |
1069 | "Failed to query live viewer session ids"); | |
f79c2d7a FD |
1070 | goto end; |
1071 | } else if (status == LTTNG_LIVE_VIEWER_STATUS_INTERRUPTED) { | |
1072 | goto end; | |
7cdc2bab MD |
1073 | } |
1074 | ||
f79c2d7a FD |
1075 | end: |
1076 | return status; | |
7cdc2bab MD |
1077 | } |
1078 | ||
1079 | static | |
f79c2d7a | 1080 | enum lttng_live_viewer_status receive_streams(struct lttng_live_session *session, |
851de941 SM |
1081 | uint32_t stream_count, |
1082 | bt_self_message_iterator *self_msg_iter) | |
7cdc2bab | 1083 | { |
7cdc2bab | 1084 | uint32_t i; |
14f28187 | 1085 | struct lttng_live_msg_iter *lttng_live_msg_iter = |
0f1979c3 | 1086 | session->lttng_live_msg_iter; |
f79c2d7a | 1087 | enum lttng_live_viewer_status status; |
14f28187 | 1088 | struct live_viewer_connection *viewer_connection = |
0f1979c3 | 1089 | lttng_live_msg_iter->viewer_connection; |
1419db2b | 1090 | bt_self_component *self_comp = viewer_connection->self_comp; |
7cdc2bab | 1091 | |
f93afbf9 | 1092 | BT_COMP_LOGI("Getting %" PRIu32 " new streams", stream_count); |
7cdc2bab MD |
1093 | for (i = 0; i < stream_count; i++) { |
1094 | struct lttng_viewer_stream stream; | |
1095 | struct lttng_live_stream_iterator *live_stream; | |
1096 | uint64_t stream_id; | |
1097 | uint64_t ctf_trace_id; | |
1098 | ||
f79c2d7a FD |
1099 | status = lttng_live_recv(viewer_connection, &stream, |
1100 | sizeof(stream)); | |
1101 | if (status != LTTNG_LIVE_VIEWER_STATUS_OK) { | |
1102 | viewer_handle_recv_status(self_comp, NULL, | |
1103 | status, "stream reply"); | |
1104 | goto end; | |
7cdc2bab | 1105 | } |
7cdc2bab MD |
1106 | stream.path_name[LTTNG_VIEWER_PATH_MAX - 1] = '\0'; |
1107 | stream.channel_name[LTTNG_VIEWER_NAME_MAX - 1] = '\0'; | |
1108 | stream_id = be64toh(stream.id); | |
1109 | ctf_trace_id = be64toh(stream.ctf_trace_id); | |
1110 | ||
1111 | if (stream.metadata_flag) { | |
2ece7dd0 | 1112 | BT_COMP_LOGI(" metadata stream %" PRIu64 " : %s/%s", |
0f1979c3 | 1113 | stream_id, stream.path_name, stream.channel_name); |
7cdc2bab | 1114 | if (lttng_live_metadata_create_stream(session, |
06994c71 MD |
1115 | ctf_trace_id, stream_id, |
1116 | stream.path_name)) { | |
1419db2b FD |
1117 | BT_COMP_LOGE_APPEND_CAUSE(self_comp, |
1118 | "Error creating metadata stream"); | |
f79c2d7a FD |
1119 | status = LTTNG_LIVE_VIEWER_STATUS_ERROR; |
1120 | goto end; | |
7cdc2bab | 1121 | } |
d6e69534 | 1122 | session->lazy_stream_msg_init = true; |
7cdc2bab | 1123 | } else { |
2ece7dd0 | 1124 | BT_COMP_LOGI(" stream %" PRIu64 " : %s/%s", |
0f1979c3 | 1125 | stream_id, stream.path_name, stream.channel_name); |
7cdc2bab | 1126 | live_stream = lttng_live_stream_iterator_create(session, |
851de941 | 1127 | ctf_trace_id, stream_id, self_msg_iter); |
7cdc2bab | 1128 | if (!live_stream) { |
1419db2b FD |
1129 | BT_COMP_LOGE_APPEND_CAUSE(self_comp, |
1130 | "Error creating stream"); | |
f79c2d7a FD |
1131 | status = LTTNG_LIVE_VIEWER_STATUS_ERROR; |
1132 | goto end; | |
7cdc2bab MD |
1133 | } |
1134 | } | |
1135 | } | |
f79c2d7a | 1136 | status = LTTNG_LIVE_VIEWER_STATUS_OK; |
7cdc2bab | 1137 | |
f79c2d7a FD |
1138 | end: |
1139 | return status; | |
7cdc2bab MD |
1140 | } |
1141 | ||
1142 | BT_HIDDEN | |
36e94ad6 | 1143 | enum lttng_live_viewer_status lttng_live_session_attach( |
851de941 SM |
1144 | struct lttng_live_session *session, |
1145 | bt_self_message_iterator *self_msg_iter) | |
7cdc2bab MD |
1146 | { |
1147 | struct lttng_viewer_cmd cmd; | |
f79c2d7a | 1148 | enum lttng_live_viewer_status status; |
7cdc2bab MD |
1149 | struct lttng_viewer_attach_session_request rq; |
1150 | struct lttng_viewer_attach_session_response rp; | |
0f1979c3 FD |
1151 | struct lttng_live_msg_iter *lttng_live_msg_iter = |
1152 | session->lttng_live_msg_iter; | |
14f28187 | 1153 | struct live_viewer_connection *viewer_connection = |
0f1979c3 | 1154 | lttng_live_msg_iter->viewer_connection; |
1419db2b | 1155 | bt_self_component *self_comp = viewer_connection->self_comp; |
7cdc2bab MD |
1156 | uint64_t session_id = session->id; |
1157 | uint32_t streams_count; | |
bdcbd52e JR |
1158 | const size_t cmd_buf_len = sizeof(cmd) + sizeof(rq); |
1159 | char cmd_buf[cmd_buf_len]; | |
7cdc2bab | 1160 | |
f93afbf9 FD |
1161 | BT_COMP_LOGD("Attaching to session: cmd=%s, session-id=%" PRIu64 |
1162 | ", seek=%s", | |
1163 | lttng_viewer_command_string(LTTNG_VIEWER_ATTACH_SESSION), | |
1164 | session_id, | |
1165 | lttng_viewer_seek_string(LTTNG_VIEWER_SEEK_LAST)); | |
ecb4ba8a | 1166 | |
7cdc2bab MD |
1167 | cmd.cmd = htobe32(LTTNG_VIEWER_ATTACH_SESSION); |
1168 | cmd.data_size = htobe64((uint64_t) sizeof(rq)); | |
1169 | cmd.cmd_version = htobe32(0); | |
1170 | ||
1171 | memset(&rq, 0, sizeof(rq)); | |
1172 | rq.session_id = htobe64(session_id); | |
1173 | // TODO: add cmd line parameter to select seek beginning | |
1174 | // rq.seek = htobe32(LTTNG_VIEWER_SEEK_BEGINNING); | |
1175 | rq.seek = htobe32(LTTNG_VIEWER_SEEK_LAST); | |
1176 | ||
bdcbd52e JR |
1177 | /* |
1178 | * Merge the cmd and connection request to prevent a write-write | |
1179 | * sequence on the TCP socket. Otherwise, a delayed ACK will prevent the | |
1180 | * second write to be performed quickly in presence of Nagle's algorithm. | |
1181 | */ | |
1182 | memcpy(cmd_buf, &cmd, sizeof(cmd)); | |
1183 | memcpy(cmd_buf + sizeof(cmd), &rq, sizeof(rq)); | |
f79c2d7a FD |
1184 | status = lttng_live_send(viewer_connection, &cmd_buf, cmd_buf_len); |
1185 | if (status != LTTNG_LIVE_VIEWER_STATUS_OK) { | |
1186 | viewer_handle_send_status(self_comp, NULL, | |
1187 | status, "attach session command"); | |
1188 | goto end; | |
7cdc2bab | 1189 | } |
7cdc2bab | 1190 | |
f79c2d7a FD |
1191 | status = lttng_live_recv(viewer_connection, &rp, sizeof(rp)); |
1192 | if (status != LTTNG_LIVE_VIEWER_STATUS_OK) { | |
1193 | viewer_handle_recv_status(self_comp, NULL, | |
1194 | status, "attach session reply"); | |
1195 | goto end; | |
7cdc2bab | 1196 | } |
7cdc2bab MD |
1197 | |
1198 | streams_count = be32toh(rp.streams_count); | |
1199 | switch(be32toh(rp.status)) { | |
1200 | case LTTNG_VIEWER_ATTACH_OK: | |
1201 | break; | |
1202 | case LTTNG_VIEWER_ATTACH_UNK: | |
1419db2b FD |
1203 | BT_COMP_LOGE_APPEND_CAUSE(self_comp, |
1204 | "Session id %" PRIu64 " is unknown", session_id); | |
f79c2d7a FD |
1205 | status = LTTNG_LIVE_VIEWER_STATUS_ERROR; |
1206 | goto end; | |
7cdc2bab | 1207 | case LTTNG_VIEWER_ATTACH_ALREADY: |
1419db2b FD |
1208 | BT_COMP_LOGE_APPEND_CAUSE(self_comp, |
1209 | "There is already a viewer attached to this session"); | |
f79c2d7a FD |
1210 | status = LTTNG_LIVE_VIEWER_STATUS_ERROR; |
1211 | goto end; | |
7cdc2bab | 1212 | case LTTNG_VIEWER_ATTACH_NOT_LIVE: |
1419db2b | 1213 | BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Not a live session"); |
f79c2d7a FD |
1214 | status = LTTNG_LIVE_VIEWER_STATUS_ERROR; |
1215 | goto end; | |
7cdc2bab | 1216 | case LTTNG_VIEWER_ATTACH_SEEK_ERR: |
1419db2b | 1217 | BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Wrong seek parameter"); |
f79c2d7a FD |
1218 | status = LTTNG_LIVE_VIEWER_STATUS_ERROR; |
1219 | goto end; | |
7cdc2bab | 1220 | default: |
1419db2b FD |
1221 | BT_COMP_LOGE_APPEND_CAUSE(self_comp, |
1222 | "Unknown attach return code %u", be32toh(rp.status)); | |
f79c2d7a FD |
1223 | status = LTTNG_LIVE_VIEWER_STATUS_ERROR; |
1224 | goto end; | |
7cdc2bab MD |
1225 | } |
1226 | ||
1227 | /* We receive the initial list of streams. */ | |
f79c2d7a FD |
1228 | status = receive_streams(session, streams_count, self_msg_iter); |
1229 | switch (status) { | |
1230 | case LTTNG_LIVE_VIEWER_STATUS_OK: | |
1231 | break; | |
1232 | case LTTNG_LIVE_VIEWER_STATUS_INTERRUPTED: | |
1233 | goto end; | |
1234 | case LTTNG_LIVE_VIEWER_STATUS_ERROR: | |
1419db2b | 1235 | BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Error receiving streams"); |
f79c2d7a FD |
1236 | goto end; |
1237 | default: | |
1238 | bt_common_abort(); | |
7cdc2bab MD |
1239 | } |
1240 | ||
1241 | session->attached = true; | |
1242 | session->new_streams_needed = false; | |
1243 | ||
eee8e741 | 1244 | end: |
f79c2d7a | 1245 | return status; |
7cdc2bab MD |
1246 | } |
1247 | ||
1248 | BT_HIDDEN | |
36e94ad6 | 1249 | enum lttng_live_viewer_status lttng_live_session_detach( |
f79c2d7a | 1250 | struct lttng_live_session *session) |
7cdc2bab MD |
1251 | { |
1252 | struct lttng_viewer_cmd cmd; | |
f79c2d7a | 1253 | enum lttng_live_viewer_status status; |
7cdc2bab MD |
1254 | struct lttng_viewer_detach_session_request rq; |
1255 | struct lttng_viewer_detach_session_response rp; | |
0f1979c3 FD |
1256 | struct lttng_live_msg_iter *lttng_live_msg_iter = |
1257 | session->lttng_live_msg_iter; | |
f79c2d7a | 1258 | bt_self_component *self_comp = session->self_comp; |
14f28187 | 1259 | struct live_viewer_connection *viewer_connection = |
0f1979c3 | 1260 | lttng_live_msg_iter->viewer_connection; |
7cdc2bab | 1261 | uint64_t session_id = session->id; |
bdcbd52e JR |
1262 | const size_t cmd_buf_len = sizeof(cmd) + sizeof(rq); |
1263 | char cmd_buf[cmd_buf_len]; | |
7cdc2bab | 1264 | |
b197ca37 FD |
1265 | /* |
1266 | * The session might already be detached and the viewer socket might | |
1267 | * already been closed. This happens when calling this function when | |
1268 | * tearing down the graph after an error. | |
1269 | */ | |
1270 | if (!session->attached || viewer_connection->control_sock == BT_INVALID_SOCKET) { | |
087cd0f5 | 1271 | return LTTNG_LIVE_VIEWER_STATUS_OK; |
7cdc2bab MD |
1272 | } |
1273 | ||
f93afbf9 FD |
1274 | BT_COMP_LOGD("Detaching from session: cmd=%s, session-id=%" PRIu64, |
1275 | lttng_viewer_command_string(LTTNG_VIEWER_DETACH_SESSION), | |
1276 | session_id); | |
1277 | ||
7cdc2bab MD |
1278 | cmd.cmd = htobe32(LTTNG_VIEWER_DETACH_SESSION); |
1279 | cmd.data_size = htobe64((uint64_t) sizeof(rq)); | |
1280 | cmd.cmd_version = htobe32(0); | |
1281 | ||
1282 | memset(&rq, 0, sizeof(rq)); | |
1283 | rq.session_id = htobe64(session_id); | |
1284 | ||
bdcbd52e JR |
1285 | /* |
1286 | * Merge the cmd and connection request to prevent a write-write | |
1287 | * sequence on the TCP socket. Otherwise, a delayed ACK will prevent the | |
1288 | * second write to be performed quickly in presence of Nagle's algorithm. | |
1289 | */ | |
1290 | memcpy(cmd_buf, &cmd, sizeof(cmd)); | |
1291 | memcpy(cmd_buf + sizeof(cmd), &rq, sizeof(rq)); | |
f79c2d7a FD |
1292 | status = lttng_live_send(viewer_connection, &cmd_buf, cmd_buf_len); |
1293 | if (status != LTTNG_LIVE_VIEWER_STATUS_OK) { | |
1294 | viewer_handle_send_status(self_comp, NULL, | |
1295 | status, "detach session command"); | |
1296 | goto end; | |
7cdc2bab | 1297 | } |
7cdc2bab | 1298 | |
f79c2d7a FD |
1299 | status = lttng_live_recv(viewer_connection, &rp, sizeof(rp)); |
1300 | if (status != LTTNG_LIVE_VIEWER_STATUS_OK) { | |
1301 | viewer_handle_recv_status(self_comp, NULL, | |
1302 | status, "detach session reply"); | |
1303 | goto end; | |
7cdc2bab | 1304 | } |
7cdc2bab MD |
1305 | |
1306 | switch(be32toh(rp.status)) { | |
1307 | case LTTNG_VIEWER_DETACH_SESSION_OK: | |
1308 | break; | |
1309 | case LTTNG_VIEWER_DETACH_SESSION_UNK: | |
2ece7dd0 | 1310 | BT_COMP_LOGW("Session id %" PRIu64 " is unknown", session_id); |
f79c2d7a FD |
1311 | status = LTTNG_LIVE_VIEWER_STATUS_ERROR; |
1312 | goto end; | |
7cdc2bab | 1313 | case LTTNG_VIEWER_DETACH_SESSION_ERR: |
2ece7dd0 | 1314 | BT_COMP_LOGW("Error detaching session id %" PRIu64 "", session_id); |
f79c2d7a FD |
1315 | status = LTTNG_LIVE_VIEWER_STATUS_ERROR; |
1316 | goto end; | |
7cdc2bab | 1317 | default: |
2ece7dd0 | 1318 | BT_COMP_LOGE("Unknown detach return code %u", be32toh(rp.status)); |
f79c2d7a FD |
1319 | status = LTTNG_LIVE_VIEWER_STATUS_ERROR; |
1320 | goto end; | |
7cdc2bab MD |
1321 | } |
1322 | ||
1323 | session->attached = false; | |
1324 | ||
f79c2d7a | 1325 | status = LTTNG_LIVE_VIEWER_STATUS_OK; |
7cdc2bab | 1326 | |
f79c2d7a FD |
1327 | end: |
1328 | return status; | |
7cdc2bab MD |
1329 | } |
1330 | ||
1331 | BT_HIDDEN | |
c28512ab FD |
1332 | enum lttng_live_get_one_metadata_status lttng_live_get_one_metadata_packet( |
1333 | struct lttng_live_trace *trace, FILE *fp, size_t *reply_len) | |
7cdc2bab MD |
1334 | { |
1335 | uint64_t len = 0; | |
f79c2d7a FD |
1336 | enum lttng_live_get_one_metadata_status status; |
1337 | enum lttng_live_viewer_status viewer_status; | |
7cdc2bab MD |
1338 | struct lttng_viewer_cmd cmd; |
1339 | struct lttng_viewer_get_metadata rq; | |
1340 | struct lttng_viewer_metadata_packet rp; | |
b7370030 | 1341 | gchar *data = NULL; |
0e73b4c2 | 1342 | ssize_t writelen; |
7cdc2bab | 1343 | struct lttng_live_session *session = trace->session; |
0f1979c3 FD |
1344 | struct lttng_live_msg_iter *lttng_live_msg_iter = |
1345 | session->lttng_live_msg_iter; | |
7cdc2bab | 1346 | struct lttng_live_metadata *metadata = trace->metadata; |
14f28187 | 1347 | struct live_viewer_connection *viewer_connection = |
0f1979c3 | 1348 | lttng_live_msg_iter->viewer_connection; |
1419db2b | 1349 | bt_self_component *self_comp = viewer_connection->self_comp; |
bdcbd52e JR |
1350 | const size_t cmd_buf_len = sizeof(cmd) + sizeof(rq); |
1351 | char cmd_buf[cmd_buf_len]; | |
7cdc2bab | 1352 | |
f93afbf9 FD |
1353 | BT_COMP_LOGD("Requesting new metadata for trace:" |
1354 | "cmd=%s, trace-id=%" PRIu64 ", metadata-stream-id=%" PRIu64, | |
1355 | lttng_viewer_command_string(LTTNG_VIEWER_GET_METADATA), | |
ecb4ba8a FD |
1356 | trace->id, metadata->stream_id); |
1357 | ||
7cdc2bab MD |
1358 | rq.stream_id = htobe64(metadata->stream_id); |
1359 | cmd.cmd = htobe32(LTTNG_VIEWER_GET_METADATA); | |
1360 | cmd.data_size = htobe64((uint64_t) sizeof(rq)); | |
1361 | cmd.cmd_version = htobe32(0); | |
1362 | ||
bdcbd52e JR |
1363 | /* |
1364 | * Merge the cmd and connection request to prevent a write-write | |
1365 | * sequence on the TCP socket. Otherwise, a delayed ACK will prevent the | |
1366 | * second write to be performed quickly in presence of Nagle's algorithm. | |
1367 | */ | |
1368 | memcpy(cmd_buf, &cmd, sizeof(cmd)); | |
1369 | memcpy(cmd_buf + sizeof(cmd), &rq, sizeof(rq)); | |
f79c2d7a FD |
1370 | viewer_status = lttng_live_send(viewer_connection, &cmd_buf, cmd_buf_len); |
1371 | if (viewer_status != LTTNG_LIVE_VIEWER_STATUS_OK) { | |
1372 | viewer_handle_send_status(self_comp, NULL, | |
1373 | viewer_status, "get metadata command"); | |
1374 | status = (enum lttng_live_get_one_metadata_status) viewer_status; | |
1375 | goto end; | |
7cdc2bab | 1376 | } |
7cdc2bab | 1377 | |
f79c2d7a FD |
1378 | viewer_status = lttng_live_recv(viewer_connection, &rp, sizeof(rp)); |
1379 | if (viewer_status != LTTNG_LIVE_VIEWER_STATUS_OK) { | |
1380 | viewer_handle_recv_status(self_comp, NULL, | |
1381 | viewer_status, "get metadata reply"); | |
1382 | status = (enum lttng_live_get_one_metadata_status) viewer_status; | |
1383 | goto end; | |
7cdc2bab | 1384 | } |
7cdc2bab MD |
1385 | |
1386 | switch (be32toh(rp.status)) { | |
1387 | case LTTNG_VIEWER_METADATA_OK: | |
1419db2b | 1388 | BT_COMP_LOGD("Received get_metadata response: ok"); |
7cdc2bab MD |
1389 | break; |
1390 | case LTTNG_VIEWER_NO_NEW_METADATA: | |
c28512ab | 1391 | BT_COMP_LOGD("Received get_metadata response: no new"); |
f79c2d7a | 1392 | status = LTTNG_LIVE_GET_ONE_METADATA_STATUS_END; |
7cdc2bab MD |
1393 | goto end; |
1394 | case LTTNG_VIEWER_METADATA_ERR: | |
c28512ab FD |
1395 | /* |
1396 | * The Relayd cannot find this stream id. Maybe its | |
1397 | * gone already. This can happen in short lived UST app | |
1398 | * in a per-pid session. | |
1399 | */ | |
1400 | BT_COMP_LOGD("Received get_metadata response: error"); | |
f79c2d7a | 1401 | status = LTTNG_LIVE_GET_ONE_METADATA_STATUS_CLOSED; |
c28512ab | 1402 | goto end; |
7cdc2bab | 1403 | default: |
1419db2b FD |
1404 | BT_COMP_LOGE_APPEND_CAUSE(self_comp, |
1405 | "Received get_metadata response: unknown"); | |
f79c2d7a | 1406 | status = LTTNG_LIVE_GET_ONE_METADATA_STATUS_ERROR; |
b7370030 | 1407 | goto end; |
7cdc2bab MD |
1408 | } |
1409 | ||
1410 | len = be64toh(rp.len); | |
2ece7dd0 | 1411 | BT_COMP_LOGD("Writing %" PRIu64" bytes to metadata", len); |
7cdc2bab | 1412 | if (len <= 0) { |
1419db2b FD |
1413 | BT_COMP_LOGE_APPEND_CAUSE(self_comp, |
1414 | "Erroneous response length"); | |
f79c2d7a | 1415 | status = LTTNG_LIVE_GET_ONE_METADATA_STATUS_ERROR; |
b7370030 | 1416 | goto end; |
7cdc2bab MD |
1417 | } |
1418 | ||
b7370030 | 1419 | data = g_new0(gchar, len); |
7cdc2bab | 1420 | if (!data) { |
1419db2b FD |
1421 | BT_COMP_LOGE_APPEND_CAUSE_ERRNO(self_comp, |
1422 | "Failed to allocate data buffer", "."); | |
f79c2d7a | 1423 | status = LTTNG_LIVE_GET_ONE_METADATA_STATUS_ERROR; |
b7370030 | 1424 | goto end; |
7cdc2bab | 1425 | } |
f79c2d7a FD |
1426 | |
1427 | viewer_status = lttng_live_recv(viewer_connection, data, len); | |
1428 | if (viewer_status != LTTNG_LIVE_VIEWER_STATUS_OK) { | |
1429 | viewer_handle_recv_status(self_comp, NULL, | |
1430 | viewer_status, "get metadata packet"); | |
1431 | status = (enum lttng_live_get_one_metadata_status) viewer_status; | |
b7370030 | 1432 | goto end; |
7cdc2bab | 1433 | } |
7cdc2bab | 1434 | |
f79c2d7a FD |
1435 | /* |
1436 | * Write the metadata to the file handle. | |
1437 | */ | |
0e73b4c2 FD |
1438 | writelen = fwrite(data, sizeof(uint8_t), len, fp); |
1439 | if (writelen != len) { | |
1419db2b FD |
1440 | BT_COMP_LOGE_APPEND_CAUSE(self_comp, |
1441 | "Writing in the metadata file stream"); | |
f79c2d7a | 1442 | status = LTTNG_LIVE_GET_ONE_METADATA_STATUS_ERROR; |
b7370030 | 1443 | goto end; |
7cdc2bab | 1444 | } |
0e73b4c2 | 1445 | |
c28512ab | 1446 | *reply_len = len; |
f79c2d7a | 1447 | status = LTTNG_LIVE_GET_ONE_METADATA_STATUS_OK; |
c28512ab | 1448 | |
c28512ab | 1449 | end: |
b7370030 | 1450 | g_free(data); |
f79c2d7a | 1451 | return status; |
7cdc2bab MD |
1452 | } |
1453 | ||
1454 | /* | |
1455 | * Assign the fields from a lttng_viewer_index to a packet_index. | |
1456 | */ | |
1457 | static | |
1458 | void lttng_index_to_packet_index(struct lttng_viewer_index *lindex, | |
1459 | struct packet_index *pindex) | |
1460 | { | |
f6ccaed9 PP |
1461 | BT_ASSERT(lindex); |
1462 | BT_ASSERT(pindex); | |
7cdc2bab MD |
1463 | |
1464 | pindex->offset = be64toh(lindex->offset); | |
1465 | pindex->packet_size = be64toh(lindex->packet_size); | |
1466 | pindex->content_size = be64toh(lindex->content_size); | |
1467 | pindex->ts_cycles.timestamp_begin = be64toh(lindex->timestamp_begin); | |
1468 | pindex->ts_cycles.timestamp_end = be64toh(lindex->timestamp_end); | |
1469 | pindex->events_discarded = be64toh(lindex->events_discarded); | |
1470 | } | |
1471 | ||
36e94ad6 FD |
1472 | static |
1473 | void lttng_live_need_new_streams(struct lttng_live_msg_iter *lttng_live_msg_iter) | |
1474 | { | |
1475 | uint64_t session_idx; | |
f93afbf9 FD |
1476 | struct live_viewer_connection *viewer_connection = |
1477 | lttng_live_msg_iter->viewer_connection; | |
36e94ad6 FD |
1478 | |
1479 | for (session_idx = 0; session_idx < lttng_live_msg_iter->sessions->len; | |
1480 | session_idx++) { | |
1481 | struct lttng_live_session *session = | |
087cd0f5 | 1482 | (lttng_live_session *) g_ptr_array_index(lttng_live_msg_iter->sessions, session_idx); |
f93afbf9 FD |
1483 | BT_COMP_LOGD("Marking session as needing new streams: " |
1484 | "session-id=%" PRIu64, session->id); | |
36e94ad6 FD |
1485 | session->new_streams_needed = true; |
1486 | } | |
1487 | } | |
1488 | ||
7cdc2bab | 1489 | BT_HIDDEN |
14f28187 FD |
1490 | enum lttng_live_iterator_status lttng_live_get_next_index( |
1491 | struct lttng_live_msg_iter *lttng_live_msg_iter, | |
7cdc2bab MD |
1492 | struct lttng_live_stream_iterator *stream, |
1493 | struct packet_index *index) | |
1494 | { | |
1495 | struct lttng_viewer_cmd cmd; | |
1496 | struct lttng_viewer_get_next_index rq; | |
f79c2d7a | 1497 | enum lttng_live_viewer_status viewer_status; |
7cdc2bab | 1498 | struct lttng_viewer_index rp; |
f79c2d7a | 1499 | enum lttng_live_iterator_status status; |
14f28187 | 1500 | struct live_viewer_connection *viewer_connection = |
1419db2b FD |
1501 | lttng_live_msg_iter->viewer_connection; |
1502 | bt_self_component *self_comp = viewer_connection->self_comp; | |
7cdc2bab | 1503 | struct lttng_live_trace *trace = stream->trace; |
bdcbd52e JR |
1504 | const size_t cmd_buf_len = sizeof(cmd) + sizeof(rq); |
1505 | char cmd_buf[cmd_buf_len]; | |
f79c2d7a | 1506 | uint32_t flags, rp_status; |
7cdc2bab | 1507 | |
f93afbf9 FD |
1508 | BT_COMP_LOGD("Requesting next index for stream: cmd=%s, " |
1509 | "viewer-stream-id=%" PRIu64, | |
1510 | lttng_viewer_command_string(LTTNG_VIEWER_GET_NEXT_INDEX), | |
1511 | stream->viewer_stream_id); | |
7cdc2bab MD |
1512 | cmd.cmd = htobe32(LTTNG_VIEWER_GET_NEXT_INDEX); |
1513 | cmd.data_size = htobe64((uint64_t) sizeof(rq)); | |
1514 | cmd.cmd_version = htobe32(0); | |
1515 | ||
1516 | memset(&rq, 0, sizeof(rq)); | |
1517 | rq.stream_id = htobe64(stream->viewer_stream_id); | |
1518 | ||
bdcbd52e JR |
1519 | /* |
1520 | * Merge the cmd and connection request to prevent a write-write | |
1521 | * sequence on the TCP socket. Otherwise, a delayed ACK will prevent the | |
1522 | * second write to be performed quickly in presence of Nagle's algorithm. | |
1523 | */ | |
1524 | memcpy(cmd_buf, &cmd, sizeof(cmd)); | |
1525 | memcpy(cmd_buf + sizeof(cmd), &rq, sizeof(rq)); | |
f93afbf9 | 1526 | |
f79c2d7a FD |
1527 | viewer_status = lttng_live_send(viewer_connection, &cmd_buf, cmd_buf_len); |
1528 | if (viewer_status != LTTNG_LIVE_VIEWER_STATUS_OK) { | |
1529 | viewer_handle_send_status(self_comp, NULL, | |
1530 | viewer_status, "get next index command"); | |
7cdc2bab MD |
1531 | goto error; |
1532 | } | |
7cdc2bab | 1533 | |
f79c2d7a FD |
1534 | viewer_status = lttng_live_recv(viewer_connection, &rp, sizeof(rp)); |
1535 | if (viewer_status != LTTNG_LIVE_VIEWER_STATUS_OK) { | |
1536 | viewer_handle_recv_status(self_comp, NULL, | |
1537 | viewer_status, "get next index reply"); | |
7cdc2bab MD |
1538 | goto error; |
1539 | } | |
7cdc2bab MD |
1540 | |
1541 | flags = be32toh(rp.flags); | |
f79c2d7a | 1542 | rp_status = be32toh(rp.status); |
7cdc2bab | 1543 | |
f93afbf9 FD |
1544 | BT_COMP_LOGD("Received response from relay daemon: cmd=%s, response=%s", |
1545 | lttng_viewer_command_string(LTTNG_VIEWER_GET_NEXT_INDEX), | |
1546 | lttng_viewer_next_index_return_code_string(rp_status)); | |
f79c2d7a | 1547 | switch (rp_status) { |
7cdc2bab MD |
1548 | case LTTNG_VIEWER_INDEX_INACTIVE: |
1549 | { | |
1550 | uint64_t ctf_stream_class_id; | |
1551 | ||
7cdc2bab MD |
1552 | memset(index, 0, sizeof(struct packet_index)); |
1553 | index->ts_cycles.timestamp_end = be64toh(rp.timestamp_end); | |
14f28187 | 1554 | stream->current_inactivity_ts = index->ts_cycles.timestamp_end; |
7cdc2bab | 1555 | ctf_stream_class_id = be64toh(rp.stream_id); |
1a258819 FD |
1556 | if (stream->ctf_stream_class_id.is_set) { |
1557 | BT_ASSERT(stream->ctf_stream_class_id.value== | |
7cdc2bab MD |
1558 | ctf_stream_class_id); |
1559 | } else { | |
1a258819 FD |
1560 | stream->ctf_stream_class_id.value = ctf_stream_class_id; |
1561 | stream->ctf_stream_class_id.is_set = true; | |
7cdc2bab | 1562 | } |
34533ae0 | 1563 | lttng_live_stream_iterator_set_state(stream, LTTNG_LIVE_STREAM_QUIESCENT); |
f79c2d7a | 1564 | status = LTTNG_LIVE_ITERATOR_STATUS_OK; |
7cdc2bab MD |
1565 | break; |
1566 | } | |
1567 | case LTTNG_VIEWER_INDEX_OK: | |
1568 | { | |
1569 | uint64_t ctf_stream_class_id; | |
1570 | ||
7cdc2bab MD |
1571 | lttng_index_to_packet_index(&rp, index); |
1572 | ctf_stream_class_id = be64toh(rp.stream_id); | |
1a258819 FD |
1573 | if (stream->ctf_stream_class_id.is_set) { |
1574 | BT_ASSERT(stream->ctf_stream_class_id.value== | |
7cdc2bab MD |
1575 | ctf_stream_class_id); |
1576 | } else { | |
1a258819 FD |
1577 | stream->ctf_stream_class_id.value = ctf_stream_class_id; |
1578 | stream->ctf_stream_class_id.is_set = true; | |
7cdc2bab MD |
1579 | } |
1580 | ||
34533ae0 | 1581 | lttng_live_stream_iterator_set_state(stream, LTTNG_LIVE_STREAM_ACTIVE_DATA); |
7cdc2bab MD |
1582 | |
1583 | if (flags & LTTNG_VIEWER_FLAG_NEW_METADATA) { | |
f93afbf9 FD |
1584 | BT_COMP_LOGD("Marking trace as needing new metadata: " |
1585 | "response=%s, response-flag=NEW_METADATA, trace-id=%" PRIu64, | |
1586 | lttng_viewer_next_index_return_code_string(rp_status), | |
1587 | trace->id); | |
76bbaebc | 1588 | trace->metadata_stream_state = LTTNG_LIVE_METADATA_STREAM_STATE_NEEDED; |
7cdc2bab MD |
1589 | } |
1590 | if (flags & LTTNG_VIEWER_FLAG_NEW_STREAM) { | |
f93afbf9 FD |
1591 | BT_COMP_LOGD("Marking all sessions as possibly needing new streams: " |
1592 | "response=%s, response-flag=NEW_STREAM", | |
1593 | lttng_viewer_next_index_return_code_string(rp_status)); | |
14f28187 | 1594 | lttng_live_need_new_streams(lttng_live_msg_iter); |
7cdc2bab | 1595 | } |
f79c2d7a | 1596 | status = LTTNG_LIVE_ITERATOR_STATUS_OK; |
7cdc2bab MD |
1597 | break; |
1598 | } | |
1599 | case LTTNG_VIEWER_INDEX_RETRY: | |
7cdc2bab | 1600 | memset(index, 0, sizeof(struct packet_index)); |
34533ae0 | 1601 | lttng_live_stream_iterator_set_state(stream, LTTNG_LIVE_STREAM_ACTIVE_NO_DATA); |
f79c2d7a | 1602 | status = LTTNG_LIVE_ITERATOR_STATUS_AGAIN; |
7cdc2bab MD |
1603 | goto end; |
1604 | case LTTNG_VIEWER_INDEX_HUP: | |
7cdc2bab MD |
1605 | memset(index, 0, sizeof(struct packet_index)); |
1606 | index->offset = EOF; | |
34533ae0 | 1607 | lttng_live_stream_iterator_set_state(stream, LTTNG_LIVE_STREAM_EOF); |
4a39caef | 1608 | stream->has_stream_hung_up = true; |
f79c2d7a | 1609 | status = LTTNG_LIVE_ITERATOR_STATUS_END; |
7cdc2bab MD |
1610 | break; |
1611 | case LTTNG_VIEWER_INDEX_ERR: | |
7cdc2bab | 1612 | memset(index, 0, sizeof(struct packet_index)); |
34533ae0 | 1613 | lttng_live_stream_iterator_set_state(stream, LTTNG_LIVE_STREAM_ACTIVE_NO_DATA); |
f79c2d7a FD |
1614 | status = LTTNG_LIVE_ITERATOR_STATUS_ERROR; |
1615 | goto end; | |
7cdc2bab | 1616 | default: |
1419db2b | 1617 | BT_COMP_LOGD("Received get_next_index response: unknown value"); |
7cdc2bab | 1618 | memset(index, 0, sizeof(struct packet_index)); |
34533ae0 | 1619 | lttng_live_stream_iterator_set_state(stream, LTTNG_LIVE_STREAM_ACTIVE_NO_DATA); |
f79c2d7a FD |
1620 | status = LTTNG_LIVE_ITERATOR_STATUS_ERROR; |
1621 | goto end; | |
7cdc2bab | 1622 | } |
f79c2d7a | 1623 | goto end; |
7cdc2bab MD |
1624 | |
1625 | error: | |
f79c2d7a FD |
1626 | status = viewer_status_to_live_iterator_status(viewer_status); |
1627 | end: | |
1628 | return status; | |
7cdc2bab MD |
1629 | } |
1630 | ||
1631 | BT_HIDDEN | |
18a1979b | 1632 | enum ctf_msg_iter_medium_status lttng_live_get_stream_bytes( |
14f28187 FD |
1633 | struct lttng_live_msg_iter *lttng_live_msg_iter, |
1634 | struct lttng_live_stream_iterator *stream, uint8_t *buf, | |
1635 | uint64_t offset, uint64_t req_len, uint64_t *recv_len) | |
7cdc2bab | 1636 | { |
f79c2d7a FD |
1637 | enum ctf_msg_iter_medium_status status; |
1638 | enum lttng_live_viewer_status viewer_status; | |
0f1979c3 | 1639 | struct lttng_viewer_trace_packet rp; |
7cdc2bab MD |
1640 | struct lttng_viewer_cmd cmd; |
1641 | struct lttng_viewer_get_packet rq; | |
14f28187 | 1642 | struct live_viewer_connection *viewer_connection = |
1419db2b FD |
1643 | lttng_live_msg_iter->viewer_connection; |
1644 | bt_self_component *self_comp = viewer_connection->self_comp; | |
7cdc2bab | 1645 | struct lttng_live_trace *trace = stream->trace; |
bdcbd52e JR |
1646 | const size_t cmd_buf_len = sizeof(cmd) + sizeof(rq); |
1647 | char cmd_buf[cmd_buf_len]; | |
f79c2d7a | 1648 | uint32_t flags, rp_status; |
7cdc2bab | 1649 | |
f93afbf9 FD |
1650 | BT_COMP_LOGD("Requesting data from stream: cmd=%s, " |
1651 | "offset=%" PRIu64 ", request-len=%" PRIu64, | |
1652 | lttng_viewer_command_string(LTTNG_VIEWER_GET_PACKET), | |
7cdc2bab | 1653 | offset, req_len); |
f93afbf9 | 1654 | |
7cdc2bab MD |
1655 | cmd.cmd = htobe32(LTTNG_VIEWER_GET_PACKET); |
1656 | cmd.data_size = htobe64((uint64_t) sizeof(rq)); | |
1657 | cmd.cmd_version = htobe32(0); | |
1658 | ||
1659 | memset(&rq, 0, sizeof(rq)); | |
1660 | rq.stream_id = htobe64(stream->viewer_stream_id); | |
1661 | rq.offset = htobe64(offset); | |
1662 | rq.len = htobe32(req_len); | |
1663 | ||
bdcbd52e JR |
1664 | /* |
1665 | * Merge the cmd and connection request to prevent a write-write | |
1666 | * sequence on the TCP socket. Otherwise, a delayed ACK will prevent the | |
1667 | * second write to be performed quickly in presence of Nagle's algorithm. | |
1668 | */ | |
1669 | memcpy(cmd_buf, &cmd, sizeof(cmd)); | |
1670 | memcpy(cmd_buf + sizeof(cmd), &rq, sizeof(rq)); | |
f93afbf9 | 1671 | |
f79c2d7a FD |
1672 | viewer_status = lttng_live_send(viewer_connection, &cmd_buf, cmd_buf_len); |
1673 | if (viewer_status != LTTNG_LIVE_VIEWER_STATUS_OK) { | |
1674 | viewer_handle_send_status(self_comp, NULL, | |
1675 | viewer_status, "get data packet command"); | |
535fb48a | 1676 | goto error_convert_status; |
7cdc2bab | 1677 | } |
7cdc2bab | 1678 | |
f79c2d7a FD |
1679 | viewer_status = lttng_live_recv(viewer_connection, &rp, sizeof(rp)); |
1680 | if (viewer_status != LTTNG_LIVE_VIEWER_STATUS_OK) { | |
1681 | viewer_handle_recv_status(self_comp, NULL, | |
1682 | viewer_status, "get data packet reply"); | |
535fb48a | 1683 | goto error_convert_status; |
7cdc2bab MD |
1684 | } |
1685 | ||
1686 | flags = be32toh(rp.flags); | |
f79c2d7a | 1687 | rp_status = be32toh(rp.status); |
7cdc2bab | 1688 | |
f93afbf9 FD |
1689 | BT_COMP_LOGD("Received response from relay daemon: cmd=%s, response=%s", |
1690 | lttng_viewer_command_string(LTTNG_VIEWER_GET_PACKET), | |
1691 | lttng_viewer_get_packet_return_code_string(rp_status)); | |
f79c2d7a | 1692 | switch (rp_status) { |
7cdc2bab MD |
1693 | case LTTNG_VIEWER_GET_PACKET_OK: |
1694 | req_len = be32toh(rp.len); | |
f93afbf9 FD |
1695 | BT_COMP_LOGD("Got packet from relay daemon: response=%s, packet-len=%" PRIu64 "", |
1696 | lttng_viewer_get_packet_return_code_string(rp_status), | |
1697 | req_len); | |
f79c2d7a | 1698 | status = CTF_MSG_ITER_MEDIUM_STATUS_OK; |
7cdc2bab MD |
1699 | break; |
1700 | case LTTNG_VIEWER_GET_PACKET_RETRY: | |
1701 | /* Unimplemented by relay daemon */ | |
f79c2d7a | 1702 | status = CTF_MSG_ITER_MEDIUM_STATUS_AGAIN; |
7cdc2bab MD |
1703 | goto end; |
1704 | case LTTNG_VIEWER_GET_PACKET_ERR: | |
1705 | if (flags & LTTNG_VIEWER_FLAG_NEW_METADATA) { | |
f93afbf9 FD |
1706 | BT_COMP_LOGD("Marking trace as needing new metadata: " |
1707 | "response=%s, response-flag=NEW_METADATA, trace-id=%" PRIu64, | |
1708 | lttng_viewer_next_index_return_code_string(rp_status), | |
1709 | trace->id); | |
76bbaebc | 1710 | trace->metadata_stream_state = LTTNG_LIVE_METADATA_STREAM_STATE_NEEDED; |
7cdc2bab MD |
1711 | } |
1712 | if (flags & LTTNG_VIEWER_FLAG_NEW_STREAM) { | |
f93afbf9 FD |
1713 | BT_COMP_LOGD("Marking all sessions as possibly needing new streams: " |
1714 | "response=%s, response-flag=NEW_STREAM", | |
1715 | lttng_viewer_next_index_return_code_string(rp_status)); | |
14f28187 | 1716 | lttng_live_need_new_streams(lttng_live_msg_iter); |
7cdc2bab MD |
1717 | } |
1718 | if (flags & (LTTNG_VIEWER_FLAG_NEW_METADATA | |
1719 | | LTTNG_VIEWER_FLAG_NEW_STREAM)) { | |
f79c2d7a | 1720 | status = CTF_MSG_ITER_MEDIUM_STATUS_AGAIN; |
f93afbf9 FD |
1721 | BT_COMP_LOGD("Reply with any one flags set means we should retry: response=%s", |
1722 | lttng_viewer_get_packet_return_code_string(rp_status)); | |
7cdc2bab MD |
1723 | goto end; |
1724 | } | |
1419db2b FD |
1725 | BT_COMP_LOGE_APPEND_CAUSE(self_comp, |
1726 | "Received get_data_packet response: error"); | |
f79c2d7a FD |
1727 | status = CTF_MSG_ITER_MEDIUM_STATUS_ERROR; |
1728 | goto end; | |
7cdc2bab | 1729 | case LTTNG_VIEWER_GET_PACKET_EOF: |
f79c2d7a | 1730 | status = CTF_MSG_ITER_MEDIUM_STATUS_EOF; |
7cdc2bab MD |
1731 | goto end; |
1732 | default: | |
1419db2b | 1733 | BT_COMP_LOGE_APPEND_CAUSE(self_comp, |
535fb48a | 1734 | "Received get_data_packet response: unknown (%d)", rp_status); |
f79c2d7a | 1735 | status = CTF_MSG_ITER_MEDIUM_STATUS_ERROR; |
535fb48a | 1736 | goto end; |
7cdc2bab MD |
1737 | } |
1738 | ||
1739 | if (req_len == 0) { | |
f79c2d7a | 1740 | status = CTF_MSG_ITER_MEDIUM_STATUS_ERROR; |
535fb48a | 1741 | goto end; |
7cdc2bab MD |
1742 | } |
1743 | ||
f79c2d7a FD |
1744 | viewer_status = lttng_live_recv(viewer_connection, buf, req_len); |
1745 | if (viewer_status != LTTNG_LIVE_VIEWER_STATUS_OK) { | |
1746 | viewer_handle_recv_status(self_comp, NULL, | |
1747 | viewer_status, "get data packet"); | |
535fb48a | 1748 | goto error_convert_status; |
7cdc2bab | 1749 | } |
f79c2d7a | 1750 | *recv_len = req_len; |
7cdc2bab | 1751 | |
f79c2d7a FD |
1752 | status = CTF_MSG_ITER_MEDIUM_STATUS_OK; |
1753 | goto end; | |
f79c2d7a | 1754 | |
535fb48a | 1755 | error_convert_status: |
f79c2d7a FD |
1756 | status = viewer_status_to_ctf_msg_iter_medium_status(viewer_status); |
1757 | end: | |
1758 | return status; | |
7cdc2bab MD |
1759 | } |
1760 | ||
1761 | /* | |
1762 | * Request new streams for a session. | |
1763 | */ | |
1764 | BT_HIDDEN | |
36e94ad6 | 1765 | enum lttng_live_iterator_status lttng_live_session_get_new_streams( |
851de941 SM |
1766 | struct lttng_live_session *session, |
1767 | bt_self_message_iterator *self_msg_iter) | |
7cdc2bab | 1768 | { |
14f28187 FD |
1769 | enum lttng_live_iterator_status status = |
1770 | LTTNG_LIVE_ITERATOR_STATUS_OK; | |
7cdc2bab MD |
1771 | struct lttng_viewer_cmd cmd; |
1772 | struct lttng_viewer_new_streams_request rq; | |
1773 | struct lttng_viewer_new_streams_response rp; | |
14f28187 FD |
1774 | struct lttng_live_msg_iter *lttng_live_msg_iter = |
1775 | session->lttng_live_msg_iter; | |
f79c2d7a | 1776 | enum lttng_live_viewer_status viewer_status; |
14f28187 FD |
1777 | struct live_viewer_connection *viewer_connection = |
1778 | lttng_live_msg_iter->viewer_connection; | |
1419db2b | 1779 | bt_self_component *self_comp = viewer_connection->self_comp; |
7cdc2bab | 1780 | uint32_t streams_count; |
bdcbd52e JR |
1781 | const size_t cmd_buf_len = sizeof(cmd) + sizeof(rq); |
1782 | char cmd_buf[cmd_buf_len]; | |
7cdc2bab MD |
1783 | |
1784 | if (!session->new_streams_needed) { | |
f79c2d7a FD |
1785 | status = LTTNG_LIVE_ITERATOR_STATUS_OK; |
1786 | goto end; | |
7cdc2bab MD |
1787 | } |
1788 | ||
0c4e4aa8 | 1789 | BT_COMP_LOGD("Requesting new streams for session: cmd=%s, " |
f93afbf9 FD |
1790 | "session-id=%" PRIu64, |
1791 | lttng_viewer_command_string(LTTNG_VIEWER_GET_NEW_STREAMS), | |
1792 | session->id); | |
ecb4ba8a | 1793 | |
7cdc2bab MD |
1794 | cmd.cmd = htobe32(LTTNG_VIEWER_GET_NEW_STREAMS); |
1795 | cmd.data_size = htobe64((uint64_t) sizeof(rq)); | |
1796 | cmd.cmd_version = htobe32(0); | |
1797 | ||
1798 | memset(&rq, 0, sizeof(rq)); | |
1799 | rq.session_id = htobe64(session->id); | |
1800 | ||
bdcbd52e JR |
1801 | /* |
1802 | * Merge the cmd and connection request to prevent a write-write | |
1803 | * sequence on the TCP socket. Otherwise, a delayed ACK will prevent the | |
1804 | * second write to be performed quickly in presence of Nagle's algorithm. | |
1805 | */ | |
1806 | memcpy(cmd_buf, &cmd, sizeof(cmd)); | |
1807 | memcpy(cmd_buf + sizeof(cmd), &rq, sizeof(rq)); | |
f93afbf9 | 1808 | |
f79c2d7a FD |
1809 | viewer_status = lttng_live_send(viewer_connection, &cmd_buf, cmd_buf_len); |
1810 | if (viewer_status != LTTNG_LIVE_VIEWER_STATUS_OK) { | |
1811 | viewer_handle_send_status(self_comp, NULL, | |
1812 | viewer_status, "get new streams command"); | |
1813 | status = viewer_status_to_live_iterator_status(viewer_status); | |
1814 | goto end; | |
7cdc2bab | 1815 | } |
7cdc2bab | 1816 | |
f79c2d7a FD |
1817 | viewer_status = lttng_live_recv(viewer_connection, &rp, sizeof(rp)); |
1818 | if (viewer_status != LTTNG_LIVE_VIEWER_STATUS_OK) { | |
1819 | viewer_handle_recv_status(self_comp, NULL, | |
1820 | viewer_status, "get new streams reply"); | |
1821 | status = viewer_status_to_live_iterator_status(viewer_status); | |
1822 | goto end; | |
7cdc2bab | 1823 | } |
7cdc2bab MD |
1824 | |
1825 | streams_count = be32toh(rp.streams_count); | |
1826 | ||
1827 | switch(be32toh(rp.status)) { | |
1828 | case LTTNG_VIEWER_NEW_STREAMS_OK: | |
1829 | session->new_streams_needed = false; | |
1830 | break; | |
1831 | case LTTNG_VIEWER_NEW_STREAMS_NO_NEW: | |
1832 | session->new_streams_needed = false; | |
1833 | goto end; | |
1834 | case LTTNG_VIEWER_NEW_STREAMS_HUP: | |
1835 | session->new_streams_needed = false; | |
1836 | session->closed = true; | |
14f28187 | 1837 | status = LTTNG_LIVE_ITERATOR_STATUS_END; |
7cdc2bab MD |
1838 | goto end; |
1839 | case LTTNG_VIEWER_NEW_STREAMS_ERR: | |
1419db2b | 1840 | BT_COMP_LOGD("Received get_new_streams response: error"); |
f79c2d7a FD |
1841 | status = LTTNG_LIVE_ITERATOR_STATUS_ERROR; |
1842 | goto end; | |
7cdc2bab | 1843 | default: |
1419db2b FD |
1844 | BT_COMP_LOGE_APPEND_CAUSE(self_comp, |
1845 | "Received get_new_streams response: Unknown:" | |
1846 | "return code %u", be32toh(rp.status)); | |
f79c2d7a FD |
1847 | status = LTTNG_LIVE_ITERATOR_STATUS_ERROR; |
1848 | goto end; | |
7cdc2bab MD |
1849 | } |
1850 | ||
f79c2d7a FD |
1851 | viewer_status = receive_streams(session, streams_count, self_msg_iter); |
1852 | if (viewer_status != LTTNG_LIVE_VIEWER_STATUS_OK) { | |
1853 | viewer_handle_recv_status(self_comp, NULL, | |
1854 | viewer_status, "new streams"); | |
1855 | status = viewer_status_to_live_iterator_status(viewer_status); | |
1856 | goto end; | |
7cdc2bab | 1857 | } |
7cdc2bab | 1858 | |
f79c2d7a FD |
1859 | status = LTTNG_LIVE_ITERATOR_STATUS_OK; |
1860 | end: | |
7cdc2bab MD |
1861 | return status; |
1862 | } | |
1863 | ||
1864 | BT_HIDDEN | |
f79c2d7a | 1865 | enum lttng_live_viewer_status live_viewer_connection_create( |
1419db2b FD |
1866 | bt_self_component *self_comp, |
1867 | bt_self_component_class *self_comp_class, | |
f79c2d7a FD |
1868 | bt_logging_level log_level, |
1869 | const char *url, bool in_query, | |
1870 | struct lttng_live_msg_iter *lttng_live_msg_iter, | |
1871 | struct live_viewer_connection **viewer) | |
7cdc2bab | 1872 | { |
14f28187 | 1873 | struct live_viewer_connection *viewer_connection; |
f79c2d7a | 1874 | enum lttng_live_viewer_status status; |
7cdc2bab | 1875 | |
14f28187 | 1876 | viewer_connection = g_new0(struct live_viewer_connection, 1); |
7cdc2bab | 1877 | |
550004b4 | 1878 | if (bt_socket_init(log_level) != 0) { |
1419db2b FD |
1879 | BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp, |
1880 | self_comp_class, "Failed to init socket"); | |
f79c2d7a | 1881 | status = LTTNG_LIVE_VIEWER_STATUS_ERROR; |
1cb3cdd7 MJ |
1882 | goto error; |
1883 | } | |
1884 | ||
550004b4 PP |
1885 | viewer_connection->log_level = log_level; |
1886 | ||
1419db2b FD |
1887 | viewer_connection->self_comp = self_comp; |
1888 | viewer_connection->self_comp_class = self_comp_class; | |
550004b4 | 1889 | |
1cb3cdd7 | 1890 | viewer_connection->control_sock = BT_INVALID_SOCKET; |
7cdc2bab | 1891 | viewer_connection->port = -1; |
14f28187 FD |
1892 | viewer_connection->in_query = in_query; |
1893 | viewer_connection->lttng_live_msg_iter = lttng_live_msg_iter; | |
7cdc2bab MD |
1894 | viewer_connection->url = g_string_new(url); |
1895 | if (!viewer_connection->url) { | |
1419db2b FD |
1896 | BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp, |
1897 | self_comp_class, "Failed to allocate URL buffer"); | |
f79c2d7a | 1898 | status = LTTNG_LIVE_VIEWER_STATUS_ERROR; |
7cdc2bab MD |
1899 | goto error; |
1900 | } | |
1901 | ||
ecb4ba8a FD |
1902 | BT_COMP_OR_COMP_CLASS_LOGD(self_comp, self_comp_class, |
1903 | "Establishing connection to url \"%s\"...", url); | |
f79c2d7a FD |
1904 | status = lttng_live_connect_viewer(viewer_connection); |
1905 | /* | |
1906 | * Only print error and append cause in case of error. not in case of | |
1907 | * interruption. | |
1908 | */ | |
1909 | if (status == LTTNG_LIVE_VIEWER_STATUS_ERROR) { | |
1419db2b FD |
1910 | BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp, |
1911 | self_comp_class, "Failed to establish connection: " | |
1912 | "url=\"%s\"", url); | |
1913 | goto error; | |
f79c2d7a FD |
1914 | } else if (status == LTTNG_LIVE_VIEWER_STATUS_INTERRUPTED) { |
1915 | goto error; | |
7cdc2bab | 1916 | } |
ecb4ba8a FD |
1917 | BT_COMP_OR_COMP_CLASS_LOGD(self_comp, self_comp_class, |
1918 | "Connection to url \"%s\" is established", url); | |
f79c2d7a FD |
1919 | |
1920 | *viewer = viewer_connection; | |
1921 | status = LTTNG_LIVE_VIEWER_STATUS_OK; | |
1922 | goto end; | |
7cdc2bab | 1923 | |
7cdc2bab | 1924 | error: |
2f767475 PP |
1925 | if (viewer_connection) { |
1926 | live_viewer_connection_destroy(viewer_connection); | |
1927 | } | |
f79c2d7a FD |
1928 | end: |
1929 | return status; | |
7cdc2bab MD |
1930 | } |
1931 | ||
1932 | BT_HIDDEN | |
14f28187 FD |
1933 | void live_viewer_connection_destroy( |
1934 | struct live_viewer_connection *viewer_connection) | |
7cdc2bab | 1935 | { |
ecb4ba8a FD |
1936 | bt_self_component *self_comp = viewer_connection->self_comp; |
1937 | bt_self_component_class *self_comp_class = viewer_connection->self_comp_class; | |
b9e6ec43 FD |
1938 | |
1939 | if (!viewer_connection) { | |
1940 | goto end; | |
1941 | } | |
1942 | ||
ecb4ba8a FD |
1943 | BT_COMP_OR_COMP_CLASS_LOGD(self_comp, self_comp_class, |
1944 | "Closing connection to relay:" | |
1945 | "relay-url=\"%s\"", viewer_connection->url->str); | |
1946 | ||
7cdc2bab | 1947 | lttng_live_disconnect_viewer(viewer_connection); |
b9e6ec43 | 1948 | |
2f767475 PP |
1949 | if (viewer_connection->url) { |
1950 | g_string_free(viewer_connection->url, true); | |
1951 | } | |
b9e6ec43 | 1952 | |
94b828f3 | 1953 | if (viewer_connection->relay_hostname) { |
14f28187 | 1954 | g_string_free(viewer_connection->relay_hostname, true); |
94b828f3 | 1955 | } |
b9e6ec43 | 1956 | |
94b828f3 | 1957 | if (viewer_connection->target_hostname) { |
14f28187 | 1958 | g_string_free(viewer_connection->target_hostname, true); |
94b828f3 | 1959 | } |
b9e6ec43 | 1960 | |
94b828f3 | 1961 | if (viewer_connection->session_name) { |
14f28187 | 1962 | g_string_free(viewer_connection->session_name, true); |
94b828f3 | 1963 | } |
b9e6ec43 | 1964 | |
ecb4ba8a FD |
1965 | if (viewer_connection->proto) { |
1966 | g_string_free(viewer_connection->proto, true); | |
1967 | } | |
1968 | ||
7cdc2bab | 1969 | g_free(viewer_connection); |
1cb3cdd7 MJ |
1970 | |
1971 | bt_socket_fini(); | |
b9e6ec43 FD |
1972 | |
1973 | end: | |
1974 | return; | |
7cdc2bab | 1975 | } |