Compartir a través de


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.