*/
#include "qemu-common.h"
#include "qemu/timer.h"
-#include "char/char.h"
+#include "sysemu/char.h"
#include "slirp.h"
#include "hw/hw.h"
0x52, 0x55, 0x00, 0x00, 0x00, 0x00
};
-static const uint8_t zero_ethaddr[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
-
-/* XXX: suppress those select globals */
-fd_set *global_readfds, *global_writefds, *global_xfds;
-
u_int curtime;
-static u_int time_fasttimo, last_slowtimo;
-static int do_slowtimo;
static QTAILQ_HEAD(slirp_instances, Slirp) slirp_instances =
QTAILQ_HEAD_INITIALIZER(slirp_instances);
static struct in_addr dns_addr;
static u_int dns_addr_time;
+#define TIMEOUT_FAST 2 /* milliseconds */
+#define TIMEOUT_SLOW 499 /* milliseconds */
+/* for the aging of certain requests like DNS */
+#define TIMEOUT_DEFAULT 1000 /* milliseconds */
+
#ifdef _WIN32
int get_dns_addr(struct in_addr *pdns_addr)
IP_ADDR_STRING *pIPAddr;
struct in_addr tmp_addr;
- if (dns_addr.s_addr != 0 && (curtime - dns_addr_time) < 1000) {
+ if (dns_addr.s_addr != 0 && (curtime - dns_addr_time) < TIMEOUT_DEFAULT) {
*pdns_addr = dns_addr;
return 0;
}
if (dns_addr.s_addr != 0) {
struct stat old_stat;
- if ((curtime - dns_addr_time) < 1000) {
+ if ((curtime - dns_addr_time) < TIMEOUT_DEFAULT) {
*pdns_addr = dns_addr;
return 0;
}
return -1;
#ifdef DEBUG
- lprint("IP address of your DNS(s): ");
+ fprintf(stderr, "IP address of your DNS(s): ");
#endif
while (fgets(buff, 512, f) != NULL) {
if (sscanf(buff, "nameserver%*[ \t]%256s", buff2) == 1) {
}
#ifdef DEBUG
else
- lprint(", ");
+ fprintf(stderr, ", ");
#endif
if (++found > 3) {
#ifdef DEBUG
- lprint("(more)");
+ fprintf(stderr, "(more)");
#endif
break;
}
#ifdef DEBUG
else
- lprint("%s", inet_ntoa(tmp_addr));
+ fprintf(stderr, "%s", inet_ntoa(tmp_addr));
#endif
}
}
#define CONN_CANFSEND(so) (((so)->so_state & (SS_FCANTSENDMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED)
#define CONN_CANFRCV(so) (((so)->so_state & (SS_FCANTRCVMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED)
-#define UPD_NFDS(x) if (nfds < (x)) nfds = (x)
-void slirp_update_timeout(uint32_t *timeout)
+static void slirp_update_timeout(uint32_t *timeout)
{
- if (!QTAILQ_EMPTY(&slirp_instances)) {
- *timeout = MIN(1000, *timeout);
+ Slirp *slirp;
+ uint32_t t;
+
+ if (*timeout <= TIMEOUT_FAST) {
+ return;
+ }
+
+ t = MIN(1000, *timeout);
+
+ /* If we have tcp timeout with slirp, then we will fill @timeout with
+ * more precise value.
+ */
+ QTAILQ_FOREACH(slirp, &slirp_instances, entry) {
+ if (slirp->time_fasttimo) {
+ *timeout = TIMEOUT_FAST;
+ return;
+ }
+ if (slirp->do_slowtimo) {
+ t = MIN(TIMEOUT_SLOW, t);
+ }
}
+ *timeout = t;
}
-void slirp_select_fill(int *pnfds,
- fd_set *readfds, fd_set *writefds, fd_set *xfds)
+void slirp_pollfds_fill(GArray *pollfds, uint32_t *timeout)
{
Slirp *slirp;
struct socket *so, *so_next;
- int nfds;
if (QTAILQ_EMPTY(&slirp_instances)) {
return;
}
- /* fail safe */
- global_readfds = NULL;
- global_writefds = NULL;
- global_xfds = NULL;
-
- nfds = *pnfds;
/*
* First, TCP sockets
*/
- do_slowtimo = 0;
QTAILQ_FOREACH(slirp, &slirp_instances, entry) {
/*
* *_slowtimo needs calling if there are IP fragments
* in the fragment queue, or there are TCP connections active
*/
- do_slowtimo |= ((slirp->tcb.so_next != &slirp->tcb) ||
+ slirp->do_slowtimo = ((slirp->tcb.so_next != &slirp->tcb) ||
(&slirp->ipq.ip_link != slirp->ipq.ip_link.next));
for (so = slirp->tcb.so_next; so != &slirp->tcb;
so = so_next) {
+ int events = 0;
+
so_next = so->so_next;
+ so->pollfds_idx = -1;
+
/*
* See if we need a tcp_fasttimo
*/
- if (time_fasttimo == 0 && so->so_tcpcb->t_flags & TF_DELACK) {
- time_fasttimo = curtime; /* Flag when we want a fasttimo */
+ if (slirp->time_fasttimo == 0 &&
+ so->so_tcpcb->t_flags & TF_DELACK) {
+ slirp->time_fasttimo = curtime; /* Flag when want a fasttimo */
}
/*
* Set for reading sockets which are accepting
*/
if (so->so_state & SS_FACCEPTCONN) {
- FD_SET(so->s, readfds);
- UPD_NFDS(so->s);
+ GPollFD pfd = {
+ .fd = so->s,
+ .events = G_IO_IN | G_IO_HUP | G_IO_ERR,
+ };
+ so->pollfds_idx = pollfds->len;
+ g_array_append_val(pollfds, pfd);
continue;
}
* Set for writing sockets which are connecting
*/
if (so->so_state & SS_ISFCONNECTING) {
- FD_SET(so->s, writefds);
- UPD_NFDS(so->s);
+ GPollFD pfd = {
+ .fd = so->s,
+ .events = G_IO_OUT | G_IO_ERR,
+ };
+ so->pollfds_idx = pollfds->len;
+ g_array_append_val(pollfds, pfd);
continue;
}
* we have something to send
*/
if (CONN_CANFSEND(so) && so->so_rcv.sb_cc) {
- FD_SET(so->s, writefds);
- UPD_NFDS(so->s);
+ events |= G_IO_OUT | G_IO_ERR;
}
/*
*/
if (CONN_CANFRCV(so) &&
(so->so_snd.sb_cc < (so->so_snd.sb_datalen/2))) {
- FD_SET(so->s, readfds);
- FD_SET(so->s, xfds);
- UPD_NFDS(so->s);
+ events |= G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_PRI;
+ }
+
+ if (events) {
+ GPollFD pfd = {
+ .fd = so->s,
+ .events = events,
+ };
+ so->pollfds_idx = pollfds->len;
+ g_array_append_val(pollfds, pfd);
}
}
so = so_next) {
so_next = so->so_next;
+ so->pollfds_idx = -1;
+
/*
* See if it's timed out
*/
udp_detach(so);
continue;
} else {
- do_slowtimo = 1; /* Let socket expire */
+ slirp->do_slowtimo = true; /* Let socket expire */
}
}
* (XXX <= 4 ?)
*/
if ((so->so_state & SS_ISFCONNECTED) && so->so_queued <= 4) {
- FD_SET(so->s, readfds);
- UPD_NFDS(so->s);
+ GPollFD pfd = {
+ .fd = so->s,
+ .events = G_IO_IN | G_IO_HUP | G_IO_ERR,
+ };
+ so->pollfds_idx = pollfds->len;
+ g_array_append_val(pollfds, pfd);
}
}
so = so_next) {
so_next = so->so_next;
+ so->pollfds_idx = -1;
+
/*
* See if it's timed out
*/
icmp_detach(so);
continue;
} else {
- do_slowtimo = 1; /* Let socket expire */
+ slirp->do_slowtimo = true; /* Let socket expire */
}
}
if (so->so_state & SS_ISFCONNECTED) {
- FD_SET(so->s, readfds);
- UPD_NFDS(so->s);
+ GPollFD pfd = {
+ .fd = so->s,
+ .events = G_IO_IN | G_IO_HUP | G_IO_ERR,
+ };
+ so->pollfds_idx = pollfds->len;
+ g_array_append_val(pollfds, pfd);
}
}
}
-
- *pnfds = nfds;
+ slirp_update_timeout(timeout);
}
-void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds,
- int select_error)
+void slirp_pollfds_poll(GArray *pollfds, int select_error)
{
Slirp *slirp;
struct socket *so, *so_next;
return;
}
- global_readfds = readfds;
- global_writefds = writefds;
- global_xfds = xfds;
-
- curtime = qemu_get_clock_ms(rt_clock);
+ curtime = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
QTAILQ_FOREACH(slirp, &slirp_instances, entry) {
/*
* See if anything has timed out
*/
- if (time_fasttimo && ((curtime - time_fasttimo) >= 2)) {
+ if (slirp->time_fasttimo &&
+ ((curtime - slirp->time_fasttimo) >= TIMEOUT_FAST)) {
tcp_fasttimo(slirp);
- time_fasttimo = 0;
+ slirp->time_fasttimo = 0;
}
- if (do_slowtimo && ((curtime - last_slowtimo) >= 499)) {
+ if (slirp->do_slowtimo &&
+ ((curtime - slirp->last_slowtimo) >= TIMEOUT_SLOW)) {
ip_slowtimo(slirp);
tcp_slowtimo(slirp);
- last_slowtimo = curtime;
+ slirp->last_slowtimo = curtime;
}
/*
*/
for (so = slirp->tcb.so_next; so != &slirp->tcb;
so = so_next) {
+ int revents;
+
so_next = so->so_next;
- /*
- * FD_ISSET is meaningless on these sockets
- * (and they can crash the program)
- */
+ revents = 0;
+ if (so->pollfds_idx != -1) {
+ revents = g_array_index(pollfds, GPollFD,
+ so->pollfds_idx).revents;
+ }
+
if (so->so_state & SS_NOFDREF || so->s == -1) {
continue;
}
/*
* Check for URG data
* This will soread as well, so no need to
- * test for readfds below if this succeeds
+ * test for G_IO_IN below if this succeeds
*/
- if (FD_ISSET(so->s, xfds)) {
+ if (revents & G_IO_PRI) {
sorecvoob(so);
}
/*
* Check sockets for reading
*/
- else if (FD_ISSET(so->s, readfds)) {
+ else if (revents & (G_IO_IN | G_IO_HUP | G_IO_ERR)) {
/*
* Check for incoming connections
*/
/*
* Check sockets for writing
*/
- if (FD_ISSET(so->s, writefds)) {
+ if (!(so->so_state & SS_NOFDREF) &&
+ (revents & (G_IO_OUT | G_IO_ERR))) {
/*
* Check for non-blocking, still-connecting sockets
*/
*/
for (so = slirp->udb.so_next; so != &slirp->udb;
so = so_next) {
+ int revents;
+
so_next = so->so_next;
- if (so->s != -1 && FD_ISSET(so->s, readfds)) {
+ revents = 0;
+ if (so->pollfds_idx != -1) {
+ revents = g_array_index(pollfds, GPollFD,
+ so->pollfds_idx).revents;
+ }
+
+ if (so->s != -1 &&
+ (revents & (G_IO_IN | G_IO_HUP | G_IO_ERR))) {
sorecvfrom(so);
}
}
*/
for (so = slirp->icmp.so_next; so != &slirp->icmp;
so = so_next) {
- so_next = so->so_next;
+ int revents;
+
+ so_next = so->so_next;
+
+ revents = 0;
+ if (so->pollfds_idx != -1) {
+ revents = g_array_index(pollfds, GPollFD,
+ so->pollfds_idx).revents;
+ }
- if (so->s != -1 && FD_ISSET(so->s, readfds)) {
+ if (so->s != -1 &&
+ (revents & (G_IO_IN | G_IO_HUP | G_IO_ERR))) {
icmp_receive(so);
}
}
if_start(slirp);
}
-
- /* clear global file descriptor sets.
- * these reside on the stack in vl.c
- * so they're unusable if we're not in
- * slirp_select_fill or slirp_select_poll.
- */
- global_readfds = NULL;
- global_writefds = NULL;
- global_xfds = NULL;
}
static void arp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len)
return 1;
}
+ if (iph->ip_dst.s_addr == 0) {
+ /* 0.0.0.0 can not be a destination address, something went wrong,
+ * avoid making it worse */
+ return 1;
+ }
if (!arp_table_search(slirp, iph->ip_dst.s_addr, ethaddr)) {
uint8_t arp_req[ETH_HLEN + sizeof(struct arphdr)];
struct ethhdr *reh = (struct ethhdr *)arp_req;
ifm->arp_requested = true;
/* Expire request and drop outgoing packet after 1 second */
- ifm->expiration_date = qemu_get_clock_ns(rt_clock) + 1000000000ULL;
+ ifm->expiration_date = qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + 1000000000ULL;
}
return 0;
} else {