]> Git Repo - qemu.git/blobdiff - slirp/socket.c
slirp: add tftp tracing
[qemu.git] / slirp / socket.c
index b336586c7b384eb8add1bf5edee01130c0fdd9ac..041ec5061a10247c17c46a7b9b9d809ca2f8f0a8 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>
@@ -46,17 +46,36 @@ struct socket *solookup(struct socket **last, struct socket *head,
 struct socket *
 socreate(Slirp *slirp)
 {
-  struct socket *so;
+    struct socket *so = g_new(struct socket, 1);
 
-  so = (struct socket *)malloc(sizeof(struct socket));
-  if(so) {
     memset(so, 0, sizeof(struct socket));
     so->so_state = SS_NOFDREF;
     so->s = -1;
     so->slirp = slirp;
     so->pollfds_idx = -1;
-  }
-  return(so);
+
+    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;
+            }
+        }
+    }
 }
 
 /*
@@ -67,10 +86,9 @@ sofree(struct socket *so)
 {
   Slirp *slirp = so->slirp;
 
-  if (so->so_emu==EMU_RSH && so->extra) {
-       sofree(so->extra);
-       so->extra=NULL;
-  }
+  soqfree(so, &slirp->if_fastq);
+  soqfree(so, &slirp->if_batchq);
+
   if (so == slirp->tcp_last_so) {
       slirp->tcp_last_so = &slirp->tcb;
   } else if (so == slirp->udp_last_so) {
@@ -83,7 +101,10 @@ sofree(struct socket *so)
   if(so->so_next && so->so_prev)
     remque(so);  /* crashes if so is not in a queue */
 
-  free(so);
+  if (so->so_tcpcb) {
+      free(so->so_tcpcb);
+  }
+  g_free(so);
 }
 
 size_t sopreprbuf(struct socket *so, struct iovec *iov, int *np)
@@ -177,12 +198,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)));
@@ -313,7 +341,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);
@@ -325,34 +353,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))
@@ -377,7 +412,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;
        }
@@ -421,11 +464,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
@@ -452,6 +491,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;
 }
 
 /*
@@ -656,21 +702,18 @@ 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);
-       if (!so) {
-         return NULL;
-       }
 
        /* Don't tcp_attach... we don't need so_snd nor so_rcv */
        if ((so->so_tcpcb = tcp_newtcpcb(so)) == NULL) {
-               free(so);
-               return NULL;
+            g_free(so);
+            return NULL;
        }
        insque(so, &slirp->tcb);
 
@@ -696,7 +739,9 @@ tcp_listen(Slirp *slirp, uint32_t haddr, u_int hport, uint32_t laddr,
            (listen(s,1) < 0)) {
                int tmperrno = errno; /* Don't clobber the real reason we failed */
 
-               close(s);
+                if (s >= 0) {
+                    closesocket(s);
+                }
                sofree(so);
                /* Restore the real errno */
 #ifdef _WIN32
@@ -707,6 +752,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;
@@ -816,9 +863,12 @@ void sotranslate_out(struct socket *so, struct sockaddr_storage *addr)
         if (in6_equal_net(&so->so_faddr6, &slirp->vprefix_addr6,
                     slirp->vprefix_len)) {
             if (in6_equal(&so->so_faddr6, &slirp->vnameserver_addr6)) {
-                /*if (get_dns_addr(&addr) < 0) {*/ /* TODO */
+                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;
             }
This page took 0.032523 seconds and 4 git commands to generate.