Activation et désactivation des fonctions de rappel d’événements

Une application WSK (Winsock Kernel) peut implémenter des fonctions de rappel d’événements que le sous-système WSK appelle de manière asynchrone pour notifier l’application lorsque certains événements se produisent sur un socket. Une application WSK peut fournir une structure de table de répartition cliente au sous-système WSK chaque fois qu’elle crée un socket ou accepte un socket sur un socket d’écoute. Cette table de répartition contient des pointeurs vers les fonctions de rappel d’événements de l’application WSK pour le nouveau socket. Si une application WSK n’implémente aucune fonction de rappel d’événement pour un socket particulier, elle n’a pas besoin de fournir une structure de table de répartition cliente au sous-système WSK pour ce socket.

Toutes les fonctions de rappel d’événements d’un socket, à l’exception des fonctions de rappel d’événements WskInspectEvent et WskAbortEvent d’un socket d’écoute , peuvent être activées ou désactivées à l’aide de l’option de socket SO_WSK_EVENT_CALLBACK . Une application WSK peut activer plusieurs fonctions de rappel d’événements sur un socket en même temps. Toutefois, une application WSK doit désactiver chaque fonction de rappel d’événement individuellement.

L’exemple de code suivant montre comment une application WSK peut utiliser l’option de socket SO_WSK_EVENT_CALLBACK pour activer les fonctions de rappel d’événements WskDisconnectEvent et WskReceiveEvent sur un socket orienté connexion.

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

L’exemple de code suivant montre comment une application WSK peut utiliser l’option de socket SO_WSK_EVENT_CALLBACK pour désactiver les fonctions de rappel d’événement WskReceiveEvent sur un socket orienté connexion.

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

Pour les sockets d’écoute, les fonctions de rappel des événements WskInspectEvent et WskAbortEvent sont activées uniquement si l’application WSK active le mode d’acceptation conditionnelle sur le socket. Une application WSK active le mode d’acceptation conditionnelle sur un socket d’écoute en définissant l’option de socket SO_CONDITIONAL_ACCEPT pour le socket avant de lier le socket à une adresse de transport locale. Pour plus d’informations sur la définition des options de socket, consultez Exécution d’opérations de contrôle sur un socket.

Une fois le mode d’acceptation conditionnelle activé sur un socket d’écoute, les fonctions de rappel des événements WskInspectEvent et WskAbortEvent du socket ne peuvent pas être désactivées. Pour plus d’informations sur l’acceptation conditionnelle des connexions entrantes sur les sockets d’écoute, consultez Écoute pour et acceptation des connexions entrantes.

Un socket d’écoute peut activer automatiquement les fonctions de rappel d’événements sur les sockets orientés connexion qui sont acceptés par la fonction de rappel d’événements WskAcceptEvent du socket d’écoute. Une application WSK active automatiquement ces fonctions de rappel en activant les fonctions de rappel d’événements socket orientées connexion sur le socket d’écoute. Pour plus d’informations sur ce processus, consultez SO_WSK_EVENT_CALLBACK.

Si une application WSK active toujours certaines fonctions de rappel d’événements sur chaque socket qu’elle crée, l’application peut configurer le sous-système WSK pour activer automatiquement ces fonctions de rappel d’événements à l’aide de l’opération de contrôle client WSK_SET_STATIC_EVENT_CALLBACKS . Les fonctions de rappel d’événements activées de cette manière sont toujours activées et ne peuvent pas être désactivées ou réactivée ultérieurement par l’application WSK. Si une application WSK active toujours certaines fonctions de rappel d’événements sur chaque socket qu’elle crée, l’application doit utiliser cette méthode pour activer automatiquement ces fonctions de rappel d’événements, car elle génère de bien meilleures performances.

L’exemple de code suivant montre comment une application WSK peut utiliser l’opération de contrôle client WSK_SET_STATIC_EVENT_CALLBACKS pour activer automatiquement la fonction de rappel d’événements WskReceiveFromEvent sur les sockets de datagram et la fonction de rappel d’événements WskReceiveEvent sur les sockets orientés connexion.

// 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 une application WSK utilise l’opération de contrôle client WSK_SET_STATIC_EVENT_CALLBACKS pour activer automatiquement certaines fonctions de rappel d’événements, elle doit le faire avant de créer des sockets.