server: Add socket-side support for the interface change notification object.

This commit is contained in:
Erich E. Hoover 2014-05-06 08:39:18 -06:00 committed by Alexandre Julliard
parent 1239663fcb
commit 315de61bb2

View file

@ -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)
{