Udostępnij za pośrednictwem


Włączanie i wyłączanie funkcji wywołania zwrotnego zdarzeń

Aplikacja Winsock Kernel (WSK) może implementować funkcje wywołania zwrotnego zdarzeń, które podsystem WSK wywołuje asynchronicznie, aby powiadomić aplikację, gdy niektóre zdarzenia wystąpią na gnieździe. Aplikacja WSK może zapewnić klientowi strukturę tablicy dyspozytorów podsystemowi WSK za każdym razem, gdy tworzy gniazdo lub akceptuje gniazdo na gnieździe nasłuchującym. Ta tabela zdarzeń zawiera wskaźniki do funkcji wywoływania zwrotnego zdarzeń aplikacji WSK dla nowego gniazda. Jeśli aplikacja WSK nie implementuje żadnych funkcji wywołania zwrotnego zdarzeń dla określonego gniazda, nie musi zapewniać struktury tabeli wysyłania klienta do podsystemu WSK dla tego gniazda.

Wszystkie funkcje wywoływania zwrotnego zdarzeń gniazda, z wyjątkiem funkcji wywoływania zdarzeń dla gniazda nasłuchującego WskInspectEvent oraz WskAbortEvent, można włączyć lub wyłączyć, korzystając z opcji gniazda SO_WSK_EVENT_CALLBACK. Aplikacja WSK może jednocześnie włączyć wiele funkcji wywołania zwrotnego zdarzeń na jednym gnieździe. Jednak aplikacja WSK musi osobno wyłączyć każdą funkcję wywołania zwrotnego zdarzenia.

Poniższy przykład kodu pokazuje, jak aplikacja WSK może użyć opcji gniazda SO_WSK_EVENT_CALLBACK, aby włączyć funkcje wywołania zwrotnego dla zdarzeń WskDisconnectEvent oraz WskReceiveEvent na gnieździe zorientowanym na połączenie.

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

Poniższy przykład kodu pokazuje, jak aplikacja WSK może użyć opcji gniazda SO_WSK_EVENT_CALLBACK, aby wyłączyć funkcje zwrotnych wywołań zdarzeń WskReceiveEvent na gnieździe zorientowanym na połączenie.

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

W przypadku gniazd nasłuchiwania, funkcje wywołania zwrotnego zdarzeń WskInspectEvent i WskAbortEvent są włączone tylko wtedy, gdy aplikacja WSK włącza w gnieździe tryb akceptacji warunkowej. Aplikacja WSK włącza tryb warunkowego akceptowania na gnieździe nasłuchującym, ustawiając opcję gniazda SO_CONDITIONAL_ACCEPT dla gniazda przed związaniem gniazda z lokalnym adresem transportowym. Aby uzyskać więcej informacji na temat ustawiania opcji gniazda, zobacz Wykonywanie operacji sterowania na gnieździe.

Po włączeniu trybu akceptowania warunkowego na gnieździe nasłuchującym nie można wyłączyć funkcji wywołania zwrotnego zdarzeń WskInspectEvent oraz WskAbortEvent. Aby uzyskać więcej informacji na temat warunkowego akceptowania połączeń przychodzących na gniazdach nasłuchiwania, zobacz Nasłuchiwanie i akceptowanie połączeń przychodzących.

Gniazdo nasłuchiwania może automatycznie włączać funkcje zwrotne wywołania zdarzeń na gniazdach zorientowanych na połączenie, które są akceptowane przez funkcję wywołania zwrotnego zdarzeń WskAcceptEvent gniazda nasłuchującego. Aplikacja WSK automatycznie włącza te funkcje wywołania zwrotnego, umożliwiając włączenie funkcji wywołania zwrotnego zdarzeń gniazda zorientowanego na połączenie na gnieździe nasłuchującym. Aby uzyskać więcej informacji na temat tego procesu, zobacz SO_WSK_EVENT_CALLBACK.

Jeśli aplikacja WSK zawsze włącza pewne funkcje zwrotne zdarzeń na każdym gnieździe, które tworzy, aplikacja może skonfigurować podsystem WSK, aby automatycznie włączyć te funkcje zwrotne zdarzeń przy użyciu operacji sterowania klientem WSK_SET_STATIC_EVENT_CALLBACKS. Funkcje wywołania zwrotnego zdarzeń, które zostały w ten sposób włączone, są zawsze włączone i nie mogą być wyłączone ani ponownie włączone później przez aplikację WSK. Jeśli aplikacja WSK zawsze włącza pewne funkcje wywołania zwrotnego zdarzeń na każdym utworzonym przez nią gniazdo, aplikacja powinna użyć tej metody, aby automatycznie włączyć te funkcje wywołania zwrotnego zdarzeń, ponieważ zapewni znacznie lepszą wydajność.

Poniższy przykład kodu pokazuje, jak aplikacja WSK może używać operacji sterowania klienta WSK_SET_STATIC_EVENT_CALLBACKS w celu automatycznego włączenia funkcji zdarzeń zwrotnych WskReceiveFromEvent na gniazdach datagramowych oraz funkcji WskReceiveEvent na gniazdach zorientowanych na połączenie.

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

Jeśli aplikacja WSK używa operacji sterowania klienta WSK_SET_STATIC_EVENT_CALLBACKS, aby automatycznie włączyć niektóre funkcje wywołania zwrotnego zdarzeń, musi to zrobić przed utworzeniem jakichkolwiek gniazd.