qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel][PATCH] Tap and VLAN socket support for win32


From: Kazu
Subject: Re: [Qemu-devel][PATCH] Tap and VLAN socket support for win32
Date: Thu, 9 Feb 2006 11:29:28 +0900

Sunday, February 05, 2006 3:28 AM Fabrice  Bellard wrote:
Kazu wrote:
Thursday, February 02, 2006 8:10 AM Fabrice Bellard wrote:

Hi,

I merged your patches and I made important changes to simplify them. I
did not do any tests so tell me if you see problems.


-net socket,connect doesn't work. On Windows host, connect returns with
err
= WSAEWOULDBLOCK and second time err = WSAEINVAL. I think changing the
place
of EWOULDBLOCK would be good. On Linux host, EWOULDBLOCK is the same as
EAGAIN but a patch works on both Linux and Windows.

Unfortunately on Linux the correct return value we are expecting is
EINPROGRESS. EAGAIN means that the 'connect' was not initiated so it is
necessary to redo it.


There is not good way to detect a completion of asynchronous connect. So I
used an event object to detect it. A patch is attached.


For -net socket,mcast, bind have to be done by sin_addr.s_addr =
INADDR_ANY.
It seems that it works on Linux host.

It works on Linux but it is not correct because it prevents from listening
to several multicast addresses at the same time. If doing the same on
Windows is not possible I agree to make a special case.


I couldn't find a way to set a multicast address. I made it a special case
in the patch

Regard,
Kazu

Index: vl.c
===================================================================
RCS file: /sources/qemu/qemu/vl.c,v
retrieving revision 1.162
diff -u -r1.162 vl.c
--- vl.c 5 Feb 2006 04:14:41 -0000 1.162
+++ vl.c 8 Feb 2006 05:50:28 -0000
@@ -1083,9 +1083,10 @@

#define socket_error() WSAGetLastError()
#undef EINTR
-#define EWOULDBLOCK WSAEWOULDBLOCK
-#define EINTR       WSAEINTR
-#define EINPROGRESS WSAEINPROGRESS
+#define EWOULDBLOCK   WSAEWOULDBLOCK
+#define EINTR         WSAEINTR
+#define EINPROGRESS   WSAEINPROGRESS
+#define EADDRNOTAVAIL WSAEADDRNOTAVAIL

static void socket_cleanup(void)
{
@@ -1136,6 +1137,59 @@
    ioctlsocket(fd, FIONBIO, &opt);
}

+static int socket_set_event(SOCKET fd, WSAEVENT *phEvent)
+{
+    int ret;
+
+    *phEvent = WSACreateEvent();
+    if (*phEvent == WSA_INVALID_EVENT) {
+        perror("connect: CreateEvent");
+        return -1;
+    }
+
+    ret = WSAEventSelect(fd, *phEvent, FD_CONNECT);
+    if (ret == SOCKET_ERROR) {
+        perror("connect: EventSelect");
+        return -1;
+    }
+    return 0;
+}
+
+static int socket_wait_event(SOCKET fd, WSAEVENT *phEvent)
+{
+    WSANETWORKEVENTS events;
+    int ret;
+
+    ret = WSAWaitForMultipleEvents(1, phEvent, FALSE, WSA_INFINITE, FALSE);
+    if (ret == WSA_WAIT_FAILED) {
+        perror("connect: Wait");
+        goto fail;
+    }
+
+    ret = WSAEnumNetworkEvents(fd, *phEvent, &events);
+    if (ret == SOCKET_ERROR) {
+        perror("connect: EnumEvent");
+        goto fail;
+    } else {
+        if (events.lNetworkEvents & FD_CONNECT) {
+            if (events.iErrorCode[FD_CONNECT_BIT] == 0) {
+                if (*phEvent != WSA_INVALID_EVENT)
+                    WSACloseEvent(*phEvent);
+                return 1;
+            } else {
+                perror("connect: refused");
+                goto fail;
+            }
+        } else {
+            perror("connect: fd_connect");
+            goto fail;
+        }
+    }
+ fail:
+    if (*phEvent != WSA_INVALID_EVENT)
+        WSACloseEvent(*phEvent);
+    return 0;
+}
#else

#define socket_error() errno
@@ -2330,7 +2384,9 @@
{
    struct ip_mreq imr;
    int fd;
-    int val, ret;
+    int val, ret, err;
+    struct sockaddr_in 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",
  inet_ntoa(mcastaddr->sin_addr),
@@ -2354,8 +2410,22 @@

    ret = bind(fd, (struct sockaddr *)mcastaddr, sizeof(*mcastaddr));
    if (ret < 0) {
-        perror("bind");
-        goto fail;
+        err = socket_error();
+        if (err == EADDRNOTAVAIL) {
+            memset(&addr, 0, sizeof(addr));
+            addr.sin_family = AF_INET;
+            addr.sin_port = mcastaddr->sin_port;
+            addr.sin_addr.s_addr = INADDR_ANY;
+
+            ret = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
+            if (ret < 0) {
+                perror("bind");
+                goto fail;
+            }
+        } else {
+            perror("bind");
+            goto fail;
+        }
    }

    /* Add host to multicast group */
@@ -2557,11 +2627,15 @@
    return 0;
}

+
static int net_socket_connect_init(VLANState *vlan, const char *host_str)
{
    NetSocketState *s;
    int fd, connected, ret, err;
    struct sockaddr_in saddr;
+#ifdef _WIN32
+    WSAEVENT hEvent;
+#endif

    if (parse_host_port(&saddr, host_str) < 0)
        return -1;
@@ -2573,6 +2647,26 @@
    }
    socket_set_nonblock(fd);

+#ifdef _WIN32
+    ret = socket_set_event(fd, &hEvent);
+    if (ret < 0) {
+        perror("connect: set_event");
+        closesocket(fd);
+        return -1;
+    }
+
+    connected = 0;
+    ret = connect(fd, (struct sockaddr *)&saddr, sizeof(saddr));
+
+    err = socket_wait_event(fd, &hEvent);
+    if (err > 0) {
+        connected = 1;
+    } else {
+        perror("connect");
+        closesocket(fd);
+        return -1;
+    }
+#else
    connected = 0;
    for(;;) {
        ret = connect(fd, (struct sockaddr *)&saddr, sizeof(saddr));
@@ -2591,6 +2685,8 @@
            break;
        }
    }
+#endif
+
    s = net_socket_fd_init(vlan, fd, connected);
    if (!s)
        return -1;

Attachment: qemu-20060208-vlan-2.patch.gz
Description: GNU Zip compressed data


reply via email to

[Prev in Thread] Current Thread [Next in Thread]