xref: /xnu-10002.81.5/tests/accept_race.c (revision 5e3eaea39dcf651e66cb99ba7d70e32cc4a99587)
1 #include <pthread.h>
2 #include <stdlib.h>
3 #include <arpa/inet.h>
4 #include <netinet/in.h>
5 #include <stdio.h>
6 #include <sys/socket.h>
7 #include <sys/types.h>
8 #include <sys/uio.h>
9 #include <unistd.h>
10 #include <darwintest.h>
11 
12 #define BASE_PORT 2020
13 
14 static int port = BASE_PORT;
15 static bool server_ready = false;
16 
17 static void
client(void)18 client(void)
19 {
20 	int i = 0;
21 	while (i < 9000) {
22 		int sock = socket(PF_INET, SOCK_STREAM, 0);
23 		T_QUIET; T_ASSERT_POSIX_SUCCESS(sock, "socket");
24 		struct sockaddr_in raddr;
25 		raddr.sin_family = AF_INET;
26 		raddr.sin_port = htons(port);
27 		raddr.sin_addr.s_addr = inet_addr("127.0.0.1");
28 		int res = connect(sock, (struct sockaddr *)&raddr, sizeof(raddr));
29 		if (res < 0 && (errno == EADDRNOTAVAIL || errno == ECONNREFUSED)) {
30 			close(sock);
31 			return;
32 		} else if (res < 0 && errno == ECONNREFUSED) {
33 		} else {
34 			T_QUIET; T_ASSERT_POSIX_SUCCESS(res, "connect");
35 		}
36 		close(sock);
37 		i++;
38 	}
39 }
40 
41 static void *
server(void * arg __unused)42 server(void *arg __unused)
43 {
44 	int sock = socket(PF_INET, SOCK_STREAM, 0);
45 	T_ASSERT_POSIX_SUCCESS(sock, "socket");
46 
47 	struct sockaddr_in laddr;
48 	laddr.sin_family = AF_INET;
49 	laddr.sin_port = htons(port);
50 	laddr.sin_addr.s_addr = 0;
51 	int res = bind(sock, (struct sockaddr *)&laddr, sizeof(laddr));
52 	if (res == -1 && errno == EADDRNOTAVAIL) {
53 		port = BASE_PORT;
54 		port += arc4random_uniform(512);
55 		res = bind(sock, (struct sockaddr *)&laddr, sizeof(laddr));
56 	}
57 	T_ASSERT_POSIX_SUCCESS(res, "bind");
58 	T_ASSERT_POSIX_SUCCESS(listen(sock, 10), "listen");
59 	server_ready = true;
60 	while (1) {
61 		struct sockaddr_in sin;
62 		socklen_t slen = sizeof(sin);
63 		int c = accept(sock, (struct sockaddr *)&sin, &slen);
64 		T_QUIET; T_ASSERT_POSIX_SUCCESS(c, "accept");
65 		char buf[1];
66 		T_QUIET; T_ASSERT_POSIX_SUCCESS(read(c, buf, 1), "read");
67 		close(c);
68 	}
69 	return NULL;
70 }
71 
72 T_DECL(accept_race,
73     "Exercises a race condition between socantrcvmore() and accept()",
74     T_META_CHECK_LEAKS(false))
75 {
76 	// Pick a random port
77 	port += arc4random_uniform(1024);
78 
79 	pthread_t server_th;
80 	if (pthread_create(&server_th, 0, server, NULL)) {
81 		T_FAIL("pthread_create failed");
82 	}
83 	while (!server_ready) {
84 		sleep(1);
85 	}
86 	client();
87 }
88