diff options
Diffstat (limited to 'src/microhttpd/daemon.c')
-rw-r--r-- | src/microhttpd/daemon.c | 249 |
1 files changed, 139 insertions, 110 deletions
diff --git a/src/microhttpd/daemon.c b/src/microhttpd/daemon.c index 0c2c4d3c..1c86057f 100644 --- a/src/microhttpd/daemon.c +++ b/src/microhttpd/daemon.c | |||
@@ -64,10 +64,6 @@ | |||
64 | #include <process.h> | 64 | #include <process.h> |
65 | #endif | 65 | #endif |
66 | 66 | ||
67 | #if HAVE_ACCEPT4+0 != 0 && (defined(HAVE_SOCK_NONBLOCK) || (SOCK_CLOEXEC+0 != 0)) | ||
68 | #define USE_ACCEPT4 1 | ||
69 | #endif | ||
70 | |||
71 | /** | 67 | /** |
72 | * Default connection limit. | 68 | * Default connection limit. |
73 | */ | 69 | */ |
@@ -115,6 +111,10 @@ | |||
115 | #define EPOLL_CLOEXEC 0 | 111 | #define EPOLL_CLOEXEC 0 |
116 | #endif | 112 | #endif |
117 | 113 | ||
114 | #if HAVE_ACCEPT4+0 != 0 && (defined(HAVE_SOCK_NONBLOCK) || (SOCK_CLOEXEC+0 != 0)) | ||
115 | #define USE_ACCEPT4 1 | ||
116 | #endif | ||
117 | |||
118 | 118 | ||
119 | /** | 119 | /** |
120 | * Default implementation of the panic function, | 120 | * Default implementation of the panic function, |
@@ -157,6 +157,50 @@ void *mhd_panic_cls; | |||
157 | static int mhd_winsock_inited_ = 0; | 157 | static int mhd_winsock_inited_ = 0; |
158 | #endif | 158 | #endif |
159 | 159 | ||
160 | |||
161 | /** | ||
162 | * Change socket options to be non-blocking. | ||
163 | * | ||
164 | * @param daemon daemon context | ||
165 | * @param sock socket to manipulate | ||
166 | * @return #MHD_YES if succeeded, #MHD_NO otherwise | ||
167 | */ | ||
168 | static int | ||
169 | make_nonblocking (struct MHD_Daemon *daemon, | ||
170 | MHD_socket sock) | ||
171 | { | ||
172 | #ifdef MHD_WINSOCK_SOCKETS | ||
173 | unsigned long flags = 1; | ||
174 | |||
175 | if (0 != ioctlsocket (sock, FIONBIO, &flags)) | ||
176 | { | ||
177 | #ifdef HAVE_MESSAGES | ||
178 | MHD_DLOG (daemon, | ||
179 | "Failed to make socket non-blocking: %s\n", | ||
180 | MHD_socket_last_strerr_ ()); | ||
181 | #endif | ||
182 | return MHD_NO; | ||
183 | } | ||
184 | #else /* MHD_POSIX_SOCKETS */ | ||
185 | int flags; | ||
186 | |||
187 | flags = fcntl (sock, F_GETFD); | ||
188 | if ( ( (-1 == flags) || | ||
189 | ( (flags != (flags | O_NONBLOCK)) && | ||
190 | (0 != fcntl (sock, F_SETFD, flags | O_NONBLOCK)) ) ) ) | ||
191 | { | ||
192 | #ifdef HAVE_MESSAGES | ||
193 | MHD_DLOG (daemon, | ||
194 | "Failed to make socket non-blocking: %s\n", | ||
195 | MHD_socket_last_strerr_ ()); | ||
196 | #endif | ||
197 | return MHD_NO; | ||
198 | } | ||
199 | #endif /* MHD_POSIX_SOCKETS */ | ||
200 | return MHD_YES; | ||
201 | } | ||
202 | |||
203 | |||
160 | /** | 204 | /** |
161 | * Trace up to and return master daemon. If the supplied daemon | 205 | * Trace up to and return master daemon. If the supplied daemon |
162 | * is a master, then return the daemon itself. | 206 | * is a master, then return the daemon itself. |
@@ -1462,30 +1506,7 @@ internal_add_connection (struct MHD_Daemon *daemon, | |||
1462 | { | 1506 | { |
1463 | /* in turbo mode, we assume that non-blocking was already set | 1507 | /* in turbo mode, we assume that non-blocking was already set |
1464 | by 'accept4' or whoever calls 'MHD_add_connection' */ | 1508 | by 'accept4' or whoever calls 'MHD_add_connection' */ |
1465 | 1509 | make_nonblocking (daemon, connection->socket_fd); | |
1466 | /* make socket non-blocking */ | ||
1467 | #if !defined(MHD_WINSOCK_SOCKETS) | ||
1468 | int flags = fcntl (connection->socket_fd, F_GETFL); | ||
1469 | if ( (-1 == flags) || | ||
1470 | (0 != fcntl (connection->socket_fd, F_SETFL, flags | O_NONBLOCK)) ) | ||
1471 | { | ||
1472 | #ifdef HAVE_MESSAGES | ||
1473 | MHD_DLOG (daemon, | ||
1474 | "Failed to make socket non-blocking: %s\n", | ||
1475 | MHD_socket_last_strerr_ ()); | ||
1476 | #endif | ||
1477 | } | ||
1478 | #else | ||
1479 | unsigned long flags = 1; | ||
1480 | if (0 != ioctlsocket (connection->socket_fd, FIONBIO, &flags)) | ||
1481 | { | ||
1482 | #ifdef HAVE_MESSAGES | ||
1483 | MHD_DLOG (daemon, | ||
1484 | "Failed to make socket non-blocking: %s\n", | ||
1485 | MHD_socket_last_strerr_ ()); | ||
1486 | #endif | ||
1487 | } | ||
1488 | #endif | ||
1489 | } | 1510 | } |
1490 | 1511 | ||
1491 | #if HTTPS_SUPPORT | 1512 | #if HTTPS_SUPPORT |
@@ -1833,34 +1854,59 @@ resume_suspended_connections (struct MHD_Daemon *daemon) | |||
1833 | 1854 | ||
1834 | 1855 | ||
1835 | /** | 1856 | /** |
1836 | * Change socket options to be non-blocking, non-inheritable. | 1857 | * Change socket options to be non-inheritable. |
1837 | * | 1858 | * |
1838 | * @param daemon daemon context | 1859 | * @param daemon daemon context |
1839 | * @param sock socket to manipulate | 1860 | * @param sock socket to manipulate |
1861 | * @return #MHD_YES if succeeded, #MHD_NO otherwise | ||
1840 | */ | 1862 | */ |
1841 | static void | 1863 | static int |
1842 | make_nonblocking_noninheritable (struct MHD_Daemon *daemon, | 1864 | make_noninheritable (struct MHD_Daemon *daemon, |
1843 | MHD_socket sock) | 1865 | MHD_socket sock) |
1844 | { | 1866 | { |
1845 | #ifdef MHD_WINSOCK_SOCKETS | 1867 | #ifdef MHD_WINSOCK_SOCKETS |
1846 | unsigned long flags = 1; | 1868 | if (!SetHandleInformation ((HANDLE)sock, HANDLE_FLAG_INHERIT, 0)) |
1847 | |||
1848 | if (0 != ioctlsocket (sock, FIONBIO, &flags)) | ||
1849 | { | 1869 | { |
1850 | #ifdef HAVE_MESSAGES | 1870 | #ifdef HAVE_MESSAGES |
1851 | MHD_DLOG (daemon, | 1871 | MHD_DLOG (daemon, |
1852 | "Failed to make socket non-blocking: %s\n", | 1872 | "Failed to make socket non-inheritable: %u\n", |
1853 | MHD_socket_last_strerr_ ()); | 1873 | (unsigned int)GetLastError ()); |
1854 | #endif | 1874 | #endif |
1875 | return MHD_NO; | ||
1855 | } | 1876 | } |
1856 | if (!SetHandleInformation ((HANDLE) sock, HANDLE_FLAG_INHERIT, 0)) | 1877 | #else /* MHD_POSIX_SOCKETS */ |
1878 | int flags; | ||
1879 | |||
1880 | flags = fcntl (sock, F_GETFD); | ||
1881 | if ( ( (-1 == flags) || | ||
1882 | ( (flags != (flags | FD_CLOEXEC)) && | ||
1883 | (0 != fcntl (sock, F_SETFD, flags | FD_CLOEXEC)) ) ) ) | ||
1857 | { | 1884 | { |
1858 | #ifdef HAVE_MESSAGES | 1885 | #ifdef HAVE_MESSAGES |
1859 | MHD_DLOG (daemon, | 1886 | MHD_DLOG (daemon, |
1860 | "Failed to make socket non-inheritable: %u\n", | 1887 | "Failed to make socket non-inheritable: %s\n", |
1861 | (unsigned int) GetLastError ()); | 1888 | MHD_socket_last_strerr_ ()); |
1862 | #endif | 1889 | #endif |
1890 | return MHD_NO; | ||
1863 | } | 1891 | } |
1892 | #endif /* MHD_POSIX_SOCKETS */ | ||
1893 | return MHD_YES; | ||
1894 | } | ||
1895 | |||
1896 | |||
1897 | /** | ||
1898 | * Change socket options to be non-blocking, non-inheritable. | ||
1899 | * | ||
1900 | * @param daemon daemon context | ||
1901 | * @param sock socket to manipulate | ||
1902 | */ | ||
1903 | static void | ||
1904 | make_nonblocking_noninheritable (struct MHD_Daemon *daemon, | ||
1905 | MHD_socket sock) | ||
1906 | { | ||
1907 | #ifdef MHD_WINSOCK_SOCKETS | ||
1908 | (void)make_nonblocking (daemon, sock); | ||
1909 | (void)make_noninheritable (daemon, sock); | ||
1864 | #else | 1910 | #else |
1865 | int flags; | 1911 | int flags; |
1866 | 1912 | ||
@@ -1914,8 +1960,11 @@ MHD_add_connection (struct MHD_Daemon *daemon, | |||
1914 | const struct sockaddr *addr, | 1960 | const struct sockaddr *addr, |
1915 | socklen_t addrlen) | 1961 | socklen_t addrlen) |
1916 | { | 1962 | { |
1917 | make_nonblocking_noninheritable (daemon, | 1963 | /* internal_add_connection() assume that non-blocking is |
1918 | client_socket); | 1964 | already set in MHD_USE_EPOLL_TURBO mode */ |
1965 | if (0 != (daemon->options & MHD_USE_EPOLL_TURBO)) | ||
1966 | make_nonblocking_noninheritable (daemon, | ||
1967 | client_socket); | ||
1919 | return internal_add_connection (daemon, | 1968 | return internal_add_connection (daemon, |
1920 | client_socket, | 1969 | client_socket, |
1921 | addr, addrlen, | 1970 | addr, addrlen, |
@@ -1985,8 +2034,12 @@ MHD_accept_connection (struct MHD_Daemon *daemon) | |||
1985 | } | 2034 | } |
1986 | return MHD_NO; | 2035 | return MHD_NO; |
1987 | } | 2036 | } |
1988 | #if !defined(USE_ACCEPT4) || !defined(HAVE_SOCK_NONBLOCK) || SOCK_CLOEXEC+0 == 0 | 2037 | #if !defined(USE_ACCEPT4) |
1989 | make_nonblocking_noninheritable (daemon, s); | 2038 | make_nonblocking_noninheritable (daemon, s); |
2039 | #elif !defined(HAVE_SOCK_NONBLOCK) | ||
2040 | make_nonblocking (daemon, s); | ||
2041 | #elif SOCK_CLOEXEC+0 == 0 | ||
2042 | make_noninheritable (daemon, s); | ||
1990 | #endif | 2043 | #endif |
1991 | #ifdef HAVE_MESSAGES | 2044 | #ifdef HAVE_MESSAGES |
1992 | #if DEBUG_CONNECT | 2045 | #if DEBUG_CONNECT |
@@ -3519,24 +3572,33 @@ parse_options_va (struct MHD_Daemon *daemon, | |||
3519 | * @param protocol desired protocol, 0 for default | 3572 | * @param protocol desired protocol, 0 for default |
3520 | */ | 3573 | */ |
3521 | static MHD_socket | 3574 | static MHD_socket |
3522 | create_socket (struct MHD_Daemon *daemon, | 3575 | create_listen_socket (struct MHD_Daemon *daemon, |
3523 | int domain, int type, int protocol) | 3576 | int domain, int type, int protocol) |
3524 | { | 3577 | { |
3525 | int ctype = type | SOCK_CLOEXEC; | ||
3526 | MHD_socket fd; | 3578 | MHD_socket fd; |
3579 | int cloexec_set; | ||
3527 | 3580 | ||
3528 | /* use SOCK_STREAM rather than ai_socktype: some getaddrinfo | 3581 | /* use SOCK_STREAM rather than ai_socktype: some getaddrinfo |
3529 | * implementations do not set ai_socktype, e.g. RHL6.2. */ | 3582 | * implementations do not set ai_socktype, e.g. RHL6.2. */ |
3530 | fd = socket (domain, ctype, protocol); | 3583 | #if defined(MHD_POSIX_SOCKETS) && SOCK_CLOEXEC+0 != 0 |
3531 | if ( (MHD_INVALID_SOCKET == fd) && (EINVAL == MHD_socket_errno_) && (0 != SOCK_CLOEXEC) ) | 3584 | fd = socket (domain, type | SOCK_CLOEXEC, protocol); |
3532 | { | 3585 | cloexec_set = MHD_YES; |
3533 | ctype = type; | 3586 | #elif defined(MHD_WINSOCK_SOCKETS) && defined (WSA_FLAG_NO_HANDLE_INHERIT) |
3534 | fd = socket(domain, type, protocol); | 3587 | fd = WSASocketW (domain, type, protocol, NULL, 0, WSA_FLAG_NO_HANDLE_INHERIT); |
3535 | } | 3588 | cloexec_set = MHD_YES; |
3589 | #else /* !SOCK_CLOEXEC */ | ||
3590 | fd = socket (domain, type, protocol); | ||
3591 | cloexec_set = MHD_NO; | ||
3592 | #endif /* !SOCK_CLOEXEC */ | ||
3593 | if ( (MHD_INVALID_SOCKET == fd) && (MHD_NO != cloexec_set) ) | ||
3594 | { | ||
3595 | fd = socket (domain, type, protocol); | ||
3596 | cloexec_set = MHD_NO; | ||
3597 | } | ||
3536 | if (MHD_INVALID_SOCKET == fd) | 3598 | if (MHD_INVALID_SOCKET == fd) |
3537 | return MHD_INVALID_SOCKET; | 3599 | return MHD_INVALID_SOCKET; |
3538 | if (type == ctype) | 3600 | if (MHD_NO == cloexec_set) |
3539 | make_nonblocking_noninheritable (daemon, fd); | 3601 | make_noninheritable (daemon, fd); |
3540 | return fd; | 3602 | return fd; |
3541 | } | 3603 | } |
3542 | 3604 | ||
@@ -3568,23 +3630,10 @@ setup_epoll_to_listen (struct MHD_Daemon *daemon) | |||
3568 | #endif | 3630 | #endif |
3569 | return MHD_NO; | 3631 | return MHD_NO; |
3570 | } | 3632 | } |
3571 | #ifndef HAVE_EPOLL_CREATE1 | 3633 | #if !defined(HAVE_EPOLL_CREATE1) || EPOLL_CLOEXEC+0 == 0 |
3572 | else | 3634 | make_noninheritable (daemon, |
3573 | { | 3635 | daemon->epoll_fd); |
3574 | int fdflags = fcntl (daemon->epoll_fd, F_GETFD); | 3636 | #endif /* !HAVE_EPOLL_CREATE1 || !EPOLL_CLOEXEC */ |
3575 | if (0 > fdflags || 0 > fcntl (daemon->epoll_fd, F_SETFD, fdflags | FD_CLOEXEC)) | ||
3576 | { | ||
3577 | #ifdef HAVE_MESSAGES | ||
3578 | MHD_DLOG (daemon, | ||
3579 | "Failed to change flags on epoll fd: %s\n", | ||
3580 | MHD_socket_last_strerr_ ()); | ||
3581 | #endif /* HAVE_MESSAGES */ | ||
3582 | } | ||
3583 | } | ||
3584 | #endif /* !HAVE_EPOLL_CREATE1 */ | ||
3585 | if (0 == EPOLL_CLOEXEC) | ||
3586 | make_nonblocking_noninheritable (daemon, | ||
3587 | daemon->epoll_fd); | ||
3588 | if (MHD_INVALID_SOCKET == daemon->socket_fd) | 3637 | if (MHD_INVALID_SOCKET == daemon->socket_fd) |
3589 | return MHD_YES; /* non-listening daemon */ | 3638 | return MHD_YES; /* non-listening daemon */ |
3590 | event.events = EPOLLIN; | 3639 | event.events = EPOLLIN; |
@@ -3870,10 +3919,10 @@ MHD_start_daemon_va (unsigned int flags, | |||
3870 | { | 3919 | { |
3871 | /* try to open listen socket */ | 3920 | /* try to open listen socket */ |
3872 | if (0 != (flags & MHD_USE_IPv6)) | 3921 | if (0 != (flags & MHD_USE_IPv6)) |
3873 | socket_fd = create_socket (daemon, | 3922 | socket_fd = create_listen_socket (daemon, |
3874 | PF_INET6, SOCK_STREAM, 0); | 3923 | PF_INET6, SOCK_STREAM, 0); |
3875 | else | 3924 | else |
3876 | socket_fd = create_socket (daemon, | 3925 | socket_fd = create_listen_socket (daemon, |
3877 | PF_INET, SOCK_STREAM, 0); | 3926 | PF_INET, SOCK_STREAM, 0); |
3878 | if (MHD_INVALID_SOCKET == socket_fd) | 3927 | if (MHD_INVALID_SOCKET == socket_fd) |
3879 | { | 3928 | { |
@@ -4073,23 +4122,24 @@ MHD_start_daemon_va (unsigned int flags, | |||
4073 | } | 4122 | } |
4074 | } | 4123 | } |
4075 | #endif | 4124 | #endif |
4076 | #if EPOLL_SUPPORT | 4125 | if (MHD_NO == make_nonblocking (daemon, socket_fd)) |
4077 | if (0 != (flags & MHD_USE_EPOLL_LINUX_ONLY)) | 4126 | { |
4078 | { | ||
4079 | int sk_flags = fcntl (socket_fd, F_GETFL); | ||
4080 | if (0 != fcntl (socket_fd, F_SETFL, sk_flags | O_NONBLOCK)) | ||
4081 | { | ||
4082 | #ifdef HAVE_MESSAGES | 4127 | #ifdef HAVE_MESSAGES |
4083 | MHD_DLOG (daemon, | 4128 | MHD_DLOG (daemon, |
4084 | "Failed to make listen socket non-blocking: %s\n", | 4129 | "Failed to make listen socket non-blocking: %s\n", |
4085 | MHD_socket_last_strerr_ ()); | 4130 | MHD_socket_last_strerr_ ()); |
4086 | #endif | 4131 | #endif /* HAVE_MESSAGES */ |
4087 | if (0 != MHD_socket_close_ (socket_fd)) | 4132 | if (0 != (flags & MHD_USE_EPOLL_LINUX_ONLY) || |
4088 | MHD_PANIC ("close failed\n"); | 4133 | daemon->worker_pool_size > 0) |
4089 | goto free_and_fail; | 4134 | { |
4090 | } | 4135 | /* Accept must be non-blocking. Multiple children may wake up |
4091 | } | 4136 | * to handle a new connection, but only one will win the race. |
4092 | #endif | 4137 | * The others must immediately return. */ |
4138 | if (0 != MHD_socket_close_ (socket_fd)) | ||
4139 | MHD_PANIC ("close failed\n"); | ||
4140 | goto free_and_fail; | ||
4141 | } | ||
4142 | } | ||
4093 | if (listen (socket_fd, daemon->listen_backlog_size) < 0) | 4143 | if (listen (socket_fd, daemon->listen_backlog_size) < 0) |
4094 | { | 4144 | { |
4095 | #ifdef HAVE_MESSAGES | 4145 | #ifdef HAVE_MESSAGES |
@@ -4211,12 +4261,6 @@ MHD_start_daemon_va (unsigned int flags, | |||
4211 | if ( (daemon->worker_pool_size > 0) && | 4261 | if ( (daemon->worker_pool_size > 0) && |
4212 | (0 == (daemon->options & MHD_USE_NO_LISTEN_SOCKET)) ) | 4262 | (0 == (daemon->options & MHD_USE_NO_LISTEN_SOCKET)) ) |
4213 | { | 4263 | { |
4214 | #if !defined(MHD_WINSOCK_SOCKETS) | ||
4215 | int sk_flags; | ||
4216 | #else | ||
4217 | unsigned long sk_flags; | ||
4218 | #endif | ||
4219 | |||
4220 | /* Coarse-grained count of connections per thread (note error | 4264 | /* Coarse-grained count of connections per thread (note error |
4221 | * due to integer division). Also keep track of how many | 4265 | * due to integer division). Also keep track of how many |
4222 | * connections are leftover after an equal split. */ | 4266 | * connections are leftover after an equal split. */ |
@@ -4227,21 +4271,6 @@ MHD_start_daemon_va (unsigned int flags, | |||
4227 | 4271 | ||
4228 | i = 0; /* we need this in case fcntl or malloc fails */ | 4272 | i = 0; /* we need this in case fcntl or malloc fails */ |
4229 | 4273 | ||
4230 | /* Accept must be non-blocking. Multiple children may wake up | ||
4231 | * to handle a new connection, but only one will win the race. | ||
4232 | * The others must immediately return. */ | ||
4233 | #if !defined(MHD_WINSOCK_SOCKETS) | ||
4234 | sk_flags = fcntl (socket_fd, F_GETFL); | ||
4235 | if (sk_flags < 0) | ||
4236 | goto thread_failed; | ||
4237 | if (0 != fcntl (socket_fd, F_SETFL, sk_flags | O_NONBLOCK)) | ||
4238 | goto thread_failed; | ||
4239 | #else | ||
4240 | sk_flags = 1; | ||
4241 | if (SOCKET_ERROR == ioctlsocket (socket_fd, FIONBIO, &sk_flags)) | ||
4242 | goto thread_failed; | ||
4243 | #endif /* MHD_WINSOCK_SOCKETS */ | ||
4244 | |||
4245 | /* Allocate memory for pooled objects */ | 4274 | /* Allocate memory for pooled objects */ |
4246 | daemon->worker_pool = malloc (sizeof (struct MHD_Daemon) | 4275 | daemon->worker_pool = malloc (sizeof (struct MHD_Daemon) |
4247 | * daemon->worker_pool_size); | 4276 | * daemon->worker_pool_size); |