5544c1b
From 176b159d70cb26b24ce928497ae269b294e503d8 Mon Sep 17 00:00:00 2001
5544c1b
From: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
5544c1b
Date: Mon, 20 Aug 2012 10:21:54 +0100
5544c1b
Subject: [PATCH] net: asynchronous send/receive infrastructure for
5544c1b
 net/socket.c
5544c1b
5544c1b
The net/socket.c net client is not truly asynchronous.  This patch
5544c1b
borrows the qemu_set_fd_handler2() code from net/tap.c as the basis for
5544c1b
proper asynchronous send/receive.
5544c1b
5544c1b
Only read packets from the socket when the peer is able to receive.
5544c1b
This avoids needless queuing.
5544c1b
5544c1b
Later patches implement asynchronous send.
5544c1b
5544c1b
Signed-off-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
5544c1b
(cherry picked from commit 863f678fba4191f3b695620f41056cb7c124425d)
5544c1b
5544c1b
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
5544c1b
---
5544c1b
 net/socket.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++------
5544c1b
 1 file changed, 52 insertions(+), 6 deletions(-)
5544c1b
5544c1b
diff --git a/net/socket.c b/net/socket.c
5544c1b
index c172c24..54e32f0 100644
5544c1b
--- a/net/socket.c
5544c1b
+++ b/net/socket.c
5544c1b
@@ -42,9 +42,51 @@ typedef struct NetSocketState {
5544c1b
     unsigned int packet_len;
5544c1b
     uint8_t buf[4096];
5544c1b
     struct sockaddr_in dgram_dst; /* contains inet host and port destination iff connectionless (SOCK_DGRAM) */
5544c1b
+    IOHandler *send_fn;           /* differs between SOCK_STREAM/SOCK_DGRAM */
5544c1b
+    bool read_poll;               /* waiting to receive data? */
5544c1b
+    bool write_poll;              /* waiting to transmit data? */
5544c1b
 } NetSocketState;
5544c1b
 
5544c1b
 static void net_socket_accept(void *opaque);
5544c1b
+static void net_socket_writable(void *opaque);
5544c1b
+
5544c1b
+/* Only read packets from socket when peer can receive them */
5544c1b
+static int net_socket_can_send(void *opaque)
5544c1b
+{
5544c1b
+    NetSocketState *s = opaque;
5544c1b
+
5544c1b
+    return qemu_can_send_packet(&s->nc);
5544c1b
+}
5544c1b
+
5544c1b
+static void net_socket_update_fd_handler(NetSocketState *s)
5544c1b
+{
5544c1b
+    qemu_set_fd_handler2(s->fd,
5544c1b
+                         s->read_poll  ? net_socket_can_send : NULL,
5544c1b
+                         s->read_poll  ? s->send_fn : NULL,
5544c1b
+                         s->write_poll ? net_socket_writable : NULL,
5544c1b
+                         s);
5544c1b
+}
5544c1b
+
5544c1b
+static void net_socket_read_poll(NetSocketState *s, bool enable)
5544c1b
+{
5544c1b
+    s->read_poll = enable;
5544c1b
+    net_socket_update_fd_handler(s);
5544c1b
+}
5544c1b
+
5544c1b
+static void net_socket_write_poll(NetSocketState *s, bool enable)
5544c1b
+{
5544c1b
+    s->write_poll = enable;
5544c1b
+    net_socket_update_fd_handler(s);
5544c1b
+}
5544c1b
+
5544c1b
+static void net_socket_writable(void *opaque)
5544c1b
+{
5544c1b
+    NetSocketState *s = opaque;
5544c1b
+
5544c1b
+    net_socket_write_poll(s, false);
5544c1b
+
5544c1b
+    qemu_flush_queued_packets(&s->nc);
5544c1b
+}
5544c1b
 
5544c1b
 /* XXX: we consider we can send the whole packet without blocking */
5544c1b
 static ssize_t net_socket_receive(NetClientState *nc, const uint8_t *buf, size_t size)
5544c1b
@@ -81,7 +123,8 @@ static void net_socket_send(void *opaque)
5544c1b
     } else if (size == 0) {
5544c1b
         /* end of connection */
5544c1b
     eoc:
5544c1b
-        qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
5544c1b
+        net_socket_read_poll(s, false);
5544c1b
+        net_socket_write_poll(s, false);
5544c1b
         if (s->listen_fd != -1) {
5544c1b
             qemu_set_fd_handler(s->listen_fd, net_socket_accept, NULL, s);
5544c1b
         }
5544c1b
@@ -152,7 +195,8 @@ static void net_socket_send_dgram(void *opaque)
5544c1b
         return;
5544c1b
     if (size == 0) {
5544c1b
         /* end of connection */
5544c1b
-        qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
5544c1b
+        net_socket_read_poll(s, false);
5544c1b
+        net_socket_write_poll(s, false);
5544c1b
         return;
5544c1b
     }
5544c1b
     qemu_send_packet(&s->nc, s->buf, size);
5544c1b
@@ -243,7 +287,8 @@ static void net_socket_cleanup(NetClientState *nc)
5544c1b
 {
5544c1b
     NetSocketState *s = DO_UPCAST(NetSocketState, nc, nc);
5544c1b
     if (s->fd != -1) {
5544c1b
-        qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
5544c1b
+        net_socket_read_poll(s, false);
5544c1b
+        net_socket_write_poll(s, false);
5544c1b
         close(s->fd);
5544c1b
         s->fd = -1;
5544c1b
     }
5544c1b
@@ -314,8 +359,8 @@ static NetSocketState *net_socket_fd_init_dgram(NetClientState *peer,
5544c1b
 
5544c1b
     s->fd = fd;
5544c1b
     s->listen_fd = -1;
5544c1b
-
5544c1b
-    qemu_set_fd_handler(s->fd, net_socket_send_dgram, NULL, s);
5544c1b
+    s->send_fn = net_socket_send_dgram;
5544c1b
+    net_socket_read_poll(s, true);
5544c1b
 
5544c1b
     /* mcast: save bound address as dst */
5544c1b
     if (is_connected) {
5544c1b
@@ -332,7 +377,8 @@ err:
5544c1b
 static void net_socket_connect(void *opaque)
5544c1b
 {
5544c1b
     NetSocketState *s = opaque;
5544c1b
-    qemu_set_fd_handler(s->fd, net_socket_send, NULL, s);
5544c1b
+    s->send_fn = net_socket_send;
5544c1b
+    net_socket_read_poll(s, true);
5544c1b
 }
5544c1b
 
5544c1b
 static NetClientInfo net_socket_info = {