xref: /haiku/src/tests/system/network/unix_dgram_test.cpp (revision e1c4049fed1047bdb957b0529e1921e97ef94770)
1 /*
2  * Copyright 2023, Trung Nguyen, trungnt282910@gmail.com.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include <errno.h>
8 #include <stdio.h>
9 #include <string.h>
10 
11 #include <fcntl.h>
12 #include <sys/mman.h>
13 #include <sys/socket.h>
14 #include <sys/stat.h>
15 #include <sys/un.h>
16 #include <unistd.h>
17 
18 
19 #define REPORT_ERROR(msg, ...) \
20 	fprintf(stderr, "%s:%d: " msg "\n", __FILE__, __LINE__, ##__VA_ARGS__)
21 
22 
23 int
24 connect_test()
25 {
26 	unlink("test.sock");
27 	unlink("test1.sock");
28 	unlink("test2.sock");
29 
30 	int status;
31 
32 	int sock = socket(AF_UNIX, SOCK_DGRAM, 0);
33 	if (sock == -1) {
34 		REPORT_ERROR("socket() failed: %s\n", strerror(errno));
35 		return 1;
36 	}
37 
38 	struct sockaddr_un addr;
39 	addr.sun_family = AF_UNIX;
40 	strcpy(addr.sun_path, "test.sock");
41 	status = bind(sock, (struct sockaddr*)&addr, sizeof(addr));
42 	if (status == -1) {
43 		REPORT_ERROR("bind() failed: %s\n", strerror(errno));
44 		return 1;
45 	}
46 
47 	int sock1 = socket(AF_UNIX, SOCK_DGRAM, 0);
48 	if (sock1 == -1) {
49 		REPORT_ERROR("socket() failed: %s\n", strerror(errno));
50 		return 1;
51 	}
52 
53 	struct sockaddr_un addr1;
54 	addr1.sun_family = AF_UNIX;
55 	strcpy(addr1.sun_path, "test1.sock");
56 	status = bind(sock1, (struct sockaddr*)&addr1, sizeof(addr1));
57 	if (status == -1) {
58 		REPORT_ERROR("bind() failed: %s\n", strerror(errno));
59 		return 1;
60 	}
61 
62 	// Set non-blocking on both sockets
63 	int flags1 = fcntl(sock, F_GETFL, 0);
64 	if (flags1 == -1) {
65 		REPORT_ERROR("fcntl() failed: %s\n", strerror(errno));
66 		return 1;
67 	}
68 	status = fcntl(sock, F_SETFL, flags1 | O_NONBLOCK);
69 	if (status == -1) {
70 		REPORT_ERROR("fcntl() failed: %s\n", strerror(errno));
71 		return 1;
72 	}
73 	status = fcntl(sock1, F_SETFL, flags1 | O_NONBLOCK);
74 	if (status == -1) {
75 		REPORT_ERROR("fcntl() failed: %s\n", strerror(errno));
76 		return 1;
77 	}
78 
79 	status = connect(sock, (struct sockaddr*)&addr1, sizeof(addr1));
80 	if (status == -1) {
81 		REPORT_ERROR("connect() failed: %s\n", strerror(errno));
82 		return 1;
83 	}
84 
85 	// Connect in the opposite way
86 	status = connect(sock1, (struct sockaddr*)&addr, sizeof(addr));
87 	if (status == -1) {
88 		REPORT_ERROR("connect() failed: %s\n", strerror(errno));
89 		return 1;
90 	}
91 
92 	// Reconnect a connected DGRAM socket
93 	status = connect(sock, (struct sockaddr*)&addr1, sizeof(addr1));
94 	if (status == -1) {
95 		REPORT_ERROR("connect() failed: %s\n", strerror(errno));
96 		return 1;
97 	}
98 
99 	int sock2 = socket(AF_UNIX, SOCK_DGRAM, 0);
100 	if (sock2 == -1) {
101 		REPORT_ERROR("socket() failed: %s\n", strerror(errno));
102 		return 1;
103 	}
104 
105 	struct sockaddr_un addr2;
106 	addr2.sun_family = AF_UNIX;
107 	strcpy(addr2.sun_path, "test2.sock");
108 	status = bind(sock2, (struct sockaddr*)&addr2, sizeof(addr2));
109 	if (status == -1) {
110 		REPORT_ERROR("bind() failed: %s\n", strerror(errno));
111 		return 1;
112 	}
113 
114 	// Connect to a socket that are already connected
115 	status = connect(sock2, (struct sockaddr*)&addr1, sizeof(addr1));
116 	if (status != -1) {
117 		REPORT_ERROR("connect() succeeded unexpectedly\n");
118 		return 1;
119 	}
120 	if (errno != EPERM) {
121 		REPORT_ERROR("connect() failed with unexpected error: %s\n", strerror(errno));
122 		return 1;
123 	}
124 
125 	status = close(sock2);
126 	if (status == -1) {
127 		REPORT_ERROR("close() failed: %s\n", strerror(errno));
128 		return 1;
129 	}
130 
131 	// Connect to a closed socket
132 	status = connect(sock, (struct sockaddr*)&addr2, sizeof(addr2));
133 	if (status != -1) {
134 		REPORT_ERROR("connect() succeeded unexpectedly\n");
135 		return 1;
136 	}
137 	if (errno != ECONNREFUSED) {
138 		REPORT_ERROR("connect() failed with unexpected error: %s\n", strerror(errno));
139 		return 1;
140 	}
141 
142 	close(sock);
143 	close(sock1);
144 
145 	unlink("test.sock");
146 	unlink("test1.sock");
147 	unlink("test2.sock");
148 
149 	return 0;
150 }
151 
152 
153 int
154 send_test()
155 {
156 	unlink("test.sock");
157 	unlink("test1.sock");
158 	unlink("test2.sock");
159 
160 	int status;
161 
162 	int sock = socket(AF_UNIX, SOCK_DGRAM, 0);
163 	if (sock == -1) {
164 		REPORT_ERROR("socket() failed: %s\n", strerror(errno));
165 		return 1;
166 	}
167 
168 	struct sockaddr_un addr;
169 	memset(&addr, 0, sizeof(addr));
170 	addr.sun_family = AF_UNIX;
171 	strcpy(addr.sun_path, "test.sock");
172 	status = bind(sock, (struct sockaddr*)&addr, sizeof(addr));
173 	if (status == -1) {
174 		REPORT_ERROR("bind() failed: %s\n", strerror(errno));
175 		return 1;
176 	}
177 
178 	status = send(sock, "test", 4, 0);
179 	if (status != -1) {
180 		REPORT_ERROR("send() succeeded unexpectedly\n");
181 		return 1;
182 	}
183 	// if (errno != ENOTCONN) {
184 	// 	REPORT_ERROR("send() failed with unexpected error: %s\n", strerror(errno));
185 	// 	return 1;
186 	// }
187 
188 	int sock1 = socket(AF_UNIX, SOCK_DGRAM, 0);
189 	if (sock1 == -1) {
190 		REPORT_ERROR("socket() failed: %s\n", strerror(errno));
191 		return 1;
192 	}
193 
194 	struct sockaddr_un addr1;
195 	addr1.sun_family = AF_UNIX;
196 	strcpy(addr1.sun_path, "test1.sock");
197 	status = bind(sock1, (struct sockaddr*)&addr1, sizeof(addr1));
198 	if (status == -1) {
199 		REPORT_ERROR("bind() failed: %s\n", strerror(errno));
200 		return 1;
201 	}
202 
203 	// Set non-blocking on both sockets
204 	status = fcntl(sock, F_SETFL, O_NONBLOCK);
205 	if (status == -1) {
206 		REPORT_ERROR("fcntl() failed: %s\n", strerror(errno));
207 		return 1;
208 	}
209 	status = fcntl(sock1, F_SETFL, O_NONBLOCK);
210 	if (status == -1) {
211 		REPORT_ERROR("fcntl() failed: %s\n", strerror(errno));
212 		return 1;
213 	}
214 
215 	status = sendto(sock, "test1", 5, 0, (struct sockaddr*)&addr1, sizeof(addr1));
216 	if (status == -1) {
217 		REPORT_ERROR("sendto() failed: %s\n", strerror(errno));
218 		return 1;
219 	}
220 
221 	status = connect(sock, (struct sockaddr*)&addr1, sizeof(addr1));
222 	if (status == -1) {
223 		REPORT_ERROR("connect() failed: %s\n", strerror(errno));
224 		return 1;
225 	}
226 	status = connect(sock1, (struct sockaddr*)&addr, sizeof(addr));
227 	if (status == -1) {
228 		REPORT_ERROR("connect() failed: %s\n", strerror(errno));
229 		return 1;
230 	}
231 
232 	status = send(sock, "test2", 5, 0);
233 	if (status == -1) {
234 		REPORT_ERROR("send() failed: %s\n", strerror(errno));
235 		return 1;
236 	}
237 
238 	int sock2 = socket(AF_UNIX, SOCK_DGRAM, 0);
239 	if (sock2 == -1) {
240 		REPORT_ERROR("socket() failed: %s\n", strerror(errno));
241 		return 1;
242 	}
243 
244 	struct sockaddr_un addr2;
245 	addr2.sun_family = AF_UNIX;
246 	strcpy(addr2.sun_path, "test2.sock");
247 	status = bind(sock2, (struct sockaddr*)&addr2, sizeof(addr2));
248 	if (status == -1) {
249 		REPORT_ERROR("bind() failed: %s\n", strerror(errno));
250 		return 1;
251 	}
252 
253 	status = sendto(sock2, "test3", 5, 0, (struct sockaddr*)&addr1, sizeof(addr1));
254 	if (status != -1) {
255 		REPORT_ERROR("sendto() succeeded unexpectedly\n");
256 		return 1;
257 	}
258 	if (errno != EPERM) {
259 		REPORT_ERROR("sendto() failed with unexpected error: %s\n", strerror(errno));
260 		return 1;
261 	}
262 
263 	char buf[16];
264 	memset(buf, 0, sizeof(buf));
265 	status = recv(sock1, buf, sizeof(buf), 0);
266 	if (status == -1) {
267 		REPORT_ERROR("recv() failed: %s\n", strerror(errno));
268 		return 1;
269 	}
270 	if (strcmp(buf, "test1") != 0) {
271 		REPORT_ERROR("recv() received unexpected data: %s\n", buf);
272 		return 1;
273 	}
274 
275 	memset(buf, 0, sizeof(buf));
276 	struct sockaddr_un addr3;
277 	memset(&addr3, 0, sizeof(addr3));
278 	socklen_t addrlen = sizeof(addr3);
279 	status = recvfrom(sock1, buf, sizeof(buf), 0, (struct sockaddr*)&addr3, &addrlen);
280 	if (status == -1) {
281 		REPORT_ERROR("recv() failed: %s\n", strerror(errno));
282 		return 1;
283 	}
284 	if (strcmp(buf, "test2") != 0) {
285 		REPORT_ERROR("recv() received unexpected data: %s\n", buf);
286 		return 1;
287 	}
288 	if (strcmp(addr.sun_path, addr3.sun_path) != 0) {
289 		REPORT_ERROR("recv() received unexpected address: %s\n", addr3.sun_path);
290 		return 1;
291 	}
292 
293 	status = send(sock, "test4", 4, 0);
294 	if (status == -1) {
295 		REPORT_ERROR("send() failed: %s\n", strerror(errno));
296 		return 1;
297 	}
298 
299 	status = send(sock, "test5", 5, 0);
300 	if (status == -1) {
301 		REPORT_ERROR("send() failed: %s\n", strerror(errno));
302 		return 1;
303 	}
304 
305 	memset(buf, 0, sizeof(buf));
306 	status = recv(sock1, buf, 4, 0);
307 	if (status == -1) {
308 		REPORT_ERROR("recv() failed: %s\n", strerror(errno));
309 		return 1;
310 	}
311 	if (strcmp(buf, "test") != 0) {
312 		REPORT_ERROR("recv() received unexpected data: %s\n", buf);
313 		return 1;
314 	}
315 
316 	// The last byte of the previous datagram should be discarded.
317 	memset(buf, 0, sizeof(buf));
318 	status = recv(sock1, buf, sizeof(buf), 0);
319 	if (status == -1) {
320 		REPORT_ERROR("recv() failed: %s\n", strerror(errno));
321 		return 1;
322 	}
323 	if (strcmp(buf, "test5") != 0) {
324 		REPORT_ERROR("recv() received unexpected data: %s\n", buf);
325 		return 1;
326 	}
327 
328 	close(sock1);
329 	status = send(sock, "test6", 5, 0);
330 	if (status != -1) {
331 		REPORT_ERROR("send() succeeded unexpectedly\n");
332 		return 1;
333 	}
334 	if (errno != ECONNREFUSED) {
335 		REPORT_ERROR("send() failed with unexpected error: %s\n", strerror(errno));
336 		return 1;
337 	}
338 
339 	close(sock);
340 	close(sock2);
341 
342 	unlink("test.sock");
343 	unlink("test1.sock");
344 	unlink("test2.sock");
345 
346 	return 0;
347 }
348 
349 
350 int
351 shutdown_test()
352 {
353 	unlink("test.sock");
354 	unlink("test1.sock");
355 
356 	int status;
357 
358 	int sock = socket(AF_UNIX, SOCK_DGRAM, 0);
359 	if (sock == -1) {
360 		REPORT_ERROR("socket() failed: %s\n", strerror(errno));
361 		return 1;
362 	}
363 
364 	struct sockaddr_un addr;
365 	addr.sun_family = AF_UNIX;
366 	strcpy(addr.sun_path, "test.sock");
367 	status = bind(sock, (struct sockaddr*)&addr, sizeof(addr));
368 	if (status == -1) {
369 		REPORT_ERROR("bind() failed: %s\n", strerror(errno));
370 		return 1;
371 	}
372 
373 	int sock1 = socket(AF_UNIX, SOCK_DGRAM, 0);
374 	if (sock1 == -1) {
375 		REPORT_ERROR("socket() failed: %s\n", strerror(errno));
376 		return 1;
377 	}
378 
379 	struct sockaddr_un addr1;
380 	addr1.sun_family = AF_UNIX;
381 	strcpy(addr1.sun_path, "test1.sock");
382 	status = bind(sock1, (struct sockaddr*)&addr1, sizeof(addr1));
383 	if (status == -1) {
384 		REPORT_ERROR("bind() failed: %s\n", strerror(errno));
385 		return 1;
386 	}
387 
388 	status = shutdown(sock, SHUT_WR);
389 	if (status == -1) {
390 		REPORT_ERROR("shutdown() failed: %s\n", strerror(errno));
391 		return 1;
392 	}
393 
394 	status = sendto(sock, "test", 4, 0, (struct sockaddr*)&addr1, sizeof(addr1));
395 	if (status != -1) {
396 		REPORT_ERROR("send() succeeded unexpectedly\n");
397 		return 1;
398 	}
399 	if (errno != EPIPE) {
400 		REPORT_ERROR("send() failed with unexpected error: %s\n", strerror(errno));
401 		return 1;
402 	}
403 
404 	status = sendto(sock1, "test", 4, 0, (struct sockaddr*)&addr, sizeof(addr));
405 	if (status == -1) {
406 		REPORT_ERROR("send() failed: %s\n", strerror(errno));
407 		return 1;
408 	}
409 
410 	status = shutdown(sock, SHUT_RD);
411 	if (status == -1) {
412 		REPORT_ERROR("shutdown() failed: %s\n", strerror(errno));
413 		return 1;
414 	}
415 
416 	status = sendto(sock1, "test", 4, 0, (struct sockaddr*)&addr, sizeof(addr));
417 	if (status != -1) {
418 		REPORT_ERROR("send() succeeded unexpectedly\n");
419 		return 1;
420 	}
421 	if (errno != EPIPE) {
422 		REPORT_ERROR("send() failed with unexpected error: %s\n", strerror(errno));
423 		return 1;
424 	}
425 
426 	char buf[16];
427 	memset(buf, 0, sizeof(buf));
428 	status = recv(sock, buf, sizeof(buf), 0);
429 	if (status == -1) {
430 		REPORT_ERROR("recv() failed: %s\n", strerror(errno));
431 		return 1;
432 	}
433 	if (status != 0) {
434 		REPORT_ERROR("recv() received unexpected data\n");
435 		return 1;
436 	}
437 
438 	close(sock);
439 	close(sock1);
440 
441 	unlink("test.sock");
442 	unlink("test1.sock");
443 
444 	return 0;
445 }
446 
447 
448 int
449 send_fd_test()
450 {
451 	unlink("test.sock");
452 	unlink("test1.sock");
453 
454 	int status;
455 
456 	int sock = socket(AF_UNIX, SOCK_DGRAM, 0);
457 	if (sock == -1) {
458 		REPORT_ERROR("socket() failed: %s\n", strerror(errno));
459 		return 1;
460 	}
461 
462 	struct sockaddr_un addr;
463 	addr.sun_family = AF_UNIX;
464 	strcpy(addr.sun_path, "test.sock");
465 	status = bind(sock, (struct sockaddr*)&addr, sizeof(addr));
466 	if (status == -1) {
467 		REPORT_ERROR("bind() failed: %s\n", strerror(errno));
468 		return 1;
469 	}
470 
471 	int sock1 = socket(AF_UNIX, SOCK_DGRAM, 0);
472 	if (sock1 == -1) {
473 		REPORT_ERROR("socket() failed: %s\n", strerror(errno));
474 		return 1;
475 	}
476 
477 	struct sockaddr_un addr1;
478 	addr1.sun_family = AF_UNIX;
479 	strcpy(addr1.sun_path, "test1.sock");
480 	status = bind(sock1, (struct sockaddr*)&addr1, sizeof(addr1));
481 	if (status == -1) {
482 		REPORT_ERROR("bind() failed: %s\n", strerror(errno));
483 		return 1;
484 	}
485 
486 	status = connect(sock, (struct sockaddr*)&addr1, sizeof(addr1));
487 	if (status == -1) {
488 		REPORT_ERROR("connect() failed: %s\n", strerror(errno));
489 		return 1;
490 	}
491 
492 	int fd = shm_open("test_shm", O_CREAT | O_RDWR, 0666);
493 	if (fd == -1) {
494 		REPORT_ERROR("shm_open() failed: %s\n", strerror(errno));
495 		return 1;
496 	}
497 	shm_unlink("test_shm");
498 
499 	// Send FD
500 	char iobuf[] = "test";
501 	struct iovec iov {
502 		.iov_base = iobuf,
503 		.iov_len = sizeof(iobuf),
504 	};
505 
506 	struct msghdr msg;
507 	memset(&msg, 0, sizeof(msg));
508 
509 	struct cmsghdr *cmsg;
510 	char buf[CMSG_SPACE(sizeof(fd))];
511 	memset(buf, 0, sizeof(buf));
512 	msg.msg_control = buf;
513 	msg.msg_controllen = sizeof(buf);
514 	msg.msg_iov = &iov;
515 	msg.msg_iovlen = 1;
516 
517 	cmsg = CMSG_FIRSTHDR(&msg);
518 	cmsg->cmsg_level = SOL_SOCKET;
519 	cmsg->cmsg_type = SCM_RIGHTS;
520 	cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
521 	memcpy(CMSG_DATA(cmsg), &fd, sizeof(fd));
522 	msg.msg_controllen = cmsg->cmsg_len;
523 
524 	status = sendmsg(sock, &msg, 0);
525 	if (status == -1) {
526 		REPORT_ERROR("sendmsg() failed: %s\n", strerror(errno));
527 		return 1;
528 	}
529 
530 	// Receive FD
531 	memset(buf, 0, sizeof(buf));
532 	msg.msg_control = buf;
533 	msg.msg_controllen = sizeof(buf);
534 	msg.msg_iov = &iov;
535 	msg.msg_iovlen = 1;
536 
537 	status = recvmsg(sock1, &msg, 0);
538 	if (status == -1) {
539 		REPORT_ERROR("recvmsg() failed: %s\n", strerror(errno));
540 		return 1;
541 	}
542 
543 	cmsg = CMSG_FIRSTHDR(&msg);
544 	if (cmsg == NULL) {
545 		REPORT_ERROR("recvmsg() failed: no control message\n");
546 		return 1;
547 	}
548 	if (cmsg->cmsg_level != SOL_SOCKET) {
549 		REPORT_ERROR("recvmsg() failed: unexpected level %d\n", cmsg->cmsg_level);
550 		return 1;
551 	}
552 	if (cmsg->cmsg_type != SCM_RIGHTS) {
553 		REPORT_ERROR("recvmsg() failed: unexpected type %d\n", cmsg->cmsg_type);
554 		return 1;
555 	}
556 	if (cmsg->cmsg_len != CMSG_LEN(sizeof(fd))) {
557 		REPORT_ERROR("recvmsg() failed: unexpected length %ld\n", cmsg->cmsg_len);
558 		return 1;
559 	}
560 
561 	int fd1;
562 	memcpy(&fd1, CMSG_DATA(cmsg), sizeof(fd1));
563 	if (fd1 == -1) {
564 		REPORT_ERROR("recvmsg() failed: unexpected fd %d\n", fd1);
565 		return 1;
566 	}
567 
568 	// Check that the FD refers to the same file
569 	struct stat statbuf;
570 	status = fstat(fd, &statbuf);
571 	if (status == -1) {
572 		REPORT_ERROR("fstat() failed: %s\n", strerror(errno));
573 		return 1;
574 	}
575 
576 	struct stat statbuf1;
577 	status = fstat(fd1, &statbuf1);
578 	if (status == -1) {
579 		REPORT_ERROR("fstat() failed: %s\n", strerror(errno));
580 		return 1;
581 	}
582 
583 	if (statbuf.st_dev != statbuf1.st_dev) {
584 		REPORT_ERROR("recvmsg() failed: unexpected device %ld\n", (long)statbuf1.st_dev);
585 		return 1;
586 	}
587 	if (statbuf.st_ino != statbuf1.st_ino) {
588 		REPORT_ERROR("recvmsg() failed: unexpected inode %ld\n", (long)statbuf1.st_ino);
589 		return 1;
590 	}
591 
592 	close(sock);
593 	close(sock1);
594 	close(fd);
595 	close(fd1);
596 
597 	unlink("test.sock");
598 	unlink("test1.sock");
599 
600 	return 0;
601 }
602 
603 
604 int
605 main()
606 {
607 	if (connect_test() != 0)
608 		return 1;
609 
610 	if (send_test() != 0)
611 		return 1;
612 
613 	if (shutdown_test() != 0)
614 		return 1;
615 
616 	if (send_fd_test() != 0)
617 		return 1;
618 
619 	return 0;
620 }
621