1 /* -*- Mode: c; tab-width: 8; indent-tabs-mode: 1; c-basic-offset: 8; -*- */
3 #include <darwintest.h>
8 #include <sys/socket.h>
9 #include <netinet/in.h>
10 #include <arpa/inet.h>
14 #include <TargetConditionals.h>
16 T_GLOBAL_META(T_META_RUN_CONCURRENTLY(true));
21 sock_open_common(int pf
, int type
)
25 s
= socket(pf
, type
, 0);
27 T_ASSERT_POSIX_SUCCESS(s
, "socket(%d, %d, 0)", pf
, type
);
34 return sock_open_common(PF_INET
, type
);
38 sock_bind(int s
, int port
)
40 struct sockaddr_in sin
= {
41 .sin_len
= sizeof(sin
),
42 .sin_family
= AF_INET
,
45 sin
.sin_port
= htons(port
);
46 return bind(s
, (const struct sockaddr
*)&sin
, sizeof(sin
));
52 return sock_open_common(PF_INET6
, type
);
56 sockv6_bind(int s
, int port
)
58 struct sockaddr_in6 sin6
= {
59 .sin6_len
= sizeof(sin6
),
60 .sin6_family
= AF_INET6
,
63 sin6
.sin6_port
= htons(port
);
64 return bind(s
, (const struct sockaddr
*)&sin6
, sizeof(sin6
));
68 sock_get_port(int sockfd
)
72 union sockaddr_in_4_6 sin
;
75 sin_len
= sizeof(sin
);
77 error
= getsockname(sockfd
, (struct sockaddr
*)&sin
, &sin_len
);
79 T_EXPECT_POSIX_ZERO(error
, "getsockname(%d)", sockfd
);
83 switch (sin
.sa
.sa_family
) {
88 p
= sin
.sin6
.sin6_port
;
91 T_ASSERT_FAIL("unknown address family %d\n",
103 } SocketInfo
, * SocketInfoRef
;
106 bind_sockets(SocketInfoRef info
, const char * msg
)
108 for (int i
= 0; i
< info
->socket_count
; i
++) {
113 error
= sockv6_bind(info
->socket_list
[i
], 0);
115 error
= sock_bind(info
->socket_list
[i
], 0);
117 port
= sock_get_port(info
->socket_list
[i
]);
119 T_LOG( "%s: fd %d port is %d error %d",
120 msg
, info
->socket_list
[i
], ntohs(port
), error
);
127 second_thread(void * arg
)
129 SocketInfoRef info
= (SocketInfoRef
)arg
;
131 bind_sockets(info
, "second");
136 multithreaded_bind_test(bool v6
, int socket_count
)
140 int socket_list
[socket_count
];
144 for (int i
= 0; i
< socket_count
; i
++) {
146 socket_list
[i
] = sockv6_open(SOCK_STREAM
);
148 socket_list
[i
] = sock_open(SOCK_STREAM
);
151 info
.socket_count
= socket_count
;
152 info
.socket_list
= socket_list
;
153 error
= pthread_create(&thread
, NULL
, second_thread
, &info
);
155 T_ASSERT_POSIX_ZERO(error
, "pthread_create");
157 /* compete with second thread */
158 bind_sockets(&info
, "main");
159 error
= pthread_join(thread
, NULL
);
161 T_ASSERT_POSIX_ZERO(error
, "pthread_join");
163 for (int i
= 0; i
< socket_count
; i
++) {
164 error
= close(socket_list
[i
]);
166 T_ASSERT_POSIX_ZERO(error
, "close socket %d", socket_list
[i
]);
171 run_multithreaded_bind_test(int number_of_runs
, bool v6
, int socket_count
)
174 T_SKIP("Not enough memory to handle this test");
175 #else /* TARGET_OS_BRIDGE */
176 for (int i
= 0; i
< number_of_runs
; i
++) {
177 multithreaded_bind_test(v6
, socket_count
);
179 T_PASS("multithreaded_bind_test %s", v6
? "IPv6" : "IPv4");
180 #endif /* TARGET_OS_BRIDGE */
183 T_DECL(socket_bind_35685803
,
184 "multithreaded bind IPv4 socket as root",
185 T_META_ASROOT(false),
186 T_META_CHECK_LEAKS(false))
188 run_multithreaded_bind_test(100, false, 100);
191 T_DECL(socket_bind_35685803_root
,
192 "multithreaded bind IPv4 socket",
195 run_multithreaded_bind_test(100, false, 100);
198 T_DECL(socket_bind_35685803_v6
,
199 "multithreaded bind IPv6 socket as root",
200 T_META_ASROOT(false),
201 T_META_CHECK_LEAKS(false))
203 run_multithreaded_bind_test(100, true, 100);
206 T_DECL(socket_bind_35685803_v6_root
,
207 "multithreaded bind IPv6 socket",
210 run_multithreaded_bind_test(100, true, 100);