Expose udpx_listen and tcpx_listen as taking sockaddr

This generalizes adding hostfwd, and opens the path for cross ipv4/6
forward.

Signed-off-by: Samuel Thibault <samuel.thibault@ens-lyon.org>
diff --git a/src/socket.c b/src/socket.c
index d77b059..ff2d0d4 100644
--- a/src/socket.c
+++ b/src/socket.c
@@ -736,12 +736,11 @@
 /*
  * Listen for incoming TCP connections
  */
-static struct socket *tcpx_listen(Slirp *slirp, int family,
-                                  in4or6_addr haddr, unsigned hport,
-                                  in4or6_addr laddr, unsigned lport,
-                                  int flags)
+struct socket *tcpx_listen(Slirp *slirp,
+                           union slirp_sockaddr *haddr, socklen_t haddrlen,
+                           union slirp_sockaddr *laddr, socklen_t laddrlen,
+                           int flags)
 {
-    union slirp_sockaddr addr;
     struct socket *so;
     int s, opt = 1;
     socklen_t addrlen;
@@ -749,14 +748,16 @@
     DEBUG_CALL("tcpx_listen");
     /* AF_INET6 addresses are bigger than AF_INET, so this is big enough. */
     char addrstr[INET6_ADDRSTRLEN];
-    const char *str = inet_ntop(family, &haddr, addrstr, sizeof(addrstr));
-    g_assert(str != NULL);
-    DEBUG_ARG("haddr = %s", str);
-    DEBUG_ARG("hport = %d", ntohs(hport));
-    str = inet_ntop(family, &laddr, addrstr, sizeof(addrstr));
-    g_assert(str != NULL);
-    DEBUG_ARG("laddr = %s", str);
-    DEBUG_ARG("lport = %d", ntohs(lport));
+    char portstr[6];
+    int ret;
+    ret = getnameinfo((struct sockaddr *) haddr, haddrlen, addrstr, sizeof(addrstr), portstr, sizeof(portstr), NI_NUMERICHOST|NI_NUMERICSERV);
+    g_assert(ret == 0);
+    DEBUG_ARG("haddr = %s", addrstr);
+    DEBUG_ARG("hport = %s", portstr);
+    ret = getnameinfo((struct sockaddr *) laddr, laddrlen, addrstr, sizeof(addrstr), portstr, sizeof(portstr), NI_NUMERICHOST|NI_NUMERICSERV);
+    g_assert(ret == 0);
+    DEBUG_ARG("laddr = %s", addrstr);
+    DEBUG_ARG("lport = %s", portstr);
     DEBUG_ARG("flags = %x", flags);
 
     so = socreate(slirp);
@@ -776,33 +777,12 @@
 
     so->so_state &= SS_PERSISTENT_MASK;
     so->so_state |= (SS_FACCEPTCONN | flags);
-    so->so_lfamily = family;
-    /* Address,port are kept in network format */
-    if (family == AF_INET) {
-        so->so_laddr = laddr.addr4;
-        so->so_lport = lport;
-    } else {
-        so->so_laddr6 = laddr.addr6;
-        so->so_lport6 = lport;
-    }
+    so->lhost = *laddr;
 
-    memset(&addr, 0, sizeof(addr));
-    if (family == AF_INET) {
-        addr.sin.sin_family = family;
-        addr.sin.sin_addr = haddr.addr4;
-        addr.sin.sin_port = hport;
-        addrlen = sizeof(addr.sin);
-    } else {
-        addr.sin6.sin6_family = family;
-        addr.sin6.sin6_addr = haddr.addr6;
-        addr.sin6.sin6_port = hport;
-        addrlen = sizeof(addr.sin6);
-    }
-
-    s = slirp_socket(family, SOCK_STREAM, 0);
+    s = slirp_socket(haddr->ss.ss_family, SOCK_STREAM, 0);
     if ((s < 0) ||
         (slirp_socket_set_fast_reuse(s) < 0) ||
-        (bind(s, (struct sockaddr *)&addr, addrlen) < 0) ||
+        (bind(s, (struct sockaddr *)haddr, haddrlen) < 0) ||
         (listen(s, 1) < 0)) {
         int tmperrno = errno; /* Don't clobber the real reason we failed */
         if (s >= 0) {
@@ -820,39 +800,49 @@
     setsockopt(s, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(int));
     slirp_socket_set_nodelay(s);
 
-    getsockname(s, (struct sockaddr *)&addr, &addrlen);
-    if (family == AF_INET) {
-        so->fhost.sin = addr.sin;
-    } else {
-        so->fhost.sin6 = addr.sin6;
-    }
+    addrlen = sizeof(so->fhost);
+    getsockname(s, (struct sockaddr *)&so->fhost, &addrlen);
     sotranslate_accept(so);
 
     so->s = s;
     return so;
 }
 
-/* TODO: rather fuse tcp_listen and tcp6_listen into tcp_listen that takes two
- * sockaddr */
 struct socket *tcp_listen(Slirp *slirp, uint32_t haddr, unsigned hport,
                           uint32_t laddr, unsigned lport, int flags)
 {
-    in4or6_addr haddr4, laddr4;
+    struct sockaddr_in hsa, lsa;
 
-    haddr4.addr4.s_addr = haddr;
-    laddr4.addr4.s_addr = laddr;
-    return tcpx_listen(slirp, AF_INET, haddr4, hport, laddr4, lport, flags);
+    memset(&hsa, 0, sizeof(hsa));
+    hsa.sin_family = AF_INET;
+    hsa.sin_addr.s_addr = haddr;
+    hsa.sin_port = hport;
+
+    memset(&lsa, 0, sizeof(lsa));
+    lsa.sin_family = AF_INET;
+    lsa.sin_addr.s_addr = laddr;
+    lsa.sin_port = lport;
+
+    return tcpx_listen(slirp, (union slirp_sockaddr*) &hsa, sizeof(hsa), (union slirp_sockaddr*) &lsa, sizeof(lsa), flags);
 }
 
 struct socket *
 tcp6_listen(Slirp *slirp, struct in6_addr haddr, u_int hport,
             struct in6_addr laddr, u_int lport, int flags)
 {
-    in4or6_addr haddr6, laddr6;
+    struct sockaddr_in6 hsa, lsa;
 
-    haddr6.addr6 = haddr;
-    laddr6.addr6 = laddr;
-    return tcpx_listen(slirp, AF_INET6, haddr6, hport, laddr6, lport, flags);
+    memset(&hsa, 0, sizeof(hsa));
+    hsa.sin6_family = AF_INET6;
+    hsa.sin6_addr = haddr;
+    hsa.sin6_port = hport;
+
+    memset(&lsa, 0, sizeof(lsa));
+    lsa.sin6_family = AF_INET6;
+    lsa.sin6_addr = laddr;
+    lsa.sin6_port = lport;
+
+    return tcpx_listen(slirp, (union slirp_sockaddr*) &hsa, sizeof(hsa), (union slirp_sockaddr*) &lsa, sizeof(lsa), flags);
 }
 
 /*
diff --git a/src/socket.h b/src/socket.h
index 1a885a0..3a546fc 100644
--- a/src/socket.h
+++ b/src/socket.h
@@ -158,6 +158,10 @@
 struct socket *tcp_listen(Slirp *, uint32_t, unsigned, uint32_t, unsigned, int);
 struct socket *tcp6_listen(Slirp *, struct in6_addr, u_int,
                            struct in6_addr, u_int, int);
+struct socket *tcpx_listen(Slirp *slirp,
+                           union slirp_sockaddr *haddr, socklen_t haddrlen,
+                           union slirp_sockaddr *laddr, socklen_t laddrlen,
+                           int flags);
 void soisfconnecting(register struct socket *);
 void soisfconnected(register struct socket *);
 void sofwdrain(struct socket *);
diff --git a/src/udp.c b/src/udp.c
index 2b86c93..3b57d70 100644
--- a/src/udp.c
+++ b/src/udp.c
@@ -353,17 +353,16 @@
     return 0;
 }
 
-static struct socket *udpx_listen(Slirp *slirp, int family,
-                                  in4or6_addr haddr, unsigned hport,
-                                  in4or6_addr laddr, unsigned lport,
-                                  int flags)
+struct socket *udpx_listen(Slirp *slirp,
+                           union slirp_sockaddr *haddr, socklen_t haddrlen,
+                           union slirp_sockaddr *laddr, socklen_t laddrlen,
+                           int flags)
 {
-    union slirp_sockaddr addr;
     struct socket *so;
     socklen_t addrlen;
 
     so = socreate(slirp);
-    so->s = slirp_socket(family, SOCK_DGRAM, 0);
+    so->s = slirp_socket(haddr->ss.ss_family, SOCK_DGRAM, 0);
     if (so->s < 0) {
         sofree(so);
         return NULL;
@@ -371,41 +370,17 @@
     so->so_expire = curtime + SO_EXPIRE;
     insque(so, &slirp->udb);
 
-    memset(&addr, 0, sizeof(addr));
-    if (family == AF_INET) {
-        addr.sin.sin_family = family;
-        addr.sin.sin_addr = haddr.addr4;
-        addr.sin.sin_port = hport;
-        addrlen = sizeof(addr.sin);
-    } else {
-        addr.sin6.sin6_family = family;
-        addr.sin6.sin6_addr = haddr.addr6;
-        addr.sin6.sin6_port = hport;
-        addrlen = sizeof(addr.sin6);
-    }
-
-    if (bind(so->s, (struct sockaddr *)&addr, addrlen) < 0) {
+    if (bind(so->s, (struct sockaddr *)haddr, haddrlen) < 0) {
         udp_detach(so);
         return NULL;
     }
     slirp_socket_set_fast_reuse(so->s);
 
-    getsockname(so->s, (struct sockaddr *)&addr, &addrlen);
-    if (family == AF_INET) {
-        so->fhost.sin = addr.sin;
-    } else {
-        so->fhost.sin6 = addr.sin6;
-    }
+    addrlen = sizeof(so->fhost);
+    getsockname(so->s, (struct sockaddr *)&so->fhost, &addrlen);
     sotranslate_accept(so);
 
-    so->so_lfamily = family;
-    if (family == AF_INET) {
-        so->so_laddr = laddr.addr4;
-        so->so_lport = lport;
-    } else {
-        so->so_laddr6 = laddr.addr6;
-        so->so_lport6 = lport;
-    }
+    so->lhost = *laddr;
 
     if (flags != SS_FACCEPTONCE)
         so->so_expire = 0;
@@ -415,25 +390,39 @@
     return so;
 }
 
-/* TODO: rather fuse udp_listen and udp6_listen into udp_listen that takes two
- * sockaddr */
 struct socket *udp_listen(Slirp *slirp, uint32_t haddr, unsigned hport,
                           uint32_t laddr, unsigned lport, int flags)
 {
-    in4or6_addr haddr4, laddr4;
+    struct sockaddr_in hsa, lsa;
 
-    haddr4.addr4.s_addr = haddr;
-    laddr4.addr4.s_addr = laddr;
-    return udpx_listen(slirp, AF_INET, haddr4, hport, laddr4, lport, flags);
+    memset(&hsa, 0, sizeof(hsa));
+    hsa.sin_family = AF_INET;
+    hsa.sin_addr.s_addr = haddr;
+    hsa.sin_port = hport;
+
+    memset(&lsa, 0, sizeof(lsa));
+    lsa.sin_family = AF_INET;
+    lsa.sin_addr.s_addr = laddr;
+    lsa.sin_port = lport;
+
+    return udpx_listen(slirp, (union slirp_sockaddr*) &hsa, sizeof(hsa), (union slirp_sockaddr*) &lsa, sizeof(lsa), flags);
 }
 
 struct socket *
 udp6_listen(Slirp *slirp, struct in6_addr haddr, u_int hport,
             struct in6_addr laddr, u_int lport, int flags)
 {
-    in4or6_addr haddr6, laddr6;
+    struct sockaddr_in6 hsa, lsa;
 
-    haddr6.addr6 = haddr;
-    laddr6.addr6 = laddr;
-    return udpx_listen(slirp, AF_INET6, haddr6, hport, laddr6, lport, flags);
+    memset(&hsa, 0, sizeof(hsa));
+    hsa.sin6_family = AF_INET6;
+    hsa.sin6_addr = haddr;
+    hsa.sin6_port = hport;
+
+    memset(&lsa, 0, sizeof(lsa));
+    lsa.sin6_family = AF_INET6;
+    lsa.sin6_addr = laddr;
+    lsa.sin6_port = lport;
+
+    return udpx_listen(slirp, (union slirp_sockaddr*) &hsa, sizeof(hsa), (union slirp_sockaddr*) &lsa, sizeof(lsa), flags);
 }
diff --git a/src/udp.h b/src/udp.h
index b3fbeac..5361c2b 100644
--- a/src/udp.h
+++ b/src/udp.h
@@ -34,6 +34,8 @@
 #ifndef UDP_H
 #define UDP_H
 
+#include "socket.h"
+
 #define UDP_TTL 0x60
 #define UDP_UDPDATALEN 16192
 
@@ -82,6 +84,10 @@
 struct socket *udp_listen(Slirp *, uint32_t, unsigned, uint32_t, unsigned, int);
 struct socket *udp6_listen(Slirp *slirp, struct in6_addr, u_int,
                             struct in6_addr, u_int, int);
+struct socket *udpx_listen(Slirp *,
+                           union slirp_sockaddr *haddr, socklen_t haddrlen,
+                           union slirp_sockaddr *laddr, socklen_t laddrlen,
+                           int flags);
 int udp_output(struct socket *so, struct mbuf *m, struct sockaddr_in *saddr,
                struct sockaddr_in *daddr, int iptos);