J'ai un petit souci avec mon programme. Je suis en train de développer un nouveau protocole sur ethernet. J'utilise donc des RAW socket.
Tout va super bien. J'atteint 1,6 Gb/s sur le loopback avec des packets de 1500 octet (ethernet oblige, si pas de jumbo frame ^_^)
Mon problème vient de la fermeture de ladite socket. La fonction recvmsg ne me retourne jamais -1 quand je ferme la socket.
J'ai isolé le bug ans un petit programme que voici (désolé pour le format, j'ai du mal à le formater) :
#include pthread.h
#include sys/socket.h
#include netpacket/packet.h
#include net/ethernet.h
#include arpa/inet.h
#include sys/ioctl.h
#include linux/if.h
#include string.h
#include stdio.h
#include errno.h
int sock;
struct msghdr packet = {0};
struct sockaddr_ll addr = {0};
struct iovec iov = {0};
struct ifreq ifr = { 0 };
char *name="lo";
char buffer[1500] = {0};
pthread_t tid;
pthread_mutex_t mutex;
pthread_cond_t cond;
int recivelen;
static void *reciver(void *arg)
{
pthread_mutex_lock(&mutex);
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
while((recivelen=recvmsg(sock,&packet,0))>0)
printf("recvmsg return : %d\n",recivelen);
}
int main()
{
int errorCondition = 0;
// overture de la socket
sock = socket ( PF_PACKET, SOCK_DGRAM, htons ( ETH_P_ALL ) );
if ( !sock )
return -1;
// attachement sur le loopback
errorCondition = setsockopt ( sock,SOL_SOCKET,SO_BINDTODEVICE,name,2);
if ( errorCondition )
return errorCondition;
// recupère l'index de l'interface. Pas utile ici mais on ne sait jamais
strcpy ( ifr.ifr_name, name);
errorCondition = ioctl ( sock, SIOCGIFINDEX, &ifr );
if ( errorCondition )
return errorCondition;
//construction du packet
addr.sll_family = AF_PACKET;
addr.sll_ifindex = ifr.ifr_ifindex;
addr.sll_halen = ETH_ALEN;
addr.sll_protocol = htons ( ETH_P_ALL );
packet.msg_name=&addr
packet.msg_namelen = sizeof ( struct sockaddr_ll );
packet.msg_iov = &iov
packet.msg_iovlen = 1;
iov.iov_base=&buffer
iov.iov_len=1500;
packet.msg_control = NULL;
packet.msg_controllen = 0;
packet.msg_flags = 0;
// initialisation du mutex pour une sychronisation
pthread_mutex_init(&mutex,NULL);
pthread_cond_init(&cond,NULL);
// démarrage du thread d'écoute
pthread_mutex_lock(&mutex);
pthread_create(&tid,NULL,&reciver,NULL);
// attente du bon démarrage, sinon ça fausse le test
pthread_cond_wait(&cond,&mutex);
pthread_mutex_unlock(&mutex);
// tentative de fermeture avec shutdown, l'erreur est normale
errorCondition = shutdown(sock,SHUT_RDWR);
if(errorCondition)
printf("shutdown fail. errno : %d\n",errno);
// fermeture avec close. Pas d'erreurs mais est-ce vrai ?
errorCondition = close(sock);
if(errorCondition)
printf("close fail. errno : %d\n",errno);
// attente de la fin du thread
pthread_join(tid,NULL); // BUG, le thread ne fini jamais, il continue d'ecouter alors que sa socket est fermé
}
a compiller avec l'option -lpthread
Pouvez vous m'aider, ou est-ce un bug du noyau linux ?
Merci a vous
# Threads
Posté par peck (site web personnel) . Évalué à 3.
je pense que ton problème est l'utilisation de shutdown. C'est une fonction servant à fermer une connexion, or les socket raw sont des socket non connectées.
Ce que tu peux faire c'est de la fermer avec un close, auquel cas recvmsg te retournera une erreur, ce qui est normal.
[^] # Re: Threads
Posté par DeadMaXfr . Évalué à 1.
Commençons par les threads : tu ferme la socket pendant sont utilisation par un autre thread. Il te faudrait un mutex dessus pour faire propre.
Oui, c'est le but. Car recvmsg est un appel bloquant, donc pour l'annuler, un close sur la socket me semblait un bonne idée.
je pense que ton problème est l'utilisation de shutdown. C'est une fonction servant à fermer une connexion, or les socket raw sont des socket non connectées.
Comme mis en commentaire dans mon source, c'est normal qu'il ne marche pas.
Ce que tu peux faire c'est de la fermer avec un close, auquel cas recvmsg te retournera une erreur, ce qui est normal.
C'est là ou ça ne marche plus. Le recvmsg ne termine pas !
Comment faire ?
[^] # Re: Threads
Posté par peck (site web personnel) . Évalué à 1.
OK, j'avais mal lu.
Oui, c'est le but.
Non, tu ne protège pas l'accès à ta socket dans ton cas, je ne connais pas assez bien le noyau pour savoir si c'est sensé fonctionner comme tu veux.
Car recvmsg est un appel bloquant, donc pour l'annuler, un close sur la socket me semblait un bonne idée.
Tu ne peux pas arrêter un appel bloquant avec un close. Il te faut un signal pour ça (et encore pour recvmsg je ne sais pas).
En fait tu est sensé faire un select dans ton while avant d'appeler recvmsg pour détecter les conditions d'arrêt.
# ben chez moi
Posté par Alex . Évalué à 1.
[^] # Re: ben chez moi
Posté par DeadMaXfr . Évalué à 1.
Tu doit avoir du trafic sur le loopback car le programme écrit reçoit qu'un packet et de n'importe quel type (P_ETH_ALL).
Coupe tout ce qui utilise le loopback avant de lancer le programme.
[^] # Re: ben chez moi
Posté par Alex . Évalué à 1.
en fait c'est juste que la socket me semblait bien fermer vu que le recv me sort un beau errno (ENOTSOCK je crois)
je retesterai
[^] # Re: ben chez moi
Posté par Alex . Évalué à 1.
juste en relisant le code, il est évidant qu'en recevant des infos par lo, le prochain recv se fera après la fermeture de la socket
bon, si vous pouviez moinser...
sinon c'est vrai que la solution est surement un select ou un poll
[^] # Re: ben chez moi
Posté par DeadMaXfr . Évalué à 1.
Dans le morceau de code donné, je ne boucle pas si la socket reçoit un message. Donc ça se termine bien.
Par contre, si tu me dit que tu n'as pas de trafic et que la fonction recvmsg se termine en erreur (c'est le but), c'est que j'ai un bug avec mon noyau.
Pourrais tu faire le test à nouveau ?
Merci
# socket non bloquant...
Posté par Daniel Caujolle-Bert . Évalué à 2.
select() est aussi ton ami.
---
[^] # Re: socket non bloquant...
Posté par Daniel Caujolle-Bert . Évalué à 1.
[^] # Re: socket non bloquant...
Posté par DeadMaXfr . Évalué à 1.
Pour faire un recvmsg non-bloquant => non car le programme bouclerait et donc 100% de cpu. Pas bien
Je vais regarder du coté de select. C'est une bonne alternative.
L'inconvénient c'est que je suit dans l'obligation d'attendre le timeout lors de la fin du programme.
C'est pour cela que je n'ai pas pensé tout de suite à l'utiliser.
Si quelqu'un a une solution autre que select, je prend, c'est peut-être une combinaison de chaque qui fera l'affaire
[^] # Re: socket non bloquant...
Posté par Daniel Caujolle-Bert . Évalué à 1.
# [ RESOLU ]
Posté par DeadMaXfr . Évalué à 3.
Suivre le flux des commentaires
Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.