Habilitando e desabilitando funções de retorno de chamada de evento

Um aplicativo WSK (Winsock Kernel) pode implementar funções de retorno de chamada de evento que o subsistema WSK chama de forma assíncrona para notificar o aplicativo quando determinados eventos ocorrem em um soquete. Um aplicativo WSK pode fornecer uma estrutura de tabela de expedição do cliente para o subsistema WSK sempre que ele cria um soquete ou aceita um soquete em um soquete de escuta. Esta tabela de expedição contém ponteiros para as funções de retorno de chamada de evento do aplicativo WSK para o novo soquete. Se um aplicativo WSK não implementar nenhuma função de retorno de chamada de evento para um soquete específico, ele não precisará fornecer uma estrutura de tabela de expedição do cliente para o subsistema WSK para esse soquete.

Todas as funções de retorno de chamada de evento de um soquete, exceto as funções de retorno de chamada de evento WskInspectEvent e WskAbortEvent de um soquete de escuta, podem ser habilitadas ou desabilitadas usando a opção de soquete SO_WSK_EVENT_CALLBACK . Um aplicativo WSK pode habilitar várias funções de retorno de chamada de evento em um soquete ao mesmo tempo. No entanto, um aplicativo WSK deve desabilitar cada função de retorno de chamada de evento individualmente.

O exemplo de código a seguir mostra como um aplicativo WSK pode usar a opção de soquete SO_WSK_EVENT_CALLBACK para habilitar as funções de retorno de chamada de evento WskDisconnectEvent e WskReceiveEvent em um soquete orientado a conexão.

// 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;
}

O exemplo de código a seguir mostra como um aplicativo WSK pode usar a opção de soquete SO_WSK_EVENT_CALLBACK para desabilitar as funções de retorno de chamada de evento WskReceiveEvent em um soquete orientado a conexão.

// 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 soquetes de escuta, as funções de retorno de chamada de evento WskInspectEvent e WskAbortEvent serão habilitadas somente se o aplicativo WSK habilitar o modo de aceitação condicional no soquete. Um aplicativo WSK permite o modo de aceitação condicional em um soquete de escuta definindo a opção de soquete SO_CONDITIONAL_ACCEPT para o soquete antes de associar o soquete a um endereço de transporte local. Para obter mais informações sobre como definir opções de soquete, consulte Executando operações de controle em um soquete.

Depois que o modo de aceitação condicional tiver sido habilitado em um soquete de escuta, as funções de retorno de chamada de evento WskInspectEvent e WskAbortEvent do soquete não poderão ser desabilitadas. Para obter mais informações sobre como aceitar condicionalmente conexões de entrada em soquetes de escuta, consulte Escutando e aceitando conexões de entrada.

Um soquete de escuta pode habilitar automaticamente funções de retorno de chamada de evento em soquetes orientados à conexão que são aceitos pela função de retorno de chamada de evento WskAcceptEvent do soquete de escuta. Um aplicativo WSK habilita automaticamente essas funções de retorno de chamada habilitando as funções de retorno de chamada de evento de soquete orientadas à conexão no soquete de escuta. Para obter mais informações sobre esse processo, consulte SO_WSK_EVENT_CALLBACK.

Se um aplicativo WSK sempre habilitar determinadas funções de retorno de chamada de evento em cada soquete que ele cria, o aplicativo poderá configurar o subsistema WSK para habilitar automaticamente essas funções de retorno de chamada de evento usando o WSK_SET_STATIC_EVENT_CALLBACKS operação de controle do cliente. As funções de retorno de chamada de evento habilitadas dessa maneira são sempre habilitadas e não podem ser desabilitadas ou reabilitadas posteriormente pelo aplicativo WSK. Se um aplicativo WSK sempre habilitar determinadas funções de retorno de chamada de evento em cada soquete que ele cria, o aplicativo deverá usar esse método para habilitar automaticamente essas funções de retorno de chamada de evento, pois ele produzirá um desempenho muito melhor.

O exemplo de código a seguir mostra como um aplicativo WSK pode usar o WSK_SET_STATIC_EVENT_CALLBACKS operação de controle de cliente para habilitar automaticamente a função de retorno de chamada de evento WskReceiveFromEvent em soquetes de datagrama e a função de retorno de chamada de evento WskReceiveEvent em soquetes orientados à conexão.

// 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;
}

Se um aplicativo WSK usar o WSK_SET_STATIC_EVENT_CALLBACKS operação de controle de cliente para habilitar automaticamente determinadas funções de retorno de chamada de evento, ele deverá fazer isso antes de criar qualquer soquete.