Network overhaul : support for multiple NICs, performance improvement
- Add support for multiple NICs - Switch from polling to an event loop for the host networking to avoid latency and locking issues
This commit is contained in:
@@ -24,52 +24,51 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <inttypes.h>
|
||||
#include <wchar.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <slirp/libslirp.h>
|
||||
#define HAVE_STDARG_H
|
||||
#include <86box/86box.h>
|
||||
#include <86box/device.h>
|
||||
#include <86box/plat.h>
|
||||
#include <86box/thread.h>
|
||||
#include <86box/timer.h>
|
||||
#include <86box/network.h>
|
||||
#include <86box/machine.h>
|
||||
#include <86box/timer.h>
|
||||
#include <86box/config.h>
|
||||
|
||||
|
||||
/* SLiRP can use poll() or select() for socket polling.
|
||||
poll() is best on *nix but slow and limited on Windows. */
|
||||
#ifndef _WIN32
|
||||
# define SLIRP_USE_POLL 1
|
||||
#endif
|
||||
#ifdef SLIRP_USE_POLL
|
||||
# ifdef _WIN32
|
||||
# include <winsock2.h>
|
||||
# define poll WSAPoll
|
||||
# else
|
||||
# include <poll.h>
|
||||
# endif
|
||||
#include <86box/video.h>
|
||||
#ifdef _WIN32
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <poll.h>
|
||||
#endif
|
||||
#include <86box/net_event.h>
|
||||
|
||||
enum {
|
||||
NET_EVENT_STOP = 0,
|
||||
NET_EVENT_TX,
|
||||
NET_EVENT_RX,
|
||||
NET_EVENT_MAX
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
Slirp *slirp;
|
||||
void *mac;
|
||||
const netcard_t *card; /* netcard attached to us */
|
||||
volatile thread_t *poll_tid;
|
||||
event_t *poll_state;
|
||||
uint8_t stop;
|
||||
#ifdef SLIRP_USE_POLL
|
||||
uint32_t pfd_len, pfd_size;
|
||||
struct pollfd *pfd;
|
||||
Slirp *slirp;
|
||||
uint8_t mac_addr[6];
|
||||
netcard_t *card; /* netcard attached to us */
|
||||
thread_t *poll_tid;
|
||||
net_evt_t tx_event;
|
||||
net_evt_t stop_event;
|
||||
netpkt_t pkt;
|
||||
#ifdef _WIN32
|
||||
HANDLE sock_event;
|
||||
#else
|
||||
uint32_t nfds;
|
||||
fd_set rfds, wfds, xfds;
|
||||
uint32_t pfd_len, pfd_size;
|
||||
struct pollfd *pfd;
|
||||
#endif
|
||||
} slirp_t;
|
||||
|
||||
static slirp_t *slirp;
|
||||
|
||||
} net_slirp_t;
|
||||
|
||||
#ifdef ENABLE_SLIRP_LOG
|
||||
int slirp_do_log = ENABLE_SLIRP_LOG;
|
||||
@@ -101,7 +100,7 @@ net_slirp_guest_error(const char *msg, void *opaque)
|
||||
static int64_t
|
||||
net_slirp_clock_get_ns(void *opaque)
|
||||
{
|
||||
return (TIMER_USEC ? (tsc / (TIMER_USEC / 1000)) : 0);
|
||||
return (int64_t)((double)tsc / cpuclock * 1000000000.0);
|
||||
}
|
||||
|
||||
|
||||
@@ -118,13 +117,14 @@ static void
|
||||
net_slirp_timer_free(void *timer, void *opaque)
|
||||
{
|
||||
timer_stop(timer);
|
||||
free(timer);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
net_slirp_timer_mod(void *timer, int64_t expire_timer, void *opaque)
|
||||
{
|
||||
timer_set_delay_u64(timer, expire_timer);
|
||||
timer_on_auto(timer, expire_timer * 1000);
|
||||
}
|
||||
|
||||
|
||||
@@ -154,138 +154,131 @@ net_slirp_notify(void *opaque)
|
||||
ssize_t
|
||||
net_slirp_send_packet(const void *qp, size_t pkt_len, void *opaque)
|
||||
{
|
||||
slirp_t *slirp = (slirp_t *) opaque;
|
||||
uint8_t *mac = slirp->mac;
|
||||
net_slirp_t *slirp = (net_slirp_t *) opaque;
|
||||
uint8_t *mac = slirp->mac_addr;
|
||||
uint32_t mac_cmp32[2];
|
||||
uint16_t mac_cmp16[2];
|
||||
|
||||
if (!(slirp->card->set_link_state && slirp->card->set_link_state(slirp->card->priv)) && !(slirp->card->wait && slirp->card->wait(slirp->card->priv))) {
|
||||
slirp_log("SLiRP: received %d-byte packet\n", pkt_len);
|
||||
slirp_log("SLiRP: received %d-byte packet\n", pkt_len);
|
||||
|
||||
/* Received MAC. */
|
||||
mac_cmp32[0] = *(uint32_t *) (((uint8_t *) qp) + 6);
|
||||
mac_cmp16[0] = *(uint16_t *) (((uint8_t *) qp) + 10);
|
||||
/* Received MAC. */
|
||||
mac_cmp32[0] = *(uint32_t *) (((uint8_t *) qp) + 6);
|
||||
mac_cmp16[0] = *(uint16_t *) (((uint8_t *) qp) + 10);
|
||||
|
||||
/* Local MAC. */
|
||||
mac_cmp32[1] = *(uint32_t *) mac;
|
||||
mac_cmp16[1] = *(uint16_t *) (mac + 4);
|
||||
if ((mac_cmp32[0] != mac_cmp32[1]) ||
|
||||
(mac_cmp16[0] != mac_cmp16[1])) {
|
||||
network_queue_put(0, slirp->card->priv, (uint8_t *) qp, pkt_len);
|
||||
}
|
||||
|
||||
return pkt_len;
|
||||
} else {
|
||||
slirp_log("SLiRP: ignored %d-byte packet\n", pkt_len);
|
||||
/* Local MAC. */
|
||||
mac_cmp32[1] = *(uint32_t *) mac;
|
||||
mac_cmp16[1] = *(uint16_t *) (mac + 4);
|
||||
if ((mac_cmp32[0] != mac_cmp32[1]) || (mac_cmp16[0] != mac_cmp16[1])) {
|
||||
network_rx_put(slirp->card, (uint8_t *) qp, pkt_len);
|
||||
}
|
||||
|
||||
return 0;
|
||||
return pkt_len;
|
||||
}
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
static int
|
||||
net_slirp_add_poll(int fd, int events, void *opaque)
|
||||
{
|
||||
slirp_t *slirp = (slirp_t *) opaque;
|
||||
#ifdef SLIRP_USE_POLL
|
||||
net_slirp_t *slirp = (net_slirp_t *) opaque;
|
||||
long bitmask = 0;
|
||||
if (events & SLIRP_POLL_IN)
|
||||
bitmask |= FD_READ | FD_ACCEPT;
|
||||
if (events & SLIRP_POLL_OUT)
|
||||
bitmask |= FD_WRITE | FD_CONNECT;
|
||||
if (events & SLIRP_POLL_HUP)
|
||||
bitmask |= FD_CLOSE;
|
||||
if (events & SLIRP_POLL_PRI)
|
||||
bitmask |= FD_OOB;
|
||||
|
||||
WSAEventSelect(fd, slirp->sock_event, bitmask);
|
||||
return fd;
|
||||
}
|
||||
#else
|
||||
static int
|
||||
net_slirp_add_poll(int fd, int events, void *opaque)
|
||||
{
|
||||
net_slirp_t *slirp = (net_slirp_t *) opaque;
|
||||
|
||||
if (slirp->pfd_len >= slirp->pfd_size) {
|
||||
int newsize = slirp->pfd_size + 16;
|
||||
struct pollfd *new = realloc(slirp->pfd, newsize * sizeof(struct pollfd));
|
||||
if (new) {
|
||||
slirp->pfd = new;
|
||||
slirp->pfd_size = newsize;
|
||||
}
|
||||
int newsize = slirp->pfd_size + 16;
|
||||
struct pollfd *new = realloc(slirp->pfd, newsize * sizeof(struct pollfd));
|
||||
if (new) {
|
||||
slirp->pfd = new;
|
||||
slirp->pfd_size = newsize;
|
||||
}
|
||||
}
|
||||
if ((slirp->pfd_len < slirp->pfd_size)) {
|
||||
int idx = slirp->pfd_len++;
|
||||
slirp->pfd[idx].fd = fd;
|
||||
int pevents = 0;
|
||||
if (events & SLIRP_POLL_IN) pevents |= POLLIN;
|
||||
if (events & SLIRP_POLL_OUT) pevents |= POLLOUT;
|
||||
# ifndef _WIN32
|
||||
/* Windows does not support some events. */
|
||||
if (events & SLIRP_POLL_ERR) pevents |= POLLERR;
|
||||
if (events & SLIRP_POLL_PRI) pevents |= POLLPRI;
|
||||
if (events & SLIRP_POLL_HUP) pevents |= POLLHUP;
|
||||
# endif
|
||||
slirp->pfd[idx].events = pevents;
|
||||
return idx;
|
||||
int idx = slirp->pfd_len++;
|
||||
slirp->pfd[idx].fd = fd;
|
||||
int pevents = 0;
|
||||
if (events & SLIRP_POLL_IN)
|
||||
pevents |= POLLIN;
|
||||
if (events & SLIRP_POLL_OUT)
|
||||
pevents |= POLLOUT;
|
||||
if (events & SLIRP_POLL_ERR)
|
||||
pevents |= POLLERR;
|
||||
if (events & SLIRP_POLL_PRI)
|
||||
pevents |= POLLPRI;
|
||||
if (events & SLIRP_POLL_HUP)
|
||||
pevents |= POLLHUP;
|
||||
slirp->pfd[idx].events = pevents;
|
||||
return idx;
|
||||
} else
|
||||
return -1;
|
||||
#else
|
||||
if (events & SLIRP_POLL_IN)
|
||||
FD_SET(fd, &slirp->rfds);
|
||||
if (events & SLIRP_POLL_OUT)
|
||||
FD_SET(fd, &slirp->wfds);
|
||||
if (events & SLIRP_POLL_PRI)
|
||||
FD_SET(fd, &slirp->xfds);
|
||||
if (fd > slirp->nfds)
|
||||
slirp->nfds = fd;
|
||||
return fd;
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
static int
|
||||
net_slirp_get_revents(int idx, void *opaque)
|
||||
{
|
||||
slirp_t *slirp = (slirp_t *) opaque;
|
||||
net_slirp_t *slirp = (net_slirp_t *) opaque;
|
||||
int ret = 0;
|
||||
#ifdef SLIRP_USE_POLL
|
||||
int events = slirp->pfd[idx].revents;
|
||||
if (events & POLLIN) ret |= SLIRP_POLL_IN;
|
||||
if (events & POLLOUT) ret |= SLIRP_POLL_OUT;
|
||||
if (events & POLLPRI) ret |= SLIRP_POLL_PRI;
|
||||
if (events & POLLERR) ret |= SLIRP_POLL_ERR;
|
||||
if (events & POLLHUP) ret |= SLIRP_POLL_HUP;
|
||||
#else
|
||||
if (FD_ISSET(idx, &slirp->rfds))
|
||||
ret |= SLIRP_POLL_IN;
|
||||
if (FD_ISSET(idx, &slirp->wfds))
|
||||
ret |= SLIRP_POLL_OUT;
|
||||
if (FD_ISSET(idx, &slirp->xfds))
|
||||
ret |= SLIRP_POLL_PRI;
|
||||
#endif
|
||||
WSANETWORKEVENTS ev;
|
||||
if (WSAEnumNetworkEvents(idx, slirp->sock_event, &ev) != 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
# define WSA_TO_POLL(_wsaev, _pollev) \
|
||||
do { \
|
||||
if (ev.lNetworkEvents & (_wsaev)) { \
|
||||
ret |= (_pollev); \
|
||||
if (ev.iErrorCode[_wsaev##_BIT] != 0) { \
|
||||
ret |= SLIRP_POLL_ERR; \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
WSA_TO_POLL(FD_READ, SLIRP_POLL_IN);
|
||||
WSA_TO_POLL(FD_ACCEPT, SLIRP_POLL_IN);
|
||||
WSA_TO_POLL(FD_WRITE, SLIRP_POLL_OUT);
|
||||
WSA_TO_POLL(FD_CONNECT, SLIRP_POLL_OUT);
|
||||
WSA_TO_POLL(FD_OOB, SLIRP_POLL_PRI);
|
||||
WSA_TO_POLL(FD_CLOSE, SLIRP_POLL_HUP);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
slirp_tic(slirp_t *slirp)
|
||||
#else
|
||||
static int
|
||||
net_slirp_get_revents(int idx, void *opaque)
|
||||
{
|
||||
int ret;
|
||||
uint32_t tmo;
|
||||
|
||||
/* Let SLiRP create a list of all open sockets. */
|
||||
#ifdef SLIRP_USE_POLL
|
||||
tmo = -1;
|
||||
slirp->pfd_len = 0;
|
||||
#else
|
||||
slirp->nfds = -1;
|
||||
FD_ZERO(&slirp->rfds);
|
||||
FD_ZERO(&slirp->wfds);
|
||||
FD_ZERO(&slirp->xfds);
|
||||
#endif
|
||||
slirp_pollfds_fill(slirp->slirp, &tmo, net_slirp_add_poll, slirp);
|
||||
|
||||
/* Now wait for something to happen, or at most 'tmo' usec. */
|
||||
#ifdef SLIRP_USE_POLL
|
||||
ret = poll(slirp->pfd, slirp->pfd_len, tmo);
|
||||
#else
|
||||
if (tmo < 0)
|
||||
tmo = 500;
|
||||
|
||||
struct timeval tv;
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = tmo;
|
||||
|
||||
ret = select(slirp->nfds + 1, &slirp->rfds, &slirp->wfds, &slirp->xfds, &tv);
|
||||
#endif
|
||||
|
||||
/* If something happened, let SLiRP handle it. */
|
||||
slirp_pollfds_poll(slirp->slirp, (ret <= 0), net_slirp_get_revents, slirp);
|
||||
net_slirp_t *slirp = (net_slirp_t *) opaque;
|
||||
int ret = 0;
|
||||
int events = slirp->pfd[idx].revents;
|
||||
if (events & POLLIN)
|
||||
ret |= SLIRP_POLL_IN;
|
||||
if (events & POLLOUT)
|
||||
ret |= SLIRP_POLL_OUT;
|
||||
if (events & POLLPRI)
|
||||
ret |= SLIRP_POLL_PRI;
|
||||
if (events & POLLERR)
|
||||
ret |= SLIRP_POLL_ERR;
|
||||
if (events & POLLHUP)
|
||||
ret |= SLIRP_POLL_HUP;
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static const SlirpCb slirp_cb = {
|
||||
.send_packet = net_slirp_send_packet,
|
||||
@@ -299,176 +292,210 @@ static const SlirpCb slirp_cb = {
|
||||
.notify = net_slirp_notify
|
||||
};
|
||||
|
||||
|
||||
/* Handle the receiving of frames. */
|
||||
/* Send a packet to the SLiRP interface. */
|
||||
static void
|
||||
poll_thread(void *arg)
|
||||
{
|
||||
slirp_t *slirp = (slirp_t *) arg;
|
||||
event_t *evt;
|
||||
int tx;
|
||||
|
||||
slirp_log("SLiRP: initializing...\n");
|
||||
|
||||
/* Set the IP addresses to use. */
|
||||
struct in_addr net = { .s_addr = htonl(0x0a000200) }; /* 10.0.2.0 */
|
||||
struct in_addr mask = { .s_addr = htonl(0xffffff00) }; /* 255.255.255.0 */
|
||||
struct in_addr host = { .s_addr = htonl(0x0a000202) }; /* 10.0.2.2 */
|
||||
struct in_addr dhcp = { .s_addr = htonl(0x0a00020f) }; /* 10.0.2.15 */
|
||||
struct in_addr dns = { .s_addr = htonl(0x0a000203) }; /* 10.0.2.3 */
|
||||
struct in_addr bind = { .s_addr = htonl(0x00000000) }; /* 0.0.0.0 */
|
||||
struct in6_addr ipv6_dummy = { 0 }; /* contents don't matter; we're not using IPv6 */
|
||||
|
||||
/* Initialize SLiRP. */
|
||||
slirp->slirp = slirp_init(0, 1, net, mask, host, 0, ipv6_dummy, 0, ipv6_dummy, NULL, NULL, NULL, NULL, dhcp, dns, ipv6_dummy, NULL, NULL, &slirp_cb, arg);
|
||||
if (!slirp->slirp) {
|
||||
slirp_log("SLiRP: initialization failed\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Set up port forwarding. */
|
||||
int udp, external, internal, i = 0;
|
||||
char *category = "SLiRP Port Forwarding";
|
||||
char key[20];
|
||||
while (1) {
|
||||
sprintf(key, "%d_protocol", i);
|
||||
udp = strcmp(config_get_string(category, key, "tcp"), "udp") == 0;
|
||||
sprintf(key, "%d_external", i);
|
||||
external = config_get_int(category, key, 0);
|
||||
sprintf(key, "%d_internal", i);
|
||||
internal = config_get_int(category, key, 0);
|
||||
if ((external <= 0) && (internal <= 0))
|
||||
break;
|
||||
else if (internal <= 0)
|
||||
internal = external;
|
||||
else if (external <= 0)
|
||||
external = internal;
|
||||
|
||||
if (slirp_add_hostfwd(slirp->slirp, udp, bind, external, dhcp, internal) == 0)
|
||||
pclog("SLiRP: Forwarded %s port external:%d to internal:%d\n", udp ? "UDP" : "TCP", external, internal);
|
||||
else
|
||||
pclog("SLiRP: Failed to forward %s port external:%d to internal:%d\n", udp ? "UDP" : "TCP", external, internal);
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
/* Start polling. */
|
||||
slirp_log("SLiRP: polling started.\n");
|
||||
thread_set_event(slirp->poll_state);
|
||||
|
||||
/* Create a waitable event. */
|
||||
evt = thread_create_event();
|
||||
|
||||
while (!slirp->stop) {
|
||||
/* Request ownership of the queue. */
|
||||
network_wait(1);
|
||||
|
||||
/* Stop processing if asked to. */
|
||||
if (slirp->stop) {
|
||||
network_wait(0);
|
||||
break;
|
||||
}
|
||||
|
||||
/* See if there is any work. */
|
||||
slirp_tic(slirp);
|
||||
|
||||
/* Wait for the next packet to arrive - network_do_tx() is called from there. */
|
||||
tx = network_tx_queue_check();
|
||||
|
||||
/* Release ownership of the queue. */
|
||||
network_wait(0);
|
||||
|
||||
/* If we did not get anything, wait a while. */
|
||||
if (!tx)
|
||||
thread_wait_event(evt, 10);
|
||||
}
|
||||
|
||||
/* No longer needed. */
|
||||
if (evt)
|
||||
thread_destroy_event(evt);
|
||||
|
||||
slirp_log("SLiRP: polling stopped.\n");
|
||||
thread_set_event(slirp->poll_state);
|
||||
|
||||
/* Destroy event here to avoid a crash. */
|
||||
slirp_log("SLiRP: thread ended\n");
|
||||
thread_destroy_event(slirp->poll_state);
|
||||
/* Free here instead of immediately freeing the global slirp on the main
|
||||
thread to avoid a race condition. */
|
||||
slirp_cleanup(slirp->slirp);
|
||||
free(slirp);
|
||||
}
|
||||
|
||||
|
||||
/* Initialize SLiRP for use. */
|
||||
int
|
||||
net_slirp_init(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Initialize SLiRP for use. */
|
||||
int
|
||||
net_slirp_reset(const netcard_t *card, uint8_t *mac)
|
||||
{
|
||||
slirp_t *new_slirp = malloc(sizeof(slirp_t));
|
||||
memset(new_slirp, 0, sizeof(slirp_t));
|
||||
new_slirp->mac = mac;
|
||||
new_slirp->card = card;
|
||||
#ifdef SLIRP_USE_POLL
|
||||
new_slirp->pfd_size = 16 * sizeof(struct pollfd);
|
||||
new_slirp->pfd = malloc(new_slirp->pfd_size);
|
||||
memset(new_slirp->pfd, 0, new_slirp->pfd_size);
|
||||
#endif
|
||||
|
||||
/* Save the callback info. */
|
||||
slirp = new_slirp;
|
||||
|
||||
slirp_log("SLiRP: creating thread...\n");
|
||||
slirp->poll_state = thread_create_event();
|
||||
slirp->poll_tid = thread_create(poll_thread, new_slirp);
|
||||
thread_wait_event(slirp->poll_state, -1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
net_slirp_close(void)
|
||||
net_slirp_in(net_slirp_t *slirp, uint8_t *pkt, int pkt_len)
|
||||
{
|
||||
if (!slirp)
|
||||
return;
|
||||
return;
|
||||
|
||||
slirp_log("SLiRP: closing\n");
|
||||
|
||||
/* Tell the polling thread to shut down. */
|
||||
slirp->stop = 1;
|
||||
|
||||
/* Tell the thread to terminate. */
|
||||
if (slirp->poll_tid) {
|
||||
/* Wait for the thread to finish. */
|
||||
slirp_log("SLiRP: waiting for thread to end...\n");
|
||||
thread_wait_event(slirp->poll_state, -1);
|
||||
}
|
||||
|
||||
/* Shutdown work is done by the thread on its local copy of slirp. */
|
||||
slirp = NULL;
|
||||
}
|
||||
|
||||
|
||||
/* Send a packet to the SLiRP interface. */
|
||||
void
|
||||
net_slirp_in(uint8_t *pkt, int pkt_len)
|
||||
{
|
||||
if (!slirp || !slirp->slirp)
|
||||
return;
|
||||
|
||||
slirp_log("SLiRP: sending %d-byte packet\n", pkt_len);
|
||||
slirp_log("SLiRP: sending %d-byte packet to host network\n", pkt_len);
|
||||
|
||||
slirp_input(slirp->slirp, (const uint8_t *) pkt, pkt_len);
|
||||
}
|
||||
|
||||
void
|
||||
net_slirp_in_available(void *priv)
|
||||
{
|
||||
net_slirp_t *slirp = (net_slirp_t *)priv;
|
||||
net_event_set(&slirp->tx_event);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
static void
|
||||
net_slirp_thread(void *priv)
|
||||
{
|
||||
net_slirp_t *slirp = (net_slirp_t *) priv;
|
||||
|
||||
/* Start polling. */
|
||||
slirp_log("SLiRP: polling started.\n");
|
||||
|
||||
HANDLE events[3];
|
||||
events[NET_EVENT_STOP] = net_event_get_handle(&slirp->stop_event);
|
||||
events[NET_EVENT_TX] = net_event_get_handle(&slirp->tx_event);
|
||||
events[NET_EVENT_RX] = slirp->sock_event;
|
||||
bool run = true;
|
||||
while (run) {
|
||||
uint32_t timeout = -1;
|
||||
slirp_pollfds_fill(slirp->slirp, &timeout, net_slirp_add_poll, slirp);
|
||||
if (timeout < 0)
|
||||
timeout = INFINITE;
|
||||
|
||||
int ret = WaitForMultipleObjects(3, events, FALSE, (DWORD)timeout);
|
||||
switch (ret - WAIT_OBJECT_0) {
|
||||
case NET_EVENT_STOP:
|
||||
run = false;
|
||||
break;
|
||||
|
||||
case NET_EVENT_TX:
|
||||
while (network_tx_pop(slirp->card, &slirp->pkt)) {
|
||||
net_slirp_in(slirp, slirp->pkt.data, slirp->pkt.len);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
slirp_pollfds_poll(slirp->slirp, ret == WAIT_FAILED, net_slirp_get_revents, slirp);
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
slirp_log("SLiRP: polling stopped.\n");
|
||||
}
|
||||
#else
|
||||
/* Handle the receiving of frames. */
|
||||
static void
|
||||
net_slirp_thread(void *priv)
|
||||
{
|
||||
net_slirp_t *slirp = (net_slirp_t *) priv;
|
||||
|
||||
/* Start polling. */
|
||||
slirp_log("SLiRP: polling started.\n");
|
||||
|
||||
while (1) {
|
||||
uint32_t timeout = -1;
|
||||
|
||||
slirp->pfd_len = 0;
|
||||
net_slirp_add_poll(net_event_get_fd(&slirp->stop_event), SLIRP_POLL_IN, slirp);
|
||||
net_slirp_add_poll(net_event_get_fd(&slirp->tx_event), SLIRP_POLL_IN, slirp);
|
||||
|
||||
slirp_pollfds_fill(slirp->slirp, &timeout, net_slirp_add_poll, slirp);
|
||||
|
||||
int ret = poll(slirp->pfd, slirp->pfd_len, timeout);
|
||||
|
||||
slirp_pollfds_poll(slirp->slirp, (ret < 0), net_slirp_get_revents, slirp);
|
||||
|
||||
if (slirp->pfd[NET_EVENT_STOP].revents & POLLIN) {
|
||||
net_event_clear(&slirp->stop_event);
|
||||
break;
|
||||
}
|
||||
|
||||
if (slirp->pfd[NET_EVENT_TX].revents & POLLIN) {
|
||||
net_event_clear(&slirp->tx_event);
|
||||
|
||||
if (network_tx_pop(slirp->card, &slirp->pkt)) {
|
||||
net_slirp_in(slirp, slirp->pkt.data, slirp->pkt.len);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
slirp_log("SLiRP: polling stopped.\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
static int slirp_card_num = 2;
|
||||
|
||||
/* Initialize SLiRP for use. */
|
||||
void *
|
||||
net_slirp_init(const netcard_t *card, const uint8_t *mac_addr, void *priv)
|
||||
{
|
||||
slirp_log("SLiRP: initializing...\n");
|
||||
net_slirp_t *slirp = calloc(1, sizeof(net_slirp_t));
|
||||
memcpy(slirp->mac_addr, mac_addr, sizeof(slirp->mac_addr));
|
||||
slirp->card = (netcard_t*)card;
|
||||
|
||||
#ifndef _WIN32
|
||||
slirp->pfd_size = 16 * sizeof(struct pollfd);
|
||||
slirp->pfd = malloc(slirp->pfd_size);
|
||||
memset(slirp->pfd, 0, slirp->pfd_size);
|
||||
#endif
|
||||
|
||||
/* Set the IP addresses to use. */
|
||||
struct in_addr net = { .s_addr = htonl(0x0a000000 | (slirp_card_num << 8)) }; /* 10.0.x.0 */
|
||||
struct in_addr mask = { .s_addr = htonl(0xffffff00) }; /* 255.255.255.0 */
|
||||
struct in_addr host = { .s_addr = htonl(0x0a000002 | (slirp_card_num << 8)) }; /* 10.0.x.2 */
|
||||
struct in_addr dhcp = { .s_addr = htonl(0x0a00000f | (slirp_card_num << 8)) }; /* 10.0.x.15 */
|
||||
struct in_addr dns = { .s_addr = htonl(0x0a000003 | (slirp_card_num << 8)) }; /* 10.0.x.3 */
|
||||
struct in_addr bind = { .s_addr = htonl(0x00000000 | (slirp_card_num << 8)) }; /* 0.0.0.0 */
|
||||
struct in6_addr ipv6_dummy = { 0 }; /* contents don't matter; we're not using IPv6 */
|
||||
|
||||
/* Initialize SLiRP. */
|
||||
slirp->slirp = slirp_init(0, 1, net, mask, host, 0, ipv6_dummy, 0, ipv6_dummy, NULL, NULL, NULL, NULL, dhcp, dns, ipv6_dummy, NULL, NULL, &slirp_cb, slirp);
|
||||
if (!slirp->slirp) {
|
||||
slirp_log("SLiRP: initialization failed\n");
|
||||
free(slirp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Set up port forwarding. */
|
||||
int udp, external, internal, i = 0;
|
||||
char *category = "SLiRP Port Forwarding";
|
||||
char key[20];
|
||||
while (1) {
|
||||
sprintf(key, "%d_protocol", i);
|
||||
udp = strcmp(config_get_string(category, key, "tcp"), "udp") == 0;
|
||||
sprintf(key, "%d_external", i);
|
||||
external = config_get_int(category, key, 0);
|
||||
sprintf(key, "%d_internal", i);
|
||||
internal = config_get_int(category, key, 0);
|
||||
if ((external <= 0) && (internal <= 0))
|
||||
break;
|
||||
else if (internal <= 0)
|
||||
internal = external;
|
||||
else if (external <= 0)
|
||||
external = internal;
|
||||
|
||||
if (slirp_add_hostfwd(slirp->slirp, udp, bind, external, dhcp, internal) == 0)
|
||||
pclog("SLiRP: Forwarded %s port external:%d to internal:%d\n", udp ? "UDP" : "TCP", external, internal);
|
||||
else
|
||||
pclog("SLiRP: Failed to forward %s port external:%d to internal:%d\n", udp ? "UDP" : "TCP", external, internal);
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
slirp->pkt.data = calloc(1, NET_MAX_FRAME);
|
||||
net_event_init(&slirp->tx_event);
|
||||
net_event_init(&slirp->stop_event);
|
||||
#ifdef _WIN32
|
||||
slirp->sock_event = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||
#endif
|
||||
slirp_log("SLiRP: creating thread...\n");
|
||||
slirp->poll_tid = thread_create(net_slirp_thread, slirp);
|
||||
|
||||
slirp_card_num++;
|
||||
return slirp;
|
||||
}
|
||||
|
||||
void
|
||||
net_slirp_close(void *priv)
|
||||
{
|
||||
if (!priv)
|
||||
return;
|
||||
|
||||
net_slirp_t *slirp = (net_slirp_t *) priv;
|
||||
|
||||
slirp_log("SLiRP: closing\n");
|
||||
/* Tell the polling thread to shut down. */
|
||||
net_event_set(&slirp->stop_event);
|
||||
|
||||
/* Wait for the thread to finish. */
|
||||
slirp_log("SLiRP: waiting for thread to end...\n");
|
||||
thread_wait(slirp->poll_tid);
|
||||
|
||||
net_event_close(&slirp->tx_event);
|
||||
net_event_close(&slirp->stop_event);
|
||||
slirp_cleanup(slirp->slirp);
|
||||
free(slirp->pkt.data);
|
||||
free(slirp);
|
||||
slirp_card_num--;
|
||||
}
|
||||
|
||||
const netdrv_t net_slirp_drv = {
|
||||
&net_slirp_in_available,
|
||||
&net_slirp_init,
|
||||
&net_slirp_close
|
||||
};
|
||||
|
||||
/* Stubs to stand in for the parts of libslirp we skip compiling. */
|
||||
void ncsi_input(void *slirp, const uint8_t *pkt, int pkt_len) {}
|
||||
|
||||
Reference in New Issue
Block a user