diff --git a/patches/01-Address_Change_Notification/0001-server-Implement-an-interface-change-notification-ob.patch b/patches/01-Address_Change_Notification/0001-server-Implement-an-interface-change-notification-ob.patch deleted file mode 100644 index bb6ccbbf..00000000 --- a/patches/01-Address_Change_Notification/0001-server-Implement-an-interface-change-notification-ob.patch +++ /dev/null @@ -1,481 +0,0 @@ -From 60f7d242951be1980501f45922dbee5480ac2810 Mon Sep 17 00:00:00 2001 -From: "Erich E. Hoover" -Date: Tue, 31 Dec 2013 18:36:58 -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 | 324 ++++++++++++++++++++++++++++++++++++++++++++++++++- - 4 files changed, 334 insertions(+), 17 deletions(-) - -diff --git a/server/event.c b/server/event.c -index b8515af..e8a3888 100644 ---- a/server/event.c -+++ b/server/event.c -@@ -124,6 +124,19 @@ struct event *create_event( struct directory *root, const struct unicode_str *na - return event; - } - -+obj_handle_t alloc_wait_event( struct process *process ) -+{ -+ obj_handle_t handle = 0; -+ struct event *event = create_event( NULL, NULL, 0, 1, 0, NULL ); -+ -+ if (event) -+ { -+ handle = alloc_handle( process, event, EVENT_ALL_ACCESS, 0 ); -+ release_object( event ); -+ } -+ return handle; -+} -+ - struct event *get_event_obj( struct process *process, obj_handle_t handle, unsigned int access ) - { - return (struct event *)get_handle_obj( process, handle, access, &event_ops ); -diff --git a/server/named_pipe.c b/server/named_pipe.c -index 4c85104..6ba2145 100644 ---- a/server/named_pipe.c -+++ b/server/named_pipe.c -@@ -587,19 +587,6 @@ static enum server_fd_type pipe_client_get_fd_type( struct fd *fd ) - return FD_TYPE_PIPE; - } - --static obj_handle_t alloc_wait_event( struct process *process ) --{ -- obj_handle_t handle = 0; -- struct event *event = create_event( NULL, NULL, 0, 1, 0, NULL ); -- -- if (event) -- { -- handle = alloc_handle( process, event, EVENT_ALL_ACCESS, 0 ); -- release_object( event ); -- } -- return handle; --} -- - static obj_handle_t pipe_server_ioctl( struct fd *fd, ioctl_code_t code, const async_data_t *async_data, - int blocking, const void *data, data_size_t size ) - { -diff --git a/server/object.h b/server/object.h -index bb3ff21..bad162f 100644 ---- a/server/object.h -+++ b/server/object.h -@@ -159,6 +159,7 @@ extern struct event *create_event( struct directory *root, const struct unicode_ - const struct security_descriptor *sd ); - extern struct keyed_event *create_keyed_event( struct directory *root, const struct unicode_str *name, - unsigned int attr, const struct security_descriptor *sd ); -+extern obj_handle_t alloc_wait_event( struct process *process ); - extern struct event *get_event_obj( struct process *process, obj_handle_t handle, unsigned int access ); - 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..9c8284d 100644 ---- a/server/sock.c -+++ b/server/sock.c -@@ -23,6 +23,7 @@ - - #include "config.h" - -+#include - #include - #include - #include -@@ -44,11 +45,17 @@ - #include - #include - -+#ifdef HAVE_LINUX_RTNETLINK_H -+# include -+#endif -+ - #include "ntstatus.h" - #define WIN32_NO_STATUS - #include "windef.h" - #include "winternl.h" - #include "winerror.h" -+#define USE_WS_PREFIX -+#include "winsock2.h" - - #include "process.h" - #include "file.h" -@@ -83,9 +90,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,16 +111,28 @@ 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 */ -+ struct async_queue *ifchange_q; /* queue for interface change notifications */ -+ struct list ifchange_entry; /* entry in ifchange notification list */ - }; - -+#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 ); - static void sock_destroy( struct object *obj ); -+static void sock_destroy_ifchange_q( struct sock *sock ); - - 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 ); -+static obj_handle_t sock_ioctl( struct fd *fd, ioctl_code_t code, const async_data_t *async, -+ int blocking, const void *data, data_size_t size ); - 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,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 */ -- default_fd_ioctl, /* ioctl */ -+ sock_ioctl, /* ioctl */ - sock_queue_async, /* queue_async */ - sock_reselect_async, /* reselect_async */ - sock_cancel_async /* cancel_async */ -@@ -518,6 +534,41 @@ static enum server_fd_type sock_get_fd_type( struct fd *fd ) - return FD_TYPE_SOCKET; - } - -+obj_handle_t sock_ioctl( struct fd *fd, ioctl_code_t code, const async_data_t *async_data, -+ int blocking, const void *data, data_size_t size ) -+{ -+#ifdef HAVE_LINUX_RTNETLINK_H -+ struct sock *sock = get_fd_user( fd ); -+ obj_handle_t wait_handle = 0; -+ async_data_t new_data; -+ -+ assert( sock->obj.ops == &sock_ops ); -+ -+ if (blocking) -+ { -+ if (!(wait_handle = alloc_wait_event( current->process ))) return 0; -+ new_data = *async_data; -+ new_data.event = wait_handle; -+ async_data = &new_data; -+ } -+ switch(code) -+ { -+ case WS_SIO_ADDRESS_LIST_CHANGE: -+ if (sock_add_ifchange( sock, async_data )) -+ { -+ set_error( STATUS_PENDING ); -+ return wait_handle; -+ } -+ break; -+ default: -+ /* handled by default_fd_ioctl */ -+ break; -+ } -+ close_handle( current->process, wait_handle ); -+#endif -+ return default_fd_ioctl(fd, code, async_data, blocking, data, size); -+} -+ - static void sock_queue_async( struct fd *fd, const async_data_t *data, int type, int count ) - { - struct sock *sock = get_fd_user( fd ); -@@ -592,6 +643,7 @@ static void sock_destroy( struct object *obj ) - - free_async_queue( sock->read_q ); - free_async_queue( sock->write_q ); -+ sock_destroy_ifchange_q( sock ); - if (sock->event) release_object( sock->event ); - if (sock->fd) - { -@@ -618,6 +670,7 @@ static void init_sock(struct sock *sock) - sock->deferred = NULL; - sock->read_q = NULL; - sock->write_q = NULL; -+ sock->ifchange_q = NULL; - memset( sock->errors, 0, sizeof(sock->errors) ); - } - -@@ -906,6 +959,269 @@ 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 ); -+ -+static int ifchange_get_poll_events( struct fd *fd ); -+static void ifchange_poll_event( struct fd *fd, int event ); -+static void ifchange_reselect_async( struct fd *fd, struct async_queue *queue ); -+ -+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 */ -+}; -+ -+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 */ -+}; -+ -+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 */ -+}; -+ -+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 ); -+ -+ if (ifchange->fd) -+ { -+ /* reset the global ifchange object so that it will be recreated if it is needed again */ -+ assert( obj == ifchange_object ); -+ 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; -+} -+ -+static void ifchange_add_sock( struct object *obj, struct sock *sock ) -+{ -+ struct ifchange *ifchange = (struct ifchange *)obj; -+ -+ list_add_tail( &ifchange->sockets, &sock->ifchange_entry ); -+} -+ -+/* we only need one of these interface notification objects, all of the sockets dependent upon -+ * it will wake up when a notification event occurs */ -+static struct object *grab_ifchange( void ) -+{ -+ struct ifchange *ifchange; -+ struct sockaddr_nl addr; -+ int unix_fd; -+ -+ if (ifchange_object) -+ { -+ /* increment the refcount for each socket that uses the ifchange object */ -+ return grab_object( ifchange_object ); -+ } -+ -+ /* create the socket we need for processing interface change notifications */ -+ unix_fd = socket( PF_NETLINK, SOCK_RAW, NETLINK_ROUTE ); -+ if (unix_fd == -1) -+ { -+ sock_set_error(); -+ return NULL; -+ } -+ fcntl( unix_fd, F_SETFL, O_NONBLOCK ); /* make socket nonblocking */ -+ memset( &addr, 0, sizeof(addr) ); -+ addr.nl_family = AF_NETLINK; -+ addr.nl_groups = RTMGRP_IPV4_IFADDR; -+ /* bind the socket to the special netlink kernel interface */ -+ if (bind( unix_fd, (struct sockaddr *)&addr, sizeof(addr) ) == -1) -+ { -+ sock_set_error(); -+ close( unix_fd ); -+ return NULL; -+ } -+ if (!(ifchange = alloc_object( &ifchange_ops ))) -+ { -+ set_error( STATUS_NO_MEMORY ); -+ close( unix_fd ); -+ return NULL; -+ } -+ list_init( &ifchange->sockets ); -+ if (!(ifchange->fd = create_anonymous_fd( &ifchange_fd_ops, unix_fd, &ifchange->obj, 0 ))) -+ { -+ set_error( STATUS_NO_MEMORY ); -+ release_object( ifchange ); -+ return NULL; -+ } -+ set_fd_events( ifchange->fd, POLLIN ); /* enable read wakeup on the file descriptor */ -+ -+ /* the ifchange object is now successfully configured */ -+ ifchange_object = &ifchange->obj; -+ return ifchange_object; -+} -+ -+/* create a new ifchange queue for a specific socket or, if one already exists, reuse the existing one */ -+static struct async_queue *sock_get_ifchange_q( struct sock *sock ) -+{ -+ struct object *ifchange; -+ struct fd *fd; -+ -+ if (sock->ifchange_q) /* reuse existing ifchange_q for this socket */ -+ return sock->ifchange_q; -+ -+ if (!(ifchange = grab_ifchange())) -+ return NULL; -+ -+ /* create the ifchange notification queue */ -+ fd = ifchange_get_fd( ifchange ); -+ sock->ifchange_q = create_async_queue( fd ); -+ release_object( fd ); -+ if (!sock->ifchange_q) -+ { -+ set_error( STATUS_NO_MEMORY ); -+ release_object( ifchange ); -+ return NULL; -+ } -+ -+ /* add the socket to the ifchange notification list */ -+ ifchange_add_sock( ifchange, sock ); -+ return sock->ifchange_q; -+} -+ -+/* 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 ); -+ assert( obj == ifchange_object ); -+ -+ LIST_FOR_EACH_SAFE( ptr, next, &ifchange->sockets ) -+ { -+ struct sock *sock = LIST_ENTRY( ptr, struct sock, ifchange_entry ); -+ -+ assert( sock->ifchange_q ); -+ async_wake_up( sock->ifchange_q, status ); /* issue ifchange notification for the socket */ -+ sock_destroy_ifchange_q( sock ); /* remove socket from list and decrement ifchange refcount */ -+ } -+} -+ -+static void ifchange_poll_event( struct fd *fd, int event ) -+{ -+ struct object *ifchange = get_fd_user( fd ); -+ unsigned int status = STATUS_PENDING; -+ char buffer[PIPE_BUF]; -+ 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 */ -+static int sock_add_ifchange( struct sock *sock, const async_data_t *async_data ) -+{ -+ struct async_queue *ifchange_q; -+ struct async *async; -+ -+ if (!(ifchange_q = sock_get_ifchange_q( sock ))) -+ return FALSE; -+ -+ if (!(async = create_async( current, ifchange_q, async_data ))) -+ { -+ if (!async_queued( ifchange_q )) -+ sock_destroy_ifchange_q( sock ); -+ -+ set_error( STATUS_NO_MEMORY ); -+ return FALSE; -+ } -+ -+ release_object( async ); -+ return TRUE; -+} -+ -+#endif -+ -+/* destroy an existing ifchange queue for a specific socket */ -+static void sock_destroy_ifchange_q( struct sock *sock ) -+{ -+#ifdef HAVE_LINUX_RTNETLINK_H -+ if (sock->ifchange_q) -+ { -+ assert( ifchange_object ); -+ -+ list_remove( &sock->ifchange_entry ); -+ free_async_queue( sock->ifchange_q ); -+ sock->ifchange_q = NULL; -+ release_object( ifchange_object ); -+ } -+#endif -+} -+ - /* create a socket */ - DECL_HANDLER(create_socket) - { --- -1.7.9.5 - diff --git a/patches/01-Address_Change_Notification/0001-server-Implement-socket-specific-ioctl-routine.patch b/patches/01-Address_Change_Notification/0001-server-Implement-socket-specific-ioctl-routine.patch new file mode 100644 index 00000000..14942c0c --- /dev/null +++ b/patches/01-Address_Change_Notification/0001-server-Implement-socket-specific-ioctl-routine.patch @@ -0,0 +1,77 @@ +From a0625ca7d07703028fdad511c37c587e213ff481 Mon Sep 17 00:00:00 2001 +From: "Erich E. Hoover" +Date: Thu, 3 Apr 2014 09:21:51 -0600 +Subject: server: Implement socket-specific ioctl() routine. + +--- + server/sock.c | 26 ++++++++++++++++++++++---- + 1 file changed, 22 insertions(+), 4 deletions(-) + +diff --git a/server/sock.c b/server/sock.c +index 5ffb1fe..3eb1bdf 100644 +--- a/server/sock.c ++++ b/server/sock.c +@@ -49,6 +49,8 @@ + #include "windef.h" + #include "winternl.h" + #include "winerror.h" ++#define USE_WS_PREFIX ++#include "winsock2.h" + + #include "process.h" + #include "file.h" +@@ -83,9 +85,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 */ +@@ -117,6 +116,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 ); ++static obj_handle_t sock_ioctl( struct fd *fd, ioctl_code_t code, const async_data_t *async, ++ int blocking, const void *data, data_size_t size ); + 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,7 +152,7 @@ static const struct fd_ops sock_fd_ops = + sock_poll_event, /* poll_event */ + no_flush, /* flush */ + sock_get_fd_type, /* get_fd_type */ +- default_fd_ioctl, /* ioctl */ ++ sock_ioctl, /* ioctl */ + sock_queue_async, /* queue_async */ + sock_reselect_async, /* reselect_async */ + sock_cancel_async /* cancel_async */ +@@ -518,6 +519,23 @@ static enum server_fd_type sock_get_fd_type( struct fd *fd ) + return FD_TYPE_SOCKET; + } + ++obj_handle_t sock_ioctl( struct fd *fd, ioctl_code_t code, const async_data_t *async_data, ++ int blocking, const void *data, data_size_t size ) ++{ ++ struct sock *sock = get_fd_user( fd ); ++ ++ assert( sock->obj.ops == &sock_ops ); ++ ++ switch(code) ++ { ++ case WS_SIO_ADDRESS_LIST_CHANGE: ++ /* intentional fallthrough, not yet supported */ ++ default: ++ set_error( STATUS_NOT_SUPPORTED ); ++ return 0; ++ } ++} ++ + static void sock_queue_async( struct fd *fd, const async_data_t *data, int type, int count ) + { + struct sock *sock = get_fd_user( fd ); +-- +1.7.9.5 + diff --git a/patches/01-Address_Change_Notification/0002-server-Add-delayed-processing-for-socket-specific-io.patch b/patches/01-Address_Change_Notification/0002-server-Add-delayed-processing-for-socket-specific-io.patch new file mode 100644 index 00000000..29b1fbaf --- /dev/null +++ b/patches/01-Address_Change_Notification/0002-server-Add-delayed-processing-for-socket-specific-io.patch @@ -0,0 +1,114 @@ +From 45dfbd2ddb5ca2c64fcfd56392be9c55513abc4b Mon Sep 17 00:00:00 2001 +From: "Erich E. Hoover" +Date: Thu, 3 Apr 2014 09:23:02 -0600 +Subject: server: Add delayed processing for socket-specific ioctl(). + +--- + server/event.c | 13 +++++++++++++ + server/named_pipe.c | 13 ------------- + server/object.h | 1 + + server/sock.c | 19 +++++++++++++++++-- + 4 files changed, 31 insertions(+), 15 deletions(-) + +diff --git a/server/event.c b/server/event.c +index 4d3c562..0daa5b2 100644 +--- a/server/event.c ++++ b/server/event.c +@@ -124,6 +124,19 @@ struct event *create_event( struct directory *root, const struct unicode_str *na + return event; + } + ++obj_handle_t alloc_wait_event( struct process *process ) ++{ ++ obj_handle_t handle = 0; ++ struct event *event = create_event( NULL, NULL, 0, 1, 0, NULL ); ++ ++ if (event) ++ { ++ handle = alloc_handle( process, event, EVENT_ALL_ACCESS, 0 ); ++ release_object( event ); ++ } ++ return handle; ++} ++ + struct event *get_event_obj( struct process *process, obj_handle_t handle, unsigned int access ) + { + return (struct event *)get_handle_obj( process, handle, access, &event_ops ); +diff --git a/server/named_pipe.c b/server/named_pipe.c +index 4c85104..6ba2145 100644 +--- a/server/named_pipe.c ++++ b/server/named_pipe.c +@@ -587,19 +587,6 @@ static enum server_fd_type pipe_client_get_fd_type( struct fd *fd ) + return FD_TYPE_PIPE; + } + +-static obj_handle_t alloc_wait_event( struct process *process ) +-{ +- obj_handle_t handle = 0; +- struct event *event = create_event( NULL, NULL, 0, 1, 0, NULL ); +- +- if (event) +- { +- handle = alloc_handle( process, event, EVENT_ALL_ACCESS, 0 ); +- release_object( event ); +- } +- return handle; +-} +- + static obj_handle_t pipe_server_ioctl( struct fd *fd, ioctl_code_t code, const async_data_t *async_data, + int blocking, const void *data, data_size_t size ) + { +diff --git a/server/object.h b/server/object.h +index bb3ff21..bad162f 100644 +--- a/server/object.h ++++ b/server/object.h +@@ -159,6 +159,7 @@ extern struct event *create_event( struct directory *root, const struct unicode_ + const struct security_descriptor *sd ); + extern struct keyed_event *create_keyed_event( struct directory *root, const struct unicode_str *name, + unsigned int attr, const struct security_descriptor *sd ); ++extern obj_handle_t alloc_wait_event( struct process *process ); + extern struct event *get_event_obj( struct process *process, obj_handle_t handle, unsigned int access ); + 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 3eb1bdf..05fc38b 100644 +--- a/server/sock.c ++++ b/server/sock.c +@@ -523,17 +523,32 @@ obj_handle_t sock_ioctl( struct fd *fd, ioctl_code_t code, const async_data_t *a + int blocking, const void *data, data_size_t size ) + { + struct sock *sock = get_fd_user( fd ); ++ obj_handle_t wait_handle = 0; ++ async_data_t new_data; ++ int error; + + assert( sock->obj.ops == &sock_ops ); + ++ if (blocking) ++ { ++ if (!(wait_handle = alloc_wait_event( current->process ))) return 0; ++ new_data = *async_data; ++ new_data.event = wait_handle; ++ async_data = &new_data; ++ } + switch(code) + { + case WS_SIO_ADDRESS_LIST_CHANGE: + /* intentional fallthrough, not yet supported */ + default: +- set_error( STATUS_NOT_SUPPORTED ); +- return 0; ++ error = STATUS_NOT_SUPPORTED; ++ break; + } ++ set_error( error ); ++ if (error == STATUS_PENDING) ++ return wait_handle; ++ close_handle( current->process, wait_handle ); ++ return 0; + } + + static void sock_queue_async( struct fd *fd, const async_data_t *data, int type, int count ) +-- +1.7.9.5 + diff --git a/patches/01-Address_Change_Notification/0003-server-Add-socket-side-support-for-the-interface-cha.patch b/patches/01-Address_Change_Notification/0003-server-Add-socket-side-support-for-the-interface-cha.patch new file mode 100644 index 00000000..38bfe40b --- /dev/null +++ b/patches/01-Address_Change_Notification/0003-server-Add-socket-side-support-for-the-interface-cha.patch @@ -0,0 +1,150 @@ +From 69e77bd226057f486d1c076ccbebb963d3b750ee Mon Sep 17 00:00:00 2001 +From: "Erich E. Hoover" +Date: Thu, 3 Apr 2014 09:25:48 -0600 +Subject: server: Add socket-side support for the interface change + notification object. + +--- + server/sock.c | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 91 insertions(+), 1 deletion(-) + +diff --git a/server/sock.c b/server/sock.c +index 05fc38b..20d022f 100644 +--- a/server/sock.c ++++ b/server/sock.c +@@ -106,12 +106,18 @@ 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 */ ++ struct async_queue *ifchange_q; /* queue for interface change notifications */ ++ struct object *ifchange_obj; /* the interface change notification object */ ++ struct list ifchange_entry; /* entry in ifchange notification list */ + }; + + static void sock_dump( struct object *obj, int verbose ); ++static int sock_add_ifchange( struct sock *sock, const async_data_t *async_data ); + static int sock_signaled( struct object *obj, struct wait_queue_entry *entry ); + static struct fd *sock_get_fd( struct object *obj ); + static void sock_destroy( struct object *obj ); ++static int sock_get_ifchange_q( struct sock *sock, struct async_queue **async_queue ); ++static void sock_destroy_ifchange_q( struct sock *sock ); + + static int sock_get_poll_events( struct fd *fd ); + static void sock_poll_event( struct fd *fd, int event ); +@@ -539,7 +545,8 @@ obj_handle_t sock_ioctl( struct fd *fd, ioctl_code_t code, const async_data_t *a + switch(code) + { + case WS_SIO_ADDRESS_LIST_CHANGE: +- /* intentional fallthrough, not yet supported */ ++ error = sock_add_ifchange( sock, async_data ); ++ break; + default: + error = STATUS_NOT_SUPPORTED; + break; +@@ -625,6 +632,7 @@ static void sock_destroy( struct object *obj ) + + free_async_queue( sock->read_q ); + free_async_queue( sock->write_q ); ++ sock_destroy_ifchange_q( sock ); + if (sock->event) release_object( sock->event ); + if (sock->fd) + { +@@ -651,6 +659,8 @@ static void init_sock(struct sock *sock) + sock->deferred = NULL; + sock->read_q = NULL; + sock->write_q = NULL; ++ sock->ifchange_q = NULL; ++ sock->ifchange_obj = NULL; + memset( sock->errors, 0, sizeof(sock->errors) ); + } + +@@ -939,6 +949,86 @@ static void sock_set_error(void) + set_error( sock_get_ntstatus( errno ) ); + } + ++/* add interface change notification to a socket */ ++static int sock_add_ifchange( struct sock *sock, const async_data_t *async_data ) ++{ ++ struct async_queue *ifchange_q = NULL; ++ struct async *async; ++ int error; ++ ++ error = sock_get_ifchange_q( sock, &ifchange_q ); ++ if (error != STATUS_PENDING) ++ return error; ++ ++ if (!(async = create_async( current, ifchange_q, async_data ))) ++ { ++ if (!async_queued( ifchange_q )) ++ sock_destroy_ifchange_q( sock ); ++ ++ return STATUS_NO_MEMORY; ++ } ++ ++ release_object( async ); ++ return error; ++} ++ ++/* stub ifchange object */ ++static int get_ifchange( struct object **obj ) ++{ ++ return STATUS_NOT_SUPPORTED; ++} ++ ++/* stub ifchange add socket to list */ ++static void ifchange_add_sock( struct object *obj, struct sock *sock ) ++{ ++} ++ ++/* create a new ifchange queue for a specific socket or, if one already exists, reuse the existing one */ ++static int sock_get_ifchange_q( struct sock *sock, struct async_queue **async_queue ) ++{ ++ struct object *ifchange = NULL; ++ struct fd *fd; ++ int error; ++ ++ if (sock->ifchange_q) /* reuse existing ifchange_q for this socket */ ++ { ++ *async_queue = sock->ifchange_q; ++ return STATUS_PENDING; ++ } ++ ++ error = get_ifchange( &ifchange ); ++ if (error != STATUS_PENDING) ++ return error; ++ ++ /* create the ifchange notification queue */ ++ fd = ifchange->ops->get_fd( ifchange ); ++ sock->ifchange_q = create_async_queue( fd ); ++ release_object( fd ); ++ if (!sock->ifchange_q) ++ { ++ release_object( ifchange ); ++ return STATUS_NO_MEMORY; ++ } ++ ++ /* add the socket to the ifchange notification list */ ++ ifchange_add_sock( ifchange, sock ); ++ sock->ifchange_obj = ifchange; ++ *async_queue = sock->ifchange_q; ++ return error; ++} ++ ++/* destroy an existing ifchange queue for a specific socket */ ++static void sock_destroy_ifchange_q( struct sock *sock ) ++{ ++ if (sock->ifchange_q) ++ { ++ list_remove( &sock->ifchange_entry ); ++ free_async_queue( sock->ifchange_q ); ++ sock->ifchange_q = NULL; ++ release_object( sock->ifchange_obj ); ++ } ++} ++ + /* create a socket */ + DECL_HANDLER(create_socket) + { +-- +1.7.9.5 + diff --git a/patches/01-Address_Change_Notification/0004-server-Implement-the-interface-change-notification-o.patch b/patches/01-Address_Change_Notification/0004-server-Implement-the-interface-change-notification-o.patch new file mode 100644 index 00000000..a346c4b3 --- /dev/null +++ b/patches/01-Address_Change_Notification/0004-server-Implement-the-interface-change-notification-o.patch @@ -0,0 +1,237 @@ +From 85d0475a493be336c340f25cab9895846e202f26 Mon Sep 17 00:00:00 2001 +From: "Erich E. Hoover" +Date: Thu, 3 Apr 2014 09:26:34 -0600 +Subject: server: Implement the interface change notification object. + +--- + server/sock.c | 200 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 198 insertions(+), 2 deletions(-) + +diff --git a/server/sock.c b/server/sock.c +index 20d022f..82464f2 100644 +--- a/server/sock.c ++++ b/server/sock.c +@@ -43,6 +43,10 @@ + #endif + #include + #include ++#include ++#ifdef HAVE_LINUX_RTNETLINK_H ++# include ++#endif + + #include "ntstatus.h" + #define WIN32_NO_STATUS +@@ -972,15 +976,207 @@ static int sock_add_ifchange( struct sock *sock, const async_data_t *async_data + return error; + } + +-/* stub ifchange object */ ++#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 void ifchange_dump( struct object *obj, int verbose ); ++static struct fd *ifchange_get_fd( struct object *obj ); ++static void ifchange_destroy( struct object *obj ); ++ ++static int ifchange_get_poll_events( struct fd *fd ); ++static void ifchange_poll_event( struct fd *fd, int event ); ++static void ifchange_reselect_async( struct fd *fd, struct async_queue *queue ); ++ ++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 */ ++}; ++ ++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 */ ++}; ++ ++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 */ ++}; ++ ++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 ); ++ ++ if (ifchange->fd) ++ { ++ /* reset the global ifchange object so that it will be recreated if it is needed again */ ++ assert( obj == ifchange_object ); ++ 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 ); ++ assert( obj == ifchange_object ); ++ ++ LIST_FOR_EACH_SAFE( ptr, next, &ifchange->sockets ) ++ { ++ struct sock *sock = LIST_ENTRY( ptr, struct sock, ifchange_entry ); ++ ++ assert( sock->ifchange_q ); ++ async_wake_up( sock->ifchange_q, status ); /* issue ifchange notification for the socket */ ++ sock_destroy_ifchange_q( sock ); /* remove socket from list and decrement ifchange refcount */ ++ } ++} ++ ++static void ifchange_poll_event( struct fd *fd, int event ) ++{ ++ struct object *ifchange = get_fd_user( fd ); ++ unsigned int status = STATUS_PENDING; ++ char buffer[PIPE_BUF]; ++ 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 */ ++} ++ ++#endif ++ ++/* we only need one of these interface notification objects, all of the sockets dependent upon ++ * it will wake up when a notification event occurs */ + static int get_ifchange( struct object **obj ) + { ++#ifdef HAVE_LINUX_RTNETLINK_H ++ struct ifchange *ifchange; ++ struct sockaddr_nl addr; ++ int unix_fd; ++ ++ if (ifchange_object) ++ { ++ /* increment the refcount for each socket that uses the ifchange object */ ++ *obj = grab_object( ifchange_object ); ++ return STATUS_PENDING; ++ } ++ ++ /* create the socket we need for processing interface change notifications */ ++ unix_fd = socket( PF_NETLINK, SOCK_RAW, NETLINK_ROUTE ); ++ if (unix_fd == -1) ++ return sock_get_ntstatus( errno ); ++ fcntl( unix_fd, F_SETFL, O_NONBLOCK ); /* make socket nonblocking */ ++ memset( &addr, 0, sizeof(addr) ); ++ addr.nl_family = AF_NETLINK; ++ addr.nl_groups = RTMGRP_IPV4_IFADDR; ++ /* bind the socket to the special netlink kernel interface */ ++ if (bind( unix_fd, (struct sockaddr *)&addr, sizeof(addr) ) == -1) ++ { ++ close( unix_fd ); ++ return sock_get_ntstatus( errno ); ++ } ++ if (!(ifchange = alloc_object( &ifchange_ops ))) ++ { ++ close( unix_fd ); ++ return STATUS_NO_MEMORY; ++ } ++ list_init( &ifchange->sockets ); ++ if (!(ifchange->fd = create_anonymous_fd( &ifchange_fd_ops, unix_fd, &ifchange->obj, 0 ))) ++ { ++ release_object( ifchange ); ++ return STATUS_NO_MEMORY; ++ } ++ set_fd_events( ifchange->fd, POLLIN ); /* enable read wakeup on the file descriptor */ ++ ++ /* the ifchange object is now successfully configured */ ++ ifchange_object = &ifchange->obj; ++ *obj = &ifchange->obj; ++ return STATUS_PENDING; ++#else + return STATUS_NOT_SUPPORTED; ++#endif + } + +-/* stub ifchange add socket to list */ ++/* add the socket to the interface change notification list */ + static void ifchange_add_sock( struct object *obj, struct sock *sock ) + { ++#ifdef HAVE_LINUX_RTNETLINK_H ++ struct ifchange *ifchange = (struct ifchange *)obj; ++ ++ list_add_tail( &ifchange->sockets, &sock->ifchange_entry ); ++#endif + } + + /* create a new ifchange queue for a specific socket or, if one already exists, reuse the existing one */ +-- +1.7.9.5 + diff --git a/patches/01-Address_Change_Notification/0002-ws2_32-Add-an-interactive-test-for-interface-change-.patch b/patches/01-Address_Change_Notification/0005-ws2_32-Add-an-interactive-test-for-interface-change-.patch similarity index 93% rename from patches/01-Address_Change_Notification/0002-ws2_32-Add-an-interactive-test-for-interface-change-.patch rename to patches/01-Address_Change_Notification/0005-ws2_32-Add-an-interactive-test-for-interface-change-.patch index 5e5e4716..ec04664d 100644 --- a/patches/01-Address_Change_Notification/0002-ws2_32-Add-an-interactive-test-for-interface-change-.patch +++ b/patches/01-Address_Change_Notification/0005-ws2_32-Add-an-interactive-test-for-interface-change-.patch @@ -1,6 +1,6 @@ -From b3156dc253a94f9414a04569181728ec43608f2a Mon Sep 17 00:00:00 2001 +From 621fe55cd32221c542df779540d3bc8ea701821d Mon Sep 17 00:00:00 2001 From: "Erich E. Hoover" -Date: Mon, 18 Nov 2013 17:22:14 -0700 +Date: Thu, 3 Apr 2014 09:26:45 -0600 Subject: ws2_32: Add an interactive test for interface change notifications. --- @@ -8,10 +8,10 @@ Subject: ws2_32: Add an interactive test for interface change notifications. 1 file changed, 68 insertions(+) diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c -index 0abf732..4703e59 100644 +index dcedd99..e55273a 100644 --- a/dlls/ws2_32/tests/sock.c +++ b/dlls/ws2_32/tests/sock.c -@@ -6487,6 +6487,73 @@ static void test_sioRoutingInterfaceQuery(void) +@@ -6607,6 +6607,73 @@ static void test_sioRoutingInterfaceQuery(void) closesocket(sock); } @@ -85,7 +85,7 @@ index 0abf732..4703e59 100644 static void test_synchronous_WSAIoctl(void) { HANDLE previous_port, io_port; -@@ -7570,6 +7637,7 @@ START_TEST( sock ) +@@ -7694,6 +7761,7 @@ START_TEST( sock ) test_ConnectEx(); test_sioRoutingInterfaceQuery(); diff --git a/patches/01-Address_Change_Notification/8a366b6d-8ad6-4581-8aa9-66a03590a57b.def b/patches/01-Address_Change_Notification/8a366b6d-8ad6-4581-8aa9-66a03590a57b.def index 09e0da2d..92589fd7 100644 --- a/patches/01-Address_Change_Notification/8a366b6d-8ad6-4581-8aa9-66a03590a57b.def +++ b/patches/01-Address_Change_Notification/8a366b6d-8ad6-4581-8aa9-66a03590a57b.def @@ -1,3 +1,3 @@ -Revision: 1 +Revision: 2 Author: Erich E. Hoover Title: Implement SIO_ADDRESS_LIST_CHANGE. diff --git a/patches/patch-list.patch b/patches/patch-list.patch index c5ef03cd..0a56c597 100644 --- a/patches/patch-list.patch +++ b/patches/patch-list.patch @@ -46,7 +46,7 @@ index a273502..5fa0cd5 100644 + const char *author; + const char *title; +} wine_patch_data[] = { -+ { "8a366b6d-8ad6-4581-8aa9-66a03590a57b:1", "Erich E. Hoover", "Implement SIO_ADDRESS_LIST_CHANGE." }, ++ { "8a366b6d-8ad6-4581-8aa9-66a03590a57b:2", "Erich E. Hoover", "Implement SIO_ADDRESS_LIST_CHANGE." }, + { "92938b89-506b-430a-ba50-32de8b286e56:2", "Erich E. Hoover", "Store and return security attributes with extended file attributes." }, + { "9cb0f665-bf7c-485f-89cc-554adcdf8880:2", "Erich E. Hoover", "Allow string comparison with linguistic casing." }, + { "5d6bb7b5-ec88-4ed3-907d-9ad2173a2f88:1", "Sebastian Lackner", "Enable/disable windows when they are (un)mapped by foreign applications." },