recv, recvfrom, recvmsg - Recevoir un message sur une socket.
Les appels-système
recvfrom
et
recvmsg
sont utilisés pour recevoir des messages depuis une socket
s,
et peuvent servir sur une socket orientée connexion ou non.
Si
from
n'est pas NULL, et si la socket n'est pas orientée connexion, l'adresse
de la source du messages y est insérée.
L'argument
fromlen
est un paramètre résultat, initialisé à la taille du
buffer
from,
et modifié en retour pour indiquer la taille réelle de l'adresse
enregistrée.
L'appel
recv
est normalement utilisé sur une socket
connectée
(voir
connect(2))
et est équivalent à
recvfrom
avec un paramètre
from
nul.
Ces trois routines renvoient la longueur du message si elles
réussissent. Si un message est trop long pour tenir dans le
buffer, les octets supplémentaires peuvent être abandonnés
suivant le type de socket utilisé (voir
socket(2)).
Si aucun message n'est disponible sur la socket, les fonctions de réception se
mettent en attente, à moins que la socket soit non bloquante (voir
fcntl(2))
auquel cas la valeur -1 est renvoyée, et
errno
est positionnée à
EAGAIN.
Les fonctions de réception renvoient normalement les données disponibles
sans attendre d'avoir reçu le nombre exact réclamé.
Les appels-système
select(2)
ou
poll(2)
peuvent permettre de déterminer si des données supplémentaires sont disponibles.
L'argument
flags
de l'appel recv est constitué par un
OU binaire
entre une ou plusieurs des valeurs suivantes :
- MSG_OOB
-
permet la lecture des données hors-bande qui ne seraient autrement
pas placées dans le flux de données normales. Certains protocoles
placent ces données hors-bande en tête de la file normale, et cette
option n'a pas lieu d'être dans ce cas.
- MSG_PEEK
-
permet de lire les données en attente dans la file sans les enlever de
cette file. Ainsi une lecture ultérieure renverra à nouveau les
mêmes données.
- MSG_WAITALL
-
demande que l'opération de lecture soit bloquée jusqu'à ce que la requête
complète soit satisfaite. Toutefois la lecture peut renvoyer quand même moins
de données que prévu si un signal est reçu, ou si une erreur ou une
déconnexion se produisent.
- MSG_NOSIGNAL
-
désactive l'émission de
SIGPIPE
sur les sockets connectées dont le correspondant disparaît.
- MSG_TRUNC
-
Renvoyer la longueur réelle du paquet, même s'il était plus long que le
buffer transmis. Valide uniquement pour les sockets paquets.
- MSG_ERRQUEUE
-
Cet attribut demande que les erreurs soient reçues depuis la file d'erreur
de la socket. Les erreurs sont transmises dans un message annexe dont le
type dépend du protocole
(IP_RECVERR pour IPv4). Il faut alors fournir un buffer de taille
suffisante. Voir
cmsg(3)
et
ip(7)
pour plus de détails.
Le contenu du paquet original qui a causé l'erreur est passé en tant que
données normales dans
msg_iovec.
L'adresse de destination originale du datagramme ayant causé l'erreur est
fournie dans
msg_name.
-
Pour les erreurs locales, aucune adresse n'est passée (ceci peut être vérifié
dans le membre
cmsg_len
de
cmsghdr).
Pour les erreurs reçues, le
MSG_ERRQUEUE
est placé dans
msghdr.
Après qu'une erreur ait été transmise, l'erreur en attente sur la socket
est régénérée en fonction de la prochaine erreur dans la file, et sera
transmise lors de l'opération suivante sur la socket.
L'erreur est contenue dans une structure
sock_extended_err :
-
-
#define SO_EE_ORIGIN_NONE 0
#define SO_EE_ORIGIN_LOCAL 1
#define SO_EE_ORIGIN_ICMP 2
#define SO_EE_ORIGIN_ICMP6 3
struct sock_extended_err
{
u_int32_t ee_errno; /* numéro d'erreur */
u_int8_t ee_origin; /* origine de l'erreur */
u_int8_t ee_type; /* type */
u_int8_t ee_code; /* code */
u_int8_t ee_pad; /* remplissage */
u_int32_t ee_info; /* données supplémentaires*/
u_int32_t ee_data; /* autres données */
/* More data may follow */
};
struct sockaddr *SO_EE_OFFENDER(struct sock_extended_err *);
-
ee_errno
contient le code errno de l'erreur en file.
ee_origin
est le code d'origine de l'erreur.
Les autres champs sont spécifiques au protocole. La macro
SOCK_EE_OFFENDER
renvoie un pointeur sur l'adresse de l'objet réseau ayant déclenché
l'erreur, à partir d'un pointeur sur le message.
Si l'adresse n'est pas connue, le membre
sa_family
de la structure
sockaddr
contient
AF_UNSPEC
et les autres champs de la structure
sockaddr
sont indéfinis.
Le contenu du paquet ayant déclenché l'erreur est transmis en données normales.
-
Pour les erreurs locales, aucune adresse n'est transmise (ceci peut
être vérifié dans le champ
cmsg_len
de
cmsghdr).
À la réception d'erreur,
msghdr
sera rempli avec
MSG_ERRQUEUE.
Après la lecture d'une erreur, l'état de la socket est modifié d'après
l'erreur suivante dans la file.
L'appel
recvmsg
utilise une structure
msghdr
pour minimiser le nombre de paramètres à fournir directement. Cette
structure à la forme suivante, définie dans
<sys/socket.h>
-
-
struct msghdr {
caddr_t msg_name; /* optional address */
u_int msg_namelen; /* size of address */
struct iovec *msg_iov; /* scatter/gather array */
u_int msg_iovlen; /* # elements in msg_iov */
caddr_t msg_control; /* ancillary data, see below */
u_int msg_controllen; /* ancillary data buffer len */
int msg_flags; /* flags on received message */
};
Ici
msg_name
et
msg_namelen
spécifient l'adresse d'origine si la socket n'est pas connectée,
msg_name
peut être un pointeur nul si le nom n'est pas nécessaire.
msg_iov
et
msg_iovlen
décrivent les buffers de réception comme décrit dans
readv(2).
msg_control,
de longueur
msg_controllen,
pointe sur un buffer utilisé pour les autres messages relatifs au protocole,
ou à d'autres données annexes. Lorsqu'on invoque
recvmsg,
msg_controllen
doit contenir la longueur disponible dans le buffer
msg_control ;
au retour il contiendra la longueur de la séquence de message de contrôle.
Les messages ont la forme
-
struct cmsghdr {
u_int cmsg_len; /* data byte count, including hdr */
int cmsg_level; /* originating protocol */
int cmsg_type; /* protocol-specific type */
/* followed by
u_char cmsg_data[]; */
};
Les données de service ne doivent être manipulées qu'avec les macros de
cmsg(3)
À titre d'exemple, Linux utilise ce mécanisme pour transmettre des erreurs
étendues, des options IP, ou des descripteurs de fichiers sur des sockets Unix.
Le champ
msg_flags
du msghdr est rempli au retour de
recvmsg().
Il peut contenir plusieurs attributs :
- MSG_EOR
-
indique une fin d'enregistrement, les données reçues terminent un
enregistrement (utilisé généralement avec les sockets du type
SOCK_SEQPACKET).
- MSG_TRUNC
-
indique que la portion finale du datagramme a été abandonnée car le
datagramme était trop long pour le buffer fourni.
- MSG_CTRUNC
-
indique que des données de contrôle ont été abandonnées à cause d'un
manque de place dans le buffer de données annexes.
- MSG_OOB
-
indique que des données hors-bande ont été reçues.
- MSG_ERRQUEUE
-
indique qu'aucune donnée n'a été reçue, sauf une erreur étendue depuis la
file d'erreurs.
- MSG_DONTWAIT
-
Activer les opérations non-bloquantes. Si l'opération devait bloquer,
EAGAIN
serait renvoyé (on peut aussi activer ce comportement avec l'option
O_NONBLOCK
de la fonction
F_SETFL
de
fcntl(2).
Ces fonctions
renvoient le nombre d'octets reçus si elles réussissent,
ou -1 si elles échouent, auquel cas
errno
contient le code d'erreur.
4.4 BSD (ces fonctions sont apparues dans BSD 4.2).
Les prototypes fournis concernent la GlibC 2.
Les Spécifications Single Unix les définissent, mais le type de retour
est `ssize_t' (alors que BSD 4.*, libc4 , et libc5 renvoient un `int').
L'argument
flags
est un `int' dans BSD 4.*, mais `unsigned int' dans libc4 et libc5.
L'argument
len
est un `int' dans BSD 4.*, mais un `size_t' dans libc4 et libc5.
L'argument
fromlen
est un int *' dans BSD 4.*, libc4 et libc5.
Le type `socklen_t *' a été inventé par POSIX.
Christophe Blaess, 1996-2003.