Roxen.git / server / base_server / roxen.pike

version» Context lines:

Roxen.git/server/base_server/roxen.pike:1:   // This file is part of Roxen WebServer.   // Copyright © 1996 - 2004, Roxen IS.   //   // The Roxen WebServer main program.   //   // Per Hedbor, Henrik Grubbström, Pontus Hagland, David Hedbor and others.   // ABS and suicide systems contributed freely by Francesco Chemolli    - constant cvs_version="$Id: roxen.pike,v 1.960 2007/04/26 15:03:55 mast Exp $"; + constant cvs_version="$Id: roxen.pike,v 1.961 2007/05/03 15:59:30 mast Exp $";      //! @appears roxen   //!   //! The Roxen WebServer main program.      // The argument cache. Used by the image cache.   ArgCache argcache;      // Some headerfiles   #define IN_ROXEN
Roxen.git/server/base_server/roxen.pike:1041:   //! The function might be run in the backend thread if no thread   //! support is available, so it should never run for a long time.   //! Instead do another call to @[background_run] to queue it up again   //! after some work has been done, or use @[BackgroundProcess].   //!   //! @returns   //! If the function is queued for execution right away then zero is   //! returned. Otherwise its call out identifier is returned, which can   //! be used with @[find_call_out] or @[remove_call_out].   { +  // FIXME: Make it possible to associate the background job with a +  // RoxenModule or Configuration, so that report_error etc can log in +  // a good place.   #ifdef DEBUG_BACKGROUND_RUN    report_debug ("background_run enqueue %s (%s) [%d jobs in queue]\n",    functionp (func) ?    sprintf ("%s: %s", Function.defined (func),    master()->describe_function (func)) :    programp (func) ?    sprintf ("%s: %s", Program.defined (func),    master()->describe_program (func)) :    sprintf ("%O", func),    map (args, lambda (mixed arg)
Roxen.git/server/base_server/roxen.pike:1620:    }       void restore()    //! Restore all port options from saved values    {    foreach( (array)get_port_options( get_key() ), array kv )    set( kv[0], kv[1] );    }       static int retries; -  static void bind() +  static void bind (void|int ignore_eaddrinuse)    {    if (bound) return;    if (!port_obj) port_obj = Stdio.Port();    Privs privs = Privs (sprintf ("Binding %s", get_url()));    if (port_obj->bind(port, got_connection, ip))    {    privs = 0;    bound = 1;    return;    }    privs = 0;   #if constant(System.EAFNOSUPPORT)    if (port_obj->errno() == System.EAFNOSUPPORT) {    // Fail permanently.    error("Invalid address " + ip);    }   #endif /* System.EAFNOSUPPORT */ -  report_error(LOC_M(6, "Failed to bind %s (%s)")+"\n", -  get_url(), strerror(port_obj->errno())); - #if 0 -  werror (describe_backtrace (backtrace())); - #endif +    #if constant(System.EADDRINUSE) || constant(system.EADDRINUSE)    if (   #if constant(System.EADDRINUSE) -  (port_obj->errno() == System.EADDRINUSE) && +  (port_obj->errno() == System.EADDRINUSE)   #else /* !constant(System.EADDRINUSE) */ -  (port_obj->errno() == system.EADDRINUSE) && +  (port_obj->errno() == system.EADDRINUSE)   #endif /* constant(System.EADDRINUSE) */ -  (retries++ < 10)) { +  ) { +  if (!ignore_eaddrinuse && (retries++ < 10)) {    // We may get spurious failures on rebinding ports on some OS'es    // (eg Linux, WIN32). See [bug 3031]. -  +  report_error(LOC_M(6, "Failed to bind %s (%s)")+"\n", +  get_url(), strerror(port_obj->errno()));    report_notice(LOC_M(62, "Attempt %d. Retrying in 1 minute.")+"\n",    retries);    call_out(bind, 60);    } -  +  } +  else   #endif /* constant(System.EADDRINUSE) || constant(system.EADDRINUSE) */ -  +  { +  report_error(LOC_M(6, "Failed to bind %s (%s)")+"\n", +  get_url(), strerror(port_obj->errno())); + #if 0 +  werror (describe_backtrace (backtrace())); + #endif    } -  +  }       static array(int) get_ipv6_sequence(string partition)    {    array(int) segments = ({});    foreach(partition/":", string part) {    if (has_value(part, ".")) {    array(int) sub_segs = array_sscanf(part, "%d.%d.%d.%d");    switch(sizeof(sub_segs)) {    default:    case 4:
Roxen.git/server/base_server/roxen.pike:1788: Inside #if defined(DEBUG)
   DDUMP( rrhf );   #ifdef DEBUG    if( !requesthandler )    requesthandler = (program)(rrhf);   #endif    bound = 0;    port_obj = 0;    retries = 0;    }    -  static void create( int pn, string i ) +  static void create( int pn, string i, void|int ignore_eaddrinuse )    //! Constructor. Bind to the port 'pn' ip 'i'    {    setup (pn, i); -  bind(); +  bind (ignore_eaddrinuse);    }       static string _sprintf( )    {    return "Protocol(" + get_url() + ")";    }   }      #if constant(SSL.sslfile)   class SSLProtocol
Roxen.git/server/base_server/roxen.pike:1840:    string msg = (MSG); \    array args = ({ARGS}); \    if (sizeof (args)) msg = sprintf (msg, @args); \    report_error ("TLS port %s: %s", get_url(), msg); \    (VAR)->add_warning (msg); \    cert_err_unbind(); \    cert_failure = 1; \    return; \    } while (0)    -  void certificates_changed(Variable|void ignored) +  void certificates_changed(Variable|void ignored, +  void|int ignore_eaddrinuse)    {    int old_cert_failure = cert_failure;       string raw_keydata;    array(string) certificates = ({});    array(object) decoded_certs = ({});    Variable Certificates = getvar("ssl_cert_file");       object privs = Privs("Reading cert file");   
Roxen.git/server/base_server/roxen.pike:2015:    ctx->certificates = certificates;    }    else    CERT_ERROR (KeyFile, LOC_M(17,"No private key found.\n"));      #if EXPORT    ctx->export_mode();   #endif       if (!bound) { -  bind(); +  bind (ignore_eaddrinuse);    if (old_cert_failure && bound)    report_notice (LOC_M(64, "TLS port %s opened.\n"), get_url());    }    }       class CertificateListVariable    {    inherit Variable.FileList;       string doc()
Roxen.git/server/base_server/roxen.pike:2053:    }       RoxenSSLFile accept()    {    Stdio.File q = ::accept();    if (q)    return RoxenSSLFile (q, ctx);    return 0;    }    -  static void bind() +  static void bind (void|int ignore_eaddrinuse)    {    // Don't bind if we don't have correct certs.    if (!ctx->certificates) return; -  ::bind(); +  ::bind (ignore_eaddrinuse);    }    -  void create(int pn, string i) +  void create(int pn, string i, void|int ignore_eaddrinuse)    {   #if constant(Crypto.Random.random_string)    ctx->random = Crypto.Random.random_string;   #else    ctx->random = Crypto.randomness.reasonably_random()->read;   #endif       set_up_ssl_variables( this_object() );       ::setup(pn, i);    -  certificates_changed(); +  certificates_changed (0, ignore_eaddrinuse);       // Install the change callbacks here to avoid duplicate calls    // above.    // FIXME: Both variables ought to be updated on save before the    // changed callback is called. Currently you can get warnings    // that the files don't match if you update both variables    // at the same time.    getvar ("ssl_cert_file")->set_changed_callback (certificates_changed);    getvar ("ssl_key_file")->set_changed_callback (certificates_changed);    }
Roxen.git/server/base_server/roxen.pike:2429:    foreach(ipv6, string p) {    report_warning(LOC_M(65, "IPv6 port for URL %s disabled: %s\n"),    url, p);    }    }    required_hosts = ipv4;   #endif /* __ROXEN_SUPPORTS_IPV6__ */    }       int failures; +  int opened_ipv4_any_port;       foreach(required_hosts, string required_host)    {    if( m[ required_host ] && m[ required_host ][ port ] )    {    m[required_host][port]->ref(url, urls[url]);       urls[url]->port = m[required_host][port];    urls[ourl]->port = m[required_host][port];    continue; /* No need to open a new port */    }       if( !m[ required_host ] )    m[ required_host ] = ([ ]);       mixed err;    if (err = catch { -  m[ required_host ][ port ] = prot( port, required_host ); +  m[ required_host ][ port ] = +  prot( port, required_host, +  // Don't complain if binding IPv6 ANY fails with +  // EADDRINUSE after we've bound IPv4 ANY. At least on +  // Linux, it seems that IPv4 and IPv6 can share the +  // same interface, and in that case we're already done +  // if we've bound the IPv4 ANY. +  required_host == "::" && opened_ipv4_any_port);    }) {    failures++;    if (has_prefix(describe_error(err), "Invalid address") &&    required_host && has_value(required_host, ":")) {    report_error(sprintf("Failed to initialize IPv6 port for URL %s"    " (ip %s). Not supported?\n",    url, required_host));    } else {    report_error(sprintf("Initializing the port handler for URL %s"    " failed! (ip %s)\n"    "%s\n",    url,    required_host||"ANY",    describe_backtrace(err)));    }    continue;    }    -  +  if (!required_host) opened_ipv4_any_port = 1; +     if( !( m[ required_host ][ port ] ) )    {    m_delete( m[ required_host ], port );    failures++;    if (required_host) {    report_warning(LOC_M(22, "Binding the port on IP %s failed\n"    " for URL %s!\n"),    required_host, url);    }    continue;