socket sans bind : getsockname possible ?
Le
Olivier Miakinen

[diapublication dans trois groupes, dont ceux sur Unix et Windows,
suivi vers fr.comp.reseaux.ip seul]
Bonjour,
Dans un programme en C utilisant les sockets, une fonction
reçoit un socket initialisé par la fonction socket(), mais
où le bind() n'a pas encore été fait. La fonction voudrait
déterminer quel type d'adresse on peut attacher à ce socket
(entre AF_INET et AF_INET6 à priori) : peut-elle utiliser
la fonction getsockname() pour ce faire, ou bien est-ce que
l'on risque une erreur sur certains OS du fait que le bind()
n'est pas fait ?
P.-S. : même si la question ne se pose pas vraiment, par
curiosité j'aimerais savoir aussi ce qu'il en est des
protocoles autres que IPv4 et IPv6, par exemple AF_UNIX
Cordialement,
--
Olivier Miakinen
suivi vers fr.comp.reseaux.ip seul]
Bonjour,
Dans un programme en C utilisant les sockets, une fonction
reçoit un socket initialisé par la fonction socket(), mais
où le bind() n'a pas encore été fait. La fonction voudrait
déterminer quel type d'adresse on peut attacher à ce socket
(entre AF_INET et AF_INET6 à priori) : peut-elle utiliser
la fonction getsockname() pour ce faire, ou bien est-ce que
l'on risque une erreur sur certains OS du fait que le bind()
n'est pas fait ?
P.-S. : même si la question ne se pose pas vraiment, par
curiosité j'aimerais savoir aussi ce qu'il en est des
protocoles autres que IPv4 et IPv6, par exemple AF_UNIX
Cordialement,
--
Olivier Miakinen
Le type de la socket est connu par l'appelant, puisqu'il en a eu besoin pour
la créer. Il suffit de le fournir en argument à la fonction.
Je ne vois pas bien comment. De plus (*1) il est bien spécifié que le
comportement est indéterminé sans lien prélable...
(*1)
La seule option réaliste, par exemple pour IPv6, est de tenter de binder
l'adresse locale (::1) sur un port anonyme (0 - assigné par le système),
le tout avec REUSEADDR (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
&one..)) et de voir si cela échoue ou non, et de fermer le port
immédiatement (en cas de succès)
Mais cela ne répond pas à l'autre souci: la plupart des distributions
Linux, et c'est le cas sous Windows probablement, embarquent au moins un
localhost en V4 (ou V6), mais rien ne dit que c'est routable.
Il faut donc aller plus loin: énumérer les interfaces réseau et regarder
si une passerelle par défaut est définie ou non, ou bien pinguer une
adresse "connue", etc..
Pour du AF_UNIX, je n'ai pas trop d'idées par contre.
Si c'était la question posée, pour le type, getsockopt(fd, SOL_SOCKET,
SO_TYPE, ..) permet de le récupérer.
Mais je ne vois pas de SO_FAMILY ou de SO_DOMAIN - ais-je la berlue ?
Merci pour ce lien, je n'avais trouvé que des 'man' moins complets
(conformité POSIX 2001) :
http://linux.die.net/man/2/getsockname
http://pwet.fr/man/linux/appels_systemes/getsockname
http://unixhelp.ed.ac.uk/CGI/man-cgi?getsockname+2
http://www.man-linux-magique.net/man2/getsockname.html
etc.
Si cela ne fonctionne déjà pas pour AF_INET et AF_INET6, ma
curiosité tombe du même coup pour les autres protocoles.
En effet. Merci pour toutes ces précisions.
C'est vraiment sans importance en l'occurrence.
Cordialement,
--
Olivier Miakinen
Le type de la socket est connu par l'appelant de la fonction socket,
mais il se trouve que ce type n'est pas connu par l'appelant de la
fonction objet de ma question. Sinon, je suis bien d'accord avec toi,
il suffirait de le passer en argument.
Oui.
Un tel getsockopt existe dans Windows seulement : SO_PROTOCOL_INFO.
Tu n'as pas la berlue, je ne trouve rien de tel pour les autres OS.
Cordialement,
--
Olivier Miakinen
Ah, si, j'avais la berlue, en tout les cas sous Linux:
SO_DOMAIN (since Linux 2.6.32)
Retrieves the socket domain as an integer, returning a value
such as AF_INET6. See socket(2) for details. This socket
option is read-only.
Non, ce n'est pas une option réaliste, c'est un hack pas fiable.
La solution réaliste, c'est de faire en sorte que l'information nécessaire
soit disponible sans avoir à aller la repêcher à des endroits inaccessibles.
Si ce n'est pas le cas, il faut réorganiser le programme pour que ça le
soit.
En quoi est-ce un hack, et en quoi est-il pas fiable ?
L'idée du bind() anonyme était non pas pour repêcher le domaine de la
socket, mais savoir si la connectivité de base Ipv6 était disponible,
par exemple. Pour cet usage seul, cette solution me semble parfaitement
fiable.
Olivier Miakinen
Vu que getsockname() est une fonction POSIX, le comportement devrait
être le même sur tous les OS (qui respectent POSIX).
--
Paul Gaborit -
Tiens ? Oui.
On trouve par exemple sur la toile un code qui vérifie que le
socket est un AF_INET ou un AF_INET6 avant de lui appliquer
d'autres getsockopt :
https://git.fedorahosted.org/cgit/conga.git/plain/ricci/common/Socket.cpp