libmicrohttpd

HTTP/1.x server C library (MHD 1.x, stable)
Log | Files | Refs | Submodules | README | LICENSE

commit f5a72d27f36cdcd9958298e77aa85c2d7ee1d714
parent f73ab438317568b24cf005ae38cf36e01920d74d
Author: Evgeny Grin (Karlson2k) <k2k@narod.ru>
Date:   Wed, 15 Nov 2023 15:33:33 +0300

Implemented new option MHD_OPTION_SOCK_ADDR_LEN

Improved detection of TCP/IP port in application-provided sockaddr.
Added automatic detection of used address facility (sockets type).
Improved support of platforms with sa_len, ss_len, sin_len and sin6_len.

Diffstat:
Mconfigure.ac | 10++++++++--
Msrc/include/microhttpd.h | 22++++++++++++++++++++--
Msrc/microhttpd/daemon.c | 427+++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------------
Msrc/microhttpd/test_options.c | 176+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
4 files changed, 507 insertions(+), 128 deletions(-)

diff --git a/configure.ac b/configure.ac @@ -2552,8 +2552,8 @@ AC_INCLUDES_DEFAULT ] ) -AC_CHECK_MEMBERS([struct sockaddr_in.sin_len, struct sockaddr_in6.sin6_len, - struct sockaddr_storage.ss_len], +AC_CHECK_MEMBERS([struct sockaddr.sa_len, struct sockaddr_storage.ss_len, + struct sockaddr_in.sin_len, struct sockaddr_in6.sin6_len], [], [], [ #ifdef HAVE_SYS_TYPES_H @@ -2565,6 +2565,12 @@ AC_CHECK_MEMBERS([struct sockaddr_in.sin_len, struct sockaddr_in6.sin6_len, #ifdef HAVE_NETINET_IN_H #include <netinet/in.h> #endif +#ifdef HAVE_WINSOCK2_H +#include <winsock2.h> +#endif +#ifdef HAVE_WS2TCPIP_H +#include <ws2tcpip.h> +#endif ]) MHD_CHECK_LINK_RUN([[f][or working getsockname()]],[[mhd_cv_getsockname_usable]], diff --git a/src/include/microhttpd.h b/src/include/microhttpd.h @@ -96,7 +96,7 @@ extern "C" * they are parsed as decimal numbers. * Example: 0x01093001 = 1.9.30-1. */ -#define MHD_VERSION 0x00097705 +#define MHD_VERSION 0x00097706 /* If generic headers don't work on your platform, include headers which define 'va_list', 'size_t', 'ssize_t', 'intptr_t', 'off_t', @@ -1704,6 +1704,8 @@ enum MHD_OPTION * be followed by a `struct sockaddr *`. If #MHD_USE_IPv6 is * specified, the `struct sockaddr*` should point to a `struct * sockaddr_in6`, otherwise to a `struct sockaddr_in`. + * Silently ignored if followed by NULL pointer. + * @deprecated Use #MHD_OPTION_SOCK_ADDR_LEN */ MHD_OPTION_SOCK_ADDR = 6, @@ -2142,7 +2144,23 @@ enum MHD_OPTION * This option should be followed by a positive 'int' argument. * @note Available since #MHD_VERSION 0x00097705 */ - MHD_OPTION_APP_FD_SETSIZE = 39 + MHD_OPTION_APP_FD_SETSIZE = 39, + + /** + * Bind daemon to the supplied 'struct sockaddr'. This option should + * be followed by two parameters: 'socklen_t' the size of memory at the next + * pointer and the pointer 'const struct sockaddr *'. + * Note: the order of the arguments is not the same as for system bind() and + * other network functions. + * If #MHD_USE_IPv6 is specified, the 'struct sockaddr*' should + * point to a 'struct sockaddr_in6'. + * The socket domain (protocol family) is detected from provided + * 'struct sockaddr'. IP, IPv6 and UNIX sockets are supported (if supported + * by the platform). Other types may work occasionally. + * Silently ignored if followed by zero size and NULL pointer. + * @note Available since #MHD_VERSION 0x00097706 + */ + MHD_OPTION_SOCK_ADDR_LEN = 40 } _MHD_FIXED_ENUM; diff --git a/src/microhttpd/daemon.c b/src/microhttpd/daemon.c @@ -6181,7 +6181,22 @@ struct MHD_InterimParams_ * Application-provided listen socket. */ MHD_socket listen_fd; - + /** + * Set to 'true' if @a server_addr is set by application. + */ + bool pserver_addr_set; + /** + * Application-provided struct sockaddr to bind server to. + */ + const struct sockaddr *pserver_addr; + /** + * Set to 'true' if @a server_addr_len is set by application. + */ + bool server_addr_len_set; + /** + * Applicaiton-provided the size of the memory pointed by @a server_addr. + */ + socklen_t server_addr_len; }; /** @@ -6208,7 +6223,6 @@ typedef void */ static enum MHD_Result parse_options_va (struct MHD_Daemon *daemon, - const struct sockaddr **servaddr, struct MHD_InterimParams_ *params, va_list ap); @@ -6224,7 +6238,6 @@ parse_options_va (struct MHD_Daemon *daemon, */ static enum MHD_Result parse_options (struct MHD_Daemon *daemon, - const struct sockaddr **servaddr, struct MHD_InterimParams_ *params, ...) { @@ -6233,7 +6246,6 @@ parse_options (struct MHD_Daemon *daemon, va_start (ap, params); ret = parse_options_va (daemon, - servaddr, params, ap); va_end (ap); @@ -6507,15 +6519,13 @@ daemon_tls_priorities_init_append (struct MHD_Daemon *daemon, const char *prio) /** * Parse a list of options given as varargs. * - * @param daemon the daemon to initialize - * @param servaddr where to store the server's listen address - * @param params the interim parameters to be assigned to + * @param[in,out] daemon the daemon to initialize + * @param[out] params the interim parameters to be assigned to * @param ap the options * @return #MHD_YES on success, #MHD_NO on error */ static enum MHD_Result parse_options_va (struct MHD_Daemon *daemon, - const struct sockaddr **servaddr, struct MHD_InterimParams_ *params, va_list ap) { @@ -6618,9 +6628,19 @@ parse_options_va (struct MHD_Daemon *daemon, daemon->per_ip_connection_limit = va_arg (ap, unsigned int); break; + case MHD_OPTION_SOCK_ADDR_LEN: + params->server_addr_len = va_arg (ap, + socklen_t); + params->server_addr_len_set = true; + params->pserver_addr = va_arg (ap, + const struct sockaddr *); + params->pserver_addr_set = true; + break; case MHD_OPTION_SOCK_ADDR: - *servaddr = va_arg (ap, - const struct sockaddr *); + params->server_addr_len_set = false; + params->pserver_addr = va_arg (ap, + const struct sockaddr *); + params->pserver_addr_set = true; break; case MHD_OPTION_URI_LOG_CALLBACK: daemon->uri_log_callback = va_arg (ap, @@ -7006,7 +7026,6 @@ parse_options_va (struct MHD_Daemon *daemon, case MHD_OPTION_CONNECTION_MEMORY_INCREMENT: case MHD_OPTION_THREAD_STACK_SIZE: if (MHD_NO == parse_options (daemon, - servaddr, params, opt, (size_t) oa[i].value, @@ -7025,7 +7044,6 @@ parse_options_va (struct MHD_Daemon *daemon, case MHD_OPTION_SERVER_INSANITY: case MHD_OPTION_DIGEST_AUTH_NONCE_BIND_TYPE: if (MHD_NO == parse_options (daemon, - servaddr, params, opt, (unsigned int) oa[i].value, @@ -7036,7 +7054,6 @@ parse_options_va (struct MHD_Daemon *daemon, case MHD_OPTION_HTTPS_CRED_TYPE: #ifdef HTTPS_SUPPORT if (MHD_NO == parse_options (daemon, - servaddr, params, opt, (gnutls_credentials_type_t) oa[i].value, @@ -7047,7 +7064,6 @@ parse_options_va (struct MHD_Daemon *daemon, /* all options taking 'MHD_socket' */ case MHD_OPTION_LISTEN_SOCKET: if (MHD_NO == parse_options (daemon, - servaddr, params, opt, (MHD_socket) oa[i].value, @@ -7061,7 +7077,6 @@ parse_options_va (struct MHD_Daemon *daemon, case MHD_OPTION_TLS_NO_ALPN: case MHD_OPTION_APP_FD_SETSIZE: if (MHD_NO == parse_options (daemon, - servaddr, params, opt, (int) oa[i].value, @@ -7081,7 +7096,6 @@ parse_options_va (struct MHD_Daemon *daemon, case MHD_OPTION_HTTPS_CERT_CALLBACK: case MHD_OPTION_HTTPS_CERT_CALLBACK2: if (MHD_NO == parse_options (daemon, - servaddr, params, opt, oa[i].ptr_value, @@ -7096,7 +7110,6 @@ parse_options_va (struct MHD_Daemon *daemon, case MHD_OPTION_UNESCAPE_CALLBACK: case MHD_OPTION_GNUTLS_PSK_CRED_HANDLER: if (MHD_NO == parse_options (daemon, - servaddr, params, opt, (void *) oa[i].value, @@ -7108,7 +7121,6 @@ parse_options_va (struct MHD_Daemon *daemon, case MHD_OPTION_DIGEST_AUTH_RANDOM: case MHD_OPTION_DIGEST_AUTH_RANDOM_COPY: if (MHD_NO == parse_options (daemon, - servaddr, params, opt, (size_t) oa[i].value, @@ -7116,6 +7128,16 @@ parse_options_va (struct MHD_Daemon *daemon, MHD_OPTION_END)) return MHD_NO; break; + /* options taking socklen_t-number followed by pointer */ + case MHD_OPTION_SOCK_ADDR_LEN: + if (MHD_NO == parse_options (daemon, + params, + opt, + (socklen_t) oa[i].value, + oa[i].ptr_value, + MHD_OPTION_END)) + return MHD_NO; + break; case MHD_OPTION_END: /* Not possible */ default: return MHD_NO; @@ -7342,13 +7364,19 @@ setup_epoll_to_listen (struct MHD_Daemon *daemon) /** * Apply interim parameters - * @param d the daemon to use - * @param params the interim parameters to process + * @param[in,out] d the daemon to use + * @param[out] ppsockaddr the pointer to store the pointer to 'struct sockaddr' + * if provided by application + * @param[out] psockaddr_len the size memory area pointed by 'struct sockaddr' + * if provided by application + * @param[in] params the interim parameters to process * @return true in case of success, * false in case of critical error (the daemon must be closed). */ static bool process_interim_params (struct MHD_Daemon *d, + const struct sockaddr **ppsockaddr, + socklen_t *psockaddr_len, struct MHD_InterimParams_ *params) { if (params->fdset_size_set) @@ -7453,6 +7481,51 @@ process_interim_params (struct MHD_Daemon *d, #endif /* MHD_USE_GETSOCKNAME */ } } + + mhd_assert (! params->server_addr_len_set || params->pserver_addr_set); + if (params->pserver_addr_set) + { + if (NULL == params->pserver_addr) + { + /* The size must be zero if set */ + if (params->server_addr_len_set && (0 != params->server_addr_len)) + return false; + /* Ignore parameter if it is NULL */ + } + else if (MHD_INVALID_SOCKET != d->listen_fd) + { +#ifdef HAVE_MESSAGES + MHD_DLOG (d, + _ ("MHD_OPTION_LISTEN_SOCKET cannot be used together with " \ + "MHD_OPTION_SOCK_ADDR_LEN or MHD_OPTION_SOCK_ADDR.\n")); +#endif /* HAVE_MESSAGES */ + return false; + } + else if (0 != (d->options & MHD_USE_NO_LISTEN_SOCKET)) + { +#ifdef HAVE_MESSAGES + MHD_DLOG (d, + _ ("MHD_OPTION_SOCK_ADDR_LEN or MHD_OPTION_SOCK_ADDR " \ + "specified for daemon with MHD_USE_NO_LISTEN_SOCKET " \ + "flag set.\n")); +#endif /* HAVE_MESSAGES */ + (void) MHD_socket_close_ (params->listen_fd); + return false; + } + else + { + *ppsockaddr = params->pserver_addr; + if (params->server_addr_len_set) + { + /* The size must be non-zero if set */ + if (0 == params->server_addr_len) + return false; + *psockaddr_len = params->server_addr_len; + } + else + *psockaddr_len = 0; + } + } return true; } @@ -7490,11 +7563,7 @@ MHD_start_daemon_va (unsigned int flags, const MHD_SCKT_OPT_BOOL_ on = 1; struct MHD_Daemon *daemon; MHD_socket listen_fd; - struct sockaddr_in servaddr4; -#ifdef HAVE_INET6 - struct sockaddr_in6 servaddr6; -#endif - const struct sockaddr *servaddr = NULL; + const struct sockaddr *pservaddr = NULL; socklen_t addrlen; #if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS) unsigned int i; @@ -7666,9 +7735,12 @@ MHD_start_daemon_va (unsigned int flags, interim_params->fdset_size = 0; interim_params->listen_fd_set = false; interim_params->listen_fd = MHD_INVALID_SOCKET; + interim_params->pserver_addr_set = false; + interim_params->pserver_addr = NULL; + interim_params->server_addr_len_set = false; + interim_params->server_addr_len = 0; if (MHD_NO == parse_options_va (daemon, - &servaddr, interim_params, ap)) { @@ -7681,7 +7753,10 @@ MHD_start_daemon_va (unsigned int flags, free (daemon); return NULL; } - if (! process_interim_params (daemon, interim_params)) + if (! process_interim_params (daemon, + &pservaddr, + &addrlen, + interim_params)) { free (interim_params); free (daemon); @@ -7853,19 +7928,216 @@ MHD_start_daemon_va (unsigned int flags, goto free_and_fail; } #endif + if ( (MHD_INVALID_SOCKET == daemon->listen_fd) && (0 == (*pflags & MHD_USE_NO_LISTEN_SOCKET)) ) { /* try to open listen socket */ - int domain; - + struct sockaddr_in servaddr4; #ifdef HAVE_INET6 - domain = (*pflags & MHD_USE_IPv6) ? PF_INET6 : PF_INET; + struct sockaddr_in6 servaddr6; + const bool use_ipv6 = (0 != (*pflags & MHD_USE_IPv6)); #else /* ! HAVE_INET6 */ - if (*pflags & MHD_USE_IPv6) - goto free_and_fail; - domain = PF_INET; + const bool use_ipv6 = false; #endif /* ! HAVE_INET6 */ + int domain; + + if (NULL != pservaddr) + { +#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN + const socklen_t sa_len = pservaddr->sa_len; +#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */ +#ifdef HAVE_INET6 + if (use_ipv6 && (AF_INET6 != pservaddr->sa_family)) + { +#ifdef HAVE_MESSAGES + MHD_DLOG (daemon, + _ ("MHD_USE_IPv6 is enabled, but 'struct sockaddr *' " \ + "specified for MHD_OPTION_SOCK_ADDR_LEN or " \ + "MHD_OPTION_SOCK_ADDR is not IPv6 address.\n")); +#endif /* HAVE_MESSAGES */ + goto free_and_fail; + } +#endif /* HAVE_INET6 */ + switch (pservaddr->sa_family) + { + case AF_INET: + if (1) + { + struct sockaddr_in sa4; + uint16_t sa4_port; + if ((0 != addrlen) + && (((socklen_t) sizeof(sa4)) > addrlen)) + { +#ifdef HAVE_MESSAGES + MHD_DLOG (daemon, + _ ("The size specified for MHD_OPTION_SOCK_ADDR_LEN " \ + "option is wrong.\n")); +#endif /* HAVE_MESSAGES */ + goto free_and_fail; + } +#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN + if (0 != sa_len) + { + if (((socklen_t) sizeof(sa4)) > sa_len) + { +#ifdef HAVE_MESSAGES + MHD_DLOG (daemon, + _ ("The value of 'struct sockaddr.sa_len' provided " \ + "via MHD_OPTION_SOCK_ADDR_LEN option is not zero " \ + "and does not match 'sa_family' value of the " \ + "same structure.\n")); +#endif /* HAVE_MESSAGES */ + goto free_and_fail; + } + if ((0 == addrlen) || (sa_len < addrlen)) + addrlen = sa_len; /* Use smaller value for safety */ + } +#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */ + if (0 == addrlen) + addrlen = sizeof(sa4); + memcpy (&sa4, pservaddr, sizeof(sa4)); /* Required due to stronger alignment */ + sa4_port = (uint16_t) ntohs (sa4.sin_port); +#ifndef MHD_USE_GETSOCKNAME + if (0 != sa4_port) +#endif /* ! MHD_USE_GETSOCKNAME */ + daemon->port = sa4_port; + domain = PF_INET; + } + break; +#ifdef HAVE_INET6 + case AF_INET6: + if (1) + { + struct sockaddr_in6 sa6; + uint16_t sa6_port; + if ((0 != addrlen) + && (((socklen_t) sizeof(sa6)) > addrlen)) + { +#ifdef HAVE_MESSAGES + MHD_DLOG (daemon, + _ ("The size specified for MHD_OPTION_SOCK_ADDR_LEN " \ + "option is wrong.\n")); +#endif /* HAVE_MESSAGES */ + goto free_and_fail; + } +#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN + if (0 != sa_len) + { + if (((socklen_t) sizeof(sa6)) > sa_len) + { +#ifdef HAVE_MESSAGES + MHD_DLOG (daemon, + _ ("The value of 'struct sockaddr.sa_len' provided " \ + "via MHD_OPTION_SOCK_ADDR_LEN option is not zero " \ + "and does not match 'sa_family' value of the " \ + "same structure.\n")); +#endif /* HAVE_MESSAGES */ + goto free_and_fail; + } + if ((0 == addrlen) || (sa_len < addrlen)) + addrlen = sa_len; /* Use smaller value for safety */ + } +#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */ + if (0 == addrlen) + addrlen = sizeof(sa6); + memcpy (&sa6, pservaddr, sizeof(sa6)); /* Required due to stronger alignment */ + sa6_port = (uint16_t) ntohs (sa6.sin6_port); +#ifndef MHD_USE_GETSOCKNAME + if (0 != sa6_port) +#endif /* ! MHD_USE_GETSOCKNAME */ + daemon->port = sa6_port; + domain = PF_INET6; + *pflags |= ((enum MHD_FLAG) MHD_USE_IPv6); + } + break; +#endif /* HAVE_INET6 */ +#ifdef AF_UNIX + case AF_UNIX: +#endif /* AF_UNIX */ + default: +#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN + if (0 == addrlen) + addrlen = sa_len; + else if ((0 != sa_len) && (sa_len < addrlen)) + addrlen = sa_len; /* Use smaller value for safety */ +#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */ + if (0 >= addrlen) + { +#ifdef HAVE_MESSAGES + MHD_DLOG (daemon, + _ ("The 'sa_family' of the 'struct sockaddr' provided " \ + "via MHD_OPTION_SOCK_ADDR option is not supported.\n")); +#endif /* HAVE_MESSAGES */ + goto free_and_fail; + } +#ifdef AF_UNIX + if (AF_UNIX == pservaddr->sa_family) + { + daemon->port = 0; /* special value for UNIX domain sockets */ + daemon->listen_is_unix = _MHD_YES; +#ifdef PF_UNIX + domain = PF_UNIX; +#else /* ! PF_UNIX */ + domain = AF_UNIX; +#endif /* ! PF_UNIX */ + domain = PF_UNIX; + } + else /* combined with the next 'if' */ +#endif /* AF_UNIX */ + if (1) + { + daemon->port = 0; /* ugh */ + daemon->listen_is_unix = _MHD_UNKNOWN; + /* Assumed the same values for AF_* and PF_* */ + domain = pservaddr->sa_family; + } + break; + } + } + else + { + if (! use_ipv6) + { + memset (&servaddr4, + 0, + sizeof (struct sockaddr_in)); + servaddr4.sin_family = AF_INET; + servaddr4.sin_port = htons (port); + if (0 != INADDR_ANY) + servaddr4.sin_addr.s_addr = htonl (INADDR_ANY); +#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN + servaddr4.sin_len = sizeof (struct sockaddr_in); +#endif + pservaddr = (struct sockaddr *) &servaddr4; + addrlen = (socklen_t) sizeof(servaddr4); + daemon->listen_is_unix = _MHD_NO; + domain = PF_INET; + } +#ifdef HAVE_INET6 + else + { +#ifdef IN6ADDR_ANY_INIT + static const struct in6_addr static_in6any = IN6ADDR_ANY_INIT; +#endif + memset (&servaddr6, + 0, + sizeof (struct sockaddr_in6)); + servaddr6.sin6_family = AF_INET6; + servaddr6.sin6_port = htons (port); +#ifdef IN6ADDR_ANY_INIT + servaddr6.sin6_addr = static_in6any; +#endif +#ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_LEN + servaddr6.sin6_len = sizeof (struct sockaddr_in6); +#endif + pservaddr = (struct sockaddr *) &servaddr6; + addrlen = (socklen_t) sizeof (servaddr6); + daemon->listen_is_unix = _MHD_NO; + domain = PF_INET6; + } +#endif /* HAVE_INET6 */ + } listen_fd = MHD_socket_create_listen_ (domain); if (MHD_INVALID_SOCKET == listen_fd) @@ -7890,7 +8162,6 @@ MHD_start_daemon_va (unsigned int flags, MHD_socket_close_chk_ (listen_fd); goto free_and_fail; } - daemon->listen_is_unix = _MHD_NO; /* Apply the socket options according to listening_address_reuse. */ if (0 == daemon->listening_address_reuse) @@ -8003,87 +8274,8 @@ MHD_start_daemon_va (unsigned int flags, } /* check for user supplied sockaddr */ -#ifdef HAVE_INET6 - if (0 != (*pflags & MHD_USE_IPv6)) - addrlen = sizeof (struct sockaddr_in6); - else -#endif - addrlen = sizeof (struct sockaddr_in); - if (NULL == servaddr) - { -#ifdef HAVE_INET6 - if (0 != (*pflags & MHD_USE_IPv6)) - { -#ifdef IN6ADDR_ANY_INIT - static const struct in6_addr static_in6any = IN6ADDR_ANY_INIT; -#endif - memset (&servaddr6, - 0, - sizeof (struct sockaddr_in6)); - servaddr6.sin6_family = AF_INET6; - servaddr6.sin6_port = htons (port); -#ifdef IN6ADDR_ANY_INIT - servaddr6.sin6_addr = static_in6any; -#endif -#ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_LEN - servaddr6.sin6_len = sizeof (struct sockaddr_in6); -#endif - servaddr = (struct sockaddr *) &servaddr6; - } - else -#endif - { - memset (&servaddr4, - 0, - sizeof (struct sockaddr_in)); - servaddr4.sin_family = AF_INET; - servaddr4.sin_port = htons (port); - if (0 != INADDR_ANY) - servaddr4.sin_addr.s_addr = htonl (INADDR_ANY); -#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN - servaddr4.sin_len = sizeof (struct sockaddr_in); -#endif - servaddr = (struct sockaddr *) &servaddr4; - } - } - else - { -#ifdef MHD_USE_GETSOCKNAME - daemon->port = 0; /* Force use of autodetection */ -#else /* ! MHD_USE_GETSOCKNAME */ - switch (servaddr->sa_family) - { - case AF_INET: - { - struct sockaddr_in sa4; - memcpy (&sa4, servaddr, sizeof(sa4)); /* Required due to stronger alignment */ - daemon->port = ntohs (sa4.sin_port); - break; - } -#ifdef HAVE_INET6 - case AF_INET6: - { - struct sockaddr_in6 sa6; - memcpy (&sa6, servaddr, sizeof(sa6)); /* Required due to stronger alignment */ - daemon->port = ntohs (sa6.sin6_port); - mhd_assert (0 != (*pflags & MHD_USE_IPv6)); - break; - } -#endif /* HAVE_INET6 */ -#ifdef AF_UNIX - case AF_UNIX: - daemon->port = 0; /* special value for UNIX domain sockets */ - daemon->listen_is_unix = _MHD_YES; - break; -#endif - default: - daemon->port = 0; /* ugh */ - daemon->listen_is_unix = _MHD_UNKNOWN; - break; - } -#endif /* ! MHD_USE_GETSOCKNAME */ - } daemon->listen_fd = listen_fd; + if (0 != (*pflags & MHD_USE_IPv6)) { #ifdef IPPROTO_IPV6 @@ -8108,7 +8300,7 @@ MHD_start_daemon_va (unsigned int flags, #endif #endif } - if (0 != bind (listen_fd, servaddr, addrlen)) + if (0 != bind (listen_fd, pservaddr, addrlen)) { #ifdef HAVE_MESSAGES MHD_DLOG (daemon, @@ -8157,7 +8349,8 @@ MHD_start_daemon_va (unsigned int flags, #ifdef MHD_USE_GETSOCKNAME if ( (0 == daemon->port) && - (0 == (*pflags & MHD_USE_NO_LISTEN_SOCKET)) ) + (0 == (*pflags & MHD_USE_NO_LISTEN_SOCKET)) && + (_MHD_YES != daemon->listen_is_unix) ) { /* Get port number. */ struct sockaddr_storage bindaddr; @@ -8166,7 +8359,7 @@ MHD_start_daemon_va (unsigned int flags, sizeof (struct sockaddr_storage)); addrlen = sizeof (struct sockaddr_storage); #ifdef HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN - bindaddr.ss_len = addrlen; + bindaddr.ss_len = (socklen_t) addrlen; #endif if (0 != getsockname (listen_fd, (struct sockaddr *) &bindaddr, diff --git a/src/microhttpd/test_options.c b/src/microhttpd/test_options.c @@ -70,50 +70,212 @@ test_wrap_loc (const char *test_name, unsigned int (*test)(void)) /** - * Test daemon initialization with the MHD_OPTION_SOCK_ADDR option + * Test daemon initialization with the MHD_OPTION_SOCK_ADDR or + * the MHD_OPTION_SOCK_ADDR_LEN options */ static unsigned int test_ip_addr_option (void) { struct MHD_Daemon *d; + const union MHD_DaemonInfo *dinfo; struct sockaddr_in daemon_ip_addr; + uint16_t port4; #if defined(HAVE_INET6) && defined(USE_IPV6_TESTING) struct sockaddr_in6 daemon_ip_addr6; + uint16_t port6; #endif + unsigned int ret; memset (&daemon_ip_addr, 0, sizeof (struct sockaddr_in)); daemon_ip_addr.sin_family = AF_INET; daemon_ip_addr.sin_port = 0; daemon_ip_addr.sin_addr.s_addr = htonl (INADDR_LOOPBACK); + port4 = 0; #if defined(HAVE_INET6) && defined(USE_IPV6_TESTING) memset (&daemon_ip_addr6, 0, sizeof (struct sockaddr_in6)); daemon_ip_addr6.sin6_family = AF_INET6; daemon_ip_addr6.sin6_port = 0; daemon_ip_addr6.sin6_addr = in6addr_loopback; + port6 = 0; #endif + ret = 0; + + d = MHD_start_daemon (MHD_USE_ERROR_LOG, 0, + NULL, NULL, &ahc_echo, NULL, + MHD_OPTION_SOCK_ADDR, &daemon_ip_addr, + MHD_OPTION_END); + + if (d == 0) + return 1; + + dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT); + if (NULL == dinfo) + ret |= 1 << 1; + else + port4 = dinfo->port; + + MHD_stop_daemon (d); + + + daemon_ip_addr.sin_port = htons (port4); + d = MHD_start_daemon (MHD_USE_ERROR_LOG, 0, + NULL, NULL, &ahc_echo, NULL, + MHD_OPTION_SOCK_ADDR_LEN, + (socklen_t) sizeof(daemon_ip_addr), &daemon_ip_addr, + MHD_OPTION_END); + + if (d == 0) + return 1; + + dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT); + if (NULL == dinfo) + ret |= 1 << 1; + else if (port4 != dinfo->port) + ret |= 1 << 2; + + MHD_stop_daemon (d); + + + d = MHD_start_daemon (MHD_USE_ERROR_LOG, 0, + NULL, NULL, &ahc_echo, NULL, + MHD_OPTION_SOCK_ADDR_LEN, + (socklen_t) (sizeof(daemon_ip_addr) / 2), + &daemon_ip_addr, + MHD_OPTION_END); + + if (NULL != d) + { + MHD_stop_daemon (d); + return 1 << 3; + } + +#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN + + daemon_ip_addr.sin_len = (socklen_t) sizeof(daemon_ip_addr); d = MHD_start_daemon (MHD_USE_ERROR_LOG, 0, - NULL, NULL, &ahc_echo, NULL, MHD_OPTION_SOCK_ADDR, - &daemon_ip_addr, MHD_OPTION_END); + NULL, NULL, &ahc_echo, NULL, + MHD_OPTION_SOCK_ADDR_LEN, + (socklen_t) sizeof(daemon_ip_addr), &daemon_ip_addr, + MHD_OPTION_END); if (d == 0) return 1; + dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT); + if (NULL == dinfo) + ret |= 1 << 1; + else if (port4 != dinfo->port) + ret |= 1 << 2; + MHD_stop_daemon (d); + + daemon_ip_addr.sin_len = (socklen_t) (sizeof(daemon_ip_addr) / 2); + d = MHD_start_daemon (MHD_USE_ERROR_LOG, 0, + NULL, NULL, &ahc_echo, NULL, + MHD_OPTION_SOCK_ADDR_LEN, + (socklen_t) sizeof(daemon_ip_addr), &daemon_ip_addr, + MHD_OPTION_END); + + if (NULL != d) + { + MHD_stop_daemon (d); + return 1 << 3; + } + +#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ + + #if defined(HAVE_INET6) && defined(USE_IPV6_TESTING) d = MHD_start_daemon (MHD_USE_ERROR_LOG | MHD_USE_IPv6, 0, - NULL, NULL, &ahc_echo, NULL, MHD_OPTION_SOCK_ADDR, - &daemon_ip_addr6, MHD_OPTION_END); + NULL, NULL, &ahc_echo, NULL, + MHD_OPTION_SOCK_ADDR, &daemon_ip_addr6, + MHD_OPTION_END); if (d == 0) return 1; + dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT); + if (NULL == dinfo) + ret |= 1 << 1; + else + port6 = dinfo->port; + MHD_stop_daemon (d); -#endif - return 0; + + daemon_ip_addr6.sin6_port = htons (port6); + d = MHD_start_daemon (MHD_USE_ERROR_LOG, 0, + NULL, NULL, &ahc_echo, NULL, + MHD_OPTION_SOCK_ADDR_LEN, + (socklen_t) sizeof(daemon_ip_addr6), &daemon_ip_addr6, + MHD_OPTION_END); + + if (d == 0) + return 1; + + dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT); + if (NULL == dinfo) + ret |= 1 << 1; + else if (port6 != dinfo->port) + ret |= 1 << 2; + + MHD_stop_daemon (d); + + + d = MHD_start_daemon (MHD_USE_ERROR_LOG, 0, + NULL, NULL, &ahc_echo, NULL, + MHD_OPTION_SOCK_ADDR_LEN, + (socklen_t) (sizeof(daemon_ip_addr6) / 2), + &daemon_ip_addr6, + MHD_OPTION_END); + + if (NULL != d) + { + MHD_stop_daemon (d); + return 1 << 3; + } + +#if defined(HAVE_STRUCT_SOCKADDR_IN6_SIN6_LEN) + + daemon_ip_addr6.sin6_len = (socklen_t) sizeof(daemon_ip_addr6); + d = MHD_start_daemon (MHD_USE_ERROR_LOG, 0, + NULL, NULL, &ahc_echo, NULL, + MHD_OPTION_SOCK_ADDR_LEN, + (socklen_t) sizeof(daemon_ip_addr6), &daemon_ip_addr6, + MHD_OPTION_END); + + if (d == 0) + return 1; + + dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT); + if (NULL == dinfo) + ret |= 1 << 1; + else if (port6 != dinfo->port) + ret |= 1 << 2; + + MHD_stop_daemon (d); + + + daemon_ip_addr6.sin6_len = (socklen_t) (sizeof(daemon_ip_addr6) / 2); + d = MHD_start_daemon (MHD_USE_ERROR_LOG, 0, + NULL, NULL, &ahc_echo, NULL, + MHD_OPTION_SOCK_ADDR_LEN, + (socklen_t) sizeof(daemon_ip_addr6), &daemon_ip_addr6, + MHD_OPTION_END); + + if (NULL != d) + { + MHD_stop_daemon (d); + return 1 << 3; + } + +#endif /* HAVE_STRUCT_SOCKADDR_IN6_SIN6_LEN */ +#endif /* HAVE_INET6 && USE_IPV6_TESTING */ + + return ret; }