win32 socket support

git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1731 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
bellard 2006-02-01 21:29:26 +00:00
parent ff3fbb307d
commit fd1dff4b41

323
vl.c
View file

@ -64,6 +64,8 @@
#include <malloc.h> #include <malloc.h>
#include <sys/timeb.h> #include <sys/timeb.h>
#include <windows.h> #include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#define getopt_long_only getopt_long #define getopt_long_only getopt_long
#define memalign(align, size) malloc(size) #define memalign(align, size) malloc(size)
#endif #endif
@ -1077,20 +1079,67 @@ CharDriverState *qemu_chr_open_null(void)
return chr; return chr;
} }
#ifndef _WIN32 #ifdef _WIN32
typedef struct { #define socket_error() WSAGetLastError()
int fd_in, fd_out; #undef EINTR
IOCanRWHandler *fd_can_read; #define EWOULDBLOCK WSAEWOULDBLOCK
IOReadHandler *fd_read; #define EINTR WSAEINTR
void *fd_opaque; #define EINPROGRESS WSAEINPROGRESS
int max_size;
} FDCharDriver;
#define STDIO_MAX_CLIENTS 2 static void socket_cleanup(void)
{
WSACleanup();
}
static int stdio_nb_clients; static int socket_init(void)
static CharDriverState *stdio_clients[STDIO_MAX_CLIENTS]; {
WSADATA Data;
int ret, err;
ret = WSAStartup(MAKEWORD(2,2), &Data);
if (ret != 0) {
err = WSAGetLastError();
fprintf(stderr, "WSAStartup: %d\n", err);
return -1;
}
atexit(socket_cleanup);
return 0;
}
static int send_all(int fd, const uint8_t *buf, int len1)
{
int ret, len;
len = len1;
while (len > 0) {
ret = send(fd, buf, len, 0);
if (ret < 0) {
int errno;
errno = WSAGetLastError();
if (errno != WSAEWOULDBLOCK) {
return -1;
}
} else if (ret == 0) {
break;
} else {
buf += ret;
len -= ret;
}
}
return len1 - len;
}
void socket_set_nonblock(int fd)
{
unsigned long opt = 1;
ioctlsocket(fd, FIONBIO, &opt);
}
#else
#define socket_error() errno
#define closesocket(s) close(s)
static int unix_write(int fd, const uint8_t *buf, int len1) static int unix_write(int fd, const uint8_t *buf, int len1)
{ {
@ -1112,6 +1161,32 @@ static int unix_write(int fd, const uint8_t *buf, int len1)
return len1 - len; return len1 - len;
} }
static inline int send_all(int fd, const uint8_t *buf, int len1)
{
return unix_write(fd, buf, len1);
}
void socket_set_nonblock(int fd)
{
fcntl(fd, F_SETFL, O_NONBLOCK);
}
#endif /* !_WIN32 */
#ifndef _WIN32
typedef struct {
int fd_in, fd_out;
IOCanRWHandler *fd_can_read;
IOReadHandler *fd_read;
void *fd_opaque;
int max_size;
} FDCharDriver;
#define STDIO_MAX_CLIENTS 2
static int stdio_nb_clients;
static CharDriverState *stdio_clients[STDIO_MAX_CLIENTS];
static int fd_chr_write(CharDriverState *chr, const uint8_t *buf, int len) static int fd_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
{ {
FDCharDriver *s = chr->opaque; FDCharDriver *s = chr->opaque;
@ -1617,7 +1692,10 @@ CharDriverState *qemu_chr_open_pty(void)
CharDriverState *qemu_chr_open(const char *filename) CharDriverState *qemu_chr_open(const char *filename)
{ {
#ifndef _WIN32
const char *p; const char *p;
#endif
if (!strcmp(filename, "vc")) { if (!strcmp(filename, "vc")) {
return text_console_init(&display_state); return text_console_init(&display_state);
} else if (!strcmp(filename, "null")) { } else if (!strcmp(filename, "null")) {
@ -1731,13 +1809,9 @@ int parse_host_port(struct sockaddr_in *saddr, const char *str)
if (!inet_aton(buf, &saddr->sin_addr)) if (!inet_aton(buf, &saddr->sin_addr))
return -1; return -1;
} else { } else {
#ifdef _WIN32
return -1;
#else
if ((he = gethostbyname(buf)) == NULL) if ((he = gethostbyname(buf)) == NULL)
return - 1; return - 1;
saddr->sin_addr = *(struct in_addr *)he->h_addr; saddr->sin_addr = *(struct in_addr *)he->h_addr;
#endif
} }
} }
port = strtol(p, (char **)&r, 0); port = strtol(p, (char **)&r, 0);
@ -2127,6 +2201,8 @@ static int net_tap_init(VLANState *vlan, const char *ifname1,
return 0; return 0;
} }
#endif /* !_WIN32 */
/* network connection */ /* network connection */
typedef struct NetSocketState { typedef struct NetSocketState {
VLANClientState *vc; VLANClientState *vc;
@ -2150,8 +2226,8 @@ static void net_socket_receive(void *opaque, const uint8_t *buf, int size)
uint32_t len; uint32_t len;
len = htonl(size); len = htonl(size);
unix_write(s->fd, (const uint8_t *)&len, sizeof(len)); send_all(s->fd, (const uint8_t *)&len, sizeof(len));
unix_write(s->fd, buf, size); send_all(s->fd, buf, size);
} }
static void net_socket_receive_dgram(void *opaque, const uint8_t *buf, int size) static void net_socket_receive_dgram(void *opaque, const uint8_t *buf, int size)
@ -2164,16 +2240,20 @@ static void net_socket_receive_dgram(void *opaque, const uint8_t *buf, int size)
static void net_socket_send(void *opaque) static void net_socket_send(void *opaque)
{ {
NetSocketState *s = opaque; NetSocketState *s = opaque;
int l, size; int l, size, err;
uint8_t buf1[4096]; uint8_t buf1[4096];
const uint8_t *buf; const uint8_t *buf;
size = read(s->fd, buf1, sizeof(buf1)); size = recv(s->fd, buf1, sizeof(buf1), 0);
if (size < 0) if (size < 0) {
return; err = socket_error();
if (size == 0) { if (err != EWOULDBLOCK)
goto eoc;
} else if (size == 0) {
/* end of connection */ /* end of connection */
eoc:
qemu_set_fd_handler(s->fd, NULL, NULL, NULL); qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
closesocket(s->fd);
return; return;
} }
buf = buf1; buf = buf1;
@ -2236,7 +2316,8 @@ static int net_socket_mcast_create(struct sockaddr_in *mcastaddr)
int val, ret; int val, ret;
if (!IN_MULTICAST(ntohl(mcastaddr->sin_addr.s_addr))) { if (!IN_MULTICAST(ntohl(mcastaddr->sin_addr.s_addr))) {
fprintf(stderr, "qemu: error: specified mcastaddr \"%s\" (0x%08x) does not contain a multicast address\n", fprintf(stderr, "qemu: error: specified mcastaddr \"%s\" (0x%08x) does not contain a multicast address\n",
inet_ntoa(mcastaddr->sin_addr), ntohl(mcastaddr->sin_addr.s_addr)); inet_ntoa(mcastaddr->sin_addr),
(int)ntohl(mcastaddr->sin_addr.s_addr));
return -1; return -1;
} }
@ -2246,25 +2327,9 @@ static int net_socket_mcast_create(struct sockaddr_in *mcastaddr)
return -1; return -1;
} }
/* Add host to multicast group */
imr.imr_multiaddr = mcastaddr->sin_addr;
imr.imr_interface.s_addr = htonl(INADDR_ANY);
ret = setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void *) &imr, sizeof(struct ip_mreq));
if (ret < 0) {
perror("setsockopt(IP_ADD_MEMBERSHIP)");
goto fail;
}
/* Force mcast msgs to loopback (eg. several QEMUs in same host */
val = 1; val = 1;
ret=setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, &val, sizeof(val)); ret=setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
if (ret < 0) { (const char *)&val, sizeof(val));
perror("setsockopt(SOL_IP, IP_MULTICAST_LOOP)");
goto fail;
}
ret=setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
if (ret < 0) { if (ret < 0) {
perror("setsockopt(SOL_SOCKET, SO_REUSEADDR)"); perror("setsockopt(SOL_SOCKET, SO_REUSEADDR)");
goto fail; goto fail;
@ -2276,7 +2341,27 @@ static int net_socket_mcast_create(struct sockaddr_in *mcastaddr)
goto fail; goto fail;
} }
fcntl(fd, F_SETFL, O_NONBLOCK); /* Add host to multicast group */
imr.imr_multiaddr = mcastaddr->sin_addr;
imr.imr_interface.s_addr = htonl(INADDR_ANY);
ret = setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
(const char *)&imr, sizeof(struct ip_mreq));
if (ret < 0) {
perror("setsockopt(IP_ADD_MEMBERSHIP)");
goto fail;
}
/* Force mcast msgs to loopback (eg. several QEMUs in same host */
val = 1;
ret=setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP,
(const char *)&val, sizeof(val));
if (ret < 0) {
perror("setsockopt(SOL_IP, IP_MULTICAST_LOOP)");
goto fail;
}
socket_set_nonblock(fd);
return fd; return fd;
fail: fail:
if (fd>=0) close(fd); if (fd>=0) close(fd);
@ -2371,7 +2456,7 @@ static NetSocketState *net_socket_fd_init(VLANState *vlan, int fd,
{ {
int so_type=-1, optlen=sizeof(so_type); int so_type=-1, optlen=sizeof(so_type);
if(getsockopt(fd, SOL_SOCKET,SO_TYPE, &so_type, &optlen)< 0) { if(getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&so_type, &optlen)< 0) {
fprintf(stderr, "qemu: error: setsockopt(SO_TYPE) for fd=%d failed\n", fd); fprintf(stderr, "qemu: error: setsockopt(SO_TYPE) for fd=%d failed\n", fd);
return NULL; return NULL;
} }
@ -2433,11 +2518,11 @@ static int net_socket_listen_init(VLANState *vlan, const char *host_str)
perror("socket"); perror("socket");
return -1; return -1;
} }
fcntl(fd, F_SETFL, O_NONBLOCK); socket_set_nonblock(fd);
/* allow fast reuse */ /* allow fast reuse */
val = 1; val = 1;
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)); setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&val, sizeof(val));
ret = bind(fd, (struct sockaddr *)&saddr, sizeof(saddr)); ret = bind(fd, (struct sockaddr *)&saddr, sizeof(saddr));
if (ret < 0) { if (ret < 0) {
@ -2458,7 +2543,7 @@ static int net_socket_listen_init(VLANState *vlan, const char *host_str)
static int net_socket_connect_init(VLANState *vlan, const char *host_str) static int net_socket_connect_init(VLANState *vlan, const char *host_str)
{ {
NetSocketState *s; NetSocketState *s;
int fd, connected, ret; int fd, connected, ret, err;
struct sockaddr_in saddr; struct sockaddr_in saddr;
if (parse_host_port(&saddr, host_str) < 0) if (parse_host_port(&saddr, host_str) < 0)
@ -2469,18 +2554,19 @@ static int net_socket_connect_init(VLANState *vlan, const char *host_str)
perror("socket"); perror("socket");
return -1; return -1;
} }
fcntl(fd, F_SETFL, O_NONBLOCK); socket_set_nonblock(fd);
connected = 0; connected = 0;
for(;;) { for(;;) {
ret = connect(fd, (struct sockaddr *)&saddr, sizeof(saddr)); ret = connect(fd, (struct sockaddr *)&saddr, sizeof(saddr));
if (ret < 0) { if (ret < 0) {
if (errno == EINTR || errno == EAGAIN) { err = socket_error();
} else if (errno == EINPROGRESS) { if (err == EINTR || err == EWOULDBLOCK) {
} else if (err == EINPROGRESS) {
break; break;
} else { } else {
perror("connect"); perror("connect");
close(fd); closesocket(fd);
return -1; return -1;
} }
} else { } else {
@ -2524,8 +2610,6 @@ static int net_socket_mcast_init(VLANState *vlan, const char *host_str)
} }
#endif /* !_WIN32 */
static int get_param_value(char *buf, int buf_size, static int get_param_value(char *buf, int buf_size,
const char *tag, const char *str) const char *tag, const char *str)
{ {
@ -2649,6 +2733,7 @@ int net_client_init(const char *str)
ret = net_tap_init(vlan, ifname, setup_script); ret = net_tap_init(vlan, ifname, setup_script);
} }
} else } else
#endif
if (!strcmp(device, "socket")) { if (!strcmp(device, "socket")) {
if (get_param_value(buf, sizeof(buf), "fd", p) > 0) { if (get_param_value(buf, sizeof(buf), "fd", p) > 0) {
int fd; int fd;
@ -2667,7 +2752,6 @@ int net_client_init(const char *str)
return -1; return -1;
} }
} else } else
#endif
{ {
fprintf(stderr, "Unknown network device: %s\n", device); fprintf(stderr, "Unknown network device: %s\n", device);
return -1; return -1;
@ -2918,6 +3002,7 @@ int qemu_set_fd_handler2(int fd,
break; break;
if (ioh->fd == fd) { if (ioh->fd == fd) {
*pioh = ioh->next; *pioh = ioh->next;
qemu_free(ioh);
break; break;
} }
pioh = &ioh->next; pioh = &ioh->next;
@ -3812,80 +3897,88 @@ void qemu_system_powerdown_request(void)
void main_loop_wait(int timeout) void main_loop_wait(int timeout)
{ {
#ifndef _WIN32
struct pollfd ufds[MAX_IO_HANDLERS + 1], *pf;
IOHandlerRecord *ioh, *ioh_next; IOHandlerRecord *ioh, *ioh_next;
#endif fd_set rfds, wfds;
int ret; int ret, nfds;
struct timeval tv;
#ifdef _WIN32 #ifdef _WIN32
if (timeout > 0) /* XXX: see how to merge it with the select. The constraint is
Sleep(timeout); that the select must be interrupted by the timer */
if (timeout > 0)
Sleep(timeout);
#endif
/* poll any events */
/* XXX: separate device handlers from system ones */
nfds = -1;
FD_ZERO(&rfds);
FD_ZERO(&wfds);
for(ioh = first_io_handler; ioh != NULL; ioh = ioh->next) {
if (ioh->fd_read &&
(!ioh->fd_read_poll ||
ioh->fd_read_poll(ioh->opaque) != 0)) {
FD_SET(ioh->fd, &rfds);
if (ioh->fd > nfds)
nfds = ioh->fd;
}
if (ioh->fd_write) {
FD_SET(ioh->fd, &wfds);
if (ioh->fd > nfds)
nfds = ioh->fd;
}
}
tv.tv_sec = 0;
#ifdef _WIN32
tv.tv_usec = 0;
#else #else
/* poll any events */ tv.tv_usec = timeout * 1000;
/* XXX: separate device handlers from system ones */ #endif
pf = ufds; ret = select(nfds + 1, &rfds, &wfds, NULL, &tv);
for(ioh = first_io_handler; ioh != NULL; ioh = ioh->next) { if (ret > 0) {
pf->events = 0; /* XXX: better handling of removal */
pf->fd = ioh->fd; for(ioh = first_io_handler; ioh != NULL; ioh = ioh_next) {
if (ioh->fd_read && ioh_next = ioh->next;
(!ioh->fd_read_poll || if (FD_ISSET(ioh->fd, &rfds)) {
ioh->fd_read_poll(ioh->opaque) != 0)) { ioh->fd_read(ioh->opaque);
pf->events |= POLLIN;
} }
if (ioh->fd_write) { if (FD_ISSET(ioh->fd, &wfds)) {
pf->events |= POLLOUT; ioh->fd_write(ioh->opaque);
} }
ioh->ufd = pf;
pf++;
} }
}
ret = poll(ufds, pf - ufds, timeout);
if (ret > 0) {
/* XXX: better handling of removal */
for(ioh = first_io_handler; ioh != NULL; ioh = ioh_next) {
ioh_next = ioh->next;
pf = ioh->ufd;
if (pf->revents & POLLIN) {
ioh->fd_read(ioh->opaque);
}
if (pf->revents & POLLOUT) {
ioh->fd_write(ioh->opaque);
}
}
}
#endif /* !defined(_WIN32) */
#if defined(CONFIG_SLIRP) #if defined(CONFIG_SLIRP)
/* XXX: merge with poll() */ /* XXX: merge with the previous select() */
if (slirp_inited) { if (slirp_inited) {
fd_set rfds, wfds, xfds; fd_set rfds, wfds, xfds;
int nfds; int nfds;
struct timeval tv; struct timeval tv;
nfds = -1; nfds = -1;
FD_ZERO(&rfds); FD_ZERO(&rfds);
FD_ZERO(&wfds); FD_ZERO(&wfds);
FD_ZERO(&xfds); FD_ZERO(&xfds);
slirp_select_fill(&nfds, &rfds, &wfds, &xfds); slirp_select_fill(&nfds, &rfds, &wfds, &xfds);
tv.tv_sec = 0; tv.tv_sec = 0;
tv.tv_usec = 0; tv.tv_usec = 0;
ret = select(nfds + 1, &rfds, &wfds, &xfds, &tv); ret = select(nfds + 1, &rfds, &wfds, &xfds, &tv);
if (ret >= 0) { if (ret >= 0) {
slirp_select_poll(&rfds, &wfds, &xfds); slirp_select_poll(&rfds, &wfds, &xfds);
}
} }
}
#endif #endif
if (vm_running) { if (vm_running) {
qemu_run_timers(&active_timers[QEMU_TIMER_VIRTUAL], qemu_run_timers(&active_timers[QEMU_TIMER_VIRTUAL],
qemu_get_clock(vm_clock)); qemu_get_clock(vm_clock));
/* run dma transfers, if any */ /* run dma transfers, if any */
DMA_run(); DMA_run();
} }
/* real time timers */ /* real time timers */
qemu_run_timers(&active_timers[QEMU_TIMER_REALTIME], qemu_run_timers(&active_timers[QEMU_TIMER_REALTIME],
qemu_get_clock(rt_clock)); qemu_get_clock(rt_clock));
} }
static CPUState *cur_cpu; static CPUState *cur_cpu;
@ -4807,6 +4900,10 @@ int main(int argc, char **argv)
setvbuf(stdout, NULL, _IOLBF, 0); setvbuf(stdout, NULL, _IOLBF, 0);
#endif #endif
#ifdef _WIN32
socket_init();
#endif
/* init network clients */ /* init network clients */
if (nb_net_clients == 0) { if (nb_net_clients == 0) {
/* if no clients, we use a default config */ /* if no clients, we use a default config */