From 315de61bb20a17862911c2e77df7ab25c794e57c Mon Sep 17 00:00:00 2001 From: "Erich E. Hoover" Date: Tue, 6 May 2014 08:39:18 -0600 Subject: [PATCH] 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 6a759347708..8c8db8778ae 100644 --- a/server/sock.c +++ b/server/sock.c @@ -110,12 +110,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 ); @@ -534,7 +540,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; @@ -615,6 +622,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) { @@ -642,6 +650,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) ); } @@ -933,6 +943,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; + 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; + 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) {