chiark / gitweb /
lib/addr.c, etc.: Return plain addresses from `netaddress_resolve'.
authorMark Wooding <mdw@distorted.org.uk>
Sat, 6 Jun 2020 12:27:45 +0000 (13:27 +0100)
committerMark Wooding <mdw@distorted.org.uk>
Mon, 15 Jun 2020 12:03:09 +0000 (13:03 +0100)
Instead of a list of `struct addrinfo' structures, return a vector of
`struct resolved', each of which just contains a socket address and
length.  This is sufficient for all of the existing callers (which have
been changed to cope), and means that we don't need any awful hacks
because they're easy to free.

lib/addr.c
lib/addr.h
lib/client-common.c
lib/uaudio-rtp.c
server/state.c

index 802204a83372d2e69eef831603867ee180cf0642..0ba88f18a26206f476224a4722fc0140b8c60788 100644 (file)
@@ -339,16 +339,18 @@ void netaddress_format(const struct netaddress *na,
 /** @brief Resolve a network address
  * @param na Address structure
  * @param passive True if passive (bindable) address is desired
 /** @brief Resolve a network address
  * @param na Address structure
  * @param passive True if passive (bindable) address is desired
- * @param protocol Protocol number desired (e.g. @c IPPROTO_TCP)
- * @return List of suitable addresses or NULL
+ * @param type Socket type (e.g., @c SOCK_STREAM, @c SOCK_DGRAM)
+ * @param[out] raddr_out Vector of address/length pairs
+ * @param[out] nraddr_out Length of output vector
+ * @return Zero on success, -1 on error
  *
  *
- * Free the address using netaddress_freeaddrinfo() because it might not
- * have come from getaddrinfo() directly.
+ * Call netaddress_free_resolved() to free the resolved addresses.
  */
  */
-struct addrinfo *netaddress_resolve(const struct netaddress *na,
-                                   int passive,
-                                   int protocol) {
-  struct addrinfo *res, hints[1];
+int netaddress_resolve(const struct netaddress *na, int passive, int type,
+                      struct resolved **raddr_out, size_t *nraddr_out) {
+  struct resolved *raddr;
+  size_t i, nraddr;
+  struct addrinfo *res, *ai, hints[1];
   struct sockaddr_un *sun;
   char service[64];
   int rc;
   struct sockaddr_un *sun;
   char service[64];
   int rc;
@@ -357,26 +359,21 @@ struct addrinfo *netaddress_resolve(const struct netaddress *na,
 #if HAVE_SYS_UN_H
   if (na->af == AF_UNIX) {
     /* `getaddrinfo' won't work, so we make our own one */
 #if HAVE_SYS_UN_H
   if (na->af == AF_UNIX) {
     /* `getaddrinfo' won't work, so we make our own one */
-    res = xmalloc(sizeof(*res));
-    res->ai_flags = 0;
-    res->ai_family = AF_UNIX;
-    res->ai_socktype = (protocol == IPPROTO_UDP ? SOCK_DGRAM : SOCK_STREAM);
-    res->ai_protocol = 0;
-    res->ai_addrlen = offsetof(struct sockaddr_un, sun_path) +
+    raddr = xmalloc(sizeof(*raddr));
+    raddr->len = offsetof(struct sockaddr_un, sun_path) +
       strlen(na->address) + 1;
       strlen(na->address) + 1;
-    sun = xmalloc(res->ai_addrlen);
+    sun = xmalloc_noptr(raddr->len);
     sun->sun_family = AF_UNIX;
     strcpy(sun->sun_path, na->address);
     sun->sun_family = AF_UNIX;
     strcpy(sun->sun_path, na->address);
-    res->ai_addr = (struct sockaddr *)sun;
-    res->ai_canonname = sun->sun_path;
-    res->ai_next = 0;
+    raddr->sa = (struct sockaddr *)sun;
+    nraddr = 1;
   } else
 #endif
   {
     /* get the system to do the heavy lifting */
     memset(hints, 0, sizeof hints);
     hints->ai_family = na->af;
   } else
 #endif
   {
     /* get the system to do the heavy lifting */
     memset(hints, 0, sizeof hints);
     hints->ai_family = na->af;
-    hints->ai_protocol = protocol;
+    hints->ai_socktype = type;
     hints->ai_flags = passive ? AI_PASSIVE : 0;
     byte_snprintf(service, sizeof service, "%d", na->port);
     rc = getaddrinfo(na->address, service, hints, &res);
     hints->ai_flags = passive ? AI_PASSIVE : 0;
     byte_snprintf(service, sizeof service, "%d", na->port);
     rc = getaddrinfo(na->address, service, hints, &res);
@@ -385,24 +382,33 @@ struct addrinfo *netaddress_resolve(const struct netaddress *na,
                     na->address ? na->address : "*",
                     na->port,
                     format_error(ec_getaddrinfo, rc, errbuf, sizeof errbuf));
                     na->address ? na->address : "*",
                     na->port,
                     format_error(ec_getaddrinfo, rc, errbuf, sizeof errbuf));
-      return NULL;
+      return -1;
+    }
+    /* copy the addresses into an output vector */
+    for(ai = res, nraddr = 0; ai; ai = ai->ai_next, nraddr++);
+    raddr = xmalloc(nraddr*sizeof(*raddr));
+    for(ai = res, i = 0; ai; ai = ai->ai_next, i++) {
+      raddr[i].sa = xmalloc_noptr(ai->ai_addrlen);
+      raddr[i].len = ai->ai_addrlen;
+      memcpy(raddr[i].sa, ai->ai_addr, ai->ai_addrlen);
     }
     }
-    assert(res->ai_family != AF_UNIX);
+    freeaddrinfo(res);
   }
   }
-  return res;
+  *raddr_out = raddr;
+  *nraddr_out = nraddr;
+  return 0;
 }
 
 }
 
-/** @brief Free an address-info list from netaddress_resovle()
- * @param res Address-info list
- */
-void netaddress_freeaddrinfo(struct addrinfo *res) {
-#if HAVE_SYS_UN_H
-  if(res->ai_family == AF_UNIX) {
-    xfree(res->ai_addr);
-    xfree(res);
-  } else
-#endif
-    freeaddrinfo(res);
+/** @brief Free a vector of resolved addresses */
+void netaddress_free_resolved(struct resolved *raddr, size_t nraddr)
+{
+  size_t i;
+
+  if (!raddr)
+    return;
+  for(i = 0; i < nraddr; i++)
+    xfree(raddr[i].sa);
+  xfree(raddr);
 }
 
 /*
 }
 
 /*
index c0e82b04ec0713ec8356355fbc12aeddc6e5b97c..edb727c52d636799722d3bda5283047a6596d7a2 100644 (file)
@@ -43,6 +43,16 @@ struct netaddress {
   int port;
 };
 
   int port;
 };
 
+/** @brief A socket address and length */
+struct resolved {
+
+  /** @brief Pointer to the address */
+  struct sockaddr *sa;
+
+  /** @brief Length of the address */
+  socklen_t len;
+};
+
 struct addrinfo *get_address(const struct stringlist *a,
                             const struct addrinfo *pref,
                             char **namep)
 struct addrinfo *get_address(const struct stringlist *a,
                             const struct addrinfo *pref,
                             char **namep)
@@ -62,10 +72,10 @@ int netaddress_parse(struct netaddress *na,
 void netaddress_format(const struct netaddress *na,
                       int *nvecp,
                       char ***vecp) attribute((nonnull (1)));
 void netaddress_format(const struct netaddress *na,
                       int *nvecp,
                       char ***vecp) attribute((nonnull (1)));
-struct addrinfo *netaddress_resolve(const struct netaddress *na,
-                                   int passive,
-                                   int protocol) attribute((nonnull (1)));
-void netaddress_freeaddrinfo(struct addrinfo *res) attribute((nonnull (1)));
+int netaddress_resolve(const struct netaddress *na, int passive, int type,
+                      struct resolved **raddr_out, size_t *nraddr_out)
+  attribute((nonnull (1, 4, 5)));
+void netaddress_free_resolved(struct resolved *raddr, size_t nraddr);
 
 #endif /* ADDR_H */
 
 
 #endif /* ADDR_H */
 
index f344159308e10eb243fd0f7895883897255566d7..c2ea90d920e0a24cdf07b2ac28dcf5a1639616e8 100644 (file)
@@ -57,16 +57,16 @@ socklen_t disorder_find_server(struct config *c, unsigned flags,
 #if !_WIN32
   struct sockaddr_un su;
 #endif
 #if !_WIN32
   struct sockaddr_un su;
 #endif
-  struct addrinfo *res = 0;
+  struct resolved *res;
+  size_t nres;
   char *name = NULL;
   socklen_t len;
 
   if(c->connect.af != -1) {
   char *name = NULL;
   socklen_t len;
 
   if(c->connect.af != -1) {
-    res = netaddress_resolve(&c->connect, 0, IPPROTO_TCP);
-    if(!res) 
+    if(netaddress_resolve(&c->connect, 0, SOCK_STREAM, &res, &nres))
       return -1;
       return -1;
-    sa = res->ai_addr;
-    len = res->ai_addrlen;
+    sa = res->sa;
+    len = res->len;
   } else {
 #if _WIN32
     disorder_fatal(0, "local connections are not supported on Windows");
   } else {
 #if _WIN32
     disorder_fatal(0, "local connections are not supported on Windows");
@@ -90,6 +90,7 @@ socklen_t disorder_find_server(struct config *c, unsigned flags,
     strcpy(su.sun_path, name);
     sa = (struct sockaddr *)&su;
     len = sizeof su;
     strcpy(su.sun_path, name);
     sa = (struct sockaddr *)&su;
     len = sizeof su;
+    res = 0;
     xfree(name);
 #endif
   }
     xfree(name);
 #endif
   }
@@ -98,7 +99,7 @@ socklen_t disorder_find_server(struct config *c, unsigned flags,
   if(namep)
     *namep = format_sockaddr(sa);
   if(res)
   if(namep)
     *namep = format_sockaddr(sa);
   if(res)
-    netaddress_freeaddrinfo(res);
+    netaddress_free_resolved(res, nres);
   return len;
 }
 
   return len;
 }
 
index 9e7abde229dbb22a411ea4c81830c2aa84720daf..dc1fd6ca6527096ac673f3c2102f58451b8782a9 100644 (file)
@@ -261,7 +261,8 @@ static void hack_send_buffer_size(int fd, const char *what) {
 }
 
 static void rtp_open(void) {
 }
 
 static void rtp_open(void) {
-  struct addrinfo *dres, *sres;
+  struct resolved *dres, *sres;
+  size_t ndres, nsres;
   static const int one = 1;
   struct netaddress dst[1], src[1];
   const char *mode;
   static const int one = 1;
   struct netaddress dst[1], src[1];
   const char *mode;
@@ -287,22 +288,24 @@ static void rtp_open(void) {
                     "rtp-source-port",
                     src);
   if(dst->af != -1) {
                     "rtp-source-port",
                     src);
   if(dst->af != -1) {
-    dres = netaddress_resolve(dst, 0, IPPROTO_UDP);
-    if(!dres)
+    if(netaddress_resolve(dst, 0, SOCK_DGRAM, &dres, &ndres))
       exit(-1);
       exit(-1);
-  } else
+  } else {
     dres = 0;
     dres = 0;
+    ndres = 0;
+  }
   if(src->af != -1) {
   if(src->af != -1) {
-    sres = netaddress_resolve(src, 1, IPPROTO_UDP);
-    if(!sres)
+    if(netaddress_resolve(src, 0, SOCK_DGRAM, &sres, &nsres))
       exit(-1);
       exit(-1);
-  } else
+  } else {
     sres = 0;
     sres = 0;
+    nsres = 0;
+  }
   /* _AUTO inspects the destination address and acts accordingly */
   if(rtp_mode == RTP_AUTO) {
     if(!dres)
       rtp_mode = RTP_REQUEST;
   /* _AUTO inspects the destination address and acts accordingly */
   if(rtp_mode == RTP_AUTO) {
     if(!dres)
       rtp_mode = RTP_REQUEST;
-    else if(multicast(dres->ai_addr))
+    else if(multicast(dres->sa))
       rtp_mode = RTP_MULTICAST;
     else {
       struct ifaddrs *ifs;
       rtp_mode = RTP_MULTICAST;
     else {
       struct ifaddrs *ifs;
@@ -315,7 +318,7 @@ static void rtp_open(void) {
          * for he same interface which _does_ have ifa_broadaddr though... */
         if((ifs->ifa_flags & IFF_BROADCAST)
            && ifs->ifa_broadaddr
          * for he same interface which _does_ have ifa_broadaddr though... */
         if((ifs->ifa_flags & IFF_BROADCAST)
            && ifs->ifa_broadaddr
-           && sockaddr_equal(ifs->ifa_broadaddr, dres->ai_addr))
+           && sockaddr_equal(ifs->ifa_broadaddr, dres->sa))
           break;
         ifs = ifs->ifa_next;
       }
           break;
         ifs = ifs->ifa_next;
       }
@@ -330,9 +333,7 @@ static void rtp_open(void) {
     rtp_max_payload = 1500 - 8/*UDP*/ - 40/*IP*/ - 8/*conservatism*/;
   /* Create the sockets */
   if(rtp_mode != RTP_REQUEST) {
     rtp_max_payload = 1500 - 8/*UDP*/ - 40/*IP*/ - 8/*conservatism*/;
   /* Create the sockets */
   if(rtp_mode != RTP_REQUEST) {
-    if((rtp_fd = socket(dres->ai_family,
-                        dres->ai_socktype,
-                        dres->ai_protocol)) < 0)
+    if((rtp_fd = socket(dres->sa->sa_family, SOCK_DGRAM, IPPROTO_UDP)) < 0)
       disorder_fatal(errno, "error creating RTP transmission socket");
   }
   if((rtp_fd4 = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
       disorder_fatal(errno, "error creating RTP transmission socket");
   }
   if((rtp_fd4 = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
@@ -345,7 +346,7 @@ static void rtp_open(void) {
     /* Enable multicast options */
     const int ttl = atoi(uaudio_get("multicast-ttl", "1"));
     const int loop = !strcmp(uaudio_get("multicast-loop", "yes"), "yes");
     /* Enable multicast options */
     const int ttl = atoi(uaudio_get("multicast-ttl", "1"));
     const int loop = !strcmp(uaudio_get("multicast-loop", "yes"), "yes");
-    switch(dres->ai_family) {
+    switch(dres->sa->sa_family) {
     case PF_INET: {
       if(setsockopt(rtp_fd, IPPROTO_IP, IP_MULTICAST_TTL,
                     &ttl, sizeof ttl) < 0)
     case PF_INET: {
       if(setsockopt(rtp_fd, IPPROTO_IP, IP_MULTICAST_TTL,
                     &ttl, sizeof ttl) < 0)
@@ -365,21 +366,21 @@ static void rtp_open(void) {
       break;
     }
     default:
       break;
     }
     default:
-      disorder_fatal(0, "unsupported address family %d", dres->ai_family);
+      disorder_fatal(0, "unsupported address family %d", dres->sa->sa_family);
     }
     disorder_info("multicasting on %s TTL=%d loop=%s", 
     }
     disorder_info("multicasting on %s TTL=%d loop=%s", 
-                  format_sockaddr(dres->ai_addr), ttl, loop ? "yes" : "no");
+                  format_sockaddr(dres->sa), ttl, loop ? "yes" : "no");
     break;
   }
   case RTP_UNICAST: {
     break;
   }
   case RTP_UNICAST: {
-    disorder_info("unicasting on %s", format_sockaddr(dres->ai_addr));
+    disorder_info("unicasting on %s", format_sockaddr(dres->sa));
     break;
   }
   case RTP_BROADCAST: {
     if(setsockopt(rtp_fd, SOL_SOCKET, SO_BROADCAST, &one, sizeof one) < 0)
       disorder_fatal(errno, "error setting SO_BROADCAST on broadcast socket");
     disorder_info("broadcasting on %s", 
     break;
   }
   case RTP_BROADCAST: {
     if(setsockopt(rtp_fd, SOL_SOCKET, SO_BROADCAST, &one, sizeof one) < 0)
       disorder_fatal(errno, "error setting SO_BROADCAST on broadcast socket");
     disorder_info("broadcasting on %s", 
-                  format_sockaddr(dres->ai_addr));
+                  format_sockaddr(dres->sa));
     break;
   }
   case RTP_REQUEST: {
     break;
   }
   case RTP_REQUEST: {
@@ -394,12 +395,12 @@ static void rtp_open(void) {
   /* We might well want to set additional broadcast- or multicast-related
    * options here */
   if(rtp_mode != RTP_REQUEST) {
   /* We might well want to set additional broadcast- or multicast-related
    * options here */
   if(rtp_mode != RTP_REQUEST) {
-    if(sres && bind(rtp_fd, sres->ai_addr, sres->ai_addrlen) < 0)
+    if(sres && bind(rtp_fd, sres->sa, sres->len) < 0)
       disorder_fatal(errno, "error binding broadcast socket to %s", 
       disorder_fatal(errno, "error binding broadcast socket to %s", 
-                     format_sockaddr(sres->ai_addr));
-    if(connect(rtp_fd, dres->ai_addr, dres->ai_addrlen) < 0)
+                     format_sockaddr(sres->sa));
+    if(connect(rtp_fd, dres->sa, dres->len) < 0)
       disorder_fatal(errno, "error connecting broadcast socket to %s", 
       disorder_fatal(errno, "error connecting broadcast socket to %s", 
-                     format_sockaddr(dres->ai_addr));
+                     format_sockaddr(dres->sa));
   }
 #ifdef IP_MTU_DISCOVER
   mtu_disc = uaudio_get("rtp-mtu-discovery", "default");
   }
 #ifdef IP_MTU_DISCOVER
   mtu_disc = uaudio_get("rtp-mtu-discovery", "default");
@@ -409,7 +410,7 @@ static void rtp_open(void) {
     else break;
     if(setsockopt(rtp_fd4, IPPROTO_IP, IP_MTU_DISCOVER, &opt, sizeof opt))
       disorder_fatal(errno, "error setting MTU discovery");
     else break;
     if(setsockopt(rtp_fd4, IPPROTO_IP, IP_MTU_DISCOVER, &opt, sizeof opt))
       disorder_fatal(errno, "error setting MTU discovery");
-    if(sres->ai_family == AF_INET &&
+    if(sres->sa->sa_family == AF_INET &&
         setsockopt(rtp_fd, IPPROTO_IP, IP_MTU_DISCOVER, &opt, sizeof opt))
       disorder_fatal(errno, "error setting MTU discovery");
   } while (0);
         setsockopt(rtp_fd, IPPROTO_IP, IP_MTU_DISCOVER, &opt, sizeof opt))
       disorder_fatal(errno, "error setting MTU discovery");
   } while (0);
index 63c7c4542fab4ee3a8bd5e77a0286d88a9501728..19e8be3e4f962cb00d07c581173f7a1e6407f7be 100644 (file)
@@ -73,9 +73,9 @@ void quit(ev_source *ev) {
 }
 
 /** @brief Create a copy of an @c addrinfo structure */
 }
 
 /** @brief Create a copy of an @c addrinfo structure */
-static struct sockaddr *copy_sockaddr(const struct addrinfo *addr) {
-  struct sockaddr *sa = xmalloc_noptr(addr->ai_addrlen);
-  memcpy(sa, addr->ai_addr, addr->ai_addrlen);
+static struct sockaddr *copy_sockaddr(const struct resolved *raddr) {
+  struct sockaddr *sa = xmalloc_noptr(raddr->len);
+  memcpy(sa, raddr->sa, raddr->len);
   return sa;
 }
 
   return sa;
 }
 
@@ -114,7 +114,8 @@ static void reset_unix_socket(ev_source *ev,
 
 /** @brief Create and destroy sockets to set current configuration */
 void reset_sockets(ev_source *ev) {
 
 /** @brief Create and destroy sockets to set current configuration */
 void reset_sockets(ev_source *ev) {
-  struct addrinfo *res, *r;
+  struct resolved *res;
+  size_t i, nres;
   struct listener *l, **ll;
   const char *private_dir = config_get_file("private");
   
   struct listener *l, **ll;
   const char *private_dir = config_get_file("private");
   
@@ -128,18 +129,17 @@ void reset_sockets(ev_source *ev) {
   reset_unix_socket(ev, priv_socket, config_get_file("private/socket"), 1);
 
   /* get the new listen config */
   reset_unix_socket(ev, priv_socket, config_get_file("private/socket"), 1);
 
   /* get the new listen config */
-  if(config->listen.af != -1)
-    res = netaddress_resolve(&config->listen, 1, IPPROTO_TCP);
-  else
-    res = 0;
+  res = 0; nres = 0;
+  if(config->listen.af != -1) 
+    netaddress_resolve(&config->listen, 1, SOCK_STREAM, &res, &nres);
 
   /* Close any current listeners that aren't required any more */
   ll = &listeners;
   while((l = *ll)) {
 
   /* Close any current listeners that aren't required any more */
   ll = &listeners;
   while((l = *ll)) {
-    for(r = res; r; r = r->ai_next)
-      if(!sockaddrcmp(r->ai_addr, l->sa))
+    for(i = 0; i < nres; i++)
+      if(!sockaddrcmp(res[i].sa, l->sa))
        break;
        break;
-    if(!r) {
+    if(i >= nres) {
       /* Didn't find a match, remove this one */
       server_stop(ev, l->fd);
       *ll = l->next;
       /* Didn't find a match, remove this one */
       server_stop(ev, l->fd);
       *ll = l->next;
@@ -150,18 +150,18 @@ void reset_sockets(ev_source *ev) {
   }
 
   /* Open any new listeners that are required */
   }
 
   /* Open any new listeners that are required */
-  for(r = res; r; r = r->ai_next) {
+  for(i = 0; i < nres; i++) {
     for(l = listeners; l; l = l->next)
     for(l = listeners; l; l = l->next)
-      if(!sockaddrcmp(r->ai_addr, l->sa))
+      if(!sockaddrcmp(res[i].sa, l->sa))
        break;
     if(!l) {
       /* Didn't find a match, need a new listener */
        break;
     if(!l) {
       /* Didn't find a match, need a new listener */
-      int fd = server_start(ev, r->ai_family, r->ai_addrlen, r->ai_addr,
-                           format_sockaddr(r->ai_addr), 0);
+      int fd = server_start(ev, res[i].sa->sa_family, res[i].len, res[i].sa,
+                           format_sockaddr(res[i].sa), 0);
       if(fd >= 0) {
        l = xmalloc(sizeof *l);
        l->next = listeners;
       if(fd >= 0) {
        l = xmalloc(sizeof *l);
        l->next = listeners;
-       l->sa = copy_sockaddr(r);
+       l->sa = copy_sockaddr(&res[i]);
        l->fd = fd;
        listeners = l;
       }
        l->fd = fd;
        listeners = l;
       }
@@ -171,7 +171,7 @@ void reset_sockets(ev_source *ev) {
   }
   /* if res is still set it needs freeing */
   if(res)
   }
   /* if res is still set it needs freeing */
   if(res)
-    netaddress_freeaddrinfo(res);
+    netaddress_free_resolved(res, nres);
 }
 
 /** @brief Reconfigure the server
 }
 
 /** @brief Reconfigure the server