From 25bf8fbc0221d4d91f8fc4a36023ac5a2e7728b9 Mon Sep 17 00:00:00 2001 From: "Erich E. Hoover" Date: Thu, 5 Dec 2013 16:40:00 -0700 Subject: [PATCH] Updated SIO_ADDRESS_LIST_CHANGE patches. --- ...erver-to-process-unsupported-WSAIoct.patch | 37 ++- ...-an-interface-change-notification-ob.patch | 294 +++++++++--------- 2 files changed, 178 insertions(+), 153 deletions(-) diff --git a/patches/01-Address_Change_Notification/0001-ws2_32-Ask-the-server-to-process-unsupported-WSAIoct.patch b/patches/01-Address_Change_Notification/0001-ws2_32-Ask-the-server-to-process-unsupported-WSAIoct.patch index f62bbfe6..3b61bffc 100644 --- a/patches/01-Address_Change_Notification/0001-ws2_32-Ask-the-server-to-process-unsupported-WSAIoct.patch +++ b/patches/01-Address_Change_Notification/0001-ws2_32-Ask-the-server-to-process-unsupported-WSAIoct.patch @@ -1,14 +1,14 @@ -From c1f305f001257ac6bc215abd34c1577e7d9bf7f2 Mon Sep 17 00:00:00 2001 +From 362ec39591ce54bcb5ce825c1baab8f5d0885193 Mon Sep 17 00:00:00 2001 From: "Erich E. Hoover" -Date: Fri, 4 Oct 2013 08:10:20 -0600 +Date: Thu, 5 Dec 2013 13:32:34 -0700 Subject: ws2_32: Ask the server to process unsupported WSAIoctl operations. --- - dlls/ws2_32/socket.c | 47 ++++++++++++++++++++++++++++++++++++++++++++--- - 1 file changed, 44 insertions(+), 3 deletions(-) + dlls/ws2_32/socket.c | 56 +++++++++++++++++++++++++++++++++++++++++++------- + 1 file changed, 49 insertions(+), 7 deletions(-) diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c -index 679258b..44a9093 100644 +index 304b0eb..170dde7 100644 --- a/dlls/ws2_32/socket.c +++ b/dlls/ws2_32/socket.c @@ -3608,6 +3608,36 @@ static const char *debugstr_wsaioctl(DWORD ioctl) @@ -48,19 +48,25 @@ index 679258b..44a9093 100644 /********************************************************************** * WSAIoctl (WS2_32.50) * -@@ -3800,9 +3830,8 @@ INT WINAPI WSAIoctl(SOCKET s, DWORD code, LPVOID in_buff, DWORD in_size, LPVOID +@@ -3799,12 +3829,6 @@ INT WINAPI WSAIoctl(SOCKET s, DWORD code, LPVOID in_buff, DWORD in_size, LPVOID + break; } - case WS_SIO_ADDRESS_LIST_CHANGE: +- case WS_SIO_ADDRESS_LIST_CHANGE: - FIXME("-> SIO_ADDRESS_LIST_CHANGE request: stub\n"); - /* FIXME: error and return code depend on whether socket was created - * with WSA_FLAG_OVERLAPPED, but there is no easy way to get this */ -+ TRACE("-> SIO_ADDRESS_LIST_CHANGE request\n"); -+ status = WSAEOPNOTSUPP; /* this operation needs to be handled by the server */ - break; - +- break; +- case WS_SIO_ADDRESS_LIST_QUERY: -@@ -4045,6 +4074,18 @@ INT WINAPI WSAIoctl(SOCKET s, DWORD code, LPVOID in_buff, DWORD in_size, LPVOID + { + DWORD size; +@@ -4040,11 +4064,29 @@ INT WINAPI WSAIoctl(SOCKET s, DWORD code, LPVOID in_buff, DWORD in_size, LPVOID + WSASetLastError(WSAEOPNOTSUPP); + return SOCKET_ERROR; + default: +- FIXME("unsupported WS_IOCTL cmd (%s)\n", debugstr_wsaioctl(code)); + status = WSAEOPNOTSUPP; break; } @@ -70,10 +76,17 @@ index 679258b..44a9093 100644 + overlapped, completion); + if (status != WSAEOPNOTSUPP) + { ++ if (status == 0 || status == WSA_IO_PENDING) ++ TRACE("-> %s request\n", debugstr_wsaioctl(code)); ++ else ++ ERR("-> %s request failed with status 0x%x\n", debugstr_wsaioctl(code), status); ++ + /* overlapped and completion operations will be handled by the server */ + completion = NULL; + overlapped = NULL; + } ++ else ++ FIXME("unsupported WS_IOCTL cmd (%s)\n", debugstr_wsaioctl(code)); + } + if (completion) diff --git a/patches/01-Address_Change_Notification/0002-server-Implement-an-interface-change-notification-ob.patch b/patches/01-Address_Change_Notification/0002-server-Implement-an-interface-change-notification-ob.patch index 202c667f..2f74e538 100644 --- a/patches/01-Address_Change_Notification/0002-server-Implement-an-interface-change-notification-ob.patch +++ b/patches/01-Address_Change_Notification/0002-server-Implement-an-interface-change-notification-ob.patch @@ -1,14 +1,14 @@ -From aa5c2e5b4bf9716af3ea2065a3d3de10c840f59b Mon Sep 17 00:00:00 2001 +From 8bd705add6a11c82faa1695656fd84c2611358c1 Mon Sep 17 00:00:00 2001 From: "Erich E. Hoover" -Date: Mon, 18 Nov 2013 17:22:04 -0700 +Date: Thu, 5 Dec 2013 13:45:15 -0700 Subject: server: Implement an interface change notification object. --- server/event.c | 13 +++ server/named_pipe.c | 13 --- server/object.h | 1 + - server/sock.c | 289 ++++++++++++++++++++++++++++++++++++++++++++++++++- - 4 files changed, 301 insertions(+), 15 deletions(-) + server/sock.c | 303 ++++++++++++++++++++++++++++++++++++++++++++++++++- + 4 files changed, 313 insertions(+), 17 deletions(-) diff --git a/server/event.c b/server/event.c index b8515af..e8a3888 100644 @@ -71,7 +71,7 @@ index bb3ff21..bad162f 100644 extern struct keyed_event *get_keyed_event_obj( struct process *process, obj_handle_t handle, unsigned int access ); extern void pulse_event( struct event *event ); diff --git a/server/sock.c b/server/sock.c -index 1a3a8f7..4e41b72 100644 +index 1a3a8f7..a34d086 100644 --- a/server/sock.c +++ b/server/sock.c @@ -44,11 +44,17 @@ @@ -92,20 +92,37 @@ index 1a3a8f7..4e41b72 100644 #include "process.h" #include "file.h" -@@ -107,8 +113,12 @@ struct sock +@@ -83,9 +89,6 @@ + #define FD_WINE_RAW 0x80000000 + #define FD_WINE_INTERNAL 0xFFFF0000 + +-/* Constants for WSAIoctl() */ +-#define WSA_FLAG_OVERLAPPED 0x01 +- + struct sock + { + struct object obj; /* object header */ +@@ -107,8 +110,19 @@ struct sock struct sock *deferred; /* socket that waits for a deferred accept */ struct async_queue *read_q; /* queue for asynchronous reads */ struct async_queue *write_q; /* queue for asynchronous writes */ ++#ifdef HAVE_LINUX_RTNETLINK_H + struct async_queue *ifchange_q; /* queue for interface change notifications */ + struct list ifchange_entry; /* entry in ifchange notification list */ ++#endif }; ++#ifdef HAVE_LINUX_RTNETLINK_H ++/* only keep one ifchange object around, all sockets waiting for wakeups will look to it */ ++static struct object *ifchange_object = NULL; ++ +static int sock_add_ifchange( struct sock *sock, const async_data_t *async_data ); ++#endif + static void sock_dump( struct object *obj, int verbose ); static int sock_signaled( struct object *obj, struct wait_queue_entry *entry ); static struct fd *sock_get_fd( struct object *obj ); -@@ -117,6 +127,8 @@ static void sock_destroy( struct object *obj ); +@@ -117,6 +131,8 @@ static void sock_destroy( struct object *obj ); static int sock_get_poll_events( struct fd *fd ); static void sock_poll_event( struct fd *fd, int event ); static enum server_fd_type sock_get_fd_type( struct fd *fd ); @@ -114,7 +131,7 @@ index 1a3a8f7..4e41b72 100644 static void sock_queue_async( struct fd *fd, const async_data_t *data, int type, int count ); static void sock_reselect_async( struct fd *fd, struct async_queue *queue ); static void sock_cancel_async( struct fd *fd, struct process *process, struct thread *thread, client_ptr_t iosb ); -@@ -151,12 +163,15 @@ static const struct fd_ops sock_fd_ops = +@@ -151,7 +167,7 @@ static const struct fd_ops sock_fd_ops = sock_poll_event, /* poll_event */ no_flush, /* flush */ sock_get_fd_type, /* get_fd_type */ @@ -123,15 +140,7 @@ index 1a3a8f7..4e41b72 100644 sock_queue_async, /* queue_async */ sock_reselect_async, /* reselect_async */ sock_cancel_async /* cancel_async */ - }; - -+/* only keep one ifchange object around, all sockets waiting for wakeups will look to it */ -+static struct object *ifchange_object = NULL; -+ - - /* Permutation of 0..FD_MAX_EVENTS - 1 representing the order in which - * we post messages if there are multiple events. Used to send -@@ -518,6 +533,39 @@ static enum server_fd_type sock_get_fd_type( struct fd *fd ) +@@ -518,6 +534,43 @@ static enum server_fd_type sock_get_fd_type( struct fd *fd ) return FD_TYPE_SOCKET; } @@ -154,11 +163,15 @@ index 1a3a8f7..4e41b72 100644 + switch(code) + { + case WS_SIO_ADDRESS_LIST_CHANGE: ++#ifdef HAVE_LINUX_RTNETLINK_H + if (sock_add_ifchange( sock, async_data )) + { + set_error( STATUS_PENDING ); + return wait_handle; + } ++#else ++ set_error( STATUS_NOT_SUPPORTED ); ++#endif + break; + default: + close_handle( current->process, wait_handle ); @@ -171,37 +184,37 @@ index 1a3a8f7..4e41b72 100644 static void sock_queue_async( struct fd *fd, const async_data_t *data, int type, int count ) { struct sock *sock = get_fd_user( fd ); -@@ -587,11 +635,17 @@ static void sock_destroy( struct object *obj ) - - /* FIXME: special socket shutdown stuff? */ - -- if ( sock->deferred ) -+ if (sock->deferred) - release_object( sock->deferred ); +@@ -592,6 +645,14 @@ static void sock_destroy( struct object *obj ) free_async_queue( sock->read_q ); free_async_queue( sock->write_q ); ++#ifdef HAVE_LINUX_RTNETLINK_H + if (sock->ifchange_q) + { + free_async_queue( sock->ifchange_q ); + list_remove( &sock->ifchange_entry ); + release_object( ifchange_object ); + } ++#endif if (sock->event) release_object( sock->event ); if (sock->fd) { -@@ -618,6 +672,7 @@ static void init_sock(struct sock *sock) +@@ -618,6 +679,9 @@ static void init_sock(struct sock *sock) sock->deferred = NULL; sock->read_q = NULL; sock->write_q = NULL; ++#ifdef HAVE_LINUX_RTNETLINK_H + sock->ifchange_q = NULL; ++#endif memset( sock->errors, 0, sizeof(sock->errors) ); } -@@ -906,6 +961,236 @@ static void sock_set_error(void) +@@ -906,6 +970,237 @@ static void sock_set_error(void) set_error( sock_get_ntstatus( errno ) ); } ++#ifdef HAVE_LINUX_RTNETLINK_H ++ +static void ifchange_dump( struct object *obj, int verbose ); +static struct fd *ifchange_get_fd( struct object *obj ); +static void ifchange_destroy( struct object *obj ); @@ -212,46 +225,82 @@ index 1a3a8f7..4e41b72 100644 + +struct ifchange +{ -+ struct object obj; /* object header */ -+ struct fd *fd; /* interface change file descriptor */ -+ struct list sockets; /* list of sockets to send interface change notifications */ ++ struct object obj; /* object header */ ++ struct fd *fd; /* interface change file descriptor */ ++ struct list sockets; /* list of sockets to send interface change notifications */ +}; + +static const struct object_ops ifchange_ops = +{ -+ sizeof(struct ifchange), /* size */ -+ ifchange_dump, /* dump */ -+ no_get_type, /* get_type */ -+ add_queue, /* add_queue */ -+ NULL, /* remove_queue */ -+ NULL, /* signaled */ -+ no_satisfied, /* satisfied */ -+ no_signal, /* signal */ -+ ifchange_get_fd, /* get_fd */ -+ default_fd_map_access, /* map_access */ -+ default_get_sd, /* get_sd */ -+ default_set_sd, /* set_sd */ -+ no_lookup_name, /* lookup_name */ -+ no_open_file, /* open_file */ -+ no_close_handle, /* close_handle */ -+ ifchange_destroy /* destroy */ ++ sizeof(struct ifchange), /* size */ ++ ifchange_dump, /* dump */ ++ no_get_type, /* get_type */ ++ add_queue, /* add_queue */ ++ NULL, /* remove_queue */ ++ NULL, /* signaled */ ++ no_satisfied, /* satisfied */ ++ no_signal, /* signal */ ++ ifchange_get_fd, /* get_fd */ ++ default_fd_map_access, /* map_access */ ++ default_get_sd, /* get_sd */ ++ default_set_sd, /* set_sd */ ++ no_lookup_name, /* lookup_name */ ++ no_open_file, /* open_file */ ++ no_close_handle, /* close_handle */ ++ ifchange_destroy /* destroy */ +}; + +static const struct fd_ops ifchange_fd_ops = +{ -+ ifchange_get_poll_events, /* get_poll_events */ -+ ifchange_poll_event, /* poll_event */ -+ NULL, /* flush */ -+ NULL, /* get_fd_type */ -+ NULL, /* ioctl */ -+ NULL, /* queue_async */ -+ ifchange_reselect_async, /* reselect_async */ -+ NULL /* cancel_async */ ++ ifchange_get_poll_events, /* get_poll_events */ ++ ifchange_poll_event, /* poll_event */ ++ NULL, /* flush */ ++ NULL, /* get_fd_type */ ++ NULL, /* ioctl */ ++ NULL, /* queue_async */ ++ ifchange_reselect_async, /* reselect_async */ ++ NULL /* cancel_async */ +}; + ++static void ifchange_dump( struct object *obj, int verbose ) ++{ ++ assert( obj->ops == &ifchange_ops ); ++ printf( "ifchange\n" ); ++} ++ ++static struct fd *ifchange_get_fd( struct object *obj ) ++{ ++ struct ifchange *ifchange = (struct ifchange *)obj; ++ return (struct fd *)grab_object( ifchange->fd ); ++} ++ ++static void ifchange_destroy( struct object *obj ) ++{ ++ struct ifchange *ifchange = (struct ifchange *)obj; ++ assert( obj->ops == &ifchange_ops ); ++ ++ /* reset the global ifchange object so that it will be recreated if it is needed again */ ++ ifchange_object = NULL; ++ /* shut the socket down to force pending poll() calls in the client to return */ ++ shutdown( get_unix_fd(ifchange->fd), SHUT_RDWR ); ++ release_object( ifchange->fd ); ++} ++ ++static int ifchange_get_poll_events( struct fd *fd ) ++{ ++ return POLLIN; ++} ++ ++/* add a socket to the interface change notification's list of sockets */ ++void ifchange_add_sock( struct object *obj, struct sock *sock ) ++{ ++ struct ifchange *ifchange = (struct ifchange *)obj; ++ ++ list_add_tail( &ifchange->sockets, &sock->ifchange_entry ); ++} ++ +static int init_ifchange( struct ifchange *ifchange ) +{ -+#if defined(NETLINK_ROUTE) + struct sockaddr_nl addr; + int unix_fd; + @@ -281,11 +330,6 @@ index 1a3a8f7..4e41b72 100644 + /* enable read wakeup on the file descriptor */ + set_fd_events( ifchange->fd, POLLIN ); + return 1; -+#else -+ fprintf(stderr, "Interface change notification is not supported on this platform.\n"); -+ set_error( STATUS_NOT_SUPPORTED ); -+ return 0; -+#endif +} + +/* create a new ifchange notifier or, if one already exists, reuse the existing one */ @@ -308,14 +352,6 @@ index 1a3a8f7..4e41b72 100644 + return ifchange_object; +} + -+/* add a socket to the interface change notification's list of sockets */ -+void ifchange_add_sock( struct object *obj, struct sock *sock ) -+{ -+ struct ifchange *ifchange = (struct ifchange *)obj; -+ -+ list_add_tail( &ifchange->sockets, &sock->ifchange_entry ); -+} -+ +/* wake up an ifchange notification queue for a socket and decrement the ifchange object refcount */ +void sock_ifchange_wake_up( struct sock *sock, unsigned int status ) +{ @@ -327,6 +363,56 @@ index 1a3a8f7..4e41b72 100644 + release_object( ifchange_object ); +} + ++/* wake up all the sockets waiting for a change notification event */ ++static void ifchange_wake_up( struct object *obj, unsigned int status ) ++{ ++ struct ifchange *ifchange = (struct ifchange *)obj; ++ struct list *ptr, *next; ++ ++ assert( obj->ops == &ifchange_ops ); ++ LIST_FOR_EACH_SAFE( ptr, next, &ifchange->sockets ) ++ { ++ struct sock *sock = LIST_ENTRY( ptr, struct sock, ifchange_entry ); ++ ++ sock_ifchange_wake_up( sock, status ); ++ } ++} ++ ++static void ifchange_poll_event( struct fd *fd, int event ) ++{ ++ struct object *ifchange = get_fd_user( fd ); ++ unsigned int status = STATUS_PENDING; ++ char buffer[0x1000]; ++ int r; ++ ++ r = recv( get_unix_fd(fd), buffer, sizeof(buffer), MSG_DONTWAIT ); ++ if (r < 0) ++ { ++ if (errno == EWOULDBLOCK || errno == EAGAIN) ++ return; /* retry when poll() says the socket is ready */ ++ status = sock_get_ntstatus( errno ); ++ } ++ else if (r != 0) ++ { ++ struct nlmsghdr *nlh; ++ ++ for (nlh = (struct nlmsghdr*)buffer; NLMSG_OK(nlh, r); nlh = NLMSG_NEXT(nlh, r)) ++ { ++ if (nlh->nlmsg_type == NLMSG_DONE) ++ break; ++ if (nlh->nlmsg_type == RTM_NEWADDR || nlh->nlmsg_type == RTM_DELADDR) ++ status = STATUS_SUCCESS; ++ } ++ } ++ if (status != STATUS_PENDING) ++ ifchange_wake_up( ifchange, status ); ++} ++ ++static void ifchange_reselect_async( struct fd *fd, struct async_queue *queue ) ++{ ++ /* do nothing, this object is about to disappear */ ++} ++ +/* add interface change notification to a socket */ +int sock_add_ifchange( struct sock *sock, const async_data_t *async_data ) +{ @@ -356,81 +442,7 @@ index 1a3a8f7..4e41b72 100644 + return FALSE; +} + -+static void ifchange_dump( struct object *obj, int verbose ) -+{ -+ assert( obj->ops == &ifchange_ops ); -+ printf( "ifchange\n" ); -+} -+ -+static struct fd *ifchange_get_fd( struct object *obj ) -+{ -+ struct ifchange *ifchange = (struct ifchange *)obj; -+ return (struct fd *)grab_object( ifchange->fd ); -+} -+ -+static void ifchange_destroy( struct object *obj ) -+{ -+ struct ifchange *ifchange = (struct ifchange *)obj; -+ assert( obj->ops == &ifchange_ops ); -+ -+ /* reset the global ifchange object so that it will be recreated if it is needed again */ -+ ifchange_object = NULL; -+ /* shut the socket down to force pending poll() calls in the client to return */ -+ shutdown( get_unix_fd(ifchange->fd), SHUT_RDWR ); -+ release_object( ifchange->fd ); -+} -+ -+static int ifchange_get_poll_events( struct fd *fd ) -+{ -+ return POLLIN; -+} -+ -+/* wake up all the sockets waiting for a change notification event */ -+static void ifchange_wake_up( struct object *obj, unsigned int status ) -+{ -+ struct ifchange *ifchange = (struct ifchange *) obj; -+ struct list *ptr, *next; -+ -+ assert( obj->ops == &ifchange_ops ); -+ LIST_FOR_EACH_SAFE( ptr, next, &ifchange->sockets ) -+ { -+ struct sock *sock = LIST_ENTRY( ptr, struct sock, ifchange_entry ); -+ -+ sock_ifchange_wake_up( sock, status ); -+ } -+} -+ -+static void ifchange_poll_event( struct fd *fd, int event ) -+{ -+ struct object *ifchange = get_fd_user( fd ); -+ int r, unix_fd, wakeup = FALSE; -+ char buffer[0x1000]; -+ -+ unix_fd = get_unix_fd( fd ); -+ r = recv( unix_fd, buffer, sizeof(buffer), 0 ); -+ if (r < 0) -+ { -+ fprintf(stderr,"ifchange_poll_event(): ifchange read failed!\n"); -+ return; -+ } -+ else if (r != 0) -+ { -+#if defined(NETLINK_ROUTE) -+ struct nlmsghdr *nlh; -+ -+ nlh = (struct nlmsghdr*) buffer; -+ if (NLMSG_OK(nlh, r) && (nlh->nlmsg_type == RTM_NEWADDR || nlh->nlmsg_type == RTM_DELADDR)) -+ wakeup = TRUE; +#endif -+ } -+ if (wakeup) -+ ifchange_wake_up( ifchange, STATUS_SUCCESS ); -+} -+ -+static void ifchange_reselect_async( struct fd *fd, struct async_queue *queue ) -+{ -+ /* do nothing, this object is about to disappear */ -+} + /* create a socket */ DECL_HANDLER(create_socket)