From: "Erich E. Hoover" Subject: [PATCH 2/6] server: Add socket-side support for the interface change notification object. Message-Id: Date: Tue, 20 Jan 2015 14:46:30 -0700 This patch adds an async queue, list object, and interface change object to the socket object in order to support interface change notification objects (fully implemented in part 4). Note: This patch has been revised since the last review b/c AJ requested that changing the error code occur at each step, rather than being passed up to the ioctl() routine. From 9181be1db48843fa98d677ec75c0b283a17dc388 Mon Sep 17 00:00:00 2001 From: "Erich E. Hoover" 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 6a75934..5b7ed31 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 = 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.9.1