IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Réseau C Discussion :

[Socket Linux] Fonction Ping en C


Sujet :

Réseau C

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Inscrit en
    Juin 2007
    Messages
    22
    Détails du profil
    Informations forums :
    Inscription : Juin 2007
    Messages : 22
    Par défaut [Socket Linux] Fonction Ping en C
    Bonjour à tous !

    Voilà mon problème, dans une de mes applications j'ai besoin de savoir si un équipement en face est présent ou non sur le réseau.
    Comme je ne peux pas utiliser l'appel systeme system(ping x.x.x.x) , j'ai refait la fonction ping en C (gestion de l'ICMP etc... etc...).

    Voilà mon code (sous RTAI mais cela reste trés lisible) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
     
    int ping(char *AdresseAPinger)
    {
    	char				*Paquet;			// Paquet que l'on enverra : le ping
    	char				*Buffer;			// Buffer de reception contenant la réponse
    	struct	icmp		*HeaderICMP;		// Header contenant les paramètre IPs encapsulant l'header ICMP
    	struct	ip			*HeaderIP;			// Header contenant les paramètres ICMP : ECHO_REQUEST etc...
    	struct	sockaddr_in	stMachineAPinger;
    	struct	sockaddr_in	stMachineQuiPing;
    	int					Result 	 = 0;
    	int					Longueur = 0;
    	int					Socket   = 0;
    	int					OptVal   = 0;
     
    	// Allocation dynamique du paquet envoyé et du buffer de reception
    	Paquet = (char *)malloc(sizeof(struct icmp) + sizeof(struct ip));
    	Buffer = (char *)malloc(sizeof(struct icmp) + sizeof(struct ip));
     
    	// Association des headers dans le paquet que l'on enverra 
    	HeaderIP 	= (struct ip *) Paquet; 
        HeaderICMP	= (struct icmp *) (Paquet + sizeof(HeaderIP)); 
     
    	// Remplissage des structures qui gerent les machines : demandantes et répondantes
    	stMachineAPinger.sin_family 		= AF_INET;
    	stMachineAPinger.sin_addr.s_addr	= inet_addr(AdresseAPinger); 
    	stMachineQuiPing.sin_family			= AF_INET;
    	stMachineQuiPing.sin_addr.s_addr	= INADDR_ANY;	// Adresse de la machine qui pingue
     
    	// Remplissage du header du protocole IP
    	rt_printk("Remplissage IP header...\n");
    	HeaderIP->ip_hl   	= 5; 									// Longueur de l'en-tête
    	HeaderIP->ip_v 		= 4; 									// IPv4 
    	HeaderIP->ip_tos   	= 0; 									// Type de service
        HeaderIP->ip_len 	= sizeof(HeaderIP) + sizeof(HeaderICMP);// Longueur total du paquet IP
        HeaderIP->ip_id     = htons(getuid()); 						// Identificateur
        HeaderIP->ip_ttl    = 255;									// Temps de vie 
        HeaderIP->ip_src    = stMachineQuiPing.sin_addr;			// Adresse de la machine qui veut pinguer
        HeaderIP->ip_dst    = stMachineAPinger.sin_addr;			// Adresse de la mahcine qui repondra... ou pas
     
    	// Ouverture du socket en mode RAW
    	rt_printk("Ouverture Socket...\n");
    	Socket = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
    	if(Socket == -1)
    	{
    		rt_printk("Ping : Erreur socket !!\n");
    		return -1;
    	}
     
    	// Changement des options du socket pour manipuler le datagramme IP
    	rt_printk("Changement options Socket...\n");
    	Result = setsockopt(Socket, IPPROTO_IP, IP_HDRINCL, &OptVal, sizeof(int)); 
    	if(Socket == -1)
    	{
    		rt_printk("Ping : Erreur setup socket !!\n");
    		return -1;
    	}
     
    	// Remplissage du header du protocole ICMP
    	rt_printk("Replissage ICMP header...\n");
    	HeaderICMP->icmp_type 	= ICMP_ECHO; 			// Type de message ICMP : Echo request 
    	HeaderICMP->icmp_code 	= 0; 					// Code du message (0 pour nous)
    	HeaderICMP->icmp_cksum 	= 0;
    	// Calcul du checksum pour le datagramme ICMP
    	HeaderICMP->icmp_cksum 	= in_cksum((unsigned short *)HeaderICMP, sizeof(HeaderICMP));
     
    	// Calcul du checksum du datagramme IP précédent qui encapsule celui en ICMP
    	HeaderIP->ip_sum = in_cksum((unsigned short *)HeaderIP, sizeof(HeaderIP));
     
    	// Envois de la trame IP sur le reseau
    	rt_printk("Envois du ping...\n");
    	Result = sendto(Socket, Paquet, HeaderIP->ip_len, 0, (struct sockaddr*)&stMachineAPinger, sizeof(struct sockaddr));
    	if(Result != HeaderIP->ip_len)
    	{
    		rt_printk("Ping : Erreur envois -> longueur envoyee != longueur a envoyer");
    		return -1;	
    	}
     
    	// Reception de la réponse... ou non
    	rt_printk("Reception du ping..."); 
    	Longueur = sizeof(struct sockaddr);
    	Result = recvfrom(Socket, Buffer, (sizeof(HeaderIP) + sizeof(HeaderICMP)), 0, (struct sockaddr*)&stMachineAPinger, &Longueur);
    	if(Result == HeaderIP->ip_len)
    	{
    		rt_printk("ok\n");
    		free(Paquet);
    		free(Buffer);
    		return 1;	// Le ping c'est correctement passé, la machine distante à bien répondue
    	}
    	else
    	{
    	    rt_printk("no\n");
    	    free(Paquet);
    		free(Buffer);
    	    return -1;
    	}
    }
    Le soucis c'est que lorsque j'exécute mon programme, j'obtient ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    $ ./Ping
    Remplissage IP header...
    Ouverture Socket...
    Changement options Socket...
    Replissage ICMP hedaer...
    Envois du ping...
    Reception du ping...
    D'aprés ce résultat, on dirait que le blocage se fait au niveau du recvfrom.
    Lorsque je scan ma connexion avec ethreal j'obtiens une entrée sur le protocole ICMP :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    Internet Control Message Protocol :
       Type : 69 (Obsolete or malformed)
       Code : 0
       CRC : Incorrect
    ...
    Auriez vous une idée d'où cela pourrait provenir ?

    Merci de votre aide
    Romain

    edit : ortho

  2. #2
    Membre éprouvé Avatar de psyphi
    Profil pro
    Inscrit en
    Avril 2006
    Messages
    119
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : Allemagne

    Informations professionnelles :
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2006
    Messages : 119
    Par défaut
    C'est ce que tu envoies qui est mal formé ou bien ce que tu reçois?

  3. #3
    Membre averti
    Inscrit en
    Juin 2007
    Messages
    22
    Détails du profil
    Informations forums :
    Inscription : Juin 2007
    Messages : 22
    Par défaut
    Citation Envoyé par psyphi
    C'est ce que tu envoies qui est mal formé ou bien ce que tu reçois?
    A priori je pense que c'est ce que j'envois qui est mal formé. Car Ethreal me dit que le type de message ICMP est mauvais alors que je lui donne le correct pour le Echo Request.

  4. #4
    Membre éprouvé Avatar de psyphi
    Profil pro
    Inscrit en
    Avril 2006
    Messages
    119
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : Allemagne

    Informations professionnelles :
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2006
    Messages : 119
    Par défaut
    Avec ethereal tu peux voir qui est le destinaire et la source. Si ce que tu envoies est mal formé c'est normal que tu ne recoives rien.

  5. #5
    Membre averti
    Inscrit en
    Juin 2007
    Messages
    22
    Détails du profil
    Informations forums :
    Inscription : Juin 2007
    Messages : 22
    Par défaut
    Citation Envoyé par psyphi
    Avec ethereal tu peux voir qui est le destinaire et la source. Si ce que tu envoies est mal formé c'est normal que tu ne recoives rien.
    Mon destinataire et source sont tous les deux corrects et le CRC aussi (d'apres ethereal) donc j'en conclu que mon paquet IP est correctement construit. Seul le datagramme ICMP me parait mauvais.

  6. #6
    Membre averti
    Inscrit en
    Juin 2007
    Messages
    22
    Détails du profil
    Informations forums :
    Inscription : Juin 2007
    Messages : 22
    Par défaut
    D'aprés les resultats que me donne Ethreal, je pense que je transmet mal mon paquet ICMP et donc que le PC que je ping ne comprend pas la requete. Et donc il ne peux pas répondre à ce que je lui demande.

    Mais je ne vois pas l'erreur dans ma fonction...

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Programmation de socket linux sous windows
    Par neuro6 dans le forum Autres éditeurs
    Réponses: 5
    Dernier message: 16/10/2007, 18h35
  2. Réponses: 4
    Dernier message: 23/05/2007, 09h12
  3. Réponses: 2
    Dernier message: 24/01/2007, 13h47
  4. Réponses: 11
    Dernier message: 03/05/2006, 01h24
  5. [Debutant] Problème Socket Linux UDP
    Par AxldenieD dans le forum Réseau
    Réponses: 3
    Dernier message: 01/11/2005, 17h08

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo