Diff for /embedaddon/lighttpd/src/network.c between versions 1.1.1.1 and 1.1.1.3

version 1.1.1.1, 2013/10/14 10:32:47 version 1.1.1.3, 2016/11/02 10:35:00
Line 1 Line 1
   #include "first.h"
   
 #include "network.h"  #include "network.h"
 #include "fdevent.h"  #include "fdevent.h"
 #include "log.h"  #include "log.h"
Line 48  static void ssl_info_callback(const SSL *ssl, int wher Line 50  static void ssl_info_callback(const SSL *ssl, int wher
 }  }
 #endif  #endif
   
   void
   network_accept_tcp_nagle_disable (const int fd)
   {
       static int noinherit_tcpnodelay = -1;
       int opt;
   
       if (!noinherit_tcpnodelay) /* TCP_NODELAY inherited from listen socket */
           return;
   
       if (noinherit_tcpnodelay < 0) {
           socklen_t optlen = sizeof(opt);
           if (0 == getsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, &optlen)) {
               noinherit_tcpnodelay = !opt;
               if (opt)           /* TCP_NODELAY inherited from listen socket */
                   return;
           }
       }
   
       opt = 1;
       (void)setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt));
   }
   
 static handler_t network_server_handle_fdevent(server *srv, void *context, int revents) {  static handler_t network_server_handle_fdevent(server *srv, void *context, int revents) {
         server_socket *srv_socket = (server_socket *)context;          server_socket *srv_socket = (server_socket *)context;
         connection *con;          connection *con;
Line 67  static handler_t network_server_handle_fdevent(server  Line 91  static handler_t network_server_handle_fdevent(server 
          *           *
          * we jump out after 100 to give the waiting connections a chance */           * we jump out after 100 to give the waiting connections a chance */
         for (loops = 0; loops < 100 && NULL != (con = connection_accept(srv, srv_socket)); loops++) {          for (loops = 0; loops < 100 && NULL != (con = connection_accept(srv, srv_socket)); loops++) {
                 handler_t r;  
   
                 connection_state_machine(srv, con);                  connection_state_machine(srv, con);
   
                 switch(r = plugins_call_handle_joblist(srv, con)) {  
                 case HANDLER_FINISHED:  
                 case HANDLER_GO_ON:  
                         break;  
                 default:  
                         log_error_write(srv, __FILE__, __LINE__, "d", r);  
                         break;  
                 }  
         }          }
         return HANDLER_GO_ON;          return HANDLER_GO_ON;
 }  }
Line 108  static int network_ssl_servername_callback(SSL *ssl, i Line 121  static int network_ssl_servername_callback(SSL *ssl, i
         config_cond_cache_reset(srv, con);          config_cond_cache_reset(srv, con);
         config_setup_connection(srv, con);          config_setup_connection(srv, con);
   
        config_patch_connection(srv, con, COMP_SERVER_SOCKET);        con->conditional_is_valid[COMP_SERVER_SOCKET] = 1;
        config_patch_connection(srv, con, COMP_HTTP_SCHEME);        con->conditional_is_valid[COMP_HTTP_SCHEME] = 1;
        config_patch_connection(srv, con, COMP_HTTP_HOST);        con->conditional_is_valid[COMP_HTTP_HOST] = 1;
         config_patch_connection(srv, con);
   
        if (NULL == con->conf.ssl_ctx) {        if (NULL == con->conf.ssl_pemfile_x509 || NULL == con->conf.ssl_pemfile_pkey) {
                /* ssl_ctx <=> pemfile was set <=> ssl_ctx got patched: so this should never happen */                /* x509/pkey available <=> pemfile was set <=> pemfile got patched: so this should never happen, unless you nest $SERVER["socket"] */
                 log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",                  log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
                        "null SSL_CTX for TLS server name", con->tlsext_server_name);                        "no certificate/private key for TLS server name", con->tlsext_server_name);
                 return SSL_TLSEXT_ERR_ALERT_FATAL;                  return SSL_TLSEXT_ERR_ALERT_FATAL;
         }          }
   
        /* switch to new SSL_CTX in reaction to a client's server_name extension */        /* first set certificate! setting private key checks whether certificate matches it */
        if (con->conf.ssl_ctx != SSL_set_SSL_CTX(ssl, con->conf.ssl_ctx)) {        if (!SSL_use_certificate(ssl, con->conf.ssl_pemfile_x509)) {
                log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",                log_error_write(srv, __FILE__, __LINE__, "ssb:s", "SSL:",
                        "failed to set SSL_CTX for TLS server name", con->tlsext_server_name);                        "failed to set certificate for TLS server name", con->tlsext_server_name,
                         ERR_error_string(ERR_get_error(), NULL));
                 return SSL_TLSEXT_ERR_ALERT_FATAL;                  return SSL_TLSEXT_ERR_ALERT_FATAL;
         }          }
   
           if (!SSL_use_PrivateKey(ssl, con->conf.ssl_pemfile_pkey)) {
                   log_error_write(srv, __FILE__, __LINE__, "ssb:s", "SSL:",
                           "failed to set private key for TLS server name", con->tlsext_server_name,
                           ERR_error_string(ERR_get_error(), NULL));
                   return SSL_TLSEXT_ERR_ALERT_FATAL;
           }
   
           if (con->conf.ssl_verifyclient) {
                   if (NULL == con->conf.ssl_ca_file_cert_names) {
                           log_error_write(srv, __FILE__, __LINE__, "ssb:s", "SSL:",
                                   "can't verify client without ssl.ca-file for TLS server name", con->tlsext_server_name,
                                   ERR_error_string(ERR_get_error(), NULL));
                           return SSL_TLSEXT_ERR_ALERT_FATAL;
                   }
   
                   SSL_set_client_CA_list(ssl, SSL_dup_CA_list(con->conf.ssl_ca_file_cert_names));
                   /* forcing verification here is really not that useful - a client could just connect without SNI */
                   SSL_set_verify(
                           ssl,
                           SSL_VERIFY_PEER | (con->conf.ssl_verifyclient_enforce ? SSL_VERIFY_FAIL_IF_NO_PEER_CERT : 0),
                           NULL
                   );
                   SSL_set_verify_depth(ssl, con->conf.ssl_verifyclient_depth);
           } else {
                   SSL_set_verify(ssl, SSL_VERIFY_NONE, NULL);
           }
   
         return SSL_TLSEXT_ERR_OK;          return SSL_TLSEXT_ERR_OK;
 }  }
 #endif  #endif
Line 134  static int network_server_init(server *srv, buffer *ho Line 176  static int network_server_init(server *srv, buffer *ho
         int val;          int val;
         socklen_t addr_len;          socklen_t addr_len;
         server_socket *srv_socket;          server_socket *srv_socket;
         char *sp;  
         unsigned int port = 0;          unsigned int port = 0;
         const char *host;          const char *host;
         buffer *b;          buffer *b;
        int is_unix_domain_socket = 0;        int err;
        int fd; 
   
 #ifdef __WIN32  #ifdef __WIN32
         WORD wVersionRequested;          WORD wVersionRequested;
         WSADATA wsaData;          WSADATA wsaData;
         int err;  
   
         wVersionRequested = MAKEWORD( 2, 2 );          wVersionRequested = MAKEWORD( 2, 2 );
   
Line 155  static int network_server_init(server *srv, buffer *ho Line 194  static int network_server_init(server *srv, buffer *ho
                     return -1;                      return -1;
         }          }
 #endif  #endif
           err = -1;
   
         srv_socket = calloc(1, sizeof(*srv_socket));          srv_socket = calloc(1, sizeof(*srv_socket));
           force_assert(NULL != srv_socket);
           srv_socket->addr.plain.sa_family = AF_INET; /* default */
         srv_socket->fd = -1;          srv_socket->fd = -1;
         srv_socket->fde_ndx = -1;          srv_socket->fde_ndx = -1;
   
         srv_socket->srv_token = buffer_init();          srv_socket->srv_token = buffer_init();
        buffer_copy_string_buffer(srv_socket->srv_token, host_token);        buffer_copy_buffer(srv_socket->srv_token, host_token);
   
         b = buffer_init();          b = buffer_init();
        buffer_copy_string_buffer(b, host_token);        buffer_copy_buffer(b, host_token);
   
         /* ipv4:port  
          * [ipv6]:port  
          */  
         if (NULL == (sp = strrchr(b->ptr, ':'))) {  
                 log_error_write(srv, __FILE__, __LINE__, "sb", "value of $SERVER[\"socket\"] has to be \"ip:port\".", b);  
   
                 goto error_free_socket;  
         }  
   
         host = b->ptr;          host = b->ptr;
   
         /* check for [ and ] */  
         if (b->ptr[0] == '[' && *(sp-1) == ']') {  
                 *(sp-1) = '\0';  
                 host++;  
   
                 s->use_ipv6 = 1;  
         }  
   
         *(sp++) = '\0';  
   
         port = strtol(sp, NULL, 10);  
   
         if (host[0] == '/') {          if (host[0] == '/') {
                 /* host is a unix-domain-socket */                  /* host is a unix-domain-socket */
                 is_unix_domain_socket = 1;  
         } else if (port == 0 || port > 65535) {  
                 log_error_write(srv, __FILE__, __LINE__, "sd", "port out of range:", port);  
   
                 goto error_free_socket;  
         }  
   
         if (*host == '\0') host = NULL;  
   
         if (is_unix_domain_socket) {  
 #ifdef HAVE_SYS_UN_H  #ifdef HAVE_SYS_UN_H
   
                 srv_socket->addr.plain.sa_family = AF_UNIX;                  srv_socket->addr.plain.sa_family = AF_UNIX;
   
                 if (-1 == (srv_socket->fd = socket(srv_socket->addr.plain.sa_family, SOCK_STREAM, 0))) {  
                         log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed:", strerror(errno));  
                         goto error_free_socket;  
                 }  
 #else  #else
                 log_error_write(srv, __FILE__, __LINE__, "s",                  log_error_write(srv, __FILE__, __LINE__, "s",
                                 "ERROR: Unix Domain sockets are not supported.");                                  "ERROR: Unix Domain sockets are not supported.");
                 goto error_free_socket;                  goto error_free_socket;
 #endif  #endif
        }        } else {
                 /* ipv4:port
                  * [ipv6]:port
                  */
                 size_t len = buffer_string_length(b);
                 char *sp = NULL;
                 if (0 == len) {
                         log_error_write(srv, __FILE__, __LINE__, "s", "value of $SERVER[\"socket\"] must not be empty");
                         goto error_free_socket;
                 }
                 if ((b->ptr[0] == '[' && b->ptr[len-1] == ']') || NULL == (sp = strrchr(b->ptr, ':'))) {
                         /* use server.port if set in config, or else default from config_set_defaults() */
                         port = srv->srvconf.port;
                         sp = b->ptr + len; /* point to '\0' at end of string so end of IPv6 address can be found below */
                 } else {
                         /* found ip:port separator at *sp; port doesn't end in ']', so *sp hopefully doesn't split an IPv6 address */
                         *sp = '\0';
                         port = strtol(sp+1, NULL, 10);
                 }
   
#ifdef HAVE_IPV6                /* check for [ and ] */
        if (s->use_ipv6) {                if (b->ptr[0] == '[' && *(sp-1) == ']') {
                srv_socket->addr.plain.sa_family = AF_INET6;                        *(sp-1) = '\0';
                         host++;
   
                if (-1 == (srv_socket->fd = socket(srv_socket->addr.plain.sa_family, SOCK_STREAM, IPPROTO_TCP))) {                        s->use_ipv6 = 1;
                        log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed:", strerror(errno)); 
                        goto error_free_socket; 
                 }                  }
                 srv_socket->use_ipv6 = 1;  
         }  
 #endif  
   
        if (srv_socket->fd == -1) {                if (port == 0 || port > 65535) {
                srv_socket->addr.plain.sa_family = AF_INET;                        log_error_write(srv, __FILE__, __LINE__, "sd", "port not set or out of range:", port);
                if (-1 == (srv_socket->fd = socket(srv_socket->addr.plain.sa_family, SOCK_STREAM, IPPROTO_TCP))) {
                        log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed:", strerror(errno)); 
                         goto error_free_socket;                          goto error_free_socket;
                 }                  }
         }          }
   
#ifdef FD_CLOEXEC        if (*host == '\0') host = NULL;
        /* set FD_CLOEXEC now, fdevent_fcntl_set is called later; needed for pipe-logger forks */ 
        fcntl(srv_socket->fd, F_SETFD, FD_CLOEXEC); 
#endif 
   
        /* */#ifdef HAVE_IPV6
        srv->cur_fds = srv_socket->fd;        if (s->use_ipv6) {
                srv_socket->addr.plain.sa_family = AF_INET6;
        val = 1; 
        if (setsockopt(srv_socket->fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) { 
                log_error_write(srv, __FILE__, __LINE__, "ss", "socketsockopt(SO_REUSEADDR) failed:", strerror(errno)); 
                goto error_free_socket; 
         }          }
   #endif
   
         switch(srv_socket->addr.plain.sa_family) {          switch(srv_socket->addr.plain.sa_family) {
 #ifdef HAVE_IPV6  #ifdef HAVE_IPV6
Line 262  static int network_server_init(server *srv, buffer *ho Line 274  static int network_server_init(server *srv, buffer *ho
                         struct addrinfo hints, *res;                          struct addrinfo hints, *res;
                         int r;                          int r;
   
                         if (s->set_v6only) {  
                                 val = 1;  
                                 if (-1 == setsockopt(srv_socket->fd, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof(val))) {  
                                         log_error_write(srv, __FILE__, __LINE__, "ss", "socketsockopt(IPV6_V6ONLY) failed:", strerror(errno));  
                                         goto error_free_socket;  
                                 }  
                         } else {  
                                 log_error_write(srv, __FILE__, __LINE__, "s", "warning: server.set-v6only will be removed soon, update your config to have different sockets for ipv4 and ipv6");  
                         }  
   
                         memset(&hints, 0, sizeof(hints));                          memset(&hints, 0, sizeof(hints));
   
                         hints.ai_family   = AF_INET6;                          hints.ai_family   = AF_INET6;
Line 279  static int network_server_init(server *srv, buffer *ho Line 281  static int network_server_init(server *srv, buffer *ho
                         hints.ai_protocol = IPPROTO_TCP;                          hints.ai_protocol = IPPROTO_TCP;
   
                         if (0 != (r = getaddrinfo(host, NULL, &hints, &res))) {                          if (0 != (r = getaddrinfo(host, NULL, &hints, &res))) {
                                   hints.ai_family = AF_INET;
                                   if (
                                     #ifdef EAI_ADDRFAMILY
                                       EAI_ADDRFAMILY == r &&
                                     #endif
                                       0 == getaddrinfo(host, NULL, &hints, &res)) {
                                           memcpy(&srv_socket->addr.ipv4, res->ai_addr, res->ai_addrlen);
                                           srv_socket->addr.ipv4.sin_family = AF_INET;
                                           srv_socket->addr.ipv4.sin_port = htons(port);
                                           addr_len = sizeof(struct sockaddr_in);
                                           /*assert(addr_len == res->ai_addrlen);*/
                                           freeaddrinfo(res);
                                           break;
                                   }
   
                                 log_error_write(srv, __FILE__, __LINE__,                                  log_error_write(srv, __FILE__, __LINE__,
                                                 "sssss", "getaddrinfo failed: ",                                                  "sssss", "getaddrinfo failed: ",
                                                 gai_strerror(r), "'", host, "'");                                                  gai_strerror(r), "'", host, "'");
Line 321  static int network_server_init(server *srv, buffer *ho Line 338  static int network_server_init(server *srv, buffer *ho
                         memcpy(&(srv_socket->addr.ipv4.sin_addr.s_addr), he->h_addr_list[0], he->h_length);                          memcpy(&(srv_socket->addr.ipv4.sin_addr.s_addr), he->h_addr_list[0], he->h_length);
                 }                  }
                 srv_socket->addr.ipv4.sin_port = htons(port);                  srv_socket->addr.ipv4.sin_port = htons(port);
   
                 addr_len = sizeof(struct sockaddr_in);                  addr_len = sizeof(struct sockaddr_in);
   
                 break;                  break;
   #ifdef HAVE_SYS_UN_H
         case AF_UNIX:          case AF_UNIX:
                   memset(&srv_socket->addr, 0, sizeof(struct sockaddr_un));
                 srv_socket->addr.un.sun_family = AF_UNIX;                  srv_socket->addr.un.sun_family = AF_UNIX;
                strcpy(srv_socket->addr.un.sun_path, host);                {
                         size_t hostlen = strlen(host) + 1;
                         if (hostlen > sizeof(srv_socket->addr.un.sun_path)) {
                                 log_error_write(srv, __FILE__, __LINE__, "sS", "unix socket filename too long:", host);
                                 goto error_free_socket;
                         }
                         memcpy(srv_socket->addr.un.sun_path, host, hostlen);
   
#ifdef SUN_LEN#if defined(SUN_LEN)
                addr_len = SUN_LEN(&srv_socket->addr.un);                        addr_len = SUN_LEN(&srv_socket->addr.un);
 #else  #else
                /* stevens says: */                        /* stevens says: */
                addr_len = strlen(host) + 1 + sizeof(srv_socket->addr.un.sun_family);                        addr_len = hostlen + sizeof(srv_socket->addr.un.sun_family);
 #endif  #endif
                   }
   
                /* check if the socket exists and try to connect to it. */                break;
                if (-1 != (fd = connect(srv_socket->fd, (struct sockaddr *) &(srv_socket->addr), addr_len))) {#endif
                        close(fd);        default:
                 goto error_free_socket;
         }
   
           if (srv->srvconf.preflight_check) {
                   err = 0;
                   goto error_free_socket;
           }
   
           if (srv->sockets_disabled) { /* lighttpd -1 (one-shot mode) */
   #ifdef USE_OPENSSL
                   if (s->ssl_enabled) srv_socket->ssl_ctx = s->ssl_ctx;
   #endif
                   goto srv_sockets_append;
           }
   
   #ifdef HAVE_SYS_UN_H
           if (AF_UNIX == srv_socket->addr.plain.sa_family) {
                   /* check if the socket exists and try to connect to it. */
                   force_assert(host); /*(static analysis hint)*/
                   if (-1 == (srv_socket->fd = socket(srv_socket->addr.plain.sa_family, SOCK_STREAM, 0))) {
                           log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed:", strerror(errno));
                           goto error_free_socket;
                   }
                   if (0 == connect(srv_socket->fd, (struct sockaddr *) &(srv_socket->addr), addr_len)) {
                         log_error_write(srv, __FILE__, __LINE__, "ss",                          log_error_write(srv, __FILE__, __LINE__, "ss",
                                 "server socket is still in use:",                                  "server socket is still in use:",
                                 host);                                  host);
Line 362  static int network_server_init(server *srv, buffer *ho Line 409  static int network_server_init(server *srv, buffer *ho
   
                         goto error_free_socket;                          goto error_free_socket;
                 }                  }
           } else
   #endif
           {
                   if (-1 == (srv_socket->fd = socket(srv_socket->addr.plain.sa_family, SOCK_STREAM, IPPROTO_TCP))) {
                           log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed:", strerror(errno));
                           goto error_free_socket;
                   }
   
                break;#ifdef HAVE_IPV6
        default:                if (AF_INET6 == srv_socket->addr.plain.sa_family
                     && host != NULL) {
                         if (s->set_v6only) {
                                 val = 1;
                                 if (-1 == setsockopt(srv_socket->fd, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof(val))) {
                                         log_error_write(srv, __FILE__, __LINE__, "ss", "socketsockopt(IPV6_V6ONLY) failed:", strerror(errno));
                                         goto error_free_socket;
                                 }
                         } else {
                                 log_error_write(srv, __FILE__, __LINE__, "s", "warning: server.set-v6only will be removed soon, update your config to have different sockets for ipv4 and ipv6");
                         }
                 }
 #endif
         }
 
         /* set FD_CLOEXEC now, fdevent_fcntl_set is called later; needed for pipe-logger forks */
         fd_close_on_exec(srv_socket->fd);
 
         /* */
         srv->cur_fds = srv_socket->fd;
 
         val = 1;
         if (setsockopt(srv_socket->fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) {
                 log_error_write(srv, __FILE__, __LINE__, "ss", "socketsockopt(SO_REUSEADDR) failed:", strerror(errno));
                 goto error_free_socket;                  goto error_free_socket;
         }          }
   
           if (srv_socket->addr.plain.sa_family != AF_UNIX) {
                   val = 1;
                   if (setsockopt(srv_socket->fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val)) < 0) {
                           log_error_write(srv, __FILE__, __LINE__, "ss", "socketsockopt(TCP_NODELAY) failed:", strerror(errno));
                           goto error_free_socket;
                   }
           }
   
         if (0 != bind(srv_socket->fd, (struct sockaddr *) &(srv_socket->addr), addr_len)) {          if (0 != bind(srv_socket->fd, (struct sockaddr *) &(srv_socket->addr), addr_len)) {
                 switch(srv_socket->addr.plain.sa_family) {                  switch(srv_socket->addr.plain.sa_family) {
                 case AF_UNIX:                  case AF_UNIX:
Line 384  static int network_server_init(server *srv, buffer *ho Line 469  static int network_server_init(server *srv, buffer *ho
                 goto error_free_socket;                  goto error_free_socket;
         }          }
   
        if (-1 == listen(srv_socket->fd, 128 * 8)) {        if (-1 == listen(srv_socket->fd, s->listen_backlog)) {
                 log_error_write(srv, __FILE__, __LINE__, "ss", "listen failed: ", strerror(errno));                  log_error_write(srv, __FILE__, __LINE__, "ss", "listen failed: ", strerror(errno));
                 goto error_free_socket;                  goto error_free_socket;
         }          }
Line 409  static int network_server_init(server *srv, buffer *ho Line 494  static int network_server_init(server *srv, buffer *ho
                         log_error_write(srv, __FILE__, __LINE__, "ss", "can't set TCP_DEFER_ACCEPT: ", strerror(errno));                          log_error_write(srv, __FILE__, __LINE__, "ss", "can't set TCP_DEFER_ACCEPT: ", strerror(errno));
                 }                  }
 #endif  #endif
        } else {#if defined(__FreeBSD__) || defined(__NetBSD__) \
  || defined(__OpenBSD__) || defined(__DragonflyBSD__)
         } else if (!buffer_is_empty(s->bsd_accept_filter)
                    && (buffer_is_equal_string(s->bsd_accept_filter, CONST_STR_LEN("httpready"))
                         || buffer_is_equal_string(s->bsd_accept_filter, CONST_STR_LEN("dataready")))) {
 #ifdef SO_ACCEPTFILTER  #ifdef SO_ACCEPTFILTER
                 /* FreeBSD accf_http filter */                  /* FreeBSD accf_http filter */
                 struct accept_filter_arg afa;                  struct accept_filter_arg afa;
                 memset(&afa, 0, sizeof(afa));                  memset(&afa, 0, sizeof(afa));
                strcpy(afa.af_name, "httpready");                strncpy(afa.af_name, s->bsd_accept_filter->ptr, sizeof(afa.af_name));
                 if (setsockopt(srv_socket->fd, SOL_SOCKET, SO_ACCEPTFILTER, &afa, sizeof(afa)) < 0) {                  if (setsockopt(srv_socket->fd, SOL_SOCKET, SO_ACCEPTFILTER, &afa, sizeof(afa)) < 0) {
                         if (errno != ENOENT) {                          if (errno != ENOENT) {
                                log_error_write(srv, __FILE__, __LINE__, "ss", "can't set accept-filter 'httpready': ", strerror(errno));                                log_error_write(srv, __FILE__, __LINE__, "SBss", "can't set accept-filter '", s->bsd_accept_filter, "':", strerror(errno));
                         }                          }
                 }                  }
 #endif  #endif
   #endif
         }          }
   
   srv_sockets_append:
         srv_socket->is_ssl = s->ssl_enabled;          srv_socket->is_ssl = s->ssl_enabled;
   
         if (srv->srv_sockets.size == 0) {          if (srv->srv_sockets.size == 0) {
                 srv->srv_sockets.size = 4;                  srv->srv_sockets.size = 4;
                 srv->srv_sockets.used = 0;                  srv->srv_sockets.used = 0;
                srv->srv_sockets.ptr = malloc(srv->srv_sockets.size * sizeof(server_socket));                srv->srv_sockets.ptr = malloc(srv->srv_sockets.size * sizeof(server_socket*));
                 force_assert(NULL != srv->srv_sockets.ptr);
         } else if (srv->srv_sockets.used == srv->srv_sockets.size) {          } else if (srv->srv_sockets.used == srv->srv_sockets.size) {
                 srv->srv_sockets.size += 4;                  srv->srv_sockets.size += 4;
                srv->srv_sockets.ptr = realloc(srv->srv_sockets.ptr, srv->srv_sockets.size * sizeof(server_socket));                srv->srv_sockets.ptr = realloc(srv->srv_sockets.ptr, srv->srv_sockets.size * sizeof(server_socket*));
                 force_assert(NULL != srv->srv_sockets.ptr);
         }          }
   
         srv->srv_sockets.ptr[srv->srv_sockets.used++] = srv_socket;          srv->srv_sockets.ptr[srv->srv_sockets.used++] = srv_socket;
Line 455  error_free_socket: Line 548  error_free_socket:
   
         buffer_free(b);          buffer_free(b);
   
        return -1;        return err; /* -1 if error; 0 if srv->srvconf.preflight_check successful */
 }  }
   
 int network_close(server *srv) {  int network_close(server *srv) {
Line 487  typedef enum { Line 580  typedef enum {
         NETWORK_BACKEND_UNSET,          NETWORK_BACKEND_UNSET,
         NETWORK_BACKEND_WRITE,          NETWORK_BACKEND_WRITE,
         NETWORK_BACKEND_WRITEV,          NETWORK_BACKEND_WRITEV,
        NETWORK_BACKEND_LINUX_SENDFILE,        NETWORK_BACKEND_SENDFILE,
        NETWORK_BACKEND_FREEBSD_SENDFILE, 
        NETWORK_BACKEND_SOLARIS_SENDFILEV 
 } network_backend_t;  } network_backend_t;
   
   #ifdef USE_OPENSSL
   static X509* x509_load_pem_file(server *srv, const char *file) {
           BIO *in;
           X509 *x = NULL;
   
           in = BIO_new(BIO_s_file());
           if (NULL == in) {
                   log_error_write(srv, __FILE__, __LINE__, "S", "SSL: BIO_new(BIO_s_file()) failed");
                   goto error;
           }
   
           if (BIO_read_filename(in,file) <= 0) {
                   log_error_write(srv, __FILE__, __LINE__, "SSS", "SSL: BIO_read_filename('", file,"') failed");
                   goto error;
           }
           x = PEM_read_bio_X509(in, NULL, NULL, NULL);
   
           if (NULL == x) {
                   log_error_write(srv, __FILE__, __LINE__, "SSS", "SSL: couldn't read X509 certificate from '", file,"'");
                   goto error;
           }
   
           BIO_free(in);
           return x;
   
   error:
           if (NULL != in) BIO_free(in);
           return NULL;
   }
   
   static EVP_PKEY* evp_pkey_load_pem_file(server *srv, const char *file) {
           BIO *in;
           EVP_PKEY *x = NULL;
   
           in=BIO_new(BIO_s_file());
           if (NULL == in) {
                   log_error_write(srv, __FILE__, __LINE__, "s", "SSL: BIO_new(BIO_s_file()) failed");
                   goto error;
           }
   
           if (BIO_read_filename(in,file) <= 0) {
                   log_error_write(srv, __FILE__, __LINE__, "SSS", "SSL: BIO_read_filename('", file,"') failed");
                   goto error;
           }
           x = PEM_read_bio_PrivateKey(in, NULL, NULL, NULL);
   
           if (NULL == x) {
                   log_error_write(srv, __FILE__, __LINE__, "SSS", "SSL: couldn't read private key from '", file,"'");
                   goto error;
           }
   
           BIO_free(in);
           return x;
   
   error:
           if (NULL != in) BIO_free(in);
           return NULL;
   }
   
   static int network_openssl_load_pemfile(server *srv, size_t ndx) {
           specific_config *s = srv->config_storage[ndx];
   
   #ifdef OPENSSL_NO_TLSEXT
           {
                   data_config *dc = (data_config *)srv->config_context->data[ndx];
                   if ((ndx > 0 && (COMP_SERVER_SOCKET != dc->comp || dc->cond != CONFIG_COND_EQ))
                           || !s->ssl_enabled) {
                           log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
                                           "ssl.pemfile only works in SSL socket binding context as openssl version does not support TLS extensions");
                           return -1;
                   }
           }
   #endif
   
           if (NULL == (s->ssl_pemfile_x509 = x509_load_pem_file(srv, s->ssl_pemfile->ptr))) return -1;
           if (NULL == (s->ssl_pemfile_pkey = evp_pkey_load_pem_file(srv, s->ssl_pemfile->ptr))) return -1;
   
           if (!X509_check_private_key(s->ssl_pemfile_x509, s->ssl_pemfile_pkey)) {
                   log_error_write(srv, __FILE__, __LINE__, "sssb", "SSL:",
                                   "Private key does not match the certificate public key, reason:",
                                   ERR_error_string(ERR_get_error(), NULL),
                                   s->ssl_pemfile);
                   return -1;
           }
   
           return 0;
   }
   #endif
   
 int network_init(server *srv) {  int network_init(server *srv) {
         buffer *b;          buffer *b;
        size_t i;        size_t i, j;
         network_backend_t backend;          network_backend_t backend;
   
 #if OPENSSL_VERSION_NUMBER >= 0x0090800fL  #if OPENSSL_VERSION_NUMBER >= 0x0090800fL
Line 555  int network_init(server *srv) { Line 735  int network_init(server *srv) {
                 const char *name;                  const char *name;
         } network_backends[] = {          } network_backends[] = {
                 /* lowest id wins */                  /* lowest id wins */
   #if defined USE_SENDFILE
                   { NETWORK_BACKEND_SENDFILE,   "sendfile" },
   #endif
 #if defined USE_LINUX_SENDFILE  #if defined USE_LINUX_SENDFILE
                { NETWORK_BACKEND_LINUX_SENDFILE,       "linux-sendfile" },                { NETWORK_BACKEND_SENDFILE,   "linux-sendfile" },
 #endif  #endif
 #if defined USE_FREEBSD_SENDFILE  #if defined USE_FREEBSD_SENDFILE
                { NETWORK_BACKEND_FREEBSD_SENDFILE,     "freebsd-sendfile" },                { NETWORK_BACKEND_SENDFILE,   "freebsd-sendfile" },
 #endif  #endif
 #if defined USE_SOLARIS_SENDFILEV  #if defined USE_SOLARIS_SENDFILEV
                { NETWORK_BACKEND_SOLARIS_SENDFILEV,        "solaris-sendfilev" },                { NETWORK_BACKEND_SENDFILE,   "solaris-sendfilev" },
 #endif  #endif
 #if defined USE_WRITEV  #if defined USE_WRITEV
                { NETWORK_BACKEND_WRITEV,               "writev" },                { NETWORK_BACKEND_WRITEV,     "writev" },
 #endif  #endif
                { NETWORK_BACKEND_WRITE,                "write" },                { NETWORK_BACKEND_WRITE,      "write" },
                { NETWORK_BACKEND_UNSET,                NULL }                { NETWORK_BACKEND_UNSET,       NULL }
         };          };
   
 #ifdef USE_OPENSSL  #ifdef USE_OPENSSL
Line 578  int network_init(server *srv) { Line 761  int network_init(server *srv) {
 #ifndef SSL_OP_NO_COMPRESSION  #ifndef SSL_OP_NO_COMPRESSION
 # define SSL_OP_NO_COMPRESSION 0  # define SSL_OP_NO_COMPRESSION 0
 #endif  #endif
   #ifndef SSL_MODE_RELEASE_BUFFERS    /* OpenSSL >= 1.0.0 */
   #define SSL_MODE_RELEASE_BUFFERS 0
   #endif
                 long ssloptions =                  long ssloptions =
                         SSL_OP_ALL | SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION | SSL_OP_NO_COMPRESSION;                          SSL_OP_ALL | SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION | SSL_OP_NO_COMPRESSION;
   
                if (buffer_is_empty(s->ssl_pemfile)) continue;                if (buffer_string_is_empty(s->ssl_pemfile) && buffer_string_is_empty(s->ssl_ca_file)) continue;
   
 #ifdef OPENSSL_NO_TLSEXT  
                 {  
                         data_config *dc = (data_config *)srv->config_context->data[i];  
                         if (COMP_HTTP_HOST == dc->comp) {  
                             log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",  
                                             "can't use ssl.pemfile with $HTTP[\"host\"], openssl version does not support TLS extensions");  
                             return -1;  
                         }  
                 }  
 #endif  
   
                 if (srv->ssl_is_init == 0) {                  if (srv->ssl_is_init == 0) {
                         SSL_load_error_strings();                          SSL_load_error_strings();
                         SSL_library_init();                          SSL_library_init();
Line 607  int network_init(server *srv) { Line 782  int network_init(server *srv) {
                         }                          }
                 }                  }
   
                   if (!buffer_string_is_empty(s->ssl_pemfile)) {
   #ifdef OPENSSL_NO_TLSEXT
                           data_config *dc = (data_config *)srv->config_context->data[i];
                           if (COMP_HTTP_HOST == dc->comp) {
                                   log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
                                                   "can't use ssl.pemfile with $HTTP[\"host\"], openssl version does not support TLS extensions");
                                   return -1;
                           }
   #endif
                           if (network_openssl_load_pemfile(srv, i)) return -1;
                   }
   
   
                   if (!buffer_string_is_empty(s->ssl_ca_file)) {
                           s->ssl_ca_file_cert_names = SSL_load_client_CA_file(s->ssl_ca_file->ptr);
                           if (NULL == s->ssl_ca_file_cert_names) {
                                   log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
                                                   ERR_error_string(ERR_get_error(), NULL), s->ssl_ca_file);
                           }
                   }
   
                   if (buffer_string_is_empty(s->ssl_pemfile) || !s->ssl_enabled) continue;
   
                 if (NULL == (s->ssl_ctx = SSL_CTX_new(SSLv23_server_method()))) {                  if (NULL == (s->ssl_ctx = SSL_CTX_new(SSLv23_server_method()))) {
                         log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",                          log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
                                         ERR_error_string(ERR_get_error(), NULL));                                          ERR_error_string(ERR_get_error(), NULL));
                         return -1;                          return -1;
                 }                  }
   
                   /* completely useless identifier; required for client cert verification to work with sessions */
                   if (0 == SSL_CTX_set_session_id_context(s->ssl_ctx, (const unsigned char*) CONST_STR_LEN("lighttpd"))) {
                           log_error_write(srv, __FILE__, __LINE__, "ss:s", "SSL:",
                                   "failed to set session context",
                                   ERR_error_string(ERR_get_error(), NULL));
                           return -1;
                   }
   
                 if (s->ssl_empty_fragments) {                  if (s->ssl_empty_fragments) {
 #ifdef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS  #ifdef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS
                         ssloptions &= ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS;                          ssloptions &= ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS;
Line 628  int network_init(server *srv) { Line 834  int network_init(server *srv) {
   
                 if (!s->ssl_use_sslv2) {                  if (!s->ssl_use_sslv2) {
                         /* disable SSLv2 */                          /* disable SSLv2 */
                        if (!(SSL_OP_NO_SSLv2 & SSL_CTX_set_options(s->ssl_ctx, SSL_OP_NO_SSLv2))) {                        if ((SSL_OP_NO_SSLv2 & SSL_CTX_set_options(s->ssl_ctx, SSL_OP_NO_SSLv2)) != SSL_OP_NO_SSLv2) {
                                 log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",                                  log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
                                                 ERR_error_string(ERR_get_error(), NULL));                                                  ERR_error_string(ERR_get_error(), NULL));
                                 return -1;                                  return -1;
Line 637  int network_init(server *srv) { Line 843  int network_init(server *srv) {
   
                 if (!s->ssl_use_sslv3) {                  if (!s->ssl_use_sslv3) {
                         /* disable SSLv3 */                          /* disable SSLv3 */
                        if (!(SSL_OP_NO_SSLv3 & SSL_CTX_set_options(s->ssl_ctx, SSL_OP_NO_SSLv3))) {                        if ((SSL_OP_NO_SSLv3 & SSL_CTX_set_options(s->ssl_ctx, SSL_OP_NO_SSLv3)) != SSL_OP_NO_SSLv3) {
                                 log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",                                  log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
                                                 ERR_error_string(ERR_get_error(), NULL));                                                  ERR_error_string(ERR_get_error(), NULL));
                                 return -1;                                  return -1;
                         }                          }
                 }                  }
   
                if (!buffer_is_empty(s->ssl_cipher_list)) {                if (!buffer_string_is_empty(s->ssl_cipher_list)) {
                         /* Disable support for low encryption ciphers */                          /* Disable support for low encryption ciphers */
                         if (SSL_CTX_set_cipher_list(s->ssl_ctx, s->ssl_cipher_list->ptr) != 1) {                          if (SSL_CTX_set_cipher_list(s->ssl_ctx, s->ssl_cipher_list->ptr) != 1) {
                                 log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",                                  log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
Line 659  int network_init(server *srv) { Line 865  int network_init(server *srv) {
   
 #ifndef OPENSSL_NO_DH  #ifndef OPENSSL_NO_DH
                 /* Support for Diffie-Hellman key exchange */                  /* Support for Diffie-Hellman key exchange */
                if (!buffer_is_empty(s->ssl_dh_file)) {                if (!buffer_string_is_empty(s->ssl_dh_file)) {
                         /* DH parameters from file */                          /* DH parameters from file */
                         bio = BIO_new_file((char *) s->ssl_dh_file->ptr, "r");                          bio = BIO_new_file((char *) s->ssl_dh_file->ptr, "r");
                         if (bio == NULL) {                          if (bio == NULL) {
Line 673  int network_init(server *srv) { Line 879  int network_init(server *srv) {
                                 return -1;                                  return -1;
                         }                          }
                 } else {                  } else {
                           BIGNUM *dh_p, *dh_g;
                         /* Default DH parameters from RFC5114 */                          /* Default DH parameters from RFC5114 */
                         dh = DH_new();                          dh = DH_new();
                         if (dh == NULL) {                          if (dh == NULL) {
                                 log_error_write(srv, __FILE__, __LINE__, "s", "SSL: DH_new () failed");                                  log_error_write(srv, __FILE__, __LINE__, "s", "SSL: DH_new () failed");
                                 return -1;                                  return -1;
                         }                          }
                        dh->p = BN_bin2bn(dh1024_p,sizeof(dh1024_p), NULL);                        dh_p = BN_bin2bn(dh1024_p,sizeof(dh1024_p), NULL);
                        dh->g = BN_bin2bn(dh1024_g,sizeof(dh1024_g), NULL);                        dh_g = BN_bin2bn(dh1024_g,sizeof(dh1024_g), NULL);
                        dh->length = 160;                        if ((dh_p == NULL) || (dh_g == NULL)) {
                        if ((dh->p == NULL) || (dh->g == NULL)) { 
                                 DH_free(dh);                                  DH_free(dh);
                                 log_error_write(srv, __FILE__, __LINE__, "s", "SSL: BN_bin2bn () failed");                                  log_error_write(srv, __FILE__, __LINE__, "s", "SSL: BN_bin2bn () failed");
                                 return -1;                                  return -1;
                         }                          }
                         #if OPENSSL_VERSION_NUMBER < 0x10100000L \
                           || defined(LIBRESSL_VERSION_NUMBER)
                           dh->p = dh_p;
                           dh->g = dh_g;
                           dh->length = 160;
                         #else
                           DH_set0_pqg(dh, dh_p, NULL, dh_g);
                           DH_set_length(dh, 160);
                         #endif
                 }                  }
                 SSL_CTX_set_tmp_dh(s->ssl_ctx,dh);                  SSL_CTX_set_tmp_dh(s->ssl_ctx,dh);
                 SSL_CTX_set_options(s->ssl_ctx,SSL_OP_SINGLE_DH_USE);                  SSL_CTX_set_options(s->ssl_ctx,SSL_OP_SINGLE_DH_USE);
                 DH_free(dh);                  DH_free(dh);
 #else  #else
                if (!buffer_is_empty(s->ssl_dh_file)) {                if (!buffer_string_is_empty(s->ssl_dh_file)) {
                         log_error_write(srv, __FILE__, __LINE__, "ss", "SSL: openssl compiled without DH support, can't load parameters from", s->ssl_dh_file->ptr);                          log_error_write(srv, __FILE__, __LINE__, "ss", "SSL: openssl compiled without DH support, can't load parameters from", s->ssl_dh_file->ptr);
                 }                  }
 #endif  #endif
Line 700  int network_init(server *srv) { Line 915  int network_init(server *srv) {
 #if OPENSSL_VERSION_NUMBER >= 0x0090800fL  #if OPENSSL_VERSION_NUMBER >= 0x0090800fL
 #ifndef OPENSSL_NO_ECDH  #ifndef OPENSSL_NO_ECDH
                 /* Support for Elliptic-Curve Diffie-Hellman key exchange */                  /* Support for Elliptic-Curve Diffie-Hellman key exchange */
                if (!buffer_is_empty(s->ssl_ec_curve)) {                if (!buffer_string_is_empty(s->ssl_ec_curve)) {
                         /* OpenSSL only supports the "named curves" from RFC 4492, section 5.1.1. */                          /* OpenSSL only supports the "named curves" from RFC 4492, section 5.1.1. */
                         nid = OBJ_sn2nid((char *) s->ssl_ec_curve->ptr);                          nid = OBJ_sn2nid((char *) s->ssl_ec_curve->ptr);
                         if (nid == 0) {                          if (nid == 0) {
Line 722  int network_init(server *srv) { Line 937  int network_init(server *srv) {
 #endif  #endif
 #endif  #endif
   
                if (!buffer_is_empty(s->ssl_ca_file)) {                /* load all ssl.ca-files specified in the config into each SSL_CTX to be prepared for SNI */
                        if (1 != SSL_CTX_load_verify_locations(s->ssl_ctx, s->ssl_ca_file->ptr, NULL)) {                for (j = 0; j < srv->config_context->used; j++) {
                                log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",                        specific_config *s1 = srv->config_storage[j];
                                                ERR_error_string(ERR_get_error(), NULL), s->ssl_ca_file);
                                return -1;                        if (!buffer_string_is_empty(s1->ssl_ca_file)) {
                        }                                if (1 != SSL_CTX_load_verify_locations(s->ssl_ctx, s1->ssl_ca_file->ptr, NULL)) {
                        if (s->ssl_verifyclient) { 
                                STACK_OF(X509_NAME) *certs = SSL_load_client_CA_file(s->ssl_ca_file->ptr); 
                                if (!certs) { 
                                         log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",                                          log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
                                                        ERR_error_string(ERR_get_error(), NULL), s->ssl_ca_file);                                                        ERR_error_string(ERR_get_error(), NULL), s1->ssl_ca_file);
                                } 
                                if (SSL_CTX_set_session_id_context(s->ssl_ctx, (void*) &srv, sizeof(srv)) != 1) { 
                                        log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:", 
                                                ERR_error_string(ERR_get_error(), NULL)); 
                                         return -1;                                          return -1;
                                 }                                  }
                                SSL_CTX_set_client_CA_list(s->ssl_ctx, certs);                        }
                                SSL_CTX_set_verify(                }
                                        s->ssl_ctx,
                                        SSL_VERIFY_PEER | (s->ssl_verifyclient_enforce ? SSL_VERIFY_FAIL_IF_NO_PEER_CERT : 0),                if (s->ssl_verifyclient) {
                                        NULL                        if (NULL == s->ssl_ca_file_cert_names) {
                                 log_error_write(srv, __FILE__, __LINE__, "s",
                                         "SSL: You specified ssl.verifyclient.activate but no ca_file"
                                 );                                  );
                                SSL_CTX_set_verify_depth(s->ssl_ctx, s->ssl_verifyclient_depth);                                return -1;
                         }                          }
                } else if (s->ssl_verifyclient) {                        SSL_CTX_set_client_CA_list(s->ssl_ctx, SSL_dup_CA_list(s->ssl_ca_file_cert_names));
                        log_error_write(                        SSL_CTX_set_verify(
                                srv, __FILE__, __LINE__, "s",                                s->ssl_ctx,
                                "SSL: You specified ssl.verifyclient.activate but no ca_file"                                SSL_VERIFY_PEER | (s->ssl_verifyclient_enforce ? SSL_VERIFY_FAIL_IF_NO_PEER_CERT : 0),
                                 NULL
                         );                          );
                           SSL_CTX_set_verify_depth(s->ssl_ctx, s->ssl_verifyclient_depth);
                 }                  }
   
                if (SSL_CTX_use_certificate_file(s->ssl_ctx, s->ssl_pemfile->ptr, SSL_FILETYPE_PEM) < 0) {                if (1 != SSL_CTX_use_certificate(s->ssl_ctx, s->ssl_pemfile_x509)) {
                         log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",                          log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
                                         ERR_error_string(ERR_get_error(), NULL), s->ssl_pemfile);                                          ERR_error_string(ERR_get_error(), NULL), s->ssl_pemfile);
                         return -1;                          return -1;
                 }                  }
   
                if (SSL_CTX_use_PrivateKey_file (s->ssl_ctx, s->ssl_pemfile->ptr, SSL_FILETYPE_PEM) < 0) {                if (1 != SSL_CTX_use_PrivateKey(s->ssl_ctx, s->ssl_pemfile_pkey)) {
                         log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",                          log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
                                         ERR_error_string(ERR_get_error(), NULL), s->ssl_pemfile);                                          ERR_error_string(ERR_get_error(), NULL), s->ssl_pemfile);
                         return -1;                          return -1;
Line 774  int network_init(server *srv) { Line 986  int network_init(server *srv) {
                         return -1;                          return -1;
                 }                  }
                 SSL_CTX_set_default_read_ahead(s->ssl_ctx, 1);                  SSL_CTX_set_default_read_ahead(s->ssl_ctx, 1);
                SSL_CTX_set_mode(s->ssl_ctx, SSL_CTX_get_mode(s->ssl_ctx) | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);                SSL_CTX_set_mode(s->ssl_ctx,  SSL_CTX_get_mode(s->ssl_ctx)
                                             | SSL_MODE_ENABLE_PARTIAL_WRITE
                                             | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER
                                             | SSL_MODE_RELEASE_BUFFERS);
   
 # ifndef OPENSSL_NO_TLSEXT  # ifndef OPENSSL_NO_TLSEXT
                 if (!SSL_CTX_set_tlsext_servername_callback(s->ssl_ctx, network_ssl_servername_callback) ||                  if (!SSL_CTX_set_tlsext_servername_callback(s->ssl_ctx, network_ssl_servername_callback) ||
Line 789  int network_init(server *srv) { Line 1004  int network_init(server *srv) {
   
         b = buffer_init();          b = buffer_init();
   
        buffer_copy_string_buffer(b, srv->srvconf.bindhost);        buffer_copy_buffer(b, srv->srvconf.bindhost);
         buffer_append_string_len(b, CONST_STR_LEN(":"));          buffer_append_string_len(b, CONST_STR_LEN(":"));
        buffer_append_long(b, srv->srvconf.port);        buffer_append_int(b, srv->srvconf.port);
   
         if (0 != network_server_init(srv, b, srv->config_storage[0])) {          if (0 != network_server_init(srv, b, srv->config_storage[0])) {
                   buffer_free(b);
                 return -1;                  return -1;
         }          }
         buffer_free(b);          buffer_free(b);
Line 806  int network_init(server *srv) { Line 1022  int network_init(server *srv) {
         backend = network_backends[0].nb;          backend = network_backends[0].nb;
   
         /* match name against known types */          /* match name against known types */
        if (!buffer_is_empty(srv->srvconf.network_backend)) {        if (!buffer_string_is_empty(srv->srvconf.network_backend)) {
                 for (i = 0; network_backends[i].name; i++) {                  for (i = 0; network_backends[i].name; i++) {
                         /**/                          /**/
                         if (buffer_is_equal_string(srv->srvconf.network_backend, network_backends[i].name, strlen(network_backends[i].name))) {                          if (buffer_is_equal_string(srv->srvconf.network_backend, network_backends[i].name, strlen(network_backends[i].name))) {
Line 829  int network_init(server *srv) { Line 1045  int network_init(server *srv) {
         case NETWORK_BACKEND_WRITE:          case NETWORK_BACKEND_WRITE:
                 srv->network_backend_write = network_write_chunkqueue_write;                  srv->network_backend_write = network_write_chunkqueue_write;
                 break;                  break;
#ifdef USE_WRITEV#if defined(USE_WRITEV)
         case NETWORK_BACKEND_WRITEV:          case NETWORK_BACKEND_WRITEV:
                 srv->network_backend_write = network_write_chunkqueue_writev;                  srv->network_backend_write = network_write_chunkqueue_writev;
                 break;                  break;
 #endif  #endif
#ifdef USE_LINUX_SENDFILE#if defined(USE_SENDFILE)
        case NETWORK_BACKEND_LINUX_SENDFILE:        case NETWORK_BACKEND_SENDFILE:
                srv->network_backend_write = network_write_chunkqueue_linuxsendfile;                srv->network_backend_write = network_write_chunkqueue_sendfile;
                 break;                  break;
 #endif  #endif
 #ifdef USE_FREEBSD_SENDFILE  
         case NETWORK_BACKEND_FREEBSD_SENDFILE:  
                 srv->network_backend_write = network_write_chunkqueue_freebsdsendfile;  
                 break;  
 #endif  
 #ifdef USE_SOLARIS_SENDFILEV  
         case NETWORK_BACKEND_SOLARIS_SENDFILEV:  
                 srv->network_backend_write = network_write_chunkqueue_solarissendfilev;  
                 break;  
 #endif  
         default:          default:
                 return -1;                  return -1;
         }          }
Line 857  int network_init(server *srv) { Line 1063  int network_init(server *srv) {
         for (i = 1; i < srv->config_context->used; i++) {          for (i = 1; i < srv->config_context->used; i++) {
                 data_config *dc = (data_config *)srv->config_context->data[i];                  data_config *dc = (data_config *)srv->config_context->data[i];
                 specific_config *s = srv->config_storage[i];                  specific_config *s = srv->config_storage[i];
                 size_t j;  
   
                 /* not our stage */                  /* not our stage */
                 if (COMP_SERVER_SOCKET != dc->comp) continue;                  if (COMP_SERVER_SOCKET != dc->comp) continue;
Line 887  int network_register_fdevents(server *srv) { Line 1092  int network_register_fdevents(server *srv) {
                 return -1;                  return -1;
         }          }
   
           if (srv->sockets_disabled) return 0; /* lighttpd -1 (one-shot mode) */
   
         /* register fdevents after reset */          /* register fdevents after reset */
         for (i = 0; i < srv->srv_sockets.used; i++) {          for (i = 0; i < srv->srv_sockets.used; i++) {
                 server_socket *srv_socket = srv->srv_sockets.ptr[i];                  server_socket *srv_socket = srv->srv_sockets.ptr[i];
Line 909  int network_write_chunkqueue(server *srv, connection * Line 1116  int network_write_chunkqueue(server *srv, connection *
                 off_t limit = con->conf.global_kbytes_per_second * 1024 - *(con->conf.global_bytes_per_second_cnt_ptr);                  off_t limit = con->conf.global_kbytes_per_second * 1024 - *(con->conf.global_bytes_per_second_cnt_ptr);
                 if (limit <= 0) {                  if (limit <= 0) {
                         /* we reached the global traffic limit */                          /* we reached the global traffic limit */
   
                         con->traffic_limit_reached = 1;                          con->traffic_limit_reached = 1;
                         joblist_append(srv, con);  
   
                         return 1;                          return 1;
                 } else {                  } else {
Line 923  int network_write_chunkqueue(server *srv, connection * Line 1128  int network_write_chunkqueue(server *srv, connection *
                 off_t limit = con->conf.kbytes_per_second * 1024 - con->bytes_written_cur_second;                  off_t limit = con->conf.kbytes_per_second * 1024 - con->bytes_written_cur_second;
                 if (limit <= 0) {                  if (limit <= 0) {
                         /* we reached the traffic limit */                          /* we reached the traffic limit */
   
                         con->traffic_limit_reached = 1;                          con->traffic_limit_reached = 1;
                         joblist_append(srv, con);  
   
                         return 1;                          return 1;
                 } else {                  } else {
Line 941  int network_write_chunkqueue(server *srv, connection * Line 1144  int network_write_chunkqueue(server *srv, connection *
          */           */
         if (cq->first && cq->first->next) {          if (cq->first && cq->first->next) {
                 corked = 1;                  corked = 1;
                setsockopt(con->fd, IPPROTO_TCP, TCP_CORK, &corked, sizeof(corked));                (void)setsockopt(con->fd, IPPROTO_TCP, TCP_CORK, &corked, sizeof(corked));
         }          }
 #endif  #endif
   
Line 961  int network_write_chunkqueue(server *srv, connection * Line 1164  int network_write_chunkqueue(server *srv, connection *
 #ifdef TCP_CORK  #ifdef TCP_CORK
         if (corked) {          if (corked) {
                 corked = 0;                  corked = 0;
                setsockopt(con->fd, IPPROTO_TCP, TCP_CORK, &corked, sizeof(corked));                (void)setsockopt(con->fd, IPPROTO_TCP, TCP_CORK, &corked, sizeof(corked));
         }          }
 #endif  #endif
   

Removed from v.1.1.1.1  
changed lines
  Added in v.1.1.1.3


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>