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 애플리케이션이 시스템 시작 단계에서 매우 일찍 시작되는 경우 WSK 하위 시스템이 DriverEntry 가 실행되는 것과 다른 작업자 스레드에서 준비될 때까지 기다려야 합니다.

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

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 함수를 더 이상 호출하지 않아야 합니다.