WSAAccept 関数 (winsock2.h)

WSAAccept 関数は、条件関数の戻り値に基づいて条件付きで接続を受け入れ、サービス フローの品質仕様を提供し、接続データの転送を許可します。

構文

SOCKET WSAAPI WSAAccept(
  [in]      SOCKET          s,
  [out]     sockaddr        *addr,
  [in, out] LPINT           addrlen,
  [in]      LPCONDITIONPROC lpfnCondition,
  [in]      DWORD_PTR       dwCallbackData
);

パラメーター

[in] s

listen 関数の呼び出し後に接続をリッスンしているソケットを識別する記述子。

[out] addr

通信レイヤーと呼ばれる接続エンティティのアドレスを受け取る sockaddr 構造体への省略可能なポインター。 addr パラメーターの正確な形式は、ソケットの作成時に確立されたアドレス ファミリによって決まります。

[in, out] addrlen

addr パラメーターが指す sockaddr 構造体の長さをバイト単位で格納する整数への省略可能なポインター。

[in] lpfnCondition

パラメーターとして渡された呼び出し元情報に基づいて受け入れ/拒否の決定を行い、必要に応じてこの関数の結果パラメーター g に適切な値を割り当てることによってソケット グループを作成または結合する、オプションのアプリケーション指定条件関数のアドレス。 このパラメーターが NULL の場合、条件関数は呼び出されません。

[in] dwCallbackData

条件関数に渡される dwCallbackData パラメーターの値として、アプリケーション指定の条件関数に返されるコールバック データ。 このパラメーターは、 lpfnCondition パラメーターが NULL でない場合にのみ適用されます。 このパラメーターは、Windows ソケットでは解釈されません。

戻り値

エラーが発生しない場合、 WSAAccept は受け入れられたソケットの記述子である SOCKET 型の値を返します。 それ以外の場合は、INVALID_SOCKETの値が返され、 WSAGetLastError を呼び出すことによって特定のエラー コードを取得できます。

最初に addrlen によって参照される整数には、addr が指す領域の量が含まれています。返されたアドレスの実際の長さ (バイト単位) が返されます。

エラー コード 意味
WSAEACCES
アクセス許可で禁じられた方法でソケットにアクセスしようとしました。 このエラーは、提供された接続要求がタイムアウトまたは取り消された場合に返されます。
WSAECONNREFUSED
対象のコンピューターによって拒否されたため、接続できませんでした。 このエラーは、条件関数の戻り値 (CF_REJECT) で示されているように、接続要求が強制的に拒否された場合に返されます。
WSAECONNRESET
リモート ホストによって、既存の接続は強制的に切断されました。 このエラーは、着信接続が示されたが、その後、呼び出しを受け入れる前にリモート ピアによって終了された場合に返されます。
WSAEFAULT
呼び出しでポインター引数を使用しようとしたときに、システムにより、無効なポインター アドレスが検出されました。 このエラーは、 addrlen パラメーターが小さすぎるか、 addr または lpfnCondition がユーザー アドレス空間の一部ではない場合に返されます。
WSAEINTR
WSACancelBlockingCall の呼び出しによってブロック操作が中断されました。 このエラーは、ブロックしている Windows ソケット 1.1 呼び出しが WSACancelBlockingCall を通じて取り消された場合に返されます。
WSAEINPROGRESS
現在、ブロック操作を実行中です。 このエラーは、ブロックしている Windows ソケット 1.1 呼び出しが進行中の場合に返されます。
WSAEINVAL
無効な引数が指定されました。 このエラーは、WSAAccept より前に listen が呼び出されなかった場合、条件関数の戻り値が有効でない場合、または指定されたソケットが無効な状態にある場合に返されます。
WSAEMFILE
開いているソケットが多すぎます。 このエラーは、 WSAAccept への入力時にキューが空でない場合に、使用可能なソケット記述子がない場合に返されます。
WSAENETDOWN
ソケット操作によりネットワークの停止が検出されました。 このエラーは、ネットワーク サブシステムが失敗した場合に返されます。
WSAENOBUFS
システムに十分なバッファー領域がないか、キューがいっぱいであるため、ソケットに対する操作を実行できませんでした。 このエラーは、使用可能なバッファー領域がない場合に返されます。
WSAENOTSOCK
ソケットではないものに対して操作が試行されました。 このエラーは、 パラメーター で渡されたソケット記述子がソケットでない場合に返されます。
WSAEOPNOTSUPP
プロトコル ファミリがシステムに構成されていないか、実装が存在しません。 このエラーは、参照先のソケットが接続指向サービスをサポートする型でない場合に返されます。
WSAEWOULDBLOCK
ノンブロッキングのソケット操作をすぐに完了できませんでした。 このエラーは、ソケットが非ブロッキングとしてマークされ、受け入れられる接続がない場合に返されます。
WSANOTINITIALIZED
アプリケーションが WSAStartup を呼び出していないか、 WSAStartup に失敗しました。 このエラーは、この関数を使用する前に WSAStartup 関数 dit が正常に呼び出されなかった場合に返されます。
WSATRY_AGAIN
これは、通常、ホスト名の解決中に発生する一時エラーであり、ローカル サーバーが、権限のあるサーバーから応答を受信しなかったことを示します。 このエラーは、条件関数の戻り値 (CF_DEFER) で示されているように、接続要求の受け入れが延期された場合に返されます。

注釈

WSAAccept 関数は、ソケット s で保留中の接続のキュー上の最初の接続を抽出し、条件関数が指定されている場合 (つまり NULL ではなく) 条件関数に対して確認します。 条件関数がCF_ACCEPTを返す場合、 WSAAccept は新しいソケットを作成します。 新しく作成されたソケットには、WSAAsyncSelect または WSAEventSelect で登録された非同期イベントを含む、ソケット同じプロパティがあります。 条件関数がCF_REJECTを返す場合、 WSAAccept は接続要求を拒否します。 条件関数は、この関数と同じスレッドで実行され、できるだけ早く を返す必要があります。 決定を直ちに行うことができない場合、条件関数は、決定が行われなかったことを示すCF_DEFERを返し、サービス プロバイダーがこの接続要求に関するアクションを実行しないようにする必要があります。 アプリケーションは、接続要求に対してアクションを実行する準備ができたら、 WSAAccept を再度呼び出し、条件関数から戻り値としてCF_ACCEPTまたはCF_REJECTを返します。

アプリケーションが WSAAccept を呼び出し、キューで保留中の接続がない場合、接続が存在するまで、既定モード (ブロック) のソケットはブロックされます。

アプリケーションが WSAAccept を呼び出し、キューで保留中の接続がない場合、非ブロッキング モード (ブロッキング) のソケットはエラー WSAEWOULDBLOCK で失敗します。 WSAAccept が成功し、新しいソケット ハンドルを返した後、受け入れられたソケットを使用してそれ以上の接続を受け入れることはできません。 元のソケットは開いたままで、新しい接続要求をリッスンします。

addr パラメーターは、通信レイヤーと呼ばれる、接続エンティティのアドレスが入力された結果パラメーターです。 addr パラメーターの正確な形式は、通信が行われているアドレス ファミリによって決まります。 addrlen は値の結果パラメーターです。最初は、addr が指す領域の量を含める必要があります。返されたアドレスの実際の長さ (バイト単位) が返されます。 この呼び出しは、SOCK_STREAM などの接続指向のソケット型で使用されます。 addraddrlenNULL に等しい場合、受け入れられたソケットのリモート アドレスに関する情報は返されません。 それ以外の場合、接続が正常に受け入れられると、これら 2 つのパラメーターが入力されます。

条件関数のプロトタイプは、次のようにヘッダー ファイルで Winsock2.hLPCONDITIONPROC として定義されます。

int CALLBACK 
ConditionFunc( 
  IN     LPWSABUF    lpCallerId, 
  IN     LPWSABUF    lpCallerData, 
  IN OUT LPQOS       lpSQOS, 
  IN OUT LPQOS       lpGQOS,
  IN     LPWSABUF    lpCalleeId, 
  IN     LPWSABUF    lpCalleeData, 
  OUT    GROUP FAR * g, 	
  IN     DWORD_PTR   dwCallbackData
);

ConditionFunc は、アプリケーション指定のコールバック関数のプレースホルダーです。 実際の条件関数は、DLL またはアプリケーション モジュールに存在する必要があります。 これはモジュール定義ファイルにエクスポートされます。

lpCallerId パラメーターは、接続エンティティのアドレスを含む WSABUF 構造体を指します。ここで、len パラメーターはバッファーの長さ (バイト単位)、buf パラメーターはバッファーへのポインターです。 lpCallerData は、ユーザー データを含む値パラメーターです。 これらのパラメーターの情報は、接続要求と共に送信されます。 呼び出し元 ID または呼び出し元データが使用できない場合、対応するパラメーターは NULL になります。 多くのネットワーク プロトコルでは、接続時の呼び出し元データはサポートされていません。 ほとんどの従来のネットワーク プロトコルでは、接続要求時に呼び出し元識別子情報をサポートすることが期待できます。 lpCallerId が指す WSABUF の buf 部分は sockaddr を指します。 sockaddr 構造体は、そのアドレス ファミリに従って解釈されます (通常は、アドレス ファミリに固有の型に sockaddr をキャストします)。

lpSQOS パラメーターは、呼び出し元によって指定されたソケット sFLOWSPEC 構造体を、各方向に 1 つずつ参照し、その後にプロバイダー固有の追加パラメーターを参照します。 送信側または受信側のフロー仕様値は、任意の単一方向ソケットに対して適切に無視されます。 NULL 値は、呼び出し元が提供するサービス品質がなく、ネゴシエーションが不可能であることを示します。 NULL 以外の lpSQOS ポインターは、サービスの品質ネゴシエーションが発生すること、またはプロバイダーがネゴシエーションなしでサービス品質要求を受け入れる準備ができていることを示します。

lpGQOS パラメーターは予約されており、NULL にする必要があります。 (ソケット グループで将来使用するために予約されています) は、呼び出し元が作成するソケット グループの FLOWSPEC 構造体を参照します。その後、各方向に 1 つずつ、その後にプロバイダー固有のパラメーターが追加されます。 lpGQOSNULL 値は、呼び出し元が指定したグループのサービス品質がないことを示します。 ネゴシエーションが発生する場合は、サービスの品質情報を返すことができます。

lpCalleeId は、接続されたエンティティのローカル アドレスを含むパラメーターです。 lpCalleeId が指す WSABUF の buf 部分は、sockaddr 構造体を指します。 sockaddr 構造体は、そのアドレス ファミリに従って解釈されます (通常は、構造体sockaddr_inなど、アドレス ファミリに固有の型に sockaddr をキャストします)。

lpCalleeData は、接続エンティティにユーザー データを返すために condition 関数によって使用される結果パラメーターです。 lpCalleeData-len> には、最初にサービス プロバイダーによって割り当てられ、lpCalleeData-buf> によって指されるバッファーの長さが含まれています。 値が 0 の場合、ユーザー データを呼び出し元に戻すことはサポートされていません。 condition 関数は、lpCalleeData-len バイトまでのデータを lpCalleeData-buf>> にコピーし、転送された実際のバイト数を示すように lpCalleeData-len> を更新する必要があります。 呼び出し元にユーザー データを返さない場合、条件関数は lpCalleeData-len> を 0 に設定する必要があります。 すべてのアドレスとユーザー データの形式は、ソケットが属するアドレス ファミリに固有です。

次のいずれかのアクションを示すために、条件関数内で g パラメーターが割り当てられます。

  • g が既存のソケット グループ識別子の場合は、このグループによって設定されたすべての要件が満たされていれば、このグループに s を追加します。
  • g = SG_UNCONSTRAINED_GROUPの場合は、制約のないソケット グループを作成し、最初のメンバーとして s を持ちます。
  • g = SG_CONSTRAINED_GROUP場合は、制約付きソケット グループを作成し、最初のメンバーとして s を持ちます。
  • g = 0 の場合、グループ操作は実行されません。
制約のないグループの場合、1 つのサービス プロバイダーでサポートされている限り、ソケットのセットをグループ化できます。 制約付きソケット グループは、接続指向ソケットのみで構成でき、グループ化されたすべてのソケット上の接続が同じホスト上の同じアドレスに対して行われる必要があります。 新しく作成されたソケット グループの場合、しいグループ識別子は、level パラメーターが SOL_SOCKET に設定され、optname パラメーターが SO_GROUP_ID に設定された getsockopt 関数を使用して取得できます。 ソケット グループとそれに関連付けられているソケット グループ ID は、このソケット グループに属する最後のソケットが閉じられるまで有効なままです。 ソケット グループ ID は、特定のサービス プロバイダーのすべてのプロセスで一意です。 ソケット グループとそれに関連付けられている識別子は、このソケット グループに属する最後のソケットが閉じられるまで有効なままです。 ソケット グループ識別子は、特定のサービス プロバイダーのすべてのプロセスで一意です。 ソケット グループの詳細については、「 WSASocket 関数の解説」を参照してください。

条件関数に渡される dwCallbackData パラメーター値は、元の WSAAccept 呼び出しで dwCallbackData パラメーターとして渡される値です。 この値は、Windows ソケット バージョン 2 クライアントによってのみ解釈されます。 これにより、クライアントは WSAAccept 呼び出しサイトから条件関数にコンテキスト情報を渡すことができます。 これにより、接続を受け入れるかどうかを判断するために必要な追加情報も条件関数に提供されます。 一般的な使用方法は、このソケットが関連付けられているアプリケーション定義オブジェクトへの参照を含むデータ構造体に (適切にキャストされた) ポインターを渡すことです。

メモWSAAccept 関数の使用を SYN 攻撃から保護するには、アプリケーションが接続要求を報告する前に完全な TCP ハンドシェイク (SYN-SYNACK-ACK) を実行する必要があります。 この方法で SYN 攻撃から保護すると、SO_CONDITIONAL_ACCEPT ソケット オプションが動作不能になります。条件付き関数は引き続き呼び出され、 WSAAccept 関数は正常に動作しますが、ハンドシェイクを実行できないクライアントに依存するサーバー アプリケーションは正しく動作しません。
 
メモWSAAccept などのブロッキング Winsock 呼び出しを発行する場合、Winsock は、呼び出しが完了する前にネットワーク イベントを待機する必要がある場合があります。 Winsock は、この状況でアラート可能な待機を実行します。この待機は、同じスレッドでスケジュールされた非同期プロシージャ 呼び出し (APC) によって中断される可能性があります。 同じスレッドで進行中の Winsock 呼び出しを中断した APC 内で別のブロック Winsock 呼び出しを発行すると、未定義の動作が発生し、Winsock クライアントが試行することはできません。
 

コード例

次の例では、 WSAAccept 関数の使用方法を示します。
#include <winsock2.h>
#include <stdio.h>
#include <windows.h>

/* Define an example conditional function that depends on the pQos field */
int CALLBACK ConditionAcceptFunc(
    LPWSABUF lpCallerId,
    LPWSABUF lpCallerData,
    LPQOS pQos,
    LPQOS lpGQOS,
    LPWSABUF lpCalleeId,
    LPWSABUF lpCalleeData,
    GROUP FAR * g,
    DWORD_PTR dwCallbackData
    )
{

    if (pQos != NULL) {
        RtlZeroMemory(pQos, sizeof(QOS));
        return CF_ACCEPT;
    } else
        return CF_REJECT;
}

int main() {

    /* Declare and initialize variables */
    WSADATA wsaData;
    SOCKET ListenSocket, AcceptSocket;
    struct sockaddr_in saClient;
    int iClientSize = sizeof(saClient);
    u_short port = 27015;
    char* ip;
    sockaddr_in service;
    int error;

    /* Initialize Winsock */
    error = WSAStartup(MAKEWORD(2,2), &wsaData);
    if (error) {
        printf("WSAStartup() failed with error: %d\n", error);
        return 1;
    }

    /* Create a TCP listening socket */
    ListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (ListenSocket == INVALID_SOCKET) {  
        printf("socket() failed with error: %d\n", WSAGetLastError() );
        WSACleanup();
        return 1;
    }

    /*-----------------------------------------  
     *  Set up the sock addr structure that the listening socket
     *  will be bound to. In this case, the structure holds the
     * local IP address and the port specified. */
    service.sin_family = AF_INET;
    service.sin_port = htons(port);
    hostent* thisHost;
    thisHost = gethostbyname("");
    ip = inet_ntoa (*(struct in_addr *)*thisHost->h_addr_list);
    service.sin_addr.s_addr = inet_addr(ip);

    /*-----------------------------------------
     *  Bind the listening socket to the IP address.
     * and port number specified by the sockaddr structure. */
    error = bind(ListenSocket, (SOCKADDR *) &service, sizeof(SOCKADDR));
    if (error == SOCKET_ERROR) {  
        printf("bind() failed with error: %d\n", WSAGetLastError() );
        closesocket(ListenSocket);
        WSACleanup();
        return 1;
    }
  
    /* Make the socket listen for incoming connection requests */
    error = listen(ListenSocket, 1);
    if (error == SOCKET_ERROR) {  
        printf("listen() failed with error: %d\n", WSAGetLastError() );
        closesocket(ListenSocket);
        WSACleanup();
        return 1;
    }
    printf("Listening...\n");
  
    /*-----------------------------------------
     *  Accept an incoming connection request on the
     *  listening socket and transfer control to the 
     * accepting socket. */
    AcceptSocket = WSAAccept(ListenSocket, (SOCKADDR*) &saClient, &iClientSize, 
        &ConditionAcceptFunc, NULL);
 
    /*  Now do some work with the AcceptSocket 
     *  At this point, the application could
     *  handle data transfer on the socket, or other socket
     * functionality.*/
    
    /* Then clean up and quit */

    closesocket(AcceptSocket);
    closesocket(ListenSocket);
    WSACleanup();

    return 0;
}

Windows Phone 8: この関数は、Windows Phone 8 以降のWindows Phone ストア アプリでサポートされています。

Windows 8.1Windows Server 2012 R2: この関数は、Windows 8.1、Windows Server 2012 R2 以降の Windows ストア アプリでサポートされています。

要件

要件
サポートされている最小のクライアント Windows 8.1、 Windows Vista [デスクトップ アプリ |UWP アプリ]
サポートされている最小のサーバー Windows Server 2003 [デスクトップ アプリのみ | UWP アプリ]
対象プラットフォーム Windows
ヘッダー winsock2.h
Library Ws2_32.lib
[DLL] Ws2_32.dll

こちらもご覧ください

WSAAsyncSelect

WSAConnect

WSASocket

Winsock 関数

Winsock リファレンス

accept

bind

connect

getsockopt

listen

select

Sockaddr

socket