net: asynchronous send/receive infrastructure for net/socket.c
The net/socket.c net client is not truly asynchronous. This patch borrows the qemu_set_fd_handler2() code from net/tap.c as the basis for proper asynchronous send/receive. Only read packets from the socket when the peer is able to receive. This avoids needless queuing. Later patches implement asynchronous send. Signed-off-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
This commit is contained in:
parent
61518a74ca
commit
863f678fba
58
net/socket.c
58
net/socket.c
|
@ -42,9 +42,51 @@ typedef struct NetSocketState {
|
||||||
unsigned int packet_len;
|
unsigned int packet_len;
|
||||||
uint8_t buf[4096];
|
uint8_t buf[4096];
|
||||||
struct sockaddr_in dgram_dst; /* contains inet host and port destination iff connectionless (SOCK_DGRAM) */
|
struct sockaddr_in dgram_dst; /* contains inet host and port destination iff connectionless (SOCK_DGRAM) */
|
||||||
|
IOHandler *send_fn; /* differs between SOCK_STREAM/SOCK_DGRAM */
|
||||||
|
bool read_poll; /* waiting to receive data? */
|
||||||
|
bool write_poll; /* waiting to transmit data? */
|
||||||
} NetSocketState;
|
} NetSocketState;
|
||||||
|
|
||||||
static void net_socket_accept(void *opaque);
|
static void net_socket_accept(void *opaque);
|
||||||
|
static void net_socket_writable(void *opaque);
|
||||||
|
|
||||||
|
/* Only read packets from socket when peer can receive them */
|
||||||
|
static int net_socket_can_send(void *opaque)
|
||||||
|
{
|
||||||
|
NetSocketState *s = opaque;
|
||||||
|
|
||||||
|
return qemu_can_send_packet(&s->nc);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void net_socket_update_fd_handler(NetSocketState *s)
|
||||||
|
{
|
||||||
|
qemu_set_fd_handler2(s->fd,
|
||||||
|
s->read_poll ? net_socket_can_send : NULL,
|
||||||
|
s->read_poll ? s->send_fn : NULL,
|
||||||
|
s->write_poll ? net_socket_writable : NULL,
|
||||||
|
s);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void net_socket_read_poll(NetSocketState *s, bool enable)
|
||||||
|
{
|
||||||
|
s->read_poll = enable;
|
||||||
|
net_socket_update_fd_handler(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void net_socket_write_poll(NetSocketState *s, bool enable)
|
||||||
|
{
|
||||||
|
s->write_poll = enable;
|
||||||
|
net_socket_update_fd_handler(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void net_socket_writable(void *opaque)
|
||||||
|
{
|
||||||
|
NetSocketState *s = opaque;
|
||||||
|
|
||||||
|
net_socket_write_poll(s, false);
|
||||||
|
|
||||||
|
qemu_flush_queued_packets(&s->nc);
|
||||||
|
}
|
||||||
|
|
||||||
/* XXX: we consider we can send the whole packet without blocking */
|
/* XXX: we consider we can send the whole packet without blocking */
|
||||||
static ssize_t net_socket_receive(NetClientState *nc, const uint8_t *buf, size_t size)
|
static ssize_t net_socket_receive(NetClientState *nc, const uint8_t *buf, size_t size)
|
||||||
|
@ -81,7 +123,8 @@ static void net_socket_send(void *opaque)
|
||||||
} else if (size == 0) {
|
} else if (size == 0) {
|
||||||
/* end of connection */
|
/* end of connection */
|
||||||
eoc:
|
eoc:
|
||||||
qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
|
net_socket_read_poll(s, false);
|
||||||
|
net_socket_write_poll(s, false);
|
||||||
if (s->listen_fd != -1) {
|
if (s->listen_fd != -1) {
|
||||||
qemu_set_fd_handler(s->listen_fd, net_socket_accept, NULL, s);
|
qemu_set_fd_handler(s->listen_fd, net_socket_accept, NULL, s);
|
||||||
}
|
}
|
||||||
|
@ -152,7 +195,8 @@ static void net_socket_send_dgram(void *opaque)
|
||||||
return;
|
return;
|
||||||
if (size == 0) {
|
if (size == 0) {
|
||||||
/* end of connection */
|
/* end of connection */
|
||||||
qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
|
net_socket_read_poll(s, false);
|
||||||
|
net_socket_write_poll(s, false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
qemu_send_packet(&s->nc, s->buf, size);
|
qemu_send_packet(&s->nc, s->buf, size);
|
||||||
|
@ -243,7 +287,8 @@ static void net_socket_cleanup(NetClientState *nc)
|
||||||
{
|
{
|
||||||
NetSocketState *s = DO_UPCAST(NetSocketState, nc, nc);
|
NetSocketState *s = DO_UPCAST(NetSocketState, nc, nc);
|
||||||
if (s->fd != -1) {
|
if (s->fd != -1) {
|
||||||
qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
|
net_socket_read_poll(s, false);
|
||||||
|
net_socket_write_poll(s, false);
|
||||||
close(s->fd);
|
close(s->fd);
|
||||||
s->fd = -1;
|
s->fd = -1;
|
||||||
}
|
}
|
||||||
|
@ -314,8 +359,8 @@ static NetSocketState *net_socket_fd_init_dgram(NetClientState *peer,
|
||||||
|
|
||||||
s->fd = fd;
|
s->fd = fd;
|
||||||
s->listen_fd = -1;
|
s->listen_fd = -1;
|
||||||
|
s->send_fn = net_socket_send_dgram;
|
||||||
qemu_set_fd_handler(s->fd, net_socket_send_dgram, NULL, s);
|
net_socket_read_poll(s, true);
|
||||||
|
|
||||||
/* mcast: save bound address as dst */
|
/* mcast: save bound address as dst */
|
||||||
if (is_connected) {
|
if (is_connected) {
|
||||||
|
@ -332,7 +377,8 @@ err:
|
||||||
static void net_socket_connect(void *opaque)
|
static void net_socket_connect(void *opaque)
|
||||||
{
|
{
|
||||||
NetSocketState *s = opaque;
|
NetSocketState *s = opaque;
|
||||||
qemu_set_fd_handler(s->fd, net_socket_send, NULL, s);
|
s->send_fn = net_socket_send;
|
||||||
|
net_socket_read_poll(s, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
static NetClientInfo net_socket_info = {
|
static NetClientInfo net_socket_info = {
|
||||||
|
|
Loading…
Reference in a new issue