mhd_check_poll_quirks.m4 (10220B)
1 # SPDX-License-Identifier: FSFAP 2 # 3 # SYNOPSIS 4 # 5 # MHD_CHECK_POLL_QUIRKS 6 # 7 # DESCRIPTION 8 # 9 # Check whether the system poll() (or WSAPoll()) function has any known 10 # quirks. 11 # 12 # If any such quirks are detected, corresponding preprocessor macros 13 # are defined. 14 # 15 # The configure.ac script must check for the presence of all headers 16 # used by this macro before "invoking" it. 17 # 18 # LICENSE 19 # 20 # Copyright (c) 2025 Karlson2k (Evgeny Grin) <k2k@drgrin.dev> 21 # 22 # Copying and distribution of this file, with or without modification, are 23 # permitted in any medium without royalty provided the copyright notice 24 # and this notice are preserved. This file is offered as-is, without any 25 # warranty. 26 27 #serial 1 28 29 AC_DEFUN([MHD_CHECK_POLL_QUIRKS],[dnl 30 AC_PREREQ([2.64])dnl 31 AC_REQUIRE([AC_CANONICAL_HOST])dnl 32 AC_REQUIRE([AC_PROG_CC])dnl 33 AC_LANG_ASSERT([C])dnl 34 AS_IF([test -z "$use_itc"],[AC_MSG_FAILURE([\$use_itc is not set])]) 35 AS_VAR_IF([have_poll],["yes"],[:],[AC_MSG_FAILURE([\$have_poll is not 'yes'])]) 36 AC_CACHE_CHECK([[whether poll() clobbers fds.events]], 37 [[mhd_cv_poll_clobbers_events]], [dnl 38 AC_RUN_IFELSE([ 39 AC_LANG_SOURCE([[ 40 41 #ifdef HAVE_SYS_TYPES_H 42 # include <sys/types.h> 43 #endif 44 #ifdef HAVE_UNISTD_H 45 # include <unistd.h> 46 #endif 47 #ifdef HAVE_STDLIB_H 48 # include <stdlib.h> 49 #endif 50 #ifdef HAVE_SYS_SOCKET_H 51 # include <sys/socket.h> 52 #endif 53 #ifdef HAVE_SOCKLIB_H 54 # include <sockLib.h> 55 #endif 56 #ifdef HAVE_INETLIB_H 57 # include <inetLib.h> 58 #endif 59 #ifdef HAVE_NETINET_IN_H 60 # include <netinet/in.h> 61 #endif 62 #ifdef HAVE_SYS_UN_H 63 # include <sys/un.h> 64 #endif 65 #ifdef HAVE_ARPA_INET_H 66 # include <arpa/inet.h> 67 #endif 68 #if defined(HAVE_NETDB_H) 69 # include <netdb.h> 70 #endif 71 #ifdef HAVE_NETINET_TCP_H 72 # include <netinet/tcp.h> 73 #endif 74 #if !defined(_WIN32) || defined(__CYGWIN__) 75 # include <poll.h> 76 #else 77 # include <winsock2.h> 78 # include <ws2tcpip.h> 79 # ifndef MHD_ITC_SOCKETPAIR_ 80 #error Only socketpair ITC supported on native W32 81 choke me now 82 # endif 83 #endif 84 #include <stdio.h> 85 86 #if defined(MHD_ITC_EVENTFD_) 87 # include <sys/eventfd.h> 88 #elif defined(MHD_ITC_PIPE_) 89 /* No Additional includes */ 90 #elif defined(MHD_ITC_SOCKETPAIR_) 91 /* No Additional includes */ 92 #else 93 #error No selected ITC type 94 choke me now 95 #endif 96 97 #if defined(PF_INET) 98 # define my_PF_INET PF_INET 99 #else 100 # define my_PF_INET AF_INET 101 #endif 102 103 #if !defined(_WIN32) || defined(__CYGWIN__) 104 # define CHECK_USE_POSIX_SOCKETS 1 105 # define my_sckt_type int 106 # define MY_INVALID_SOCKET (-1) 107 # define my_send3(s,b,l) send((s),(b),(l),0) 108 # define my_fd_close(skt) close((skt)) 109 #else 110 # define CHECK_USE_WINSOCK_SOCKETS 1 111 # define my_sckt_type SOCKET 112 # define MY_INVALID_SOCKET INVALID_SOCKET 113 # define my_send3(s,b,l) send((s),(const char *)(b),(l),0) 114 # define my_fd_close(skt) closesocket((skt)) 115 #endif 116 117 #if defined(MHD_ITC_SOCKETPAIR_) 118 # ifdef CHECK_USE_POSIX_SOCKETS 119 # if defined(AF_UNIX) 120 # define my_socketpair(sk_arr) socketpair(AF_UNIX, SOCK_STREAM, 0, (sk_arr)) 121 # elif defined(AF_LOCAL) 122 # define my_socketpair(sk_arr) socketpair(AF_LOCAL, SOCK_STREAM, 0, (sk_arr)) 123 # else 124 # define my_socketpair(sk_arr) socketpair(AF_INET, SOCK_STREAM, 0, (sk_arr)) 125 # endif 126 # else /* WinSock sockets */ 127 static int my_socket_nonblocking (SOCKET sckt); 128 129 static int my_socketpair (my_sckt_type sckt[2]) 130 { 131 int i; 132 133 #define PAIR_MAX_TRIES 511 134 for (i = 0; i < PAIR_MAX_TRIES; i++) 135 { 136 struct sockaddr_in listen_addr; 137 my_sckt_type listen_s; 138 static const socklen_t c_addinlen = sizeof(struct sockaddr_in); /* Try to help compiler to optimise */ 139 socklen_t addr_len = c_addinlen; 140 141 listen_s = socket (AF_INET, 142 SOCK_STREAM, 143 0); 144 if (INVALID_SOCKET == listen_s) 145 break; /* can't create even single socket */ 146 147 listen_addr.sin_family = AF_INET; 148 listen_addr.sin_port = 0; /* same as htons(0) */ 149 listen_addr.sin_addr.s_addr = htonl (INADDR_LOOPBACK); 150 151 if ( ((0 == bind (listen_s, 152 (struct sockaddr *) &listen_addr, 153 c_addinlen)) && 154 (0 == listen (listen_s, 155 1) ) && 156 (0 == getsockname (listen_s, 157 (struct sockaddr *) &listen_addr, 158 &addr_len))) ) 159 { 160 my_sckt_type client_s = socket (AF_INET, SOCK_STREAM, 0); 161 struct sockaddr_in accepted_from_addr; 162 struct sockaddr_in client_addr; 163 164 if (INVALID_SOCKET != client_s) 165 { 166 if (my_socket_nonblocking (client_s) && 167 ( (0 == connect (client_s, 168 (struct sockaddr *) &listen_addr, 169 c_addinlen)) || 170 (WSAEWOULDBLOCK == WSAGetLastError()) )) 171 { 172 my_sckt_type server_s; 173 174 addr_len = c_addinlen; 175 server_s = accept (listen_s, 176 (struct sockaddr *) &accepted_from_addr, 177 &addr_len); 178 if (INVALID_SOCKET != server_s) 179 { 180 addr_len = c_addinlen; 181 if ( (0 == getsockname (client_s, 182 (struct sockaddr *) &client_addr, 183 &addr_len)) && 184 (accepted_from_addr.sin_port == client_addr.sin_port) && 185 (accepted_from_addr.sin_addr.s_addr == 186 client_addr.sin_addr.s_addr) ) 187 { 188 closesocket (listen_s); 189 return 0; 190 } 191 closesocket (server_s); 192 } 193 } 194 closesocket (client_s); 195 } 196 } 197 closesocket (listen_s); 198 } 199 200 sckt[0] = INVALID_SOCKET; 201 sckt[1] = INVALID_SOCKET; 202 203 return -1; 204 } 205 206 static int my_socket_nonblocking (SOCKET sckt) 207 { 208 unsigned long set_flag = 1; 209 210 if (0 == ioctlsocket (sckt, (long) FIONBIO, &set_flag)) 211 return !0; 212 213 return 0; 214 } 215 216 # endif 217 #endif 218 219 static int check_poll_fn(void) 220 { 221 int res; 222 int err_res = 0; 223 struct pollfd fds[2]; 224 #ifdef MHD_ITC_EVENTFD_ 225 my_sckt_type itc_fd; 226 #else 227 my_sckt_type itc_pair[2]; 228 #endif 229 my_sckt_type listen_skt; 230 231 #if defined(MHD_ITC_EVENTFD_) 232 itc_fd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK); 233 if (0 > itc_fd) 234 err_res = 10; 235 else 236 { 237 if (1) /* for local scope */ 238 { 239 unsigned char val[8] = {1u, 0u, 0u, 0u, 0u, 0u, 0u, 0u}; 240 if (0 > write (itc_fd, (void *) val, 8)) /* "activate" ITC */ 241 (void) res; /* ignore result */ 242 } 243 fds[0].fd = itc_fd; 244 #elif defined(MHD_ITC_PIPE_) 245 # ifdef HAVE_PIPE2_FUNC 246 res = pipe2(itc_pair, 0 247 # ifdef O_CLOEXEC 248 | O_CLOEXEC 249 # endif 250 # ifdef O_NONBLOCK 251 | O_NONBLOCK 252 # endif 253 ); 254 # else 255 res = pipe(itc_pair); 256 # endif 257 if (0 != res) 258 err_res = 11; 259 else 260 { 261 if (1) /* for local scope */ 262 { 263 unsigned char val = 1u; 264 if (0 > write (itc_pair[1], (void *) &val, 1)) /* "activate" ITC */ 265 (void) res; /* ignore result */ 266 } 267 fds[0].fd = itc_pair[0]; 268 #elif defined(MHD_ITC_SOCKETPAIR_) 269 res = my_socketpair(itc_pair); 270 if (0 != res) 271 err_res = 12; 272 else 273 { 274 if (1) /* for local scope */ 275 { 276 unsigned char val = 1u; 277 if (0 > my_send3(itc_pair[1], (void *) &val, 1)) /* "activate" ITC */ 278 (void) 0; /* ignore result */ 279 } 280 fds[0].fd = itc_pair[0]; 281 #endif 282 fds[0].events = POLLIN; 283 284 285 listen_skt = socket(my_PF_INET, SOCK_STREAM, 0); 286 if (MY_INVALID_SOCKET == listen_skt) 287 err_res = 13; 288 else 289 { 290 if (1) /* for local scope */ 291 { 292 struct sockaddr_in sk_addr; 293 294 sk_addr.sin_family = AF_INET; 295 sk_addr.sin_addr.s_addr = INADDR_ANY; 296 sk_addr.sin_port = 0; 297 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN 298 sk_addr.sin_len = sizeof(sk_addr); 299 #endif 300 301 res = bind(listen_skt, (struct sockaddr *) &sk_addr, sizeof(sk_addr)); 302 (void) res; /* ignore result */ 303 } 304 305 res = listen(listen_skt, 8); 306 (void) res; /* ignore result */ 307 308 fds[1].fd = listen_skt; 309 fds[1].events = POLLIN; 310 311 #ifdef CHECK_USE_POSIX_SOCKETS 312 res = poll(fds, 2, 0); 313 #else 314 res = WSAPoll(fds, 2, 0); 315 #endif 316 if (0 > res) 317 err_res = 14; 318 319 if (POLLIN != fds[0].events) 320 { 321 fprintf (stderr, "fds[0].events changed from 0x%X to 0x%X\n", (unsigned int) POLLIN, (unsigned int) fds[0].events); 322 err_res = 97; /* Magic number */ 323 } 324 if (POLLIN != fds[1].events) 325 { 326 fprintf (stderr, "fds[1].events changed from 0x%X to 0x%X\n", (unsigned int) POLLIN, (unsigned int) fds[1].events); 327 err_res = 97; /* Magic number */ 328 } 329 res = my_fd_close(listen_skt); 330 (void) res; /* Ignore result */ 331 } 332 #if defined(MHD_ITC_EVENTFD_) 333 res = my_fd_close(itc_fd); 334 (void) res; /* Ignore result */ 335 #else 336 res = my_fd_close(itc_pair[1]); 337 (void) res; /* Ignore result */ 338 res = my_fd_close(itc_pair[0]); 339 (void) res; /* Ignore result */ 340 #endif 341 } 342 return err_res; 343 } 344 345 int main(void) 346 { 347 int err_res; 348 #ifdef CHECK_USE_WINSOCK_SOCKETS 349 if (1) /* for local scope */ 350 { 351 WSADATA wsa_d; 352 if (0 != WSAStartup(MAKEWORD(2, 2), &wsa_d)) 353 return 5; 354 } 355 #endif 356 err_res = check_poll_fn(); 357 if ((0 != err_res) && (97 != err_res)) 358 fprintf (stderr, "Failed to preform poll() checking.\n"); 359 360 #ifdef MHD_SOCKETS_KIND_WINSOCK 361 (void) WSACleanup(); 362 #endif /* MHD_SOCKETS_KIND_WINSOCK */ 363 364 return err_res; 365 } 366 367 ]] 368 ) 369 ], 370 [mhd_cv_poll_clobbers_events="no"], 371 [ 372 test_res="$?" 373 AS_IF([test "$test_res" -eq 0],[AC_MSG_FAILURE()], 374 [test "$test_res" -eq 97],[mhd_cv_poll_clobbers_events="yes"] # Test magic number 375 ,[mhd_cv_poll_clobbers_events="assuming yes"] 376 ) 377 AS_UNSET([test_res]) 378 ], 379 [ 380 AS_CASE(["$host_os"], 381 [haiku],[mhd_cv_poll_clobbers_events="assuming yes"], 382 [mhd_cv_poll_clobbers_events="guessing no"] 383 ) 384 ] 385 ) 386 ] 387 ) 388 AS_CASE([$mhd_cv_poll_clobbers_events], 389 [*yes], 390 [AC_DEFINE([HAVE_POLL_CLOBBERS_EVENTS], 391 [1],[Define to '1' is poll() change value of 'events' member of array pointed by 'fds']) 392 ] 393 ) 394 ])