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>
18 sock_open_common(int pf
, int type
)
22 s
= socket(pf
, type
, 0);
24 T_ASSERT_POSIX_SUCCESS(s
, "socket(%d, %d, 0)", pf
, type
);
31 return (sock_open_common(PF_INET
, type
));
35 sock_bind(int s
, int port
)
37 struct sockaddr_in sin
= {
38 .sin_len
= sizeof(sin
),
39 .sin_family
= AF_INET
,
42 sin
.sin_port
= htons(port
);
43 return (bind(s
, (const struct sockaddr
*)&sin
, sizeof(sin
)));
49 return (sock_open_common(PF_INET6
, type
));
53 sockv6_bind(int s
, int port
)
55 struct sockaddr_in6 sin6
= {
56 .sin6_len
= sizeof(sin6
),
57 .sin6_family
= AF_INET6
,
60 sin6
.sin6_port
= htons(port
);
61 return (bind(s
, (const struct sockaddr
*)&sin6
, sizeof(sin6
)));
65 sock_get_port(int sockfd
)
69 union sockaddr_in_4_6 sin
;
72 sin_len
= sizeof(sin
);
74 error
= getsockname(sockfd
, (struct sockaddr
*)&sin
, &sin_len
);
76 T_EXPECT_POSIX_ZERO(error
, "getsockname(%d)", sockfd
);
80 switch (sin
.sa
.sa_family
) {
85 p
= sin
.sin6
.sin6_port
;
88 T_ASSERT_FAIL("unknown address family %d\n",
100 } SocketInfo
, * SocketInfoRef
;
103 bind_sockets(SocketInfoRef info
, const char * msg
)
105 for (int i
= 0; i
< info
->socket_count
; i
++) {
110 error
= sockv6_bind(info
->socket_list
[i
], 0);
113 error
= sock_bind(info
->socket_list
[i
], 0);
115 port
= sock_get_port(info
->socket_list
[i
]);
117 T_LOG( "%s: fd %d port is %d error %d",
118 msg
, info
->socket_list
[i
], ntohs(port
), error
);
125 second_thread(void * arg
)
127 SocketInfoRef info
= (SocketInfoRef
)arg
;
129 bind_sockets(info
, "second");
134 multithreaded_bind_test(bool v6
, int socket_count
)
138 int socket_list
[socket_count
];
142 for (int i
= 0; i
< socket_count
; i
++) {
144 socket_list
[i
] = sockv6_open(SOCK_STREAM
);
146 socket_list
[i
] = sock_open(SOCK_STREAM
);
149 info
.socket_count
= socket_count
;
150 info
.socket_list
= socket_list
;
151 error
= pthread_create(&thread
, NULL
, second_thread
, &info
);
153 T_ASSERT_POSIX_ZERO(error
, "pthread_create");
155 /* compete with second thread */
156 bind_sockets(&info
, "main");
157 error
= pthread_join(thread
, NULL
);
159 T_ASSERT_POSIX_ZERO(error
, "pthread_join");
161 for (int i
= 0; i
< socket_count
; i
++) {
162 error
= close(socket_list
[i
]);
164 T_ASSERT_POSIX_ZERO(error
, "close socket %d", socket_list
[i
]);
169 run_multithreaded_bind_test(int number_of_runs
, bool v6
, int socket_count
)
171 for (int i
= 0; i
< number_of_runs
; i
++) {
172 multithreaded_bind_test(v6
, socket_count
);
174 T_PASS("multithreaded_bind_test %s", v6
? "IPv6" : "IPv4");
177 T_DECL(socket_bind_35685803
,
178 "multithreaded bind IPv4 socket as root",
179 T_META_ASROOT(false),
180 T_META_CHECK_LEAKS(false))
182 run_multithreaded_bind_test(100, false, 100);
185 T_DECL(socket_bind_35685803_root
,
186 "multithreaded bind IPv4 socket",
189 run_multithreaded_bind_test(100, false, 100);
192 T_DECL(socket_bind_35685803_v6
,
193 "multithreaded bind IPv6 socket as root",
194 T_META_ASROOT(false),
195 T_META_CHECK_LEAKS(false))
197 run_multithreaded_bind_test(100, true, 100);
200 T_DECL(socket_bind_35685803_v6_root
,
201 "multithreaded bind IPv6 socket",
204 run_multithreaded_bind_test(100, true, 100);