Add qemu 2.4.0
[kvmfornfv.git] / qemu / slirp / sbuf.c
diff --git a/qemu/slirp/sbuf.c b/qemu/slirp/sbuf.c
new file mode 100644 (file)
index 0000000..08ec2b4
--- /dev/null
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 1995 Danny Gasparovski.
+ *
+ * Please read the file COPYRIGHT for the
+ * terms and conditions of the copyright.
+ */
+
+#include <slirp.h>
+#include <qemu/main-loop.h>
+
+static void sbappendsb(struct sbuf *sb, struct mbuf *m);
+
+void
+sbfree(struct sbuf *sb)
+{
+       free(sb->sb_data);
+}
+
+void
+sbdrop(struct sbuf *sb, int num)
+{
+    int limit = sb->sb_datalen / 2;
+
+       /*
+        * We can only drop how much we have
+        * This should never succeed
+        */
+       if(num > sb->sb_cc)
+               num = sb->sb_cc;
+       sb->sb_cc -= num;
+       sb->sb_rptr += num;
+       if(sb->sb_rptr >= sb->sb_data + sb->sb_datalen)
+               sb->sb_rptr -= sb->sb_datalen;
+
+    if (sb->sb_cc < limit && sb->sb_cc + num >= limit) {
+        qemu_notify_event();
+    }
+}
+
+void
+sbreserve(struct sbuf *sb, int size)
+{
+       if (sb->sb_data) {
+               /* Already alloced, realloc if necessary */
+               if (sb->sb_datalen != size) {
+                       sb->sb_wptr = sb->sb_rptr = sb->sb_data = (char *)realloc(sb->sb_data, size);
+                       sb->sb_cc = 0;
+                       if (sb->sb_wptr)
+                          sb->sb_datalen = size;
+                       else
+                          sb->sb_datalen = 0;
+               }
+       } else {
+               sb->sb_wptr = sb->sb_rptr = sb->sb_data = (char *)malloc(size);
+               sb->sb_cc = 0;
+               if (sb->sb_wptr)
+                  sb->sb_datalen = size;
+               else
+                  sb->sb_datalen = 0;
+       }
+}
+
+/*
+ * Try and write() to the socket, whatever doesn't get written
+ * append to the buffer... for a host with a fast net connection,
+ * this prevents an unnecessary copy of the data
+ * (the socket is non-blocking, so we won't hang)
+ */
+void
+sbappend(struct socket *so, struct mbuf *m)
+{
+       int ret = 0;
+
+       DEBUG_CALL("sbappend");
+       DEBUG_ARG("so = %lx", (long)so);
+       DEBUG_ARG("m = %lx", (long)m);
+       DEBUG_ARG("m->m_len = %d", m->m_len);
+
+       /* Shouldn't happen, but...  e.g. foreign host closes connection */
+       if (m->m_len <= 0) {
+               m_free(m);
+               return;
+       }
+
+       /*
+        * If there is urgent data, call sosendoob
+        * if not all was sent, sowrite will take care of the rest
+        * (The rest of this function is just an optimisation)
+        */
+       if (so->so_urgc) {
+               sbappendsb(&so->so_rcv, m);
+               m_free(m);
+               sosendoob(so);
+               return;
+       }
+
+       /*
+        * We only write if there's nothing in the buffer,
+        * ottherwise it'll arrive out of order, and hence corrupt
+        */
+       if (!so->so_rcv.sb_cc)
+          ret = slirp_send(so, m->m_data, m->m_len, 0);
+
+       if (ret <= 0) {
+               /*
+                * Nothing was written
+                * It's possible that the socket has closed, but
+                * we don't need to check because if it has closed,
+                * it will be detected in the normal way by soread()
+                */
+               sbappendsb(&so->so_rcv, m);
+       } else if (ret != m->m_len) {
+               /*
+                * Something was written, but not everything..
+                * sbappendsb the rest
+                */
+               m->m_len -= ret;
+               m->m_data += ret;
+               sbappendsb(&so->so_rcv, m);
+       } /* else */
+       /* Whatever happened, we free the mbuf */
+       m_free(m);
+}
+
+/*
+ * Copy the data from m into sb
+ * The caller is responsible to make sure there's enough room
+ */
+static void
+sbappendsb(struct sbuf *sb, struct mbuf *m)
+{
+       int len, n,  nn;
+
+       len = m->m_len;
+
+       if (sb->sb_wptr < sb->sb_rptr) {
+               n = sb->sb_rptr - sb->sb_wptr;
+               if (n > len) n = len;
+               memcpy(sb->sb_wptr, m->m_data, n);
+       } else {
+               /* Do the right edge first */
+               n = sb->sb_data + sb->sb_datalen - sb->sb_wptr;
+               if (n > len) n = len;
+               memcpy(sb->sb_wptr, m->m_data, n);
+               len -= n;
+               if (len) {
+                       /* Now the left edge */
+                       nn = sb->sb_rptr - sb->sb_data;
+                       if (nn > len) nn = len;
+                       memcpy(sb->sb_data,m->m_data+n,nn);
+                       n += nn;
+               }
+       }
+
+       sb->sb_cc += n;
+       sb->sb_wptr += n;
+       if (sb->sb_wptr >= sb->sb_data + sb->sb_datalen)
+               sb->sb_wptr -= sb->sb_datalen;
+}
+
+/*
+ * Copy data from sbuf to a normal, straight buffer
+ * Don't update the sbuf rptr, this will be
+ * done in sbdrop when the data is acked
+ */
+void
+sbcopy(struct sbuf *sb, int off, int len, char *to)
+{
+       char *from;
+
+       from = sb->sb_rptr + off;
+       if (from >= sb->sb_data + sb->sb_datalen)
+               from -= sb->sb_datalen;
+
+       if (from < sb->sb_wptr) {
+               if (len > sb->sb_cc) len = sb->sb_cc;
+               memcpy(to,from,len);
+       } else {
+               /* re-use off */
+               off = (sb->sb_data + sb->sb_datalen) - from;
+               if (off > len) off = len;
+               memcpy(to,from,off);
+               len -= off;
+               if (len)
+                  memcpy(to+off,sb->sb_data,len);
+       }
+}