mimetypes: add json and jsonp (distinct from js)
[project/uhttpd.git] / listen.c
index b4d51e1..adf8b16 100644 (file)
--- a/listen.c
+++ b/listen.c
@@ -1,20 +1,20 @@
 /*
  * uhttpd - Tiny single-threaded httpd
  *
- *   Copyright (C) 2010-2012 Jo-Philipp Wich <xm@subsignal.org>
- *   Copyright (C) 2012 Felix Fietkau <nbd@openwrt.org>
+ *   Copyright (C) 2010-2013 Jo-Philipp Wich <xm@subsignal.org>
+ *   Copyright (C) 2013 Felix Fietkau <nbd@openwrt.org>
  *
- *  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 <sys/types.h>
@@ -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,11 +188,12 @@ 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;
 
 error:
-               if (sock > 0)
+               if (sock > -1)
                        close(sock);
        }