이벤트 콜백 함수 사용 및 사용 안 함

WSK(Winsock Kernel) 애플리케이션은 WSK 하위 시스템이 소켓에서 특정 이벤트가 발생할 때 애플리케이션에 알리기 위해 비동기적으로 호출하는 이벤트 콜백 함수를 구현할 수 있습니다. WSK 애플리케이션은 소켓을 만들거나 수신 대기 소켓에서 소켓을 수락할 때마다 WSK 하위 시스템에 클라이언트 디스패치 테이블 구조를 제공할 수 있습니다. 이 디스패치 테이블에는 새 소켓에 대한 WSK 애플리케이션의 이벤트 콜백 함수에 대한 포인터가 포함되어 있습니다. WSK 애플리케이션이 특정 소켓에 대한 이벤트 콜백 함수를 구현하지 않는 경우 해당 소켓에 대한 WSK 하위 시스템에 클라이언트 디스패치 테이블 구조를 제공할 필요가 없습니다.

수신 대기 소켓의 WskInspectEventWskAbortEvent 이벤트 콜백 함수를 제외한 모든 소켓의 이벤트 콜백 함수는 SO_WSK_EVENT_CALLBACK 소켓 옵션을 사용하여 사용하거나 사용하지 않도록 설정할 수 있습니다. WSK 애플리케이션은 소켓에서 여러 이벤트 콜백 함수를 동시에 사용하도록 설정할 수 있습니다. 그러나 WSK 애플리케이션은 각 이벤트 콜백 함수를 개별적으로 사용하지 않도록 설정해야 합니다.

다음 코드 예제에서는 WSK 애플리케이션이 SO_WSK_EVENT_CALLBACK 소켓 옵션을 사용하여 연결 지향 소켓에서 WskDisconnectEventWskReceiveEvent 이벤트 콜백 함수를 사용하도록 설정하는 방법을 보여 줍니다.

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

수신 대기 소켓의 경우 WSK 애플리케이션이 소켓에서 조건부 수락 모드를 사용하도록 설정한 경우에만 WskInspectEventWskAbortEvent 이벤트 콜백 함수가 사용하도록 설정됩니다. WSK 애플리케이션은 소켓을 로컬 전송 주소에 바인딩하기 전에 소켓에 대한 SO_CONDITIONAL_ACCEPT 소켓 옵션을 설정하여 수신 대기 소켓에서 조건부 수락 모드를 사용하도록 설정합니다. 소켓 옵션을 설정하는 방법에 대한 자세한 내용은 소 켓에서 제어 작업 수행을 참조하세요.

수신 대기 소켓에서 조건부 수락 모드를 사용하도록 설정한 후에는 소켓의 WskInspectEventWskAbortEvent 이벤트 콜백 함수를 사용하지 않도록 설정할 수 없습니다. 수신 대기 소켓에서 들어오는 연결을 조건부로 수락하는 방법에 대한 자세한 내용은 수신 대기 및 들어오는 연결 수락을 참조하세요.

수신 소켓은 수신 대기 소켓의 WskAcceptEvent 이벤트 콜백 함수에서 허용하는 연결 지향 소켓에서 이벤트 콜백 함수를 자동으로 사용하도록 설정할 수 있습니다. WSK 애플리케이션은 수신 대기 소켓에서 연결 지향 소켓 이벤트 콜백 함수를 사용하도록 설정하여 이러한 콜백 함수를 자동으로 사용하도록 설정합니다. 이 프로세스에 대한 자세한 내용은 SO_WSK_EVENT_CALLBACK.

WSK 애플리케이션이 생성되는 모든 소켓에서 항상 특정 이벤트 콜백 함수를 사용하도록 설정하는 경우 애플리케이션은 WSK_SET_STATIC_EVENT_CALLBACKS 클라이언트 제어 작업을 사용하여 해당 이벤트 콜백 함수를 자동으로 사용하도록 WSK 하위 시스템을 구성할 수 있습니다. 이러한 방식으로 사용하도록 설정된 이벤트 콜백 함수는 항상 사용하도록 설정되며 나중에 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 클라이언트 제어 작업을 사용하여 특정 이벤트 콜백 함수를 자동으로 사용하도록 설정하는 경우 소켓을 만들기 전에 이 작업을 수행해야 합니다.