コントロール コードのSIO_ACQUIRE_PORT_RESERVATION

説明

SIO_ACQUIRE_PORT_RESERVATION制御コードは、TCP または UDP ポートのブロックのランタイム予約を取得します。

この操作を実行するには、次のパラメーターを使用して WSAIoctl または WSPIoctl 関数を呼び出します。

int WSAIoctl(
  (socket) s,             // descriptor identifying a socket
  SIO_ACQUIRE_PORT_RESERVATION, // dwIoControlCode
  (LPVOID) lpvInBuffer,  // pointer to an INET_PORT_RANGE structure
  (DWORD) cbInBuffer,    // size, in bytes, of the input buffer
  (LPVOID) lpvOutBuffer,             // pointer to an INET_PORT_RESERVATION_INSTANCE structure
  (DWORD) cbOutBuffer,   // size, in bytes, of the output buffer
  (LPDWORD) lpcbBytesReturned,    // number of bytes returned
  (LPWSAOVERLAPPED) lpOverlapped,   // OVERLAPPED structure
  (LPWSAOVERLAPPED_COMPLETION_ROUTINE) lpCompletionRoutine,  // completion routine
);
int WSPIoctl(
  (socket) s,             // descriptor identifying a socket
  SIO_ACQUIRE_PORT_RESERVATION, // dwIoControlCode
  (LPVOID) lpvInBuffer,  // pointer to an INET_PORT_RANGE structure
  (DWORD) cbInBuffer,    // size, in bytes, of the input buffer
  (LPVOID) lpvOutBuffer,             // pointer to a INET_PORT_RESERVATION_INSTANCE structure
  (DWORD) cbOutBuffer,   // size, in bytes, of the output buffer
  (LPDWORD) lpcbBytesReturned,    // number of bytes returned
  (LPWSAOVERLAPPED) lpOverlapped,   // OVERLAPPED structure
  (LPWSAOVERLAPPED_COMPLETION_ROUTINE) lpCompletionRoutine,  // completion routine
  (LPWSATHREADID) lpThreadId,   // a WSATHREADID structure
  (LPINT) lpErrno   // a pointer to the error code.
);

パラメーター

s

ソケットを識別する記述子。

dwIoControlCode

操作の制御コード。 この操作 にはSIO_ACQUIRE_PORT_RESERVATION を使用します。

lpvInBuffer

入力バッファーへのポインター。 このパラメーターには、開始点の番号と予約するポートの数を指定する INET_PORT_RANGE 構造体へのポインターが含まれています。

cbInBuffer

入力バッファーのサイズ (バイト単位)。 このパラメーターは、 INET_PORT_RANGE 構造体のサイズにする必要があります。

lpvOutBuffer

出力バッファーへのポインター。 正常に出力されると、このパラメーターには INET_PORT_RESERVATION_INSTANCE 構造体へのポインターが含まれます。

cbOutBuffer

出力バッファーのサイズ (バイト単位)。 このパラメーターは、少なくとも INET_PORT_RESERVATION_INSTANCE 構造体のサイズである必要があります。

lpcbBytesReturned

出力バッファーに格納されているデータのサイズをバイト単位で受け取る変数へのポインター。

出力バッファーが小さすぎると、呼び出しは失敗し、 WSAGetLastError はWSAEINVAL を返し、 lpcbBytesReturned パラメーターはDWORD 値 0 を指します。

lpOverlappedNULL の場合、正常な呼び出しで返される lpcbBytesReturned パラメーターが指す DWORD 値を 0 にすることはできません。

重複するソケットに 対して lpOverlapped パラメーターが NULL でない場合、すぐに完了できない操作が開始され、完了は後で示されます。 返される lpcbBytesReturned パラメーターが指す DWORD 値は、重複する操作が完了するまで格納されているデータのサイズを決定できないため、0 になる場合があります。 最終的な完了状態は、操作が完了したときに適切な完了メソッドが通知されたときに取得できます。

lpvOverlapped

WSAOVERLAPPED 構造体へのポインター。

重複する属性なしでソケット s が作成された場合、 lpOverlapped パラメーターは無視されます。

重複した属性を使用して s を開き、 lpOverlapped パラメーターが NULL でない場合、操作は重複 (非同期) 操作として実行されます。 この場合、 lpOverlapped パラメーターは有効な WSAOVERLAPPED 構造体を指している必要があります。

重複する操作の場合、 WSAIoctl または WSPIoctl 関数は直ちにを返し、操作が完了すると適切な完了メソッドが通知されます。 それ以外の場合、操作が完了するかエラーが発生するまで、関数は を返しません。

lpCompletionRoutine

種類: _In_opt_ LPWSAOVERLAPPED_COMPLETION_ROUTINE

操作が完了したときに呼び出される完了ルーチンへのポインター (重複していないソケットの場合は無視されます)。

lpThreadId

WPUQueueApc への後続の呼び出しでプロバイダーによって使用される WSATHREADID 構造体へのポインター。 プロバイダーは、WPUQueueApc 関数が返されるまで、参照先の WSATHREADID 構造体 (同じへのポインターではない) を格納する必要があります。

メモ このパラメーターは 、WSPIoctl 関数にのみ適用されます。

lpErrno

エラー コードへのポインター。

メモ このパラメーターは 、WSPIoctl 関数にのみ適用されます。

戻り値

操作が正常に完了すると、 WSAIoctl または WSPIoctl 関数は 0 を返します。

操作が失敗した場合、または保留中の場合、 WSAIoctl または WSPIoctl 関数は SOCKET_ERRORを返します。 拡張エラー情報を取得するには、 WSAGetLastError を呼び出します。

エラー コード 意味
WSA_IO_PENDING 重複した I/O 操作が進行中です。 この値は、重複した操作が正常に開始され、完了が後で示される場合に返されます。
WSA_OPERATION_ABORTED スレッドの終了またはアプリケーションの要求が原因で、I/O 操作が中止されました。 このエラーは、ソケットのクローズまたはSIO_FLUSH IOCTL コマンドの実行により、重複した操作が取り消された場合 返されます。
WSAEFAULT 呼び出しでポインター引数を使用しようとしたときに、システムによって無効なポインター アドレスが検出されました。 このエラーは、 lpvInBufferlpvoutBufferlpcbBytesReturnedlpOverlapped または lpCompletionRoutine パラメーターが、ユーザー アドレス空間の有効な部分に完全に含まれていない場合に返されます。
WSAEINPROGRESS 現在、ブロック操作を実行中です。 このエラーは、コールバックの進行中に関数が呼び出された場合に返されます。
WSAEINTR WSACancelBlockingCall の呼び出しによってブロック操作が中断されました。 このエラーは、ブロック操作が中断された場合に返されます。
WSAEINVAL 無効な引数が指定されました。 このエラーは、 dwIoControlCode パラメーターが有効なコマンドではない場合、または指定した入力パラメーターが受け入れられない場合、または指定されたソケットの型にコマンドが適用されない場合に返されます。
WSAENETDOWN ソケット操作によりネットワークの停止が検出されました。 このエラーは、ネットワーク サブシステムが失敗した場合に返されます。
WSAENOTSOCK ソケットではない何かに対して操作が試行されました。 記述子 s がソケットでない場合、このエラーが返されます。
WSAEOPNOTSUPP 参照されるオブジェクトの種類に対して、試行された操作はサポートされていません。 このエラーは、指定された IOCTL コマンドがサポートされていない場合に返されます。 このエラーは、 SIO_ACQUIRE_PORT_RESERVATION IOCTL がトランスポート プロバイダーでサポートされていない場合にも返されます。 このエラーは、 SIO_ACQUIRE_PORT_RESERVATION IOCTL の使用が UDP または TCP 以外のソケットで行われた場合にも返されます。

解説

SIO_ACQUIRE_PORT_RESERVATION IOCTL は、Windows Vista 以降のバージョンのオペレーティング システムでサポートされています。

ポートを予約する必要があるアプリケーションとサービスは、2 つのカテゴリに分類されます。 最初のカテゴリには、操作の一部として特定のポートを必要とするコンポーネントが含まれます。 このようなコンポーネントは、通常、インストール時に必要なポートを指定することを好みます (たとえば、アプリケーション マニフェスト内)。 2 番目のカテゴリには、実行時に使用可能なポートまたはポート ブロックを必要とするコンポーネントが含まれます。 これら 2 つのカテゴリは、特定のポート予約要求とワイルドカード ポート予約要求に対応します。 特定の予約要求は永続的または実行時である場合があります。一方、ワイルドカード ポート予約要求は実行時にのみサポートされます。

SIO_ACQUIRE_PORT_RESERVATION IOCTL は、TCP または UDP ポートのブロックのランタイム予約を要求するために使用されます。 ランタイム ポート予約の場合、ポート プールでは、予約が許可されたソケット上のプロセスから予約を使用する必要があります。 ランタイム ポート予約は、 SIO_ACQUIRE_PORT_RESERVATION IOCTL が呼び出されたソケットの有効期間に限り続きます。 これに対し、 CreatePersistentTcpPortReservation または CreatePersistentUdpPortReservation 関数を使用して作成された永続的なポート予約は、永続的な予約を取得する機能を持つ任意のプロセスによって使用される場合があります。

ランタイム TCP または UDP ポート予約が取得されると、アプリケーションは TCP または UDP ソケットを開き、SIO_ASSOCIATE_PORT_RESERVATION IOCTL を指定して WSAIoctl 関数を呼び出し、予約トークンを渡してからソケットのバインド関数の呼び出しを発行することで、ポート予約からポート割り当てを要求できます。

lpOverlapped パラメーターと lpCompletionRoutine パラメーターの両方が NULL の場合、この関数のソケットは重複しないソケットとして扱われます。 重複していないソケットの場合、 lpOverlapped パラメーターと lpCompletionRoutine パラメーターは無視されます。ただし、ソケット s がブロック モードの場合、関数はブロックできます。 ソケット s が非ブロッキング モードの場合、この特定の IOCTL では非ブロッキング モードがサポートされていないため、この関数は引き続きブロックされます。

重複するソケットの場合、すぐに完了できない操作が開始され、完了は後で示されます。

サービス プロバイダーの実装によっては、IOCTL が無期限にブロックされる場合があります。 アプリケーションが WSAIoctl または WSPIoctl 関数呼び出しでブロックを許容できない場合は、特にブロックする可能性が高い IOCTL に対して重複した I/O が推奨されます。

SIO_ACQUIRE_PORT_RESERVATION IOCTL は、WSAEINTR または次の場合にWSA_OPERATION_ABORTEDで失敗する可能性があります。

  • 要求は I/O マネージャーによって取り消されます。
  • ソケットが閉じています。

次の例では、ランタイム ポート予約を取得し、ソケットを作成し、ソケットのランタイム ポート予約からポートを割り当ててから、ソケットを閉じ、ランタイム ポート予約を解放します。

#ifndef UNICODE
#define UNICODE
#endif

#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif

#include <Windows.h.>
#include <winsock2.h>
#include <mstcpip.h>
#include <ws2ipdef.h>
#include <stdio.h>
#include <stdlib.h>

// Need to link with Ws2_32.lib for Winsock functions
#pragma comment(lib, "ws2_32.lib")

int wmain(int argc, WCHAR ** argv)
{

    // Declare and initialize variables

    int startPort = 0;          // host byte order
    int numPorts = 0;
    USHORT startPortns = 0;     // Network byte order

    INET_PORT_RANGE portRange = { 0 };
    INET_PORT_RESERVATION_INSTANCE portRes = { 0 };

    unsigned long status = 0;

    WSADATA wsaData = { 0 };
    int iResult = 0;

    SOCKET sock = INVALID_SOCKET;
    int iFamily = AF_INET;
    int iType = 0;
    int iProtocol = 0;

    SOCKET sockRes = INVALID_SOCKET;

    DWORD bytesReturned = 0;

    // Note that the sockaddr_in struct works only with AF_INET not AF_INET6
    // An application needs to use the sockaddr_in6 for AF_INET6
    sockaddr_in service;
    sockaddr_in sockName;
    int nameLen = sizeof (sockName);

    // Validate the parameters
    if (argc != 6) {
        wprintf
            (L"usage: %s <addressfamily> <type> <protocol> <StartingPort> <NumberOfPorts>\n",
             argv[0]);
        wprintf(L"Opens a socket for the specified family, type, & protocol\n");
        wprintf
            (L"and then acquires a runtime port reservation for the protocol specified\n");
        wprintf(L"%ws example usage\n", argv[0]);
        wprintf(L"   %ws 2 2 17 5000 20\n", argv[0]);
        wprintf(L"   where AF_INET=2 SOCK_DGRAM=2 IPPROTO_UDP=17 StartPort=5000 NumPorts=20", argv[0]);

        return 1;
    }

    iFamily = _wtoi(argv[1]);
    iType = _wtoi(argv[2]);
    iProtocol = _wtoi(argv[3]);

    startPort = _wtoi(argv[4]);
    if (startPort < 0 || startPort > 65535) {
        wprintf(L"Starting point must be either 0 or between 1 and 65,535\n");
        return 1;
    }
    startPortns = htons((USHORT) startPort);

    numPorts = _wtoi(argv[5]);
    if (numPorts < 0) {
        wprintf(L"Number of ports must be a positive number\n");
        return 1;
    }

    portRange.StartPort = startPortns;
    portRange.NumberOfPorts = (USHORT) numPorts;

    // Initialize Winsock
    iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (iResult != 0) {
        wprintf(L"WSAStartup failed with error = %d\n", iResult);
        return 1;
    }

    sock = socket(iFamily, iType, iProtocol);
    if (sock == INVALID_SOCKET) {
        wprintf(L"socket function failed with error = %d\n", WSAGetLastError());
        WSACleanup();
        return 1;
    } else {
        wprintf(L"socket function succeeded\n");

        iResult =
            WSAIoctl(sock, SIO_ACQUIRE_PORT_RESERVATION, (LPVOID) & portRange,
                     sizeof (INET_PORT_RANGE), (LPVOID) & portRes,
                     sizeof (INET_PORT_RESERVATION_INSTANCE), &bytesReturned, NULL, NULL);
        if (iResult != 0) {
            wprintf(L"WSAIoctl(SIO_ACQUIRE_PORT_RESERVATION) failed with error = %d\n",
                    WSAGetLastError());
            closesocket(sock);
            WSACleanup();
            return 1;
        } else {
            wprintf
                (L"WSAIoctl(SIO_ACQUIRE_PORT_RESERVATION) succeeded, bytesReturned = %u\n",
                 bytesReturned);
            wprintf(L"  Starting port=%d,  Number of Ports=%d, Token=%I64d\n",
                    htons(portRes.Reservation.StartPort),
                    portRes.Reservation.NumberOfPorts, portRes.Token);

            sockRes = socket(iFamily, iType, iProtocol);
            if (sockRes == INVALID_SOCKET) {
                wprintf(L"socket function for second socket failed with error = %d\n",
                        WSAGetLastError());
                closesocket(sock);
                WSACleanup();
                return 1;
            } else {
                wprintf(L"socket function for second socket succeeded\n");

                iResult =
                    WSAIoctl(sock, SIO_ASSOCIATE_PORT_RESERVATION,
                             (LPVOID) & portRes.Token, sizeof (ULONG64), NULL, 0,
                             &bytesReturned, NULL, NULL);
                if (iResult != 0) {
                    wprintf
                        (L"WSAIoctl(SIO_ASSOCIATE_PORT_RESERVATION) failed with error = %d\n",
                         WSAGetLastError());
                } else {
                    wprintf
                        (L"WSAIoctl(SIO_ASSOCIATE_PORT_RESERVATION) succeeded, bytesReturned = %u\n",
                         bytesReturned);

                    service.sin_family = (ADDRESS_FAMILY) iFamily;
                    service.sin_addr.s_addr = INADDR_ANY;
                    service.sin_port = 0;

                    iResult = bind(sock, (SOCKADDR *) & service, sizeof (service));
                    if (iResult == SOCKET_ERROR)
                        wprintf(L"bind failed with error = %d\n", WSAGetLastError());
                    else {
                        wprintf(L"bind succeeded\n");
                        iResult = getsockname(sock, (SOCKADDR *) & sockName, &nameLen);
                        if (iResult == SOCKET_ERROR)
                            wprintf(L"getsockname failed with error = %d\n",
                                    WSAGetLastError());
                        else {
                            wprintf(L"getsockname succeeded\n");
                            wprintf(L"Port number allocated = %u\n",
                                    ntohs(sockName.sin_port));
                        }
                    }
                }
            }

            // comment out this block of code if you don't want to delete the reservation just created
            iResult =
                WSAIoctl(sock, SIO_RELEASE_PORT_RESERVATION, (LPVOID) & portRes.Token,
                         sizeof (ULONG64), NULL, 0, &bytesReturned, NULL, NULL);
            if (iResult != 0) {
                wprintf
                    (L"WSAIoctl(SIO_RELEASE_PORT_RESERVATION) failed with error = %d\n",
                     WSAGetLastError());
            } else {
                wprintf
                    (L"WSAIoctl(SIO_RELEASE_PORT_RESERVATION) succeeded, bytesReturned = %u\n",
                     bytesReturned);
            }
        }

        if (sockRes != INVALID_SOCKET) {
            iResult = closesocket(sockRes);
            if (iResult == SOCKET_ERROR) {
                wprintf(L"closesocket for second socket failed with error = %d\n",
                        WSAGetLastError());
            }
        }
        if (sock != INVALID_SOCKET) {
            iResult = closesocket(sock);
            if (iResult == SOCKET_ERROR) {
                wprintf(L"closesocket for first socket failed with error = %d\n",
                        WSAGetLastError());
            }
        }
    }

    WSACleanup();

    return 0;
}

関連項目

受け入れる

バインド

CreatePersistentTcpPortReservation

CreatePersistentUdpPortReservation

DeletePersistentTcpPortReservation

DeletePersistentUdpPortReservation

INET_PORT_RANGE

INET_PORT_RESERVATION_INSTANCE

LookupPersistentTcpPortReservation

LookupPersistentUdpPortReservation

SIO_ASSOCIATE_PORT_RESERVATION

SIO_RELEASE_PORT_RESERVATION

ソケット

WSAGetLastError

WSAGetOverlappedResult

WSAIoctl

WSAOVERLAPPED

WSASocketA

WSASocketW