Merge branch 'listen_v6only' into 'master'

Listen v6only

See merge request slirp/libslirp!77
diff --git a/src/debug.h b/src/debug.h
index 47712bd..0f9f3ef 100644
--- a/src/debug.h
+++ b/src/debug.h
@@ -10,6 +10,7 @@
 #define DBG_MISC (1 << 1)
 #define DBG_ERROR (1 << 2)
 #define DBG_TFTP (1 << 3)
+#define DBG_VERBOSE_CALL (1 << 4)
 
 extern int slirp_debug;
 
@@ -20,6 +21,13 @@
         }                                         \
     } while (0)
 
+#define DEBUG_VERBOSE_CALL(fmt, ...)                      \
+    do {                                                  \
+        if (G_UNLIKELY(slirp_debug & DBG_VERBOSE_CALL)) { \
+            g_debug(fmt "...", ##__VA_ARGS__);            \
+        }                                                 \
+    } while (0)
+
 #define DEBUG_ARG(fmt, ...)                       \
     do {                                          \
         if (G_UNLIKELY(slirp_debug & DBG_CALL)) { \
diff --git a/src/if.c b/src/if.c
index 23190b5..83dcae3 100644
--- a/src/if.c
+++ b/src/if.c
@@ -143,7 +143,7 @@
     bool from_batchq = false;
     struct mbuf *ifm, *ifm_next, *ifqt;
 
-    DEBUG_CALL("if_start");
+    DEBUG_VERBOSE_CALL("if_start");
 
     if (slirp->if_start_busy) {
         return;
diff --git a/src/libslirp.h b/src/libslirp.h
index 7049e5b..aac182e 100644
--- a/src/libslirp.h
+++ b/src/libslirp.h
@@ -178,12 +178,6 @@
                           const struct sockaddr *haddr, socklen_t haddrlen,
                           int flags);
 
-int slirp_add_ipv6_hostfwd(Slirp *slirp, int is_udp,
-                           struct in6_addr host_addr, int host_port,
-                           struct in6_addr guest_addr, int guest_port);
-int slirp_remove_ipv6_hostfwd(Slirp *slirp, int is_udp,
-                              struct in6_addr host_addr, int host_port);
-
 /* Set up port forwarding between a port in the guest network and a
  * command running on the host */
 int slirp_add_exec(Slirp *slirp, const char *cmdline,
diff --git a/src/libslirp.map b/src/libslirp.map
index cae6cf8..792b0a9 100644
--- a/src/libslirp.map
+++ b/src/libslirp.map
@@ -32,7 +32,5 @@
 SLIRP_4.5 {
     slirp_add_hostxfwd;
     slirp_remove_hostxfwd;
-    slirp_add_ipv6_hostfwd;
-    slirp_remove_ipv6_hostfwd;
     slirp_neighbor_info;
 } SLIRP_4.2;
diff --git a/src/slirp.c b/src/slirp.c
index b1539af..ba41843 100644
--- a/src/slirp.c
+++ b/src/slirp.c
@@ -362,6 +362,7 @@
             { "misc", DBG_MISC },
             { "error", DBG_ERROR },
             { "tftp", DBG_TFTP },
+            { "verbose_call", DBG_VERBOSE_CALL },
         };
         slirp_debug = g_parse_debug_string(debug, keys, G_N_ELEMENTS(keys));
     }
@@ -1179,8 +1180,10 @@
     if (gaddr->sa_family == AF_INET) {
         const struct sockaddr_in *gaddr_in = (const struct sockaddr_in *) gaddr;
 
-        if (gaddrlen < sizeof(struct sockaddr_in))
+        if (gaddrlen < sizeof(struct sockaddr_in)) {
+            errno = EINVAL;
             return -1;
+        }
 
         if (!gaddr_in->sin_addr.s_addr) {
             gdhcp_addr = *gaddr_in;
@@ -1191,8 +1194,10 @@
     } else {
         const struct sockaddr_in6 *gaddr_in6 = (const struct sockaddr_in6 *) gaddr;
 
-        if (gaddrlen < sizeof(struct sockaddr_in6))
+        if (gaddrlen < sizeof(struct sockaddr_in6)) {
+            errno = EINVAL;
             return -1;
+        }
 
         if (in6_zero(&gaddr_in6->sin6_addr)) {
             /*
@@ -1200,6 +1205,7 @@
              * we can't translate "addr-any" to the guest. Instead, for now,
              * reject it.
              */
+            errno = EINVAL;
             return -1;
         }
     }
@@ -1218,58 +1224,6 @@
     return 0;
 }
 
-int slirp_remove_ipv6_hostfwd(Slirp *slirp, int is_udp,
-                              struct in6_addr host_addr, int host_port)
-{
-    struct socket *so;
-    struct socket *head = (is_udp ? &slirp->udb : &slirp->tcb);
-    struct sockaddr_in6 addr;
-    int port = htons(host_port);
-    socklen_t addr_len;
-
-    for (so = head->so_next; so != head; so = so->so_next) {
-        addr_len = sizeof(addr);
-        if ((so->so_state & SS_HOSTFWD) &&
-            getsockname(so->s, (struct sockaddr *)&addr, &addr_len) == 0 &&
-            addr_len == sizeof(addr) &&
-            addr.sin6_family == AF_INET6 &&
-            !memcmp(&addr.sin6_addr, &host_addr, sizeof(host_addr)) &&
-            addr.sin6_port == port) {
-            so->slirp->cb->unregister_poll_fd(so->s, so->slirp->opaque);
-            closesocket(so->s);
-            sofree(so);
-            return 0;
-        }
-    }
-
-    return -1;
-}
-
-int slirp_add_ipv6_hostfwd(Slirp *slirp, int is_udp,
-                          struct in6_addr host_addr, int host_port,
-                          struct in6_addr guest_addr, int guest_port)
-{
-    /*
-     * Libslirp currently only provides a stateless DHCPv6 server, thus we
-     * can't translate "addr-any" to the guest. Instead, for now, reject it.
-     */
-    if (in6_zero(&guest_addr)) {
-        return -1;
-    }
-
-    if (is_udp) {
-        if (!udp6_listen(slirp, host_addr, htons(host_port),
-                         guest_addr, htons(guest_port), SS_HOSTFWD))
-            return -1;
-    } else {
-        if (!tcp6_listen(slirp, host_addr, htons(host_port),
-                         guest_addr, htons(guest_port), SS_HOSTFWD))
-            return -1;
-    }
-
-    return 0;
-}
-
 /* TODO: IPv6 */
 static bool check_guestfwd(Slirp *slirp, struct in_addr *guest_addr,
                            int guest_port)
diff --git a/src/socket.c b/src/socket.c
index 40c32a5..bf50058 100644
--- a/src/socket.c
+++ b/src/socket.c
@@ -735,6 +735,7 @@
 
 /*
  * Listen for incoming TCP connections
+ * On failure errno contains the reason.
  */
 struct socket *tcpx_listen(Slirp *slirp,
                            const struct sockaddr *haddr, socklen_t haddrlen,
@@ -763,10 +764,7 @@
     so = socreate(slirp);
 
     /* Don't tcp_attach... we don't need so_snd nor so_rcv */
-    if ((so->so_tcpcb = tcp_newtcpcb(so)) == NULL) {
-        g_free(so);
-        return NULL;
-    }
+    so->so_tcpcb = tcp_newtcpcb(so);
     insque(so, &slirp->tcb);
 
     /*
@@ -828,25 +826,6 @@
     return tcpx_listen(slirp, (const struct sockaddr *) &hsa, sizeof(hsa), (struct 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)
-{
-    struct sockaddr_in6 hsa, lsa;
-
-    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, (const struct sockaddr *) &hsa, sizeof(hsa), (struct sockaddr*) &lsa, sizeof(lsa), flags);
-}
-
 /*
  * Various session state calls
  * XXX Should be #define's
diff --git a/src/socket.h b/src/socket.h
index 5ea3cf6..932f391 100644
--- a/src/socket.h
+++ b/src/socket.h
@@ -166,8 +166,6 @@
 void sorecvfrom(struct socket *);
 int sosendto(struct socket *, struct mbuf *);
 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,
                            const struct sockaddr *haddr, socklen_t haddrlen,
                            const struct sockaddr *laddr, socklen_t laddrlen,
diff --git a/src/udp.c b/src/udp.c
index aa44bc3..b9694c2 100644
--- a/src/udp.c
+++ b/src/udp.c
@@ -360,11 +360,14 @@
 {
     struct socket *so;
     socklen_t addrlen;
+    int save_errno;
 
     so = socreate(slirp);
     so->s = slirp_socket(haddr->sa_family, SOCK_DGRAM, 0);
     if (so->s < 0) {
+        save_errno = errno;
         sofree(so);
+        errno = save_errno;
         return NULL;
     }
     if (haddr->sa_family == AF_INET6)
@@ -373,7 +376,9 @@
     insque(so, &slirp->udb);
 
     if (bind(so->s, haddr, haddrlen) < 0) {
+        save_errno = errno;
         udp_detach(so);
+        errno = save_errno;
         return NULL;
     }
     slirp_socket_set_fast_reuse(so->s);
@@ -409,22 +414,3 @@
 
     return udpx_listen(slirp, (const struct sockaddr *) &hsa, sizeof(hsa), (struct 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)
-{
-    struct sockaddr_in6 hsa, lsa;
-
-    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, (const struct sockaddr *) &hsa, sizeof(hsa), (struct sockaddr *) &lsa, sizeof(lsa), flags);
-}
diff --git a/src/udp.h b/src/udp.h
index 0e92b48..47f4ed3 100644
--- a/src/udp.h
+++ b/src/udp.h
@@ -82,8 +82,6 @@
 int udp_attach(struct socket *, unsigned short af);
 void udp_detach(struct socket *);
 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 *,
                            const struct sockaddr *haddr, socklen_t haddrlen,
                            const struct sockaddr *laddr, socklen_t laddrlen,
diff --git a/src/util.c b/src/util.c
index 67ef667..e6bccbe 100644
--- a/src/util.c
+++ b/src/util.c
@@ -71,6 +71,7 @@
 
 /*
  * Opens a socket with FD_CLOEXEC set
+ * On failure errno contains the reason.
  */
 int slirp_socket(int domain, int type, int protocol)
 {