Winsock 커널 애플리케이션 등록

WSK 클라이언트 개체 등록

WSK(Winsock Kernel) 애플리케이션은 WskRegister 함수를 호출하여 WSK 클라이언트로 등록해야 합니다. WskRegister 를 사용하려면 WSK 애플리케이션이 WSK 클라이언트의 NPI(네트워크 프로그래밍 인터페이스)( WSK_CLIENT_NPI 구조) 및 WSK 등록 개체( WSK_REGISTRATION 구조)에 대한 포인터를 초기화하고 전달해야 합니다. 이 개체는 반환이 성공하면 WskRegister 에서 초기화됩니다.

다음 코드 예제에서는 WSK 애플리케이션이 WSK 클라이언트로 등록할 수 있는 방법을 보여 줍니다.

// Include the WSK header file
#include "wsk.h"

// WSK Client Dispatch table that denotes the WSK version
// that the WSK application wants to use and optionally a pointer
// to the WskClientEvent callback function
const WSK_CLIENT_DISPATCH WskAppDispatch = {
  MAKE_WSK_VERSION(1,0), // Use WSK version 1.0
  0,    // Reserved
  NULL  // WskClientEvent callback not required for WSK version 1.0
};

// WSK Registration object
WSK_REGISTRATION WskRegistration;

// DriverEntry function
NTSTATUS
  DriverEntry(
    PDRIVER_OBJECT DriverObject,
    PUNICODE_STRING RegistryPath
    )
{
  NTSTATUS Status;
  WSK_CLIENT_NPI wskClientNpi;

  .
  . 
  .

  // Register the WSK application
  wskClientNpi.ClientContext = NULL;
  wskClientNpi.Dispatch = &WskAppDispatch;
  Status = WskRegister(&wskClientNpi, &WskRegistration);

  if(!NT_SUCCESS(Status)) {
      .
      .
      .
      return Status;
  }

  .
  . 
  .
}

WSK 애플리케이션은 DriverEntry 함수 내에서 WskRegister를 호출할 필요가 없습니다. 예를 들어 WSK 애플리케이션이 복잡한 드라이버의 하위 구성 요소인 경우 WSK 애플리케이션 하위 구성 요소가 활성화된 경우에만 애플리케이션 등록이 발생할 수 있습니다.

WSK 애플리케이션은 WskDeregister가 호출되고 등록이 더 이상 유효하지 않을 때까지 WskRegister에 전달된 WSK_CLIENT_DISPATCH 구조를 유효하고 메모리에 상주해야 합니다. WSK 애플리케이션이 다른 WSK 등록 함수에 대한 호출을 중지할 때까지 WSK_REGISTRATION 구조도 유효하고 메모리에 상주해야 합니다. 이전 코드 예제에서는 이러한 두 구조를 드라이버의 전역 데이터 섹션에 유지하여 드라이버가 언로드될 때까지 구조체 데이터를 메모리에 유지합니다.

WSK 공급자 NPI 캡처

WSK 애플리케이션이 WskRegister를 사용하여 WSK 클라이언트로 등록되면 WSK 인터페이스 사용을 시작하려면 WSKCaptureProviderNPI 함수를 사용하여 WSK 하위 시스템의 WSK 공급자 NPI를 캡처해야 합니다.

WSK 애플리케이션이 WSK 공급자 NPI를 캡처하려고 할 때 WSK 하위 시스템이 아직 준비되지 않았을 수 있으므로 WskCaptureProviderNPI 함수를 사용하면 WSK 애플리케이션이 다음과 같이 WSK 하위 시스템을 폴링하거나 대기할 수 있습니다.

  • WaitTimeout 매개 변수가 WSK_NO_WAIT 경우 함수는 항상 기다리지 않고 즉시 반환됩니다.

  • WaitTimeout이 WSK_INFINITE_WAIT 경우 함수는 WSK 하위 시스템이 준비될 때까지 기다립니다.

  • WaitTimeout이 다른 값이면 WSK 하위 시스템이 준비되거나 대기 시간(밀리초)이 먼저 발생하는 WaitTimeout 값에 도달할 때 함수가 반환됩니다.

중요 다른 드라이버 및 서비스의 시작에 부정적인 영향을 주지 않도록 하기 위해 DriverEntry 함수에서 WskCaptureProviderNPI를 호출하는 WSK 애플리케이션은 WaitTimeout 매개 변수를 WSK_INFINITE_WAIT 또는 과도한 대기 시간으로 설정하면 안 됩니다. 또한 WSK 애플리케이션이 시스템 시작 단계 초기에 시작되는 경우 DriverEntry 가 실행되는 것과 다른 작업자 스레드에서 WSK 하위 시스템이 준비될 때까지 기다려야 합니다.

WskCaptureProviderNPI에 대한 호출이 STATUS_NOINTERFACE 실패하면 WSK 애플리케이션은 WskQueryProviderCharacteristics 함수를 사용하여 WSK 하위 시스템이 지원하는 WSK NPI 버전의 범위를 검색할 수 있습니다. WSK 애플리케이션은 WskDeregister를 호출하여 현재 등록 instance 등록을 취소한 다음 지원되는 WSK NPI 버전을 사용하는 다른 WSK_CLIENT_DISPATCH instance 사용하여 다시 등록할 수 있습니다.

WskCaptureProviderNPI가 성공적으로 반환되면 WskProviderNpi 매개 변수는 WSK 애플리케이션에서 사용할 준비가 된 WSK 공급자 NPI(WSK_PROVIDER_NPI)를 가리킵니다. WSK_PROVIDER_NPI 구조에는 WSK 클라이언트 개체( WSK_CLIENT)에 대한 포인터와 WSK 애플리케이션이 WSK 소켓을 만들고 WSK 클라이언트 개체에서 다른 작업을 수행하는 데 사용할 수 있는 WSK 함수의 WSK_PROVIDER_DISPATCH 디스패 치 테이블에 대한 포인터가 포함되어 있습니다. WSK 애플리케이션은 WSK_PROVIDER_DISPATCH 함수 사용을 완료한 후 WskReleaseProviderNPI를 호출하여 WSK 공급자 NPI를 해제해야 합니다.

다음 코드 예제에서는 WSK 애플리케이션이 WSK 공급자 NPI를 캡처하고 이를 사용하여 소켓을 만든 다음 해제하는 방법을 보여 줍니다.

// WSK application routine that waits for WSK subsystem
// to become ready and captures the WSK Provider NPI
NTSTATUS
  WskAppWorkerRoutine(
    )
{
  NTSTATUS Status;
  WSK_PROVIDER_NPI wskProviderNpi;
 
  // Capture the WSK Provider NPI. If WSK subsystem is not ready yet,
  // wait until it becomes ready.
  Status = WskCaptureProviderNPI(
    &WskRegistration, // must have been initialized with WskRegister
    WSK_INFINITE_WAIT,
    &wskProviderNpi
    );

  if(!NT_SUCCESS(Status))
  {
    // The WSK Provider NPI could not be captured.
    if( Status == STATUS_NOINTERFACE ) {
      // WSK application's requested version is not supported
    }
    else if( status == STATUS_DEVICE_NOT_READY ) {
      // WskDeregister was invoked in another thread thereby causing
      // WskCaptureProviderNPI to be canceled.
    } 
    else {
      // Some other unexpected failure has occurred
    }

    return Status;
  }

  // The WSK Provider NPI has been captured.
  // Create and set up a listening socket that accepts
   // incoming connections.
  Status = CreateListeningSocket(&wskProviderNpi, ...);

  // The WSK Provider NPI will not be used any more.
  // So, release it here immediately.
  WskReleaseProviderNPI(&WskRegistration);

  // Return result of socket creation routine
  return Status;

}

WSK 애플리케이션은 WskCaptureProviderNPI 를 두 번 이상 호출할 수 있습니다. 성공적으로 반환되는 WskCaptureProviderNPI 호출마다 WskReleaseProviderNPI에 대한 해당 호출이 있어야 합니다. WSK 애플리케이션은 WskReleaseProviderNPI를 호출한 후 WSK_PROVIDER_DISPATCH 함수를 더 이상 호출해서는 안 됩니다.