Aktivieren und Deaktivieren von Ereignisrückruffunktionen

Eine WSK-Anwendung (Winsock Kernel) kann Ereignisrückruffunktionen implementieren, die das WSK-Subsystem asynchron aufruft, um die Anwendung zu benachrichtigen, wenn bestimmte Ereignisse in einem Socket auftreten. Eine WSK-Anwendung kann eine Clientverteilungstabellenstruktur für das WSK-Subsystem bereitstellen, wenn sie einen Socket erstellt oder einen Socket in einem lauschenden Socket akzeptiert. Diese Dispatchtabelle enthält Zeiger auf die Ereignisrückruffunktionen der WSK-Anwendung für den neuen Socket. Wenn eine WSK-Anwendung keine Ereignisrückruffunktionen für einen bestimmten Socket implementiert, muss sie keine Clientverteilungstabellenstruktur für das WSK-Subsystem für diesen Socket bereitstellen.

Alle Ereignisrückruffunktionen eines Sockets, mit Ausnahme der Ereignisrückruffunktionen WskInspectEvent und WskAbortEvent eines lauschenden Sockets, können mithilfe der Option SO_WSK_EVENT_CALLBACK Sockets aktiviert oder deaktiviert werden. Eine WSK-Anwendung kann mehrere Ereignisrückruffunktionen gleichzeitig in einem Socket aktivieren. Eine WSK-Anwendung muss jedoch jede Ereignisrückruffunktion einzeln deaktivieren.

Das folgende Codebeispiel zeigt, wie eine WSK-Anwendung die Option SO_WSK_EVENT_CALLBACK Socket verwenden kann, um die Ereignisrückruffunktionen WskDisconnectEvent und WskReceiveEvent für einen verbindungsorientierten Socket zu aktivieren.

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

Das folgende Codebeispiel zeigt, wie eine WSK-Anwendung die SO_WSK_EVENT_CALLBACK Socketoption verwenden kann, um die WskReceiveEvent-Ereignisrückruffunktionen für einen verbindungsorientierten Socket zu deaktivieren.

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

Bei lauschenden Sockets sind die Ereignisrückruffunktionen WskInspectEvent und WskAbortEvent nur aktiviert, wenn die WSK-Anwendung den Modus für die bedingte Annahme im Socket aktiviert. Eine WSK-Anwendung aktiviert den Modus für die bedingte Akzeptanz für einen lauschenden Socket, indem die Option SO_CONDITIONAL_ACCEPT Sockets für den Socket festgelegt wird, bevor der Socket an eine lokale Transportadresse gebunden wird. Weitere Informationen zum Festlegen von Socketoptionen finden Sie unter Ausführen von Steuerungsvorgängen für einen Socket.

Nachdem der Modus für die bedingte Annahme für einen lauschenden Socket aktiviert wurde, können die Ereignisrückruffunktionen WskInspectEvent und WskAbortEvent des Sockets nicht deaktiviert werden. Weitere Informationen zum bedingten Akzeptieren eingehender Verbindungen auf Lauschensockets finden Sie unter Lauschen auf und Akzeptieren eingehender Verbindungen.

Ein lauschende Socket kann automatisch Ereignisrückruffunktionen für verbindungsorientierte Sockets aktivieren, die von der WskAcceptEvent-Ereignisrückruffunktion des lauschenden Sockets akzeptiert werden. Eine WSK-Anwendung aktiviert diese Rückruffunktionen automatisch, indem die verbindungsorientierten Socketereignisrückruffunktionen im lauschenden Socket aktiviert werden. Weitere Informationen zu diesem Prozess finden Sie unter SO_WSK_EVENT_CALLBACK.

Wenn eine WSK-Anwendung immer bestimmte Ereignisrückruffunktionen für jeden erstellten Socket aktiviert, kann die Anwendung das WSK-Subsystem so konfigurieren, dass diese Ereignisrückruffunktionen mithilfe des WSK_SET_STATIC_EVENT_CALLBACKS Clientsteuerungsvorgangs automatisch aktiviert werden. Die auf diese Weise aktivierten Ereignisrückruffunktionen sind immer aktiviert und können nicht später von der WSK-Anwendung deaktiviert oder wieder aktiviert werden. Wenn eine WSK-Anwendung immer bestimmte Ereignisrückruffunktionen für jeden socket aktiviert, den sie erstellt, sollte die Anwendung diese Methode verwenden, um diese Ereignisrückruffunktionen automatisch zu aktivieren, da sie eine viel bessere Leistung ergibt.

Das folgende Codebeispiel zeigt, wie eine WSK-Anwendung den WSK_SET_STATIC_EVENT_CALLBACKS Clientsteuerungsvorgang verwenden kann, um die WskReceiveFromEvent-Ereignisrückruffunktion für Datagrammsockets und die WskReceiveEvent-Ereignisrückruffunktion für verbindungsorientierte Sockets automatisch zu aktivieren.

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

Wenn eine WSK-Anwendung den WSK_SET_STATIC_EVENT_CALLBACKS Clientsteuerungsvorgang verwendet, um bestimmte Ereignisrückruffunktionen automatisch zu aktivieren, muss sie dies tun, bevor Sockets erstellt werden.