Поделиться через


Включение и отключение функций обратного вызова событий

Приложение ядра Winsock (WSK) может реализовывать функции обратного вызова событий, которые подсистема WSK вызывает асинхронно, чтобы уведомлять приложение о возникновении определенных событий в сокете. Приложение WSK может предоставлять подсистеме WSK структуру таблицы диспетчеризации клиента, когда оно создает сокет или принимает сокет в сокете для прослушивания. Эта таблица диспетчеризации содержит указатели на функции обратного вызова событий приложения WSK для нового сокета. Если приложение WSK не реализует функции обратного вызова событий для определенного сокета, ему не нужно предоставлять структуру таблицы диспетчеризации клиента подсистеме WSK для этого сокета.

Все функции обратного вызова событий сокета, за исключением функций обратного вызова событий WskInspectEvent и WskAbortEvent прослушивающего сокета, можно включить или отключить с помощью параметра сокета SO_WSK_EVENT_CALLBACK . Приложение WSK может одновременно включить несколько функций обратного вызова событий в сокете. Однако приложение WSK должно отключить каждую функцию обратного вызова события по отдельности.

В следующем примере кода показано, как приложение WSK может использовать параметр сокета SO_WSK_EVENT_CALLBACK для включения функций обратного вызова событий WskDisconnectEvent и WskReceiveEvent в сокете, ориентированном на подключение.

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

В следующем примере кода показано, как приложение WSK может использовать параметр сокета SO_WSK_EVENT_CALLBACK для отключения функций обратного вызова событий WskReceiveEvent в сокете, ориентированном на подключение.

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

Для прослушивания сокетов функции обратного вызова событий WskInspectEvent и WskAbortEvent включены только в том случае, если приложение WSK включает режим условного принятия для сокета. Приложение WSK включает режим условного принятия для прослушивающего сокета, задавая параметр SO_CONDITIONAL_ACCEPT сокета для сокета перед привязкой сокета к локальному адресу транспорта. Дополнительные сведения о настройке параметров сокета см. в разделе Выполнение управляющих операций в сокете.

После включения режима условного принятия для прослушивающего сокета функции обратного вызова событий WskInspectEvent и WskAbortEvent в сокете не могут быть отключены. Дополнительные сведения об условном принятии входящих подключений в прослушивающих сокетах см. в разделах Прослушивание и Прием входящих подключений.

Прослушивающий сокет может автоматически включать функции обратного вызова событий в сокетах, ориентированных на подключение, которые принимаются функцией обратного вызова событий WskAcceptEvent прослушивающего сокета. Приложение WSK автоматически включает эти функции обратного вызова, включив функции обратного вызова событий сокета, ориентированных на подключение, в прослушивающем сокете. Дополнительные сведения об этом процессе см. в разделе SO_WSK_EVENT_CALLBACK.

Если приложение WSK всегда включает определенные функции обратного вызова событий для каждого создаваемого сокета, приложение может настроить подсистему WSK для автоматического включения этих функций обратного вызова событий с помощью операции управления WSK_SET_STATIC_EVENT_CALLBACKS клиента. Функции обратного вызова событий, включенные таким образом, всегда включены и не могут быть отключены или повторно включены приложением WSK позже. Если приложение WSK всегда включает определенные функции обратного вызова событий в каждом создаваемом сокете, приложение должно использовать этот метод для автоматического включения этих функций обратного вызова событий, так как это обеспечит гораздо более высокую производительность.

В следующем примере кода показано, как приложение WSK может использовать операцию WSK_SET_STATIC_EVENT_CALLBACKS клиентского управления для автоматического включения функции обратного вызова событий WskReceiveFromEvent в сокетах датаграмм и функции обратного вызова событий WskReceiveEvent в сокетах, ориентированных на подключение.

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

Если приложение WSK использует операцию управления WSK_SET_STATIC_EVENT_CALLBACKS клиента для автоматического включения определенных функций обратного вызова событий, это необходимо сделать перед созданием сокетов.