Adjust the default listening address selection for the web server:
authorsimon <simon@cda61777-01e9-0310-a592-d414129be87e>
Wed, 5 Nov 2008 21:51:59 +0000 (21:51 +0000)
committersimon <simon@cda61777-01e9-0310-a592-d414129be87e>
Wed, 5 Nov 2008 21:51:59 +0000 (21:51 +0000)
be prepared to fall back to sensible localhost when MacOS doesn't
like silly localhost, and also pick a random port instead of 80 when
the user didn't specify one.

git-svn-id: svn://svn.tartarus.org/sgt/agedu@8282 cda61777-01e9-0310-a592-d414129be87e

TODO
agedu.but
httpd.c

diff --git a/TODO b/TODO
index f34f507..6549737 100644 (file)
--- a/TODO
+++ b/TODO
@@ -1,19 +1,6 @@
 TODO list for agedu
 ===================
 
- - adjust the default web server address selection.
-    + some systems (e.g. OS X) don't like us binding to random
-      localhost addresses. So if that fails, try falling back to
-      127.0.0.1 proper (and a randomly selected port) before giving
-      up.
-    + since binding to port 80 isn't generally feasible, we should
-      adjust the default behaviour when the user specifies --addr
-      with no port: it should select port zero, and then print the
-      port number on standard output. (Possibly also print the URL
-      as usual, in that situation: translate INADDR_ANY to
-      INADDR_LOOPBACK and then do the same as when we made the
-      entire address up ourself.)
-
  - we should munmap in all operating modes where we mmapped,
    otherwise chaining them will run out of address space
 
index 3eb481a..5bf5d0b 100644 (file)
--- a/agedu.but
+++ b/agedu.but
@@ -481,8 +481,8 @@ three months ago or later.
 \cw{agedu} should listen when running its web server. If you want
 \cw{agedu} to listen for connections coming in from any source, you
 should probably specify the special IP address \cw{0.0.0.0}. If the
-port number is omitted, it will be assumed to be 80 (for which
-\cw{agedu} will probably need to be running as a privileged user).
+port number is omitted, an arbitrary unused port will be chosen for
+you and displayed.
 
 \lcont{
 
diff --git a/httpd.c b/httpd.c
index 7c3f0f8..bbe82ab 100644 (file)
--- a/httpd.c
+++ b/httpd.c
@@ -403,7 +403,7 @@ static void base64_encode_atom(unsigned char *data, int n, char *out)
 void run_httpd(const void *t, int authmask, const struct httpd_config *dcfg,
               const struct html_config *incfg)
 {
-    int fd;
+    int fd, ret;
     int authtype;
     char *authstring = NULL;
     unsigned long ipaddr;
@@ -432,12 +432,24 @@ void run_httpd(const void *t, int authmask, const struct httpd_config *dcfg,
        ipaddr += (1 + rand() % 255);
        addr.sin_addr.s_addr = htonl(ipaddr);
        addr.sin_port = htons(0);
+       
     } else {
        addr.sin_addr.s_addr = inet_addr(dcfg->address);
-       addr.sin_port = dcfg->port ? htons(dcfg->port) : 80;
+       addr.sin_port = dcfg->port ? htons(dcfg->port) : 0;
     }
     addrlen = sizeof(addr);
-    if (bind(fd, (struct sockaddr *)&addr, addrlen) < 0) {
+    ret = bind(fd, (const struct sockaddr *)&addr, addrlen);
+    if (ret < 0 && errno == EADDRNOTAVAIL && !dcfg->address) {
+       /*
+        * Some systems don't like us binding to random weird
+        * localhost-space addresses. Try again with the official
+        * INADDR_LOOPBACK.
+        */
+       addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+       addr.sin_port = htons(0);
+       ret = bind(fd, (const struct sockaddr *)&addr, addrlen);
+    }
+    if (ret < 0) {
        fprintf(stderr, "bind: %s\n", strerror(errno));
        exit(1);
     }
@@ -537,13 +549,13 @@ void run_httpd(const void *t, int authmask, const struct httpd_config *dcfg,
        fprintf(stderr, PNAME ": authentication method not supported\n");
        exit(1);
     }
-    if (!dcfg->address) {
-       if (ntohs(addr.sin_port) == 80) {
-           printf("URL: http://%s/\n", inet_ntoa(addr.sin_addr));
-       } else {
-           printf("URL: http://%s:%d/\n",
-                  inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
-       }
+    if (ntohs(addr.sin_addr.s_addr) == INADDR_ANY) {
+       printf("Server port: %d\n", ntohs(addr.sin_port));
+    } else if (ntohs(addr.sin_port) == 80) {
+       printf("URL: http://%s/\n", inet_ntoa(addr.sin_addr));
+    } else {
+       printf("URL: http://%s:%d/\n",
+              inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
     }
 
     /*
@@ -589,6 +601,8 @@ void run_httpd(const void *t, int authmask, const struct httpd_config *dcfg,
 
            switch (fds[i].type) {
              case FD_CLIENT:
+               FD_SET_MAX(fds[i].fd, &rfds, maxfd);
+               break;
              case FD_LISTENER:
                FD_SET_MAX(fds[i].fd, &rfds, maxfd);
                break;