]> Git Repo - qemu.git/blobdiff - slirp/socket.c
s390x/vfio: ap: Introduce VFIO AP device
[qemu.git] / slirp / socket.c
index 86927722e1abe9f3ea2d5cc2bccfc6bb284ce766..322383a1f9f2edf28a0d740a48511bd83c863274 100644 (file)
@@ -59,6 +59,27 @@ socreate(Slirp *slirp)
   return(so);
 }
 
+/*
+ * Remove references to so from the given message queue.
+ */
+static void
+soqfree(struct socket *so, struct quehead *qh)
+{
+    struct mbuf *ifq;
+
+    for (ifq = (struct mbuf *) qh->qh_link;
+             (struct quehead *) ifq != qh;
+             ifq = ifq->ifq_next) {
+        if (ifq->ifq_so == so) {
+            struct mbuf *ifm;
+            ifq->ifq_so = NULL;
+            for (ifm = ifq->ifs_next; ifm != ifq; ifm = ifm->ifs_next) {
+                ifm->ifq_so = NULL;
+            }
+        }
+    }
+}
+
 /*
  * remque and free a socket, clobber cache
  */
@@ -66,23 +87,9 @@ 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;
-    }
-  }
+  soqfree(so, &slirp->if_fastq);
+  soqfree(so, &slirp->if_batchq);
 
   if (so->so_emu==EMU_RSH && so->extra) {
        sofree(so->extra);
@@ -100,6 +107,9 @@ sofree(struct socket *so)
   if(so->so_next && so->so_prev)
     remque(so);  /* crashes if so is not in a queue */
 
+  if (so->so_tcpcb) {
+      free(so->so_tcpcb);
+  }
   free(so);
 }
 
@@ -194,12 +204,19 @@ soread(struct socket *so)
                        return 0;
                else {
                        int err;
-                       socklen_t slen = sizeof err;
+                       socklen_t elen = sizeof err;
+                       struct sockaddr_storage addr;
+                       struct sockaddr *paddr = (struct sockaddr *) &addr;
+                       socklen_t alen = sizeof addr;
 
                        err = errno;
                        if (nn == 0) {
-                               getsockopt(so->s, SOL_SOCKET, SO_ERROR,
-                                          &err, &slen);
+                               if (getpeername(so->s, paddr, &alen) < 0) {
+                                       err = errno;
+                               } else {
+                                       getsockopt(so->s, SOL_SOCKET, SO_ERROR,
+                                               &err, &elen);
+                               }
                        }
 
                        DEBUG_MISC((dfd, " --- soread() disconnected, nn = %d, errno = %d-%s\n", nn, errno,strerror(errno)));
@@ -330,7 +347,7 @@ sosendoob(struct socket *so)
        struct sbuf *sb = &so->so_rcv;
        char buff[2048]; /* XXX Shouldn't be sending more oob data than this */
 
-       int n, len;
+       int n;
 
        DEBUG_CALL("sosendoob");
        DEBUG_ARG("so = %p", so);
@@ -342,34 +359,41 @@ sosendoob(struct socket *so)
        if (sb->sb_rptr < sb->sb_wptr) {
                /* We can send it directly */
                n = slirp_send(so, sb->sb_rptr, so->so_urgc, (MSG_OOB)); /* |MSG_DONTWAIT)); */
-               so->so_urgc -= n;
-
-               DEBUG_MISC((dfd, " --- sent %d bytes urgent data, %d urgent bytes left\n", n, so->so_urgc));
        } else {
                /*
                 * Since there's no sendv or sendtov like writev,
                 * we must copy all data to a linear buffer then
                 * send it all
                 */
-               len = (sb->sb_data + sb->sb_datalen) - sb->sb_rptr;
-               if (len > so->so_urgc) len = so->so_urgc;
+               uint32_t urgc = so->so_urgc;
+               int len = (sb->sb_data + sb->sb_datalen) - sb->sb_rptr;
+               if (len > urgc) {
+                       len = urgc;
+               }
                memcpy(buff, sb->sb_rptr, len);
-               so->so_urgc -= len;
-               if (so->so_urgc) {
+               urgc -= len;
+               if (urgc) {
                        n = sb->sb_wptr - sb->sb_data;
-                       if (n > so->so_urgc) n = so->so_urgc;
+                       if (n > urgc) {
+                               n = urgc;
+                       }
                        memcpy((buff + len), sb->sb_data, n);
-                       so->so_urgc -= n;
                        len += n;
                }
                n = slirp_send(so, buff, len, (MSG_OOB)); /* |MSG_DONTWAIT)); */
 #ifdef DEBUG
-               if (n != len)
-                  DEBUG_ERROR((dfd, "Didn't send all data urgently XXXXX\n"));
+               if (n != len) {
+                       DEBUG_ERROR((dfd, "Didn't send all data urgently XXXXX\n"));
+               }
 #endif
-               DEBUG_MISC((dfd, " ---2 sent %d bytes urgent data, %d urgent bytes left\n", n, so->so_urgc));
        }
 
+       if (n < 0) {
+               return n;
+       }
+       so->so_urgc -= n;
+       DEBUG_MISC((dfd, " ---2 sent %d bytes urgent data, %d urgent bytes left\n", n, so->so_urgc));
+
        sb->sb_cc -= n;
        sb->sb_rptr += n;
        if (sb->sb_rptr >= (sb->sb_data + sb->sb_datalen))
@@ -394,7 +418,15 @@ sowrite(struct socket *so)
        DEBUG_ARG("so = %p", so);
 
        if (so->so_urgc) {
-               sosendoob(so);
+               uint32_t expected = so->so_urgc;
+               if (sosendoob(so) < expected) {
+                       /* Treat a short write as a fatal error too,
+                        * rather than continuing on and sending the urgent
+                        * data as if it were non-urgent and leaving the
+                        * so_urgc count wrong.
+                        */
+                       goto err_disconnected;
+               }
                if (sb->sb_cc == 0)
                        return 0;
        }
@@ -438,11 +470,7 @@ sowrite(struct socket *so)
                return 0;
 
        if (nn <= 0) {
-               DEBUG_MISC((dfd, " --- sowrite disconnected, so->so_state = %x, errno = %d\n",
-                       so->so_state, errno));
-               sofcantsendmore(so);
-               tcp_sockclosed(sototcpcb(so));
-               return -1;
+               goto err_disconnected;
        }
 
 #ifndef HAVE_READV
@@ -469,6 +497,13 @@ sowrite(struct socket *so)
                sofcantsendmore(so);
 
        return nn;
+
+err_disconnected:
+       DEBUG_MISC((dfd, " --- sowrite disconnected, so->so_state = %x, errno = %d\n",
+                   so->so_state, errno));
+       sofcantsendmore(so);
+       tcp_sockclosed(sototcpcb(so));
+       return -1;
 }
 
 /*
@@ -673,10 +708,10 @@ tcp_listen(Slirp *slirp, uint32_t haddr, u_int hport, uint32_t laddr,
        memset(&addr, 0, addrlen);
 
        DEBUG_CALL("tcp_listen");
-       DEBUG_ARG("haddr = %x", haddr);
-       DEBUG_ARG("hport = %d", hport);
-       DEBUG_ARG("laddr = %x", laddr);
-       DEBUG_ARG("lport = %d", lport);
+       DEBUG_ARG("haddr = %s", inet_ntoa((struct in_addr){.s_addr = haddr}));
+       DEBUG_ARG("hport = %d", ntohs(hport));
+       DEBUG_ARG("laddr = %s", inet_ntoa((struct in_addr){.s_addr = laddr}));
+       DEBUG_ARG("lport = %d", ntohs(lport));
        DEBUG_ARG("flags = %x", flags);
 
        so = socreate(slirp);
@@ -726,6 +761,8 @@ tcp_listen(Slirp *slirp, uint32_t haddr, u_int hport, uint32_t laddr,
                return NULL;
        }
        qemu_setsockopt(s, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(int));
+       opt = 1;
+       qemu_setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(int));
 
        getsockname(s,(struct sockaddr *)&addr,&addrlen);
        so->so_ffamily = AF_INET;
This page took 0.032007 seconds and 4 git commands to generate.