X-Git-Url: http://git.archive.openwrt.org/?p=project%2Fuhttpd.git;a=blobdiff_plain;f=listen.c;h=adf8b16243dde1d0568e8a5bd7ef6dc1383763c3;hp=7e59d1dc4673280391b0a6af1b31f192c8abe8cf;hb=d09bf11d572207b79286cdb5e6253278ebec147c;hpb=54443d7f29f03987879b8f374a88cc7ea7599609 diff --git a/listen.c b/listen.c index 7e59d1d..adf8b16 100644 --- a/listen.c +++ b/listen.c @@ -1,20 +1,20 @@ /* * uhttpd - Tiny single-threaded httpd * - * Copyright (C) 2010-2012 Jo-Philipp Wich - * Copyright (C) 2012 Felix Fietkau + * Copyright (C) 2010-2013 Jo-Philipp Wich + * Copyright (C) 2013 Felix Fietkau * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include @@ -37,6 +37,14 @@ struct listener { static LIST_HEAD(listeners); static int n_blocked; +void uh_close_listen_fds(void) +{ + struct listener *l; + + list_for_each_entry(l, &listeners, list) + close(l->fd.fd); +} + static void uh_block_listener(struct listener *l) { uloop_fd_delete(&l->fd); @@ -44,39 +52,75 @@ static void uh_block_listener(struct listener *l) l->blocked = true; } -void uh_unblock_listeners(void) +static void uh_poll_listeners(struct uloop_timeout *timeout) { struct listener *l; - if (!n_blocked && conf.max_requests && - n_clients >= conf.max_requests) + if ((!n_blocked && conf.max_connections) || + n_clients >= conf.max_connections) return; list_for_each_entry(l, &listeners, list) { if (!l->blocked) continue; + l->fd.cb(&l->fd, ULOOP_READ); + if (n_clients >= conf.max_connections) + break; + n_blocked--; l->blocked = false; uloop_fd_add(&l->fd, ULOOP_READ); } } +void uh_unblock_listeners(void) +{ + static struct uloop_timeout poll_timer = { + .cb = uh_poll_listeners + }; + + uloop_timeout_set(&poll_timer, 1); +} + static void listener_cb(struct uloop_fd *fd, unsigned int events) { struct listener *l = container_of(fd, struct listener, fd); - uh_accept_client(fd->fd); + while (1) { + if (!uh_accept_client(fd->fd, l->tls)) + break; + } - if (conf.max_requests && n_clients >= conf.max_requests) + if (conf.max_connections && n_clients >= conf.max_connections) uh_block_listener(l); } void uh_setup_listeners(void) { struct listener *l; + int yes = 1; list_for_each_entry(l, &listeners, list) { + int sock = l->fd.fd; + + /* TCP keep-alive */ + if (conf.tcp_keepalive > 0) { +#ifdef linux + int tcp_ka_idl, tcp_ka_int, tcp_ka_cnt; + + tcp_ka_idl = 1; + tcp_ka_cnt = 3; + tcp_ka_int = conf.tcp_keepalive; + + setsockopt(sock, SOL_TCP, TCP_KEEPIDLE, &tcp_ka_idl, sizeof(tcp_ka_idl)); + setsockopt(sock, SOL_TCP, TCP_KEEPINTVL, &tcp_ka_int, sizeof(tcp_ka_int)); + setsockopt(sock, SOL_TCP, TCP_KEEPCNT, &tcp_ka_cnt, sizeof(tcp_ka_cnt)); +#endif + + setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &yes, sizeof(yes)); + } + l->fd.cb = listener_cb; uloop_fd_add(&l->fd, ULOOP_READ); } @@ -98,7 +142,7 @@ int uh_socket_bind(const char *host, const char *port, bool tls) if ((status = getaddrinfo(host, port, &hints, &addrs)) != 0) { fprintf(stderr, "getaddrinfo(): %s\n", gai_strerror(status)); - return -1; + return 0; } /* try to bind a new socket to each found address */ @@ -116,25 +160,6 @@ int uh_socket_bind(const char *host, const char *port, bool tls) goto error; } - /* TCP keep-alive */ - if (conf.tcp_keepalive > 0) { - int ret = 0; -#ifdef linux - int tcp_ka_idl, tcp_ka_int, tcp_ka_cnt; - - tcp_ka_idl = 1; - tcp_ka_cnt = 3; - tcp_ka_int = conf.tcp_keepalive; - ret = setsockopt(sock, SOL_TCP, TCP_KEEPIDLE, &tcp_ka_idl, sizeof(tcp_ka_idl)) || - setsockopt(sock, SOL_TCP, TCP_KEEPINTVL, &tcp_ka_int, sizeof(tcp_ka_int)) || - setsockopt(sock, SOL_TCP, TCP_KEEPCNT, &tcp_ka_cnt, sizeof(tcp_ka_cnt)); -#endif - - if (ret || setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &yes, sizeof(yes))) - fprintf(stderr, "Notice: Unable to enable TCP keep-alive: %s\n", - strerror(errno)); - } - /* required to get parallel v4 + v6 working */ if (p->ai_family == AF_INET6 && setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof(yes)) < 0) { @@ -163,6 +188,7 @@ int uh_socket_bind(const char *host, const char *port, bool tls) l->fd.fd = sock; l->tls = tls; list_add_tail(&l->list, &listeners); + bound++; continue;