Habilitación y deshabilitación de funciones de devolución de llamada de eventos
Una aplicación winsock Kernel (WSK) puede implementar funciones de devolución de llamada de eventos que el subsistema WSK llama de forma asincrónica para notificar a la aplicación cuando se producen determinados eventos en un socket. Una aplicación WSK puede proporcionar una estructura de tabla de distribución de cliente al subsistema WSK siempre que crea un socket o acepta un socket en un socket de escucha. Esta tabla de distribución contiene punteros a las funciones de devolución de llamada de eventos de la aplicación WSK para el nuevo socket. Si una aplicación WSK no implementa ninguna función de devolución de llamada de eventos para un socket determinado, no es necesario proporcionar una estructura de tabla de distribución de cliente al subsistema WSK para ese socket.
Todas las funciones de devolución de llamada de eventos de un socket, excepto para las funciones de devolución de llamada de eventos WskInspectEvent y WskAbortEvent de un socket de escucha, se pueden habilitar o deshabilitar mediante la opción de socket SO_WSK_EVENT_CALLBACK . Una aplicación WSK puede habilitar varias funciones de devolución de llamada de eventos en un socket al mismo tiempo. Sin embargo, una aplicación WSK debe deshabilitar individualmente cada función de devolución de llamada de eventos.
En el ejemplo de código siguiente se muestra cómo una aplicación WSK puede usar la opción de socket SO_WSK_EVENT_CALLBACK para habilitar las funciones de devolución de llamada de eventos WskDisconnectEvent y WskReceiveEvent en un socket orientado a la conexión.
// Function to enable the WskDisconnectEvent and WskReceiveEvent
// event callback functions on a connection-oriented socket
NTSTATUS
EnableDisconnectAndRecieveCallbacks(
PWSK_SOCKET Socket
)
{
PWSK_PROVIDER_CONNECTION_DISPATCH Dispatch;
WSK_EVENT_CALLBACK_CONTROL EventCallbackControl;
NTSTATUS Status;
// Get pointer to the socket's provider dispatch structure
Dispatch =
(PWSK_PROVIDER_CONNECTION_DISPATCH)(Socket->Dispatch);
// Specify the WSK NPI identifier
EventCallbackControl.NpiId = &NPI_WSK_INTERFACE_ID;
// Set the event flags for the event callback functions that
// are to be enabled on the socket
EventCallbackControl.EventMask =
WSK_EVENT_DISCONNECT | WSK_EVENT_RECEIVE;
// Initiate the control operation on the socket
Status =
Dispatch->WskControlSocket(
Socket,
WskSetOption,
SO_WSK_EVENT_CALLBACK,
SOL_SOCKET,
sizeof(WSK_EVENT_CALLBACK_CONTROL),
&EventCallbackControl,
0,
NULL,
NULL,
NULL // No IRP for this control operation
);
// Return the status of the call to WskControlSocket()
return Status;
}
En el ejemplo de código siguiente se muestra cómo una aplicación WSK puede usar la opción de socket SO_WSK_EVENT_CALLBACK para deshabilitar las funciones de devolución de llamada de eventos WskReceiveEvent en un socket orientado a la conexión.
// Prototype for the disable disconnect IoCompletion routine
NTSTATUS
DisableDisconnectComplete(
PDEVICE_OBJECT DeviceObject,
PIRP Irp,
PVOID Context
);
// Function to disable the WskDisconnectEvent event
// callback functions on a connection-oriented socket
NTSTATUS
DisableDisconnectCallback(
PWSK_SOCKET Socket
)
{
PWSK_PROVIDER_CONNECTION_DISPATCH Dispatch;
PIRP Irp;
WSK_EVENT_CALLBACK_CONTROL EventCallbackControl;
NTSTATUS Status;
// Get pointer to the socket's provider dispatch structure
Dispatch =
(PWSK_PROVIDER_CONNECTION_DISPATCH)(Socket->Dispatch);
// Allocate an IRP
Irp =
IoAllocateIrp(
1,
FALSE
);
// Check result
if (!Irp)
{
// Return error
return STATUS_INSUFFICIENT_RESOURCES;
}
// Set the completion routine for the IRP
IoSetCompletionRoutine(
Irp,
DisableDisconnectComplete,
Socket, // Use the socket object for the context
TRUE,
TRUE,
TRUE
);
// Specify the WSK NPI identifier
EventCallbackControl.NpiId = &NPI_WSK_INTERFACE_ID;
// Set the event flag for the event callback function that
// is to be disabled on the socket along with the disable flag
EventCallbackControl.EventMask =
WSK_EVENT_DISCONNECT | WSK_EVENT_DISABLE;
// Initiate the control operation on the socket
Status =
Dispatch->WskControlSocket(
Socket,
WskSetOption,
SO_WSK_EVENT_CALLBACK,
SOL_SOCKET,
sizeof(WSK_EVENT_CALLBACK_CONTROL),
&EventCallbackControl,
0,
NULL,
NULL,
Irp
);
// Return the status of the call to WskControlSocket()
return Status;
}
// Disable disconnect IoCompletion routine
NTSTATUS
DisableDisconnectComplete(
PDEVICE_OBJECT DeviceObject,
PIRP Irp,
PVOID Context
)
{
UNREFERENCED_PARAMETER(DeviceObject);
PWSK_SOCKET Socket;
// Check the result of the control operation
if (Irp->IoStatus.Status == STATUS_SUCCESS)
{
// The WskDisconnectEvent event callback
// function is now disabled
// Get the socket object from the context
Socket = (PWSK_SOCKET)Context;
// Perform the next operation on the socket
...
}
// Error status
else
{
// Handle error
...
}
// Free the IRP
IoFreeIrp(Irp);
// Always return STATUS_MORE_PROCESSING_REQUIRED to
// terminate the completion processing of the IRP.
return STATUS_MORE_PROCESSING_REQUIRED;
}
Para los sockets de escucha, las funciones de devolución de llamada de eventos WskInspectEvent y WskAbortEvent solo están habilitadas si la aplicación WSK habilita el modo de aceptación condicional en el socket. Una aplicación WSK habilita el modo de aceptación condicional en un socket de escucha estableciendo la opción de socket SO_CONDITIONAL_ACCEPT para el socket antes de enlazar el socket a una dirección de transporte local. Para obtener más información sobre cómo establecer las opciones de socket, vea Realizar operaciones de control en un socket.
Una vez habilitado el modo de aceptación condicional en un socket de escucha, las funciones de devolución de llamada de eventos WskInspectEvent y WskAbortEvent del socket no se pueden deshabilitar. Para obtener más información sobre la aceptación condicional de conexiones entrantes en sockets de escucha, consulte Escucha y aceptación de conexiones entrantes.
Un socket de escucha puede habilitar automáticamente funciones de devolución de llamada de eventos en sockets orientados a la conexión aceptados por la función de devolución de llamada de eventos WskAcceptEvent del socket de escucha. Una aplicación WSK habilita automáticamente estas funciones de devolución de llamada habilitando las funciones de devolución de llamada de eventos de socket orientadas a la conexión en el socket de escucha. Para obtener más información sobre este proceso, consulte SO_WSK_EVENT_CALLBACK.
Si una aplicación WSK siempre habilita determinadas funciones de devolución de llamada de eventos en cada socket que crea, la aplicación puede configurar el subsistema WSK para habilitar automáticamente esas funciones de devolución de llamada de eventos mediante la operación de control de cliente WSK_SET_STATIC_EVENT_CALLBACKS . Las funciones de devolución de llamada de eventos que están habilitadas de esta manera siempre están habilitadas y no se pueden deshabilitar ni volver a habilitar más adelante mediante la aplicación WSK. Si una aplicación WSK siempre habilita determinadas funciones de devolución de llamada de eventos en cada socket que crea, la aplicación debe usar este método para habilitar automáticamente esas funciones de devolución de llamada de eventos porque producirá un rendimiento mucho mejor.
En el ejemplo de código siguiente se muestra cómo una aplicación WSK puede usar la operación de control de cliente WSK_SET_STATIC_EVENT_CALLBACKS para habilitar automáticamente la función de devolución de llamada de eventos WskReceiveFromEvent en sockets de datagram y la función de devolución de llamada de eventos WskReceiveEvent en sockets orientados a la conexión.
// Function to set static event callbacks
NTSTATUS
SetStaticEventCallbacks(
PWSK_APP_BINDING_CONTEXT BindingContext,
)
{
WSK_EVENT_CALLBACK_CONTROL EventCallbackControl;
NTSTATUS Status;
// Specify the WSK NPI identifier
EventCallbackControl.NpiId = &NPI_WSK_INTERFACE_ID;
// Set the event flags for the event callback functions that
// are to be automatically enabled on every new socket
EventCallbackControl.EventMask =
WSK_EVENT_RECEIVE_FROM | WSK_EVENT_RECEIVE;
// Perform client control operation
Status =
BindingContext->
WskProviderDispatch->
WskControlClient(
BindingContext->WskClient,
WSK_SET_STATIC_EVENT_CALLBACKS,
sizeof(WSK_EVENT_CALLBACK_CONTROL),
&EventCallbackControl,
0,
NULL,
NULL,
NULL // No IRP for this control operation
);
// Return status of client control operation
return Status;
}
Si una aplicación WSK usa la operación de control de cliente WSK_SET_STATIC_EVENT_CALLBACKS para habilitar automáticamente determinadas funciones de devolución de llamada de eventos, debe hacerlo antes de crear los sockets.