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

321
vl.c
View File

@ -64,6 +64,8 @@
#include <malloc.h>
#include <sys/timeb.h>
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#define getopt_long_only getopt_long
#define memalign(align, size) malloc(size)
#endif
@ -1077,20 +1079,67 @@ CharDriverState *qemu_chr_open_null(void)
return chr;
}
#ifndef _WIN32
#ifdef _WIN32
typedef struct {
int fd_in, fd_out;
IOCanRWHandler *fd_can_read;
IOReadHandler *fd_read;
void *fd_opaque;
int max_size;
} FDCharDriver;
#define socket_error() WSAGetLastError()
#undef EINTR
#define EWOULDBLOCK WSAEWOULDBLOCK
#define EINTR WSAEINTR
#define EINPROGRESS WSAEINPROGRESS
#define STDIO_MAX_CLIENTS 2
static void socket_cleanup(void)
{
WSACleanup();
}
static int stdio_nb_clients;
static CharDriverState *stdio_clients[STDIO_MAX_CLIENTS];
static int socket_init(void)
{
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)
{
@ -1112,6 +1161,32 @@ static int unix_write(int fd, const uint8_t *buf, int len1)
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)
{
FDCharDriver *s = chr->opaque;
@ -1617,7 +1692,10 @@ CharDriverState *qemu_chr_open_pty(void)
CharDriverState *qemu_chr_open(const char *filename)
{
#ifndef _WIN32
const char *p;
#endif
if (!strcmp(filename, "vc")) {
return text_console_init(&display_state);
} 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))
return -1;
} else {
#ifdef _WIN32
return -1;
#else
if ((he = gethostbyname(buf)) == NULL)
return - 1;
saddr->sin_addr = *(struct in_addr *)he->h_addr;
#endif
}
}
port = strtol(p, (char **)&r, 0);
@ -2127,6 +2201,8 @@ static int net_tap_init(VLANState *vlan, const char *ifname1,
return 0;
}
#endif /* !_WIN32 */
/* network connection */
typedef struct NetSocketState {
VLANClientState *vc;
@ -2150,8 +2226,8 @@ static void net_socket_receive(void *opaque, const uint8_t *buf, int size)
uint32_t len;
len = htonl(size);
unix_write(s->fd, (const uint8_t *)&len, sizeof(len));
unix_write(s->fd, buf, size);
send_all(s->fd, (const uint8_t *)&len, sizeof(len));
send_all(s->fd, buf, 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)
{
NetSocketState *s = opaque;
int l, size;
int l, size, err;
uint8_t buf1[4096];
const uint8_t *buf;
size = read(s->fd, buf1, sizeof(buf1));
if (size < 0)
return;
if (size == 0) {
size = recv(s->fd, buf1, sizeof(buf1), 0);
if (size < 0) {
err = socket_error();
if (err != EWOULDBLOCK)
goto eoc;
} else if (size == 0) {
/* end of connection */
eoc:
qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
closesocket(s->fd);
return;
}
buf = buf1;
@ -2236,7 +2316,8 @@ static int net_socket_mcast_create(struct sockaddr_in *mcastaddr)
int val, ret;
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",
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;
}
@ -2246,11 +2327,26 @@ static int net_socket_mcast_create(struct sockaddr_in *mcastaddr)
return -1;
}
val = 1;
ret=setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
(const char *)&val, sizeof(val));
if (ret < 0) {
perror("setsockopt(SOL_SOCKET, SO_REUSEADDR)");
goto fail;
}
ret = bind(fd, (struct sockaddr *)mcastaddr, sizeof(*mcastaddr));
if (ret < 0) {
perror("bind");
goto fail;
}
/* 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));
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;
@ -2258,25 +2354,14 @@ static int net_socket_mcast_create(struct sockaddr_in *mcastaddr)
/* Force mcast msgs to loopback (eg. several QEMUs in same host */
val = 1;
ret=setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, &val, sizeof(val));
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;
}
ret=setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
if (ret < 0) {
perror("setsockopt(SOL_SOCKET, SO_REUSEADDR)");
goto fail;
}
ret = bind(fd, (struct sockaddr *)mcastaddr, sizeof(*mcastaddr));
if (ret < 0) {
perror("bind");
goto fail;
}
fcntl(fd, F_SETFL, O_NONBLOCK);
socket_set_nonblock(fd);
return fd;
fail:
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);
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);
return NULL;
}
@ -2433,11 +2518,11 @@ static int net_socket_listen_init(VLANState *vlan, const char *host_str)
perror("socket");
return -1;
}
fcntl(fd, F_SETFL, O_NONBLOCK);
socket_set_nonblock(fd);
/* allow fast reuse */
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));
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)
{
NetSocketState *s;
int fd, connected, ret;
int fd, connected, ret, err;
struct sockaddr_in saddr;
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");
return -1;
}
fcntl(fd, F_SETFL, O_NONBLOCK);
socket_set_nonblock(fd);
connected = 0;
for(;;) {
ret = connect(fd, (struct sockaddr *)&saddr, sizeof(saddr));
if (ret < 0) {
if (errno == EINTR || errno == EAGAIN) {
} else if (errno == EINPROGRESS) {
err = socket_error();
if (err == EINTR || err == EWOULDBLOCK) {
} else if (err == EINPROGRESS) {
break;
} else {
perror("connect");
close(fd);
closesocket(fd);
return -1;
}
} 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,
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);
}
} else
#endif
if (!strcmp(device, "socket")) {
if (get_param_value(buf, sizeof(buf), "fd", p) > 0) {
int fd;
@ -2667,7 +2752,6 @@ int net_client_init(const char *str)
return -1;
}
} else
#endif
{
fprintf(stderr, "Unknown network device: %s\n", device);
return -1;
@ -2918,6 +3002,7 @@ int qemu_set_fd_handler2(int fd,
break;
if (ioh->fd == fd) {
*pioh = ioh->next;
qemu_free(ioh);
break;
}
pioh = &ioh->next;
@ -3812,80 +3897,88 @@ void qemu_system_powerdown_request(void)
void main_loop_wait(int timeout)
{
#ifndef _WIN32
struct pollfd ufds[MAX_IO_HANDLERS + 1], *pf;
IOHandlerRecord *ioh, *ioh_next;
#endif
int ret;
fd_set rfds, wfds;
int ret, nfds;
struct timeval tv;
#ifdef _WIN32
if (timeout > 0)
Sleep(timeout);
/* XXX: see how to merge it with the select. The constraint is
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
/* poll any events */
/* XXX: separate device handlers from system ones */
pf = ufds;
for(ioh = first_io_handler; ioh != NULL; ioh = ioh->next) {
pf->events = 0;
pf->fd = ioh->fd;
if (ioh->fd_read &&
(!ioh->fd_read_poll ||
ioh->fd_read_poll(ioh->opaque) != 0)) {
pf->events |= POLLIN;
tv.tv_usec = timeout * 1000;
#endif
ret = select(nfds + 1, &rfds, &wfds, NULL, &tv);
if (ret > 0) {
/* XXX: better handling of removal */
for(ioh = first_io_handler; ioh != NULL; ioh = ioh_next) {
ioh_next = ioh->next;
if (FD_ISSET(ioh->fd, &rfds)) {
ioh->fd_read(ioh->opaque);
}
if (ioh->fd_write) {
pf->events |= POLLOUT;
}
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);
}
if (FD_ISSET(ioh->fd, &wfds)) {
ioh->fd_write(ioh->opaque);
}
}
#endif /* !defined(_WIN32) */
#if defined(CONFIG_SLIRP)
/* XXX: merge with poll() */
if (slirp_inited) {
fd_set rfds, wfds, xfds;
int nfds;
struct timeval tv;
}
nfds = -1;
FD_ZERO(&rfds);
FD_ZERO(&wfds);
FD_ZERO(&xfds);
slirp_select_fill(&nfds, &rfds, &wfds, &xfds);
tv.tv_sec = 0;
tv.tv_usec = 0;
ret = select(nfds + 1, &rfds, &wfds, &xfds, &tv);
if (ret >= 0) {
slirp_select_poll(&rfds, &wfds, &xfds);
}
#if defined(CONFIG_SLIRP)
/* XXX: merge with the previous select() */
if (slirp_inited) {
fd_set rfds, wfds, xfds;
int nfds;
struct timeval tv;
nfds = -1;
FD_ZERO(&rfds);
FD_ZERO(&wfds);
FD_ZERO(&xfds);
slirp_select_fill(&nfds, &rfds, &wfds, &xfds);
tv.tv_sec = 0;
tv.tv_usec = 0;
ret = select(nfds + 1, &rfds, &wfds, &xfds, &tv);
if (ret >= 0) {
slirp_select_poll(&rfds, &wfds, &xfds);
}
}
#endif
if (vm_running) {
qemu_run_timers(&active_timers[QEMU_TIMER_VIRTUAL],
qemu_get_clock(vm_clock));
/* run dma transfers, if any */
DMA_run();
}
/* real time timers */
qemu_run_timers(&active_timers[QEMU_TIMER_REALTIME],
qemu_get_clock(rt_clock));
if (vm_running) {
qemu_run_timers(&active_timers[QEMU_TIMER_VIRTUAL],
qemu_get_clock(vm_clock));
/* run dma transfers, if any */
DMA_run();
}
/* real time timers */
qemu_run_timers(&active_timers[QEMU_TIMER_REALTIME],
qemu_get_clock(rt_clock));
}
static CPUState *cur_cpu;
@ -4807,6 +4900,10 @@ int main(int argc, char **argv)
setvbuf(stdout, NULL, _IOLBF, 0);
#endif
#ifdef _WIN32
socket_init();
#endif
/* init network clients */
if (nb_net_clients == 0) {
/* if no clients, we use a default config */