On 03/08/2016 11:43 AM, Jan Kaluža wrote:
On 03/08/2016 10:25 AM, Yann Ylavic wrote:
On Tue, Mar 8, 2016 at 9:46 AM, Yann Ylavic <ylavic....@gmail.com> wrote:
On Tue, Mar 8, 2016 at 9:28 AM, Jan Kaluža <jkal...@redhat.com> wrote:

I have chosen FreeListen over the flags

FWIW, should be take the YAD path, I'd prefer ListenFree (over
FreeListen) to emphasize on the "Listen directive family" with a
prefix...

Thinking more about this, I think I second Jim on the wish to have a
single Listen directive with some parameter like
"options=freebind,backlog:4095,reuseport,...".

Thinking about right syntax for options...

I would personally like something like "Listen [IP-address:]portnumber
[protocol] [option1] [option2] ...". Do we have list of supported
protocols by Listen directive, or we support whatever protocol is there?

If we have explicit list of protocols, then the protocols itself could
become an options.

If not, can it be acceptable, that you always have to define protocol
when you wan to use options?

I've implemented the way described in that question above ^. Please see the attached patch and share your opinions.

The syntax to enable IP_FREEBIND currently is:

Listen 192.168.0.1:80 http freebind

Regards,
Jan Kaluza


Otherwise I can always implement Yann's idea with "Listen
[IP-address:]portnumber [protocol] [options=[option1,option2,...]]".

Regards,
Jan Kaluza


We could then whatever (new) IP option more easily (less docs work...)
and maybe deprecate ListenBacklog.

For example, the "reuseport" (SO_REUSEPORT) option seem to be usable
w/o the current buckets mechanism in latest linux kernels, so indeed
we may add more and more options there...



Index: docs/manual/mod/mpm_common.xml
===================================================================
--- docs/manual/mod/mpm_common.xml	(revision 1733461)
+++ docs/manual/mod/mpm_common.xml	(working copy)
@@ -171,7 +171,7 @@
 <name>Listen</name>
 <description>IP addresses and ports that the server
 listens to</description>
-<syntax>Listen [<var>IP-address</var>:]<var>portnumber</var> [<var>protocol</var>]</syntax>
+<syntax>Listen [<var>IP-address</var>:]<var>portnumber</var> [<var>protocol</var>] [<var>option</var>] [...]</syntax>
 <contextlist><context>server config</context></contextlist>
 <modulelist><module>event</module><module>worker</module>
 <module>prefork</module><module>mpm_winnt</module>
@@ -240,6 +240,17 @@
       error message.
     </note>
 
+    <p>The optional <var>option</var> arguments are used to configure
+       system specific socket options:</p>
+
+    <table border="1">
+    <tr><th>Option</th><th>Description</th></tr>
+    <tr><td>freebind</td><td>Sets the <code>IP_FREEBIND</code> socket option
+        on systems where this option is available. It is therefore possible
+        to start the server even when particular IP address set in the
+        <directive>Listen</directive> directive is not configured yet.</td></tr>
+    </table>
+
 </usage>
 <seealso><a href="../dns-caveats.html">DNS Issues</a></seealso>
 <seealso><a href="../bind.html">Setting which addresses and ports Apache HTTP Server
Index: include/ap_listen.h
===================================================================
--- include/ap_listen.h	(revision 1733461)
+++ include/ap_listen.h	(working copy)
@@ -38,6 +38,9 @@
 typedef struct ap_listen_rec ap_listen_rec;
 typedef apr_status_t (*accept_function)(void **csd, ap_listen_rec *lr, apr_pool_t *ptrans);
 
+/* Whether use APR_SO_FREEBIND */
+#define AP_LISTEN_FREEBIND 1
+
 /**
  * @brief Apache's listeners record.
  *
@@ -71,6 +74,10 @@
     const char* protocol;
 
     ap_slave_t *slave;
+    /**
+     * Options to configure socket features.
+     */
+    int options;
 };
 
 /**
@@ -149,7 +156,7 @@
 AP_INIT_TAKE1("ListenCoresBucketsRatio", ap_set_listencbratio, NULL, RSRC_CONF, \
   "Ratio between the number of CPU cores (online) and the number of listeners buckets"), \
 AP_INIT_TAKE_ARGV("Listen", ap_set_listener, NULL, RSRC_CONF, \
-  "A port number or a numeric IP address and a port number, and an optional protocol"), \
+  "A port number or a numeric IP address and a port number, an optional protocol, and options"), \
 AP_INIT_TAKE1("SendBufferSize", ap_set_send_buffer_size, NULL, RSRC_CONF, \
   "Send buffer size in bytes"), \
 AP_INIT_TAKE1("ReceiveBufferSize", ap_set_receive_buffer_size, NULL, \
Index: server/listen.c
===================================================================
--- server/listen.c	(revision 1733461)
+++ server/listen.c	(working copy)
@@ -68,7 +68,8 @@
 #endif
 
 /* TODO: make_sock is just begging and screaming for APR abstraction */
-static apr_status_t make_sock(apr_pool_t *p, ap_listen_rec *server, int do_bind_listen)
+static apr_status_t make_sock(apr_pool_t *p, ap_listen_rec *server,
+                              int do_bind_listen)
 {
     apr_socket_t *s = server->sd;
     int one = 1;
@@ -162,6 +163,22 @@
     }
 #endif
 
+   if (server->options & AP_LISTEN_FREEBIND) {
+#if defined(APR_SO_FREEBIND)
+        stat = apr_socket_opt_set(s, APR_SO_FREEBIND, one);
+        if (stat != APR_SUCCESS) {
+            ap_log_perror(APLOG_MARK, APLOG_WARNING, stat, p, APLOGNO()
+                          "make_sock: failed to set set IP_FREEBIND socket option");
+            return stat;
+        }
+#else
+        ap_log_perror(APLOG_MARK, APLOG_WARNING, stat, p, APLOGNO()
+                        "make_sock: 'freebind' Listen option not supported "
+                        "by the system");
+        return APR_ENOTIMPL;
+#endif
+    }
+
     if (do_bind_listen) {
 #if APR_HAVE_IPV6
         if (server->bind_addr->family == APR_INET6) {
@@ -348,6 +365,7 @@
     rec = apr_palloc(process->pool, sizeof(ap_listen_rec));
     rec->active = 0;
     rec->next = 0;
+    rec->options = 0;
 
     rv = apr_os_sock_make(&rec->sd, &si, process->pool);
     if (rv != APR_SUCCESS) {
@@ -406,7 +424,7 @@
 
 static const char *alloc_listener(process_rec *process, char *addr,
                                   apr_port_t port, const char* proto,
-                                  void *slave)
+                                  void *slave, int options)
 {
     ap_listen_rec **walk, *last;
     apr_status_t status;
@@ -470,6 +488,7 @@
         new->active = 0;
         new->next = 0;
         new->bind_addr = sa;
+        new->options = options;
         new->protocol = apr_pstrdup(process->pool, proto);
 
         /* Go to the next sockaddr. */
@@ -827,6 +846,7 @@
                 duplr = apr_palloc(p, sizeof(ap_listen_rec));
                 duplr->slave = NULL;
                 duplr->protocol = apr_pstrdup(p, lr->protocol);
+                duplr->options = lr->options;
                 hostname = apr_pstrdup(p, lr->bind_addr->hostname);
                 port = lr->bind_addr->port;
                 apr_sockaddr_info_get(&sa, hostname, APR_UNSPEC, port, 0, p);
@@ -961,13 +981,14 @@
     apr_port_t port;
     apr_status_t rv;
     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
+    int i;
 
     if (err != NULL) {
         return err;
     }
 
-    if (argc < 1 || argc > 2) {
-        return "Listen requires 1 or 2 arguments.";
+    if (argc < 1) {
+        return "Listen requires at least 1 argument.";
     }
 #ifdef HAVE_SYSTEMD
     if (use_systemd == -1) {
@@ -993,7 +1014,18 @@
         return "Port must be specified";
     }
 
-    if (argc != 2) {
+    int options = 0;
+    for (i = 2; i < argc; i++) {
+        const char *w = argv[i];
+        if (!strcasecmp(w, "freebind")) {
+            options |= AP_LISTEN_FREEBIND;
+        }
+        else {
+            return apr_psprintf(cmd->pool, "Unknown Listen option: %s", w);
+        }
+    }
+
+    if (argc < 2) {
         if (port == 443) {
             proto = "https";
         } else {
@@ -1011,7 +1043,8 @@
     }
 #endif
 
-    return alloc_listener(cmd->server->process, host, port, proto, NULL);
+    return alloc_listener(cmd->server->process, host, port, proto, NULL,
+                          options);
 }
 
 AP_DECLARE_NONSTD(const char *) ap_set_listenbacklog(cmd_parms *cmd,

Reply via email to