]> git.proxmox.com Git - mirror_qemu.git/blobdiff - slirp/socket.c
usb-ccid: better bulk_out error handling
[mirror_qemu.git] / slirp / socket.c
index 55150f5e5e09837375f5cece29b82439f48a64c1..6c189713688cdf10ce25b01221d67a15e864ca0b 100644 (file)
@@ -7,7 +7,7 @@
 
 #include "qemu/osdep.h"
 #include "qemu-common.h"
-#include <slirp.h>
+#include "slirp.h"
 #include "ip_icmp.h"
 #ifdef __sun__
 #include <sys/filio.h>
@@ -66,6 +66,23 @@ void
 sofree(struct socket *so)
 {
   Slirp *slirp = so->slirp;
+  struct mbuf *ifm;
+
+  for (ifm = (struct mbuf *) slirp->if_fastq.qh_link;
+       (struct quehead *) ifm != &slirp->if_fastq;
+       ifm = ifm->ifq_next) {
+    if (ifm->ifq_so == so) {
+      ifm->ifq_so = NULL;
+    }
+  }
+
+  for (ifm = (struct mbuf *) slirp->if_batchq.qh_link;
+       (struct quehead *) ifm != &slirp->if_batchq;
+       ifm = ifm->ifq_next) {
+    if (ifm->ifq_so == so) {
+      ifm->ifq_so = NULL;
+    }
+  }
 
   if (so->so_emu==EMU_RSH && so->extra) {
        sofree(so->extra);
@@ -176,9 +193,24 @@ soread(struct socket *so)
                if (nn < 0 && (errno == EINTR || errno == EAGAIN))
                        return 0;
                else {
+                       int err;
+                       socklen_t slen = sizeof err;
+
+                       err = errno;
+                       if (nn == 0) {
+                               getsockopt(so->s, SOL_SOCKET, SO_ERROR,
+                                          &err, &slen);
+                       }
+
                        DEBUG_MISC((dfd, " --- soread() disconnected, nn = %d, errno = %d-%s\n", nn, errno,strerror(errno)));
                        sofcantrcvmore(so);
-                       tcp_sockclosed(sototcpcb(so));
+
+                       if (err == ECONNRESET || err == ECONNREFUSED
+                           || err == ENOTCONN || err == EPIPE) {
+                               tcp_drop(sototcpcb(so), err);
+                       } else {
+                               tcp_sockclosed(sototcpcb(so));
+                       }
                        return -1;
                }
        }
@@ -191,7 +223,7 @@ soread(struct socket *so)
         * We don't test for <= 0 this time, because there legitimately
         * might not be any more data (since the socket is non-blocking),
         * a close will be detected on next iteration.
-        * A return of -1 wont (shouldn't) happen, since it didn't happen above
+        * A return of -1 won't (shouldn't) happen, since it didn't happen above
         */
        if (n == 2 && nn == iov[0].iov_len) {
             int ret;
@@ -260,10 +292,11 @@ err:
  * so when OOB data arrives, we soread() it and everything
  * in the send buffer is sent as urgent data
  */
-void
+int
 sorecvoob(struct socket *so)
 {
        struct tcpcb *tp = sototcpcb(so);
+       int ret;
 
        DEBUG_CALL("sorecvoob");
        DEBUG_ARG("so = %p", so);
@@ -276,11 +309,15 @@ sorecvoob(struct socket *so)
         * urgent data, or the read() doesn't return all the
         * urgent data.
         */
-       soread(so);
-       tp->snd_up = tp->snd_una + so->so_snd.sb_cc;
-       tp->t_force = 1;
-       tcp_output(tp);
-       tp->t_force = 0;
+       ret = soread(so);
+       if (ret > 0) {
+           tp->snd_up = tp->snd_una + so->so_snd.sb_cc;
+           tp->t_force = 1;
+           tcp_output(tp);
+           tp->t_force = 0;
+       }
+
+       return ret;
 }
 
 /*
@@ -483,7 +520,18 @@ sorecvfrom(struct socket *so)
          if (!m) {
              return;
          }
-         m->m_data += IF_MAXLINKHDR;
+         switch (so->so_ffamily) {
+         case AF_INET:
+             m->m_data += IF_MAXLINKHDR + sizeof(struct udpiphdr);
+             break;
+         case AF_INET6:
+             m->m_data += IF_MAXLINKHDR + sizeof(struct ip6)
+                                        + sizeof(struct udphdr);
+             break;
+         default:
+             g_assert_not_reached();
+             break;
+         }
 
          /*
           * XXX Shouldn't FIONREAD packets destined for port 53,
@@ -596,7 +644,7 @@ sosendto(struct socket *so, struct mbuf *m)
 
        /* Don't care what port we get */
        ret = sendto(so->s, m->m_data, m->m_len, 0,
-                    (struct sockaddr *)&addr, sizeof(addr));
+                    (struct sockaddr *)&addr, sockaddr_size(&addr));
        if (ret < 0)
                return -1;
 
@@ -760,6 +808,7 @@ void sotranslate_out(struct socket *so, struct sockaddr_storage *addr)
 {
     Slirp *slirp = so->slirp;
     struct sockaddr_in *sin = (struct sockaddr_in *)addr;
+    struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)addr;
 
     switch (addr->ss_family) {
     case AF_INET:
@@ -780,6 +829,22 @@ void sotranslate_out(struct socket *so, struct sockaddr_storage *addr)
             ntohs(sin->sin_port), inet_ntoa(sin->sin_addr)));
         break;
 
+    case AF_INET6:
+        if (in6_equal_net(&so->so_faddr6, &slirp->vprefix_addr6,
+                    slirp->vprefix_len)) {
+            if (in6_equal(&so->so_faddr6, &slirp->vnameserver_addr6)) {
+                uint32_t scope_id;
+                if (get_dns6_addr(&sin6->sin6_addr, &scope_id) >= 0) {
+                    sin6->sin6_scope_id = scope_id;
+                } else {
+                    sin6->sin6_addr = in6addr_loopback;
+                }
+            } else {
+                sin6->sin6_addr = in6addr_loopback;
+            }
+        }
+        break;
+
     default:
         break;
     }
@@ -789,6 +854,7 @@ void sotranslate_in(struct socket *so, struct sockaddr_storage *addr)
 {
     Slirp *slirp = so->slirp;
     struct sockaddr_in *sin = (struct sockaddr_in *)addr;
+    struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)addr;
 
     switch (addr->ss_family) {
     case AF_INET:
@@ -805,6 +871,16 @@ void sotranslate_in(struct socket *so, struct sockaddr_storage *addr)
         }
         break;
 
+    case AF_INET6:
+        if (in6_equal_net(&so->so_faddr6, &slirp->vprefix_addr6,
+                    slirp->vprefix_len)) {
+            if (in6_equal(&sin6->sin6_addr, &in6addr_loopback)
+                    || !in6_equal(&so->so_faddr6, &slirp->vhost_addr6)) {
+                sin6->sin6_addr = so->so_faddr6;
+            }
+        }
+        break;
+
     default:
         break;
     }
@@ -826,6 +902,13 @@ void sotranslate_accept(struct socket *so)
         }
         break;
 
+   case AF_INET6:
+        if (in6_equal(&so->so_faddr6, &in6addr_any) ||
+                in6_equal(&so->so_faddr6, &in6addr_loopback)) {
+           so->so_faddr6 = slirp->vhost_addr6;
+        }
+        break;
+
     default:
         break;
     }