mirror of
https://gitlab.winehq.org/wine/wine-staging.git
synced 2025-01-28 22:04:43 -08:00
Removed patches for SIO_ADDRESS_LIST_CHANGE ioctl (accepted upstream).
This commit is contained in:
parent
1ffd40e9de
commit
5188eda906
@ -193,7 +193,7 @@ Included bug fixes and improvements
|
||||
* Support for WTSEnumerateProcessesW ([Wine Bug #29903](https://bugs.winehq.org/show_bug.cgi?id=29903))
|
||||
* Support for extra large and jumbo icon lists in shell32 ([Wine Bug #24721](https://bugs.winehq.org/show_bug.cgi?id=24721))
|
||||
* Support for inherited file ACLs ([Wine Bug #34406](https://bugs.winehq.org/show_bug.cgi?id=34406))
|
||||
* Support for interface change notifications ([Wine Bug #32328](https://bugs.winehq.org/show_bug.cgi?id=32328))
|
||||
* ~~Support for interface change notifications~~ ([Wine Bug #32328](https://bugs.winehq.org/show_bug.cgi?id=32328))
|
||||
* Support for loader dll redirections
|
||||
* Support for named pipe message mode (Linux only) ([Wine Bug #17195](https://bugs.winehq.org/show_bug.cgi?id=17195))
|
||||
* Support for pasting HTML from Unix applications ([Wine Bug #7372](https://bugs.winehq.org/show_bug.cgi?id=7372))
|
||||
|
1
debian/changelog
vendored
1
debian/changelog
vendored
@ -4,6 +4,7 @@ wine-staging (1.7.37) UNRELEASED; urgency=low
|
||||
* Added patch to avoid race-conditions in NtReadFile() operations with write watches.
|
||||
* Added patch to avoid race-conditions with write watches in WS2_async_accept.
|
||||
* Removed patches for UTF7 support (accepted upstream).
|
||||
* Removed patches for SIO_ADDRESS_LIST_CHANGE ioctl (accepted upstream).
|
||||
-- Sebastian Lackner <sebastian@fds-team.de> Sun, 08 Feb 2015 20:29:38 +0100
|
||||
|
||||
wine-staging (1.7.36) unstable; urgency=low
|
||||
|
@ -150,7 +150,6 @@ patch_enable_all ()
|
||||
enable_riched20_IText_Interface="$1"
|
||||
enable_secur32_Schannel_ContextAttr="$1"
|
||||
enable_server_ACL_Compat="$1"
|
||||
enable_server_Address_Change_Notification="$1"
|
||||
enable_server_ClipCursor="$1"
|
||||
enable_server_CreateProcess_ACLs="$1"
|
||||
enable_server_Inherited_ACLs="$1"
|
||||
@ -478,9 +477,6 @@ patch_enable ()
|
||||
server-ACL_Compat)
|
||||
enable_server_ACL_Compat="$2"
|
||||
;;
|
||||
server-Address_Change_Notification)
|
||||
enable_server_Address_Change_Notification="$2"
|
||||
;;
|
||||
server-ClipCursor)
|
||||
enable_server_ClipCursor="$2"
|
||||
;;
|
||||
@ -2670,29 +2666,6 @@ if test "$enable_server_ACL_Compat" -eq 1; then
|
||||
) >> "$patchlist"
|
||||
fi
|
||||
|
||||
# Patchset server-Address_Change_Notification
|
||||
# |
|
||||
# | This patchset fixes the following Wine bugs:
|
||||
# | * [#32328] Support for interface change notifications
|
||||
# |
|
||||
# | Modified files:
|
||||
# | * Makefile.in, dlls/ws2_32/tests/sock.c, server/event.c, server/named_pipe.c, server/object.h, server/sock.c
|
||||
# |
|
||||
if test "$enable_server_Address_Change_Notification" -eq 1; then
|
||||
patch_apply server-Address_Change_Notification/0001-server-Implement-socket-specific-ioctl-routine.patch
|
||||
patch_apply server-Address_Change_Notification/0002-server-Add-socket-side-support-for-the-interface-cha.patch
|
||||
patch_apply server-Address_Change_Notification/0003-server-Add-blocked-support-for-SIO_ADDRESS_LIST_CHAN.patch
|
||||
patch_apply server-Address_Change_Notification/0004-server-Implement-the-interface-change-notification-o.patch
|
||||
patch_apply server-Address_Change_Notification/0005-ws2_32-Add-an-interactive-test-for-interface-change-.patch
|
||||
(
|
||||
echo '+ { "Erich E. Hoover", "server: Implement socket-specific ioctl() routine.", 1 },';
|
||||
echo '+ { "Erich E. Hoover", "server: Add socket-side support for the interface change notification object.", 1 },';
|
||||
echo '+ { "Erich E. Hoover", "server: Add blocked support for SIO_ADDRESS_LIST_CHANGE ioctl().", 1 },';
|
||||
echo '+ { "Erich E. Hoover", "server: Implement the interface change notification object.", 2 },';
|
||||
echo '+ { "Erich E. Hoover", "ws2_32: Add an interactive test for interface change notifications.", 1 },';
|
||||
) >> "$patchlist"
|
||||
fi
|
||||
|
||||
# Patchset server-ClipCursor
|
||||
# |
|
||||
# | This patchset fixes the following Wine bugs:
|
||||
|
@ -1,92 +0,0 @@
|
||||
From f9cff65e9092054ff1398dc426c0b8b19a3c0d8f Mon Sep 17 00:00:00 2001
|
||||
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
|
||||
Date: Thu, 3 Apr 2014 09:21:51 -0600
|
||||
Subject: server: Implement socket-specific ioctl() routine.
|
||||
|
||||
---
|
||||
Makefile.in | 3 ++-
|
||||
server/sock.c | 26 ++++++++++++++++++++++----
|
||||
2 files changed, 24 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/Makefile.in b/Makefile.in
|
||||
index 5c163b8..b600cf7 100644
|
||||
--- a/Makefile.in
|
||||
+++ b/Makefile.in
|
||||
@@ -52,7 +52,8 @@ __tooldeps__: libs/port libs/wine libs/wpp
|
||||
__builddeps__: __tooldeps__ include
|
||||
.PHONY: depend check test testclean crosstest __tooldeps__ __builddeps__
|
||||
|
||||
-loader server: libs/port libs/wine tools
|
||||
+loader: libs/port libs/wine tools
|
||||
+server: libs/port libs/wine tools include
|
||||
fonts: tools/sfnt2fon
|
||||
include: tools tools/widl
|
||||
libs/wine tools: libs/port
|
||||
diff --git a/server/sock.c b/server/sock.c
|
||||
index 4adad0f..ed36dcc 100644
|
||||
--- a/server/sock.c
|
||||
+++ b/server/sock.c
|
||||
@@ -52,6 +52,8 @@
|
||||
#include "windef.h"
|
||||
#include "winternl.h"
|
||||
#include "winerror.h"
|
||||
+#define USE_WS_PREFIX
|
||||
+#include "winsock2.h"
|
||||
|
||||
#include "process.h"
|
||||
#include "file.h"
|
||||
@@ -86,9 +88,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 */
|
||||
@@ -120,6 +119,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 );
|
||||
@@ -154,7 +155,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 */
|
||||
@@ -521,6 +522,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
|
||||
|
@ -1,145 +0,0 @@
|
||||
From 864781654bfbb059a351fdcda6773e2857019278 Mon Sep 17 00:00:00 2001
|
||||
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
|
||||
Date: Tue, 6 May 2014 08:39:18 -0600
|
||||
Subject: server: Add socket-side support for the interface change
|
||||
notification object.
|
||||
|
||||
---
|
||||
server/sock.c | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
|
||||
1 file changed, 86 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/server/sock.c b/server/sock.c
|
||||
index 3eb1bdf..ad20a69 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 void 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 struct async_queue *sock_get_ifchange_q( struct sock *sock );
|
||||
+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 );
|
||||
@@ -529,7 +535,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 */
|
||||
+ sock_add_ifchange( sock, async_data );
|
||||
+ return 0;
|
||||
default:
|
||||
set_error( STATUS_NOT_SUPPORTED );
|
||||
return 0;
|
||||
@@ -610,6 +617,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)
|
||||
{
|
||||
@@ -636,6 +644,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) );
|
||||
}
|
||||
|
||||
@@ -924,6 +934,81 @@ static void sock_set_error(void)
|
||||
set_error( sock_get_ntstatus( errno ) );
|
||||
}
|
||||
|
||||
+/* add interface change notification to a socket */
|
||||
+static void sock_add_ifchange( struct sock *sock, const async_data_t *async_data )
|
||||
+{
|
||||
+ struct async_queue *ifchange_q = NULL;
|
||||
+ struct async *async;
|
||||
+
|
||||
+ if (!(ifchange_q = sock_get_ifchange_q( sock )))
|
||||
+ return;
|
||||
+
|
||||
+ 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;
|
||||
+ }
|
||||
+
|
||||
+ release_object( async );
|
||||
+ set_error( STATUS_PENDING );
|
||||
+}
|
||||
+
|
||||
+/* stub ifchange object */
|
||||
+static struct object *get_ifchange( void )
|
||||
+{
|
||||
+ set_error( STATUS_NOT_SUPPORTED );
|
||||
+ return NULL;
|
||||
+}
|
||||
+
|
||||
+/* 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 struct async_queue *sock_get_ifchange_q( struct sock *sock )
|
||||
+{
|
||||
+ struct object *ifchange = NULL;
|
||||
+ struct fd *fd;
|
||||
+
|
||||
+ if (sock->ifchange_q) /* reuse existing ifchange_q for this socket */
|
||||
+ return sock->ifchange_q;
|
||||
+
|
||||
+ if (!(ifchange = get_ifchange()))
|
||||
+ return NULL;
|
||||
+
|
||||
+ /* 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 );
|
||||
+ set_error( STATUS_NO_MEMORY );
|
||||
+ return NULL;
|
||||
+ }
|
||||
+
|
||||
+ /* add the socket to the ifchange notification list */
|
||||
+ ifchange_add_sock( ifchange, sock );
|
||||
+ sock->ifchange_obj = ifchange;
|
||||
+ return sock->ifchange_q;
|
||||
+}
|
||||
+
|
||||
+/* 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
|
||||
|
@ -1,148 +0,0 @@
|
||||
From c93a05ca0114b76c542f251de60b8c009e4a72b0 Mon Sep 17 00:00:00 2001
|
||||
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
|
||||
Date: Tue, 6 May 2014 08:44:59 -0600
|
||||
Subject: server: Add blocked support for SIO_ADDRESS_LIST_CHANGE ioctl().
|
||||
|
||||
---
|
||||
server/event.c | 13 +++++++++++++
|
||||
server/named_pipe.c | 13 -------------
|
||||
server/object.h | 1 +
|
||||
server/sock.c | 26 ++++++++++++++++++++------
|
||||
4 files changed, 34 insertions(+), 19 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 ad20a69..a8a5ac3 100644
|
||||
--- a/server/sock.c
|
||||
+++ b/server/sock.c
|
||||
@@ -112,7 +112,7 @@ struct sock
|
||||
};
|
||||
|
||||
static void sock_dump( struct object *obj, int verbose );
|
||||
-static void sock_add_ifchange( struct sock *sock, const async_data_t *async_data );
|
||||
+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 );
|
||||
@@ -529,14 +529,27 @@ 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;
|
||||
|
||||
assert( sock->obj.ops == &sock_ops );
|
||||
|
||||
switch(code)
|
||||
{
|
||||
case WS_SIO_ADDRESS_LIST_CHANGE:
|
||||
- sock_add_ifchange( sock, async_data );
|
||||
- return 0;
|
||||
+ 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;
|
||||
+ }
|
||||
+ if (!sock_add_ifchange( sock, async_data ) && wait_handle)
|
||||
+ {
|
||||
+ close_handle( current->process, wait_handle );
|
||||
+ return 0;
|
||||
+ }
|
||||
+ return wait_handle;
|
||||
default:
|
||||
set_error( STATUS_NOT_SUPPORTED );
|
||||
return 0;
|
||||
@@ -935,13 +948,13 @@ static void sock_set_error(void)
|
||||
}
|
||||
|
||||
/* add interface change notification to a socket */
|
||||
-static void sock_add_ifchange( struct sock *sock, const async_data_t *async_data )
|
||||
+static int sock_add_ifchange( struct sock *sock, const async_data_t *async_data )
|
||||
{
|
||||
struct async_queue *ifchange_q = NULL;
|
||||
struct async *async;
|
||||
|
||||
if (!(ifchange_q = sock_get_ifchange_q( sock )))
|
||||
- return;
|
||||
+ return FALSE;
|
||||
|
||||
if (!(async = create_async( current, ifchange_q, async_data )))
|
||||
{
|
||||
@@ -949,11 +962,12 @@ static void sock_add_ifchange( struct sock *sock, const async_data_t *async_data
|
||||
sock_destroy_ifchange_q( sock );
|
||||
|
||||
set_error( STATUS_NO_MEMORY );
|
||||
- return;
|
||||
+ return FALSE;
|
||||
}
|
||||
|
||||
release_object( async );
|
||||
set_error( STATUS_PENDING );
|
||||
+ return TRUE;
|
||||
}
|
||||
|
||||
/* stub ifchange object */
|
||||
--
|
||||
1.7.9.5
|
||||
|
@ -1,243 +0,0 @@
|
||||
From 55c83dc866e2d0e2cdc15b976b6d818a03ef4b89 Mon Sep 17 00:00:00 2001
|
||||
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
|
||||
Date: Tue, 6 May 2014 08:49:52 -0600
|
||||
Subject: server: Implement the interface change notification object. (try 2)
|
||||
|
||||
---
|
||||
server/sock.c | 206 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
|
||||
1 file changed, 203 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/server/sock.c b/server/sock.c
|
||||
index a8a5ac3..2af9acc 100644
|
||||
--- a/server/sock.c
|
||||
+++ b/server/sock.c
|
||||
@@ -43,6 +43,10 @@
|
||||
#endif
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
+#include <limits.h>
|
||||
+#ifdef HAVE_LINUX_RTNETLINK_H
|
||||
+# include <linux/rtnetlink.h>
|
||||
+#endif
|
||||
|
||||
#include "ntstatus.h"
|
||||
#define WIN32_NO_STATUS
|
||||
@@ -970,16 +974,212 @@ static int sock_add_ifchange( struct sock *sock, const async_data_t *async_data
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
-/* stub ifchange object */
|
||||
-static struct object *get_ifchange( void )
|
||||
+#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 struct object *get_ifchange( void )
|
||||
+ {
|
||||
+#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 */
|
||||
+ 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)
|
||||
+ {
|
||||
+ close( unix_fd );
|
||||
+ sock_set_error();
|
||||
+ return NULL;
|
||||
+ }
|
||||
+ if (!(ifchange = alloc_object( &ifchange_ops )))
|
||||
+ {
|
||||
+ close( unix_fd );
|
||||
+ set_error( STATUS_NO_MEMORY );
|
||||
+ return NULL;
|
||||
+ }
|
||||
+ list_init( &ifchange->sockets );
|
||||
+ if (!(ifchange->fd = create_anonymous_fd( &ifchange_fd_ops, unix_fd, &ifchange->obj, 0 )))
|
||||
+ {
|
||||
+ release_object( ifchange );
|
||||
+ set_error( STATUS_NO_MEMORY );
|
||||
+ 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->obj;
|
||||
+#else
|
||||
set_error( STATUS_NOT_SUPPORTED );
|
||||
return NULL;
|
||||
+#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
|
||||
|
@ -1,98 +0,0 @@
|
||||
From 621fe55cd32221c542df779540d3bc8ea701821d Mon Sep 17 00:00:00 2001
|
||||
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
|
||||
Date: Thu, 3 Apr 2014 09:26:45 -0600
|
||||
Subject: ws2_32: Add an interactive test for interface change notifications.
|
||||
|
||||
---
|
||||
dlls/ws2_32/tests/sock.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 68 insertions(+)
|
||||
|
||||
diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c
|
||||
index dcedd99..e55273a 100644
|
||||
--- a/dlls/ws2_32/tests/sock.c
|
||||
+++ b/dlls/ws2_32/tests/sock.c
|
||||
@@ -6607,6 +6607,73 @@ static void test_sioRoutingInterfaceQuery(void)
|
||||
closesocket(sock);
|
||||
}
|
||||
|
||||
+static void test_sioAddressListChange(void)
|
||||
+{
|
||||
+ struct sockaddr_in bindAddress;
|
||||
+ struct in_addr net_address;
|
||||
+ WSAOVERLAPPED overlapped;
|
||||
+ struct hostent *h;
|
||||
+ DWORD num_bytes;
|
||||
+ SOCKET sock;
|
||||
+ int acount;
|
||||
+ int ret;
|
||||
+
|
||||
+ if (!winetest_interactive)
|
||||
+ {
|
||||
+ skip("Cannot test SIO_ADDRESS_LIST_CHANGE, interactive tests must be enabled\n");
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ /* Use gethostbyname to find the list of local network interfaces */
|
||||
+ h = gethostbyname("");
|
||||
+ if (!h)
|
||||
+ {
|
||||
+ skip("Cannot test SIO_ADDRESS_LIST_CHANGE, gethostbyname failed with %u\n",
|
||||
+ WSAGetLastError());
|
||||
+ return;
|
||||
+ }
|
||||
+ for (acount = 0; h->h_addr_list[acount]; acount++);
|
||||
+ if (acount == 0)
|
||||
+ {
|
||||
+ skip("Cannot test SIO_ADDRESS_LIST_CHANGE, test requires a network card.\n");
|
||||
+ return;
|
||||
+ }
|
||||
+ net_address.s_addr = *(ULONG *) h->h_addr_list[0];
|
||||
+
|
||||
+ /* Bind an overlapped socket to the first found network interface */
|
||||
+ sock = WSASocketW(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);
|
||||
+ ok(sock != INVALID_SOCKET, "Expected socket to return a valid socket\n");
|
||||
+ if (sock == INVALID_SOCKET)
|
||||
+ {
|
||||
+ skip("Cannot test SIO_ADDRESS_LIST_CHANGE, socket creation failed with %u\n",
|
||||
+ WSAGetLastError());
|
||||
+ return;
|
||||
+ }
|
||||
+ memset(&bindAddress, 0, sizeof(bindAddress));
|
||||
+ bindAddress.sin_family = AF_INET;
|
||||
+ bindAddress.sin_addr.s_addr = net_address.s_addr;
|
||||
+ ret = bind(sock, (struct sockaddr*)&bindAddress, sizeof(bindAddress));
|
||||
+ if (ret != 0)
|
||||
+ {
|
||||
+ skip("Cannot test SIO_ADDRESS_LIST_CHANGE, failed to bind, error %u\n", WSAGetLastError());
|
||||
+ goto end;
|
||||
+ }
|
||||
+
|
||||
+ /* Wait for address changes, request that the user connect/disconnect an interface */
|
||||
+ memset(&overlapped, 0, sizeof(overlapped));
|
||||
+ overlapped.hEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
|
||||
+ ret = WSAIoctl(sock, SIO_ADDRESS_LIST_CHANGE, NULL, 0, NULL, 0, &num_bytes, &overlapped, NULL);
|
||||
+ ok(ret == SOCKET_ERROR, "WSAIoctl succeeded unexpectedly\n");
|
||||
+ ok(WSAGetLastError() == WSA_IO_PENDING, "Expected pending last error %d\n", WSAGetLastError());
|
||||
+ trace("Testing socket-based ipv4 address list change notification. Please connect/disconnect or"
|
||||
+ " change the ipv4 address of any of the local network interfaces (10 second timeout).\n");
|
||||
+ ret = WaitForSingleObject(overlapped.hEvent, 10000);
|
||||
+ ok(ret == WAIT_OBJECT_0, "failed to get overlapped event %u\n", ret);
|
||||
+
|
||||
+end:
|
||||
+ closesocket(sock);
|
||||
+}
|
||||
+
|
||||
static void test_synchronous_WSAIoctl(void)
|
||||
{
|
||||
HANDLE previous_port, io_port;
|
||||
@@ -7694,6 +7761,7 @@ START_TEST( sock )
|
||||
test_ConnectEx();
|
||||
|
||||
test_sioRoutingInterfaceQuery();
|
||||
+ test_sioAddressListChange();
|
||||
|
||||
test_WSALookupService();
|
||||
|
||||
--
|
||||
1.7.9.5
|
||||
|
@ -1 +0,0 @@
|
||||
Fixes: [32328] Support for interface change notifications
|
Loading…
x
Reference in New Issue
Block a user