2 * Copyright (C) 2020 Jérémie Galarneau <jeremie.galarneau@efficios.com>
4 * SPDX-License-Identifier: LGPL-2.1-only
8 #include <common/compat/fcntl.h>
9 #include <common/sessiond-comm/sessiond-comm.h>
10 #include <common/payload.h>
11 #include <common/payload-view.h>
12 #include <common/unix.h>
13 #include <common/utils.h>
14 #include <common/defaults.h>
17 #include <common/error.h>
18 #include <lttng/constant.h>
23 #define HIGH_FD_COUNT LTTCOMM_MAX_SEND_FDS
24 #define MESSAGE_COUNT 4
25 #define LARGE_PAYLOAD_SIZE 4 * 1024
26 #define LARGE_PAYLOAD_RECV_SIZE 100
28 static const int TEST_COUNT
= 33;
32 int lttng_opt_verbose
;
36 * Validate that a large number of file descriptors can be received in one shot.
38 static void test_high_fd_count(unsigned int fd_count
)
40 int sockets
[2] = {-1, -1};
43 const unsigned int payload_content
= 42;
44 struct lttng_payload sent_payload
;
45 struct lttng_payload received_payload
;
47 diag("Send and receive high FD count atomically (%u FDs)", fd_count
);
48 lttng_payload_init(&sent_payload
);
49 lttng_payload_init(&received_payload
);
51 ret
= lttcomm_create_anon_unix_socketpair(sockets
);
52 ok(ret
== 0, "Created anonymous unix socket pair");
54 PERROR("Failed to create an anonymous pair of unix sockets");
58 /* Add dummy content to payload. */
59 ret
= lttng_dynamic_buffer_append(&sent_payload
.buffer
,
60 &payload_content
, sizeof(payload_content
));
62 PERROR("Failed to initialize test payload");
66 for (i
= 0; i
< fd_count
; i
++) {
67 struct fd_handle
*handle
;
68 int fd
= fcntl(STDOUT_FILENO
, F_DUPFD
, 0);
71 PERROR("Failed to create fd while creating test payload");
75 handle
= fd_handle_create(fd
);
78 PERROR("Failed to close fd while preparing test payload");
83 ret
= lttng_payload_push_fd_handle(&sent_payload
, handle
);
84 fd_handle_put(handle
);
86 PERROR("Failed to add fd handle to test payload");
94 struct lttng_payload_view pv
= lttng_payload_view_from_payload(
95 &sent_payload
, 0, -1);
97 /* Not expected to block considering the size of the payload. */
98 sock_ret
= lttcomm_send_unix_sock(
99 sockets
[0], pv
.buffer
.data
, pv
.buffer
.size
);
100 ok(sock_ret
== pv
.buffer
.size
, "Sent complete test payload");
101 if (sock_ret
!= pv
.buffer
.size
) {
102 ERR("Failed to send test payload bytes: ret = %zd, expected = %zu",
103 sock_ret
, pv
.buffer
.size
);
107 sock_ret
= lttcomm_send_payload_view_fds_unix_sock(
109 ok(sock_ret
== 1, "Sent test payload file descriptors");
112 PERROR("Failed to send test payload file descriptors: ret = %zd, expected = %d",
115 diag("Failed to send test payload file descriptors: ret = %zd, expected = %d",
123 /* Receive payload */
127 ret
= lttng_dynamic_buffer_set_size(&received_payload
.buffer
,
128 sent_payload
.buffer
.size
);
130 PERROR("Failed to pre-allocate reception buffer");
134 sock_ret
= lttcomm_recv_unix_sock(sockets
[1],
135 received_payload
.buffer
.data
,
136 received_payload
.buffer
.size
);
137 ok(sock_ret
== received_payload
.buffer
.size
,
138 "Received payload bytes");
139 if (sock_ret
!= received_payload
.buffer
.size
) {
140 ERR("Failed to receive payload bytes: ret = %zd, expected = %zu",
141 sock_ret
, received_payload
.buffer
.size
);
145 sock_ret
= lttcomm_recv_payload_fds_unix_sock(
146 sockets
[1], fd_count
, &received_payload
);
147 ok(sock_ret
== (int) (sizeof(int) * fd_count
),
148 "FD reception return value is number of fd * sizeof(int)");
149 if (sock_ret
!= (int) (sizeof(int) * fd_count
)) {
150 ERR("Failed to receive test payload file descriptors: ret = %zd, expected = %d",
152 (int) (fd_count
* sizeof(int)));
157 const struct lttng_payload_view pv
=
158 lttng_payload_view_from_payload(
159 &received_payload
, 0,
161 const int fd_handle_count
=
162 lttng_payload_view_get_fd_handle_count(
165 ok(fd_handle_count
== fd_count
,
166 "Received all test payload file descriptors in one invocation");
171 for (i
= 0; i
< 2; i
++) {
172 if (sockets
[i
] < 0) {
176 if (close(sockets
[i
])) {
177 PERROR("Failed to close unix socket");
181 lttng_payload_reset(&sent_payload
);
182 lttng_payload_reset(&received_payload
);
186 * Validate that if the sender sent multiple messages, each containing 1 fd,
187 * the receiver can receive one message at a time (the binary payload and its
188 * fd) and is not forced to receive all file descriptors at once.
190 static void test_one_fd_per_message(unsigned int message_count
)
192 const unsigned int payload_content
= 42;
193 int sockets
[2] = {-1, -1};
196 struct lttng_payload sent_payload
;
197 struct lttng_payload received_payload
;
199 diag("Send and receive small messages with one FD each (%u messages)",
201 lttng_payload_init(&sent_payload
);
202 lttng_payload_init(&received_payload
);
204 ret
= lttcomm_create_anon_unix_socketpair(sockets
);
205 ok(ret
== 0, "Created anonymous unix socket pair");
207 PERROR("Failed to create an anonymous pair of unix sockets");
211 /* Send messages with one fd each. */
212 for (i
= 0; i
< message_count
; i
++) {
213 struct fd_handle
*handle
;
216 /* Add dummy content to payload. */
217 ret
= lttng_dynamic_buffer_append(&sent_payload
.buffer
,
218 &payload_content
, sizeof(payload_content
));
220 PERROR("Failed to initialize test payload");
224 fd
= fcntl(STDOUT_FILENO
, F_DUPFD
, 0);
226 PERROR("Failed to create fd while creating test payload");
230 handle
= fd_handle_create(fd
);
233 PERROR("Failed to close fd while preparing test payload");
238 ret
= lttng_payload_push_fd_handle(&sent_payload
, handle
);
239 fd_handle_put(handle
);
241 PERROR("Failed to add fd handle to test payload");
248 struct lttng_payload_view pv
=
249 lttng_payload_view_from_payload(
250 &sent_payload
, 0, -1);
252 /* Not expected to block considering the size of the
254 sock_ret
= lttcomm_send_unix_sock(sockets
[0],
255 pv
.buffer
.data
, pv
.buffer
.size
);
256 ok(sock_ret
== pv
.buffer
.size
,
257 "Sent binary payload for message %u",
259 if (sock_ret
!= pv
.buffer
.size
) {
260 ERR("Failed to send test payload bytes: ret = %zd, expected = %zu",
261 sock_ret
, pv
.buffer
.size
);
265 sock_ret
= lttcomm_send_payload_view_fds_unix_sock(
268 "Sent file descriptors payload for message %u",
272 PERROR("Failed to send test payload file descriptors: ret = %zd, expected = %d",
275 diag("Failed to send test payload file descriptors: ret = %zd, expected = %d",
283 lttng_payload_clear(&sent_payload
);
286 /* Receive messages one at a time. */
287 for (i
= 0; i
< message_count
; i
++) {
290 ret
= lttng_dynamic_buffer_set_size(&received_payload
.buffer
,
291 sizeof(payload_content
));
293 PERROR("Failed to pre-allocate reception buffer");
297 sock_ret
= lttcomm_recv_unix_sock(sockets
[1],
298 received_payload
.buffer
.data
,
299 received_payload
.buffer
.size
);
300 ok(sock_ret
== received_payload
.buffer
.size
,
301 "Received payload bytes for message %u", i
);
302 if (sock_ret
!= received_payload
.buffer
.size
) {
303 ERR("Failed to receive payload bytes: ret = %zd, expected = %zu",
304 sock_ret
, received_payload
.buffer
.size
);
308 sock_ret
= lttcomm_recv_payload_fds_unix_sock(
309 sockets
[1], 1, &received_payload
);
310 ok(sock_ret
== (int) sizeof(int), "Received fd for message %u",
312 if (sock_ret
!= (int) sizeof(int)) {
313 ERR("Failed to receive test payload file descriptors: ret = %zd, expected = %u",
314 sock_ret
, (int) sizeof(int));
319 const struct lttng_payload_view pv
=
320 lttng_payload_view_from_payload(
321 &received_payload
, 0,
323 const int fd_handle_count
=
324 lttng_payload_view_get_fd_handle_count(
327 ok(fd_handle_count
== 1,
328 "Payload contains 1 fd for message %u",
332 lttng_payload_clear(&received_payload
);
336 for (i
= 0; i
< 2; i
++) {
337 if (sockets
[i
] < 0) {
341 if (close(sockets
[i
])) {
342 PERROR("Failed to close unix socket");
346 lttng_payload_reset(&sent_payload
);
347 lttng_payload_reset(&received_payload
);
351 * Validate that a large message can be received in multiple chunks.
353 static void test_receive_in_chunks(
354 unsigned int payload_size
, unsigned int max_recv_size
)
356 int sockets
[2] = {-1, -1};
359 struct lttng_payload sent_payload
;
360 struct lttng_payload received_payload
;
361 struct fd_handle
*handle
;
363 ssize_t sock_ret
, received
= 0;
365 diag("Receive a message in multiple chunks");
366 lttng_payload_init(&sent_payload
);
367 lttng_payload_init(&received_payload
);
369 ret
= lttcomm_create_anon_unix_socketpair(sockets
);
370 ok(ret
== 0, "Created anonymous unix socket pair");
372 PERROR("Failed to create an anonymous pair of unix sockets");
376 /* Add dummy content to payload. */
377 ret
= lttng_dynamic_buffer_set_size(&sent_payload
.buffer
, payload_size
);
379 PERROR("Failed to initialize test payload");
383 fd
= fcntl(STDOUT_FILENO
, F_DUPFD
, 0);
385 PERROR("Failed to create fd while creating test payload");
389 handle
= fd_handle_create(fd
);
392 PERROR("Failed to close fd while preparing test payload");
397 ret
= lttng_payload_push_fd_handle(&sent_payload
, handle
);
398 fd_handle_put(handle
);
400 PERROR("Failed to add fd handle to test payload");
406 struct lttng_payload_view pv
= lttng_payload_view_from_payload(
407 &sent_payload
, 0, -1);
409 /* Not expected to block considering the size of the payload. */
410 sock_ret
= lttcomm_send_unix_sock(
411 sockets
[0], pv
.buffer
.data
, pv
.buffer
.size
);
412 ok(sock_ret
== pv
.buffer
.size
, "Sent complete test payload");
413 if (sock_ret
!= pv
.buffer
.size
) {
414 ERR("Failed to send test payload bytes: ret = %zd, expected = %zu",
415 sock_ret
, pv
.buffer
.size
);
419 sock_ret
= lttcomm_send_payload_view_fds_unix_sock(
421 ok(sock_ret
== 1, "Sent test payload file descriptors");
424 PERROR("Failed to send test payload file descriptors: ret = %zd, expected = %d",
427 diag("Failed to send test payload file descriptors: ret = %zd, expected = %d",
435 /* Receive payload */
436 ret
= lttng_dynamic_buffer_set_size(
437 &received_payload
.buffer
, sent_payload
.buffer
.size
);
439 PERROR("Failed to pre-allocate reception buffer");
444 const ssize_t to_receive_this_pass
= min(max_recv_size
,
445 sent_payload
.buffer
.size
- received
);
447 sock_ret
= lttcomm_recv_unix_sock(sockets
[1],
448 received_payload
.buffer
.data
+ received
,
449 to_receive_this_pass
);
450 if (sock_ret
!= to_receive_this_pass
) {
451 ERR("Failed to receive payload bytes: ret = %zd, expected = %zu",
452 sock_ret
, to_receive_this_pass
);
456 received
+= sock_ret
;
457 } while (received
< sent_payload
.buffer
.size
);
459 ok(received
== sent_payload
.buffer
.size
,
460 "Received complete payload in chunks of %u bytes",
462 if (received
!= sent_payload
.buffer
.size
) {
466 sock_ret
= lttcomm_recv_payload_fds_unix_sock(
467 sockets
[1], 1, &received_payload
);
468 ok(sock_ret
== (int) sizeof(int),
469 "Received file descriptor after receiving payload in chunks");
470 if (sock_ret
!= (int) sizeof(int)) {
471 ERR("Failed to receive test payload file descriptors: ret = %zd, expected = %d",
472 sock_ret
, (int) sizeof(int));
477 const struct lttng_payload_view pv
=
478 lttng_payload_view_from_payload(
479 &received_payload
, 0, -1);
480 const int fd_handle_count
=
481 lttng_payload_view_get_fd_handle_count(&pv
);
483 ok(fd_handle_count
== 1,
484 "Payload contains 1 fd after receiving payload in chunks");
488 for (i
= 0; i
< 2; i
++) {
489 if (sockets
[i
] < 0) {
493 if (close(sockets
[i
])) {
494 PERROR("Failed to close unix socket");
498 lttng_payload_reset(&sent_payload
);
499 lttng_payload_reset(&received_payload
);
504 plan_tests(TEST_COUNT
);
506 test_high_fd_count(HIGH_FD_COUNT
);
507 test_one_fd_per_message(MESSAGE_COUNT
);
508 test_receive_in_chunks(LARGE_PAYLOAD_SIZE
, LARGE_PAYLOAD_RECV_SIZE
);
510 return exit_status();