Page 1 sur 1

[programmation C] IPV6 bind: invalid argument (resolu)

Publié : jeu. 30 mai 2013, 12:32
par rasta
Bonjour,

Je vien demander de l'aide dans ce forum car je suis en train de programmer un serveur qui fonctionne avec IPV6.
Après avoir trouvé de nombreux exemples, j'ai créé le mien qui est tout simple et qui pourtant ne fonctionne pas.

Le problème vien de l'appel à l'appel système bind(). il me retourne l'erreur "invalid argument", qui correspond par ailleur au code errno EINVAL.

voicie mon code qui est non fonctionnel, il est compilé sous linux avec gcc:

Code : Tout sélectionner


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <errno.h>
 
 
#define PORT	4000
//#define	IP_LO			"::1"
//#define	IP_SERV 		"fe80::2c0:caff:fe32:3de5"
 
 
int main()
{
	char ip[50];
	char HostName[100];
 
	struct sockaddr_in6 from;
	struct sockaddr_in6 server;
	struct addrinfo hints, *res;
	struct sockaddr_in6 *extract;
 
	int sockS=0, sockC=0;
	int ecode=0;
	socklen_t len =  sizeof(server);
	void *addr = NULL;
 
 
	memset( &ip, 0, sizeof(ip) );
	memset( &hints, 0, sizeof hints );
	memset( &HostName, 0, sizeof(HostName) ); 
	memset( &from, 0, sizeof(struct sockaddr_in6) );
	memset( &server, 0, sizeof(struct sockaddr_in6) );	
 
			// récupére l'IP de la machine
	if(gethostname( HostName, sizeof(HostName) ) == -1)
	{
		perror("gethostname");
		exit(1);
	}
 
	hints.ai_socktype = SOCK_STREAM;
	hints.ai_family = PF_INET6;
 
        if((ecode = getaddrinfo(HostName, NULL, &hints, &res)) != 0) 
	{
		fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(ecode));
		exit(1);
        }
 
	extract = (struct sockaddr_in6 *)res->ai_addr; 
	addr = &(extract->sin6_addr);
 
	inet_ntop(PF_INET6, addr, ip, sizeof(ip));
 
 
			/*	remplie la structure du server	*/
	server.sin6_family = PF_INET6;
	server.sin6_port = htons(PORT);
	server.sin6_flowinfo = 0;
 
	if( (ecode = inet_pton(PF_INET6, ip, &(server.sin6_addr))) == 1 )
	{
		puts(" :: IP OK ::");
	}
	else
	{
		puts(" :: Invalid Adresse or Adresse family ::");	
	}
 
/* debugage: affiche bien l'adresse IPV6 de ma machine */
inet_ntop(PF_INET6, &(server.sin6_addr), ip, INET6_ADDRSTRLEN);
printf("::<%s>::\n", ip);
 
 
			/*	construit le serveur	*/
	if((sockS = socket(PF_INET6, SOCK_STREAM, IPPROTO_TCP)) == -1) 
	{
		perror("socket");
		exit(1);
	}
 
	if(bind(sockS,  (struct sockaddr*)&server, sizeof(server)) != 0)
	{		
		perror("bind");
		exit(1);
	}
 
	if( listen(sockS, 4) == -1)
	{
		perror("listen");
		exit(1);
	}
 
	if( (sockC = accept(sockS, (struct sockaddr *)&from, &len)) == -1)
	{
		perror("accept");
		exit(1);
	}
	else	puts("connection OK");
 
 
	return 0;
}

Je n'ai pas trouvé de réponse sur d'autre forum, voilà pourquoi je me tourne vers vous.

Je pense que j'ai fais une grossière erreur pourtant je trouve rien qui cloche au niveau du code. Je précise par ailleur que ce serveur marche très bien lorsque je tente de lié à l'interface local que j'ai mis en haut "#define IP_LO "::1"".


Merci d'avance de votre aide. =-)

Re: [programmation C] IPV6 bind: invalid argument (EINVAL)

Publié : jeu. 30 mai 2013, 14:13
par benjarobin
Ton code est bon, en tout cas cela fonctionne :-)
Je pari que tu n'as pas d’adresse IPv6 globale associée à ton interface, mais uniquement une IPv6 liée au lien physique

Si tu fait par exemple

Code : Tout sélectionner

ip -6 addr add 2001:0db8:0:f101::1/64 dev eth0
pour ajouter une IPv6 à ton interface alors ton programme fonctionnera

Re: [programmation C] IPV6 bind: invalid argument (EINVAL)

Publié : jeu. 30 mai 2013, 15:53
par rasta
C'est super sa fonctionne parfaitement.

Mercie encore pour cette aide précieuse Benjarobin.

:bravo: :bravo:

Re: [programmation C] IPV6 bind: invalid argument

Publié : jeu. 30 mai 2013, 17:30
par rasta
Re-bonjour, le sujet n'est en faite pas terminé, désolé :?

Ta solution marchait benjarobin, seulement voilà j'ai de nouveau le même problème:

- j'ai créer le fichier /etc/hostname avec un nom d'hôte car il n'était pas présent sur
ma machine et depuis la fonction getaddrinfo() refuse de me donner une adresse IPv6 ou
même l'adresse IPV4 de ma machine. La fonction n'échoue pas mais en résultat elle me
donne une structure sockaddr qui ne contient aucune adresse ip et je n'ai pas d'adresse
contenue dans ma_structure->ai_next.
Le pire c'est que avant de faire cette modification sur le fichier /etc/hostname,
getaddrinfo() me donnait au moins l'ipv6 lié au lien physique de l'interface réseau.

- d'autre part j'ai exactement le même problème avec la fonction système connect(), qui me renvoi le message d'erreur "invalid argument" quant je lui donne une adresse ip d'une machine distante.

Que faire? Je suis vraiment une bille sur IPV6!! :mrgreen:

d'autre part j'ai plusieurs machines sur le réseau et elle ont toute le même préfixe:

fe80:.......

Pourquoi est il impossible de binder sur ces adresse?
De plus j'ai testé les même programme client/serveur sur windows sa marche parfaitement,
la fonction bind() configure une socket sur le lien physique qui commence par fe80:...

comment s'y retrouver avec toute ces différences ?

Re: [programmation C] IPV6 bind: invalid argument NEW

Publié : jeu. 30 mai 2013, 17:47
par chipster
Merci de corriger les phote, ça pique les nyeux

Re: [programmation C] IPV6 bind: invalid argument (en cour)

Publié : ven. 31 mai 2013, 17:00
par rasta
C'est bon, j'ai suprimé le fichier /etc/hostname et tout est comme avant (je ne comprend plus mon sytème depuis qu'il a systemd), l'appel système getaddrinfo() me renvoie bien les adresses mac créé sur mon interface réseau.

En faite si j'ai bien compris l'adresse IPV6 lié au lien physique est construite avec l'adresse mac de l'interface réseau, d'ailleur on retrouve des valeurs de celle-ci dans l'IPV6.

Est-ce le routeur qui délivre cette adresse ipv6 ou le client dhcp qui la créé?

exemple chez moi:

adresse mac: 00:c0:ca:32:3d:e5
ipv6 lien physique: fe80::2c0:caff:fe32:3de5


Pour cellui qui dévellope une application en IPV6, vaut-il mieux binder le serveur sur l'adresse Joker (ce qui n'est pas très propre je pense) ou vaut-il mieux parser la structure addr_info aprés l'appel système getaddrinfo()?

Sachant que dans la deuxième options plusieurs problème ce pose:

-on est obligé de faire un appel à bind() en boucle pour déterminer qu'elle adresse ip est réellement utilisable.

-on prend le risque de lié une socket avec une adresse IPV6 qui n'a peut-être auccune connectivité avec le réseau.

Si quelq'un a une idée un peu plus évolué sur la question je suis intéressé.
Mercie de votre aide
@+

ps: vraiment désolé pour l'hortographe, ce n'est pas la première fois