WSAAccept, fonction (winsock2.h)

La fonction WSAAccept accepte de manière conditionnelle une connexion basée sur la valeur de retour d’une fonction condition, fournit des spécifications de flux de qualité de service et autorise le transfert des données de connexion.

Syntaxe

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

Paramètres

[in] s

Descripteur qui identifie un socket qui écoute les connexions après un appel à la fonction d’écoute .

[out] addr

Pointeur facultatif vers une structure sockaddr qui reçoit l’adresse de l’entité de connexion, telle que connue pour la couche de communications. Le format exact du paramètre addr est déterminé par la famille d’adresses établie lors de la création du socket.

[in, out] addrlen

Pointeur facultatif vers un entier qui contient la longueur de la structure sockaddr pointée par le paramètre addr , en octets.

[in] lpfnCondition

Adresse d’une fonction de condition facultative spécifiée par l’application qui prendra une décision d’acceptation/rejet en fonction des informations de l’appelant passées en tant que paramètres, et éventuellement créera ou joindrea un groupe de sockets en affectant une valeur appropriée au paramètre de résultat g de cette fonction. Si ce paramètre a la valeur NULL, aucune fonction de condition n’est appelée.

[in] dwCallbackData

Données de rappel transmises à la fonction de condition spécifiée par l’application en tant que valeur du paramètre dwCallbackData passé à la fonction condition. Ce paramètre s’applique uniquement si le paramètre lpfnCondition n’est pas NULL. Ce paramètre n’est pas interprété par Windows Sockets.

Valeur retournée

Si aucune erreur ne se produit, WSAAccept retourne une valeur de type SOCKET qui est un descripteur pour le socket accepté. Sinon, une valeur de INVALID_SOCKET est retournée et un code d’erreur spécifique peut être récupéré en appelant WSAGetLastError.

L’entier auquel fait référence addrlen contient initialement la quantité d’espace pointée par addrlen. Au retour, il contient la longueur réelle en octets de l’adresse retournée.

Code d'erreur Signification
WSAEACCES
Une tentative d’accès à un socket a été effectuée de manière interdite par ses autorisations d’accès. Cette erreur est retournée si la demande de connexion qui a été proposée a expiré ou a été retirée.
WSAECONNREFUSED
Aucune connexion n'a pu être établie car l'ordinateur cible l'a expressément refusée. Cette erreur est retournée si la demande de connexion a été rejetée de force, comme indiqué dans la valeur de retour de la fonction de condition (CF_REJECT).
WSAECONNRESET
une connexion existante a dû être fermée par l’hôte distant. Cette erreur est retournée car une connexion entrante a été indiquée, mais a été arrêtée par la suite par l’homologue distant avant d’accepter l’appel.
WSAEFAULT
Le système a détecté une adresse de pointeur non valide lors de la tentative d’utilisation d’un argument pointeur dans un appel. Cette erreur est retournée si le paramètre addrlen est trop petit ou que le addr ou lpfnCondition ne fait pas partie de l’espace d’adressage utilisateur.
WSAEINTR
Une opération de blocage a été interrompue par un appel à WSACancelBlockingCall. Cette erreur est retournée si un appel Windows Sockets 1.1 bloquant a été annulé via WSACancelBlockingCall.
WSAEINPROGRESS
Une opération de blocage est actuellement en cours d'exécution. Cette erreur est retournée si un appel Windows Sockets 1.1 bloquant est en cours.
WSAEINVAL
Argument non valide fourni. Cette erreur est retournée si listen n’a pas été appelé avant WSAAccept, si la valeur de retour de la fonction condition n’est pas valide ou si le socket spécifié n’est pas dans un état non valide.
WSAEMFILE
Trop de sockets ouverts. Cette erreur est retournée si la file d’attente est vide lors de l’entrée dans WSAAccept et qu’aucun descripteur de socket n’est disponible.
WSAENETDOWN
Une opération de socket a rencontré un réseau inactif. Cette erreur est retournée si le sous-système réseau a échoué.
WSAENOBUFS
Impossible d’effectuer une opération sur un socket, car le système n’avait pas suffisamment d’espace de mémoire tampon ou car une file d’attente était pleine. Cette erreur est retournée si aucun espace de mémoire tampon n’est disponible.
WSAENOTSOCK
Une opération a été tentée sur un objet qui n’est pas un socket. Cette erreur est retournée si le descripteur de socket passé dans le paramètre s n’est pas un socket.
WSAEOPNOTSUPP
La famille de protocoles n’a pas été configurée dans le système ou il n’existe aucune implémentation pour elle. Cette erreur est retournée si le socket référencé n’est pas un type qui prend en charge le service orienté connexion.
WSAEWOULDBLOCK
Une opération de socket non bloquante n’a pas pu être effectuée immédiatement. Cette erreur est retournée si le socket est marqué comme non bloquant et qu’aucune connexion n’est présente pour être acceptée.
WSANOTINITIALISED
L’application n’a pas appelé WSAStartup ou WSAStartup a échoué. Cette erreur est retournée d’un appel réussi à la fonction WSAStartup et ne se produit pas avant l’utilisation de cette fonction.
WSATRY_AGAIN
Il s'agit habituellement d'une erreur temporaire qui se produit durant la résolution du nom d'hôte et qui signifie que le serveur local n'a pas reçu de réponse d'un serveur de référence. Cette erreur est retournée si l’acceptation de la demande de connexion a été différée comme indiqué dans la valeur de retour de la fonction de condition (CF_DEFER).

Remarques

La fonction WSAAccept extrait la première connexion dans la file d’attente des connexions en attente sur les sockets et la vérifie par rapport à la fonction condition, à condition que la fonction condition soit spécifiée (autrement dit, pas NULL). Si la fonction condition retourne CF_ACCEPT, WSAAccept crée un socket. Le socket nouvellement créé a les mêmes propriétés que les sockets, y compris les événements asynchrones inscrits auprès de WSAAsyncSelect ou avec WSAEventSelect. Si la fonction condition retourne CF_REJECT, WSAAccept rejette la demande de connexion. La fonction condition s’exécute dans le même thread que cette fonction et doit être retournée dès que possible. Si la décision ne peut pas être prise immédiatement, la fonction condition doit retourner CF_DEFER pour indiquer qu’aucune décision n’a été prise et qu’aucune action concernant cette demande de connexion ne doit être prise par le fournisseur de services. Lorsque l’application est prête à prendre des mesures sur la demande de connexion, elle appelle à nouveau WSAAccept et retourne CF_ACCEPT ou CF_REJECT en tant que valeur de retour de la fonction condition.

Un socket en mode par défaut (bloquant) se bloque jusqu’à ce qu’une connexion soit présente lorsqu’une application appelle WSAAccept et qu’aucune connexion n’est en attente dans la file d’attente.

Un socket en mode non bloquant (blocage) échoue avec l’erreur WSAEWOULDBLOCK lorsqu’une application appelle WSAAccept et qu’aucune connexion n’est en attente dans la file d’attente. Une fois que WSAAccept a réussi et retourné un nouveau handle de socket, le socket accepté ne peut plus être utilisé pour accepter d’autres connexions. Le socket d’origine reste ouvert et écoute les nouvelles demandes de connexion.

Le paramètre addr est un paramètre de résultat qui est rempli avec l’adresse de l’entité de connexion, telle que connue pour la couche de communication. Le format exact du paramètre addr est déterminé par la famille d’adresses dans laquelle la communication se produit. Addrlen est un paramètre value-result ; il doit initialement contenir la quantité d’espace pointée par addr. Au retour, il contient la longueur réelle (en octets) de l’adresse retournée. Cet appel est utilisé avec les types de sockets orientés connexion tels que SOCK_STREAM. Si addr et/ou addrlen sont égaux à NULL, aucune information sur l’adresse distante du socket accepté n’est retournée. Sinon, ces deux paramètres sont renseignés si la connexion est acceptée avec succès.

Un prototype de la fonction condition est défini dans le Winsock2.h fichier d’en-tête en tant que LPCONDITIONPROC, comme suit.

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 est un espace réservé pour la fonction de rappel spécifiée par l’application. La fonction de condition réelle doit résider dans une DLL ou un module d’application. Il est exporté dans le fichier de définition de module.

Le paramètre lpCallerId pointe vers une structure WSABUF qui contient l’adresse de l’entité de connexion, où son paramètre len est la longueur de la mémoire tampon en octets, et son paramètre buf est un pointeur vers la mémoire tampon. LpCallerData est un paramètre de valeur qui contient des données utilisateur. Les informations contenues dans ces paramètres sont envoyées avec la demande de connexion. Si aucune donnée d’identification ou d’appelant n’est disponible, les paramètres correspondants sont NULL. De nombreux protocoles réseau ne prennent pas en charge les données de l’appelant au moment de la connexion. La plupart des protocoles réseau classiques peuvent prendre en charge les informations d’identificateur de l’appelant au moment de la demande de connexion. La partie buf du WSABUF pointée vers lpCallerId pointe vers un sockaddr. La structure sockaddr est interprétée en fonction de sa famille d’adresses (généralement en castant le sockaddr sur un type spécifique à la famille d’adresses).

Le paramètre lpSQOS référence les structures FLOWSPEC pour les sockets spécifiés par l’appelant, un pour chaque direction, suivi de tous les paramètres supplémentaires spécifiques au fournisseur. Les valeurs de spécification de flux d’envoi ou de réception sont ignorées en fonction des sockets unidirectionnels. Une valeur NULL indique qu’il n’existe aucune qualité de service fournie par l’appelant et qu’aucune négociation n’est possible. Un pointeur lpSQOS non NULL indique qu’une négociation de qualité de service doit avoir lieu ou que le fournisseur est prêt à accepter la demande de qualité de service sans négociation.

Le paramètre lpGQOS est réservé et doit avoir la valeur NULL. (réservé à une utilisation ultérieure avec des groupes de sockets) fait référence à la structure FLOWSPEC pour le groupe de sockets que l’appelant doit créer, un pour chaque direction, suivi de paramètres supplémentaires spécifiques au fournisseur. Une valeur NULL pour lpGQOS n’indique aucune qualité de service de groupe spécifiée par l’appelant. Les informations sur la qualité du service peuvent être retournées si la négociation doit avoir lieu.

Le lpCalleeId est un paramètre qui contient l’adresse locale de l’entité connectée. La partie buf du WSABUF pointée vers lpCalleeId pointe vers une structure de sockaddr . La structure sockaddr est interprétée en fonction de sa famille d’adresses (généralement en cassant le sockaddr sur un type spécifique à la famille d’adresses, comme struct sockaddr_in).

LpCalleeData est un paramètre de résultat utilisé par la fonction condition pour fournir des données utilisateur à l’entité de connexion. L’objet lpCalleeData-len> contient initialement la longueur de la mémoire tampon allouée par le fournisseur de services et pointée par lpCalleeData-buf>. La valeur zéro signifie que la transmission de données utilisateur à l’appelant n’est pas prise en charge. La fonction condition doit copier jusqu’à lpCalleeData-len> octets de données dans lpCalleeData-buf>, puis mettre à jour lpCalleeData-len> pour indiquer le nombre réel d’octets transférés. Si aucune donnée utilisateur ne doit être transmise à l’appelant, la fonction condition doit définir lpCalleeData-len> sur zéro. Le format de toutes les données d’adresse et d’utilisateur est spécifique à la famille d’adresses à laquelle appartient le socket.

Le paramètre g est affecté dans la fonction condition pour indiquer l’une des actions suivantes :

  • Si g est un identificateur de groupe de sockets existant, ajoutez des s à ce groupe, à condition que toutes les exigences définies par ce groupe soient remplies.
  • Si g = SG_UNCONSTRAINED_GROUP, créez un groupe de sockets sans contrainte et avez s comme premier membre.
  • Si g = SG_CONSTRAINED_GROUP, créez un groupe de sockets contraint et avez s comme premier membre.
  • Si g = zéro, aucune opération de groupe n’est effectuée.
Pour les groupes sans contrainte, n’importe quel ensemble de sockets peut être regroupé tant qu’ils sont pris en charge par un seul fournisseur de services. Un groupe de sockets contraints ne peut se composer que de sockets orientés connexion, et nécessite que les connexions sur tous les sockets groupés soient à la même adresse sur le même hôte. Pour les groupes de sockets nouvellement créés, le nouvel identificateur de groupe peut être récupéré à l’aide de la fonction getsockopt avec le paramètre de niveau défini sur SOL_SOCKET et le paramètre optname défini sur SO_GROUP_ID. Un groupe de sockets et son ID de groupe de sockets associé restent valides jusqu’à ce que le dernier socket appartenant à ce groupe de sockets soit fermé. Les ID de groupe de sockets sont uniques pour tous les processus d’un fournisseur de services donné. Un groupe de sockets et son identificateur associé restent valides jusqu’à ce que le dernier socket appartenant à ce groupe de sockets soit fermé. Les identificateurs de groupe de sockets sont uniques pour tous les processus d’un fournisseur de services donné. Pour plus d’informations sur les groupes de sockets, consultez Remarques relatives aux fonctions WSASocket .

La valeur du paramètre dwCallbackData passée à la fonction condition est la valeur passée en tant que paramètre dwCallbackData dans l’appel WSAAccept d’origine. Cette valeur est interprétée uniquement par le client Windows Socket version 2. Cela permet à un client de transmettre certaines informations de contexte du site d’appel WSAAccept à la fonction condition. Cela fournit également à la fonction condition toutes les informations supplémentaires requises pour déterminer s’il faut accepter la connexion ou non. Une utilisation classique consiste à passer un pointeur (correctement casté) à une structure de données contenant des références aux objets définis par l’application auxquels ce socket est associé.

Note Pour protéger l’utilisation de la fonction WSAAccept contre les attaques SYN, les applications doivent effectuer des liaisons TCP complètes (SYN-SYNACK-ACK) avant de signaler la demande de connexion. La protection contre les attaques SYN de cette manière entraîne l’inopérante option de socket SO_CONDITIONAL_ACCEPT ; la fonction conditionnelle est toujours appelée et la fonction WSAAccept fonctionne correctement, mais les applications serveur qui s’appuient sur des clients ne peuvent pas effectuer l’établissement d’une liaison ne fonctionnent pas correctement.
 
Note Lors de l’émission d’un appel Winsock bloquant tel que WSAAccept, Winsock peut avoir besoin d’attendre un événement réseau avant que l’appel puisse se terminer. Winsock effectue une attente alertable dans cette situation, qui peut être interrompue par un appel de procédure asynchrone (APC) planifié sur le même thread. L’émission d’un autre appel Winsock bloquant à l’intérieur d’un APC qui a interrompu un appel Winsock bloquant en cours sur le même thread entraîne un comportement non défini et ne doit jamais être tenté par les clients Winsock.
 

Exemple de code

L’exemple suivant illustre l’utilisation de la fonction 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 : cette fonction est prise en charge pour les applications du Store Windows Phone Windows Phone 8 et versions ultérieures.

Windows 8.1 et Windows Server 2012 R2 : cette fonction est prise en charge pour les applications du Windows Store sur Windows 8.1, Windows Server 2012 R2 et versions ultérieures.

Configuration requise

Condition requise Valeur
Client minimal pris en charge Windows 8.1, Windows Vista [applications de bureau | Applications UWP]
Serveur minimal pris en charge Windows Server 2003 [applications de bureau | applications UWP]
Plateforme cible Windows
En-tête winsock2.h
Bibliothèque Ws2_32.lib
DLL Ws2_32.dll

Voir aussi

WSAAsyncSelect

WSAConnect

WSASocket

Fonctions Winsock

Informations de référence sur Winsock

Accepter

bind

connect

getsockopt

listen

select

sockaddr

socket