crash de accept()

rougevin

Membre enregistré
29 Janvier 2015
6
0
68
Bonjour à tous,

J'ai un souci en programmation des socket, avec la primitive accept()

En gros j'ai écrit en C un embryon de serveur qui renvoie juste la chaine "Hello, world!" quand on s'y connecte sur le port 3490.
Pour le tester en local, je fais juste sur une autre fenetre teminal un "telnet localhost 3490" et ça marche très bien
En revanche en distant (depuis un PC avec Putty sur le LAN), le serveur se crashe avec comme message "Abort trap: 6" et dans la console je lis : "a.out: detected buffer overflow"

J'avoue y perdre mon latin, quelqu'un a-t-il une idée ?

C:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/wait.h>

#define MYPORT 3490    /* Le port où les utilisateurs se connecteront */

#define BACKLOG 10     /* Nombre maxi de connections acceptées en file */

char* my_ntoa(long adr)
{unsigned char *s; static unsigned char out[10];
s = (unsigned char *) &adr;
sprintf(out,"%d.%d.%d.%d",s[0],s[1],s[2],s[3]);
return(out);
}

main()
{
int sockfd, new_fd;  /* Ecouter sock_fd, nouvelle connection sur new_fd */
struct sockaddr_in my_addr;    /* Adresse */
struct sockaddr_in their_addr; /* Adresse du connecté  */
int sin_size;

if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {perror("socket"); exit(1); }

my_addr.sin_family = AF_INET;         /* host byte order */
my_addr.sin_port = htons(MYPORT);     /* short, network byte order */
my_addr.sin_addr.s_addr = INADDR_ANY; /* auto-remplissage avec mon IP */
bzero(&(my_addr.sin_zero), 8);        /* zero pour le reste de struct */

if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1) {perror("bind"); exit(1);}

if (listen(sockfd, BACKLOG) == -1) {perror("listen");exit(1);}

while(1) /* main accept() loop */
{
  sin_size = sizeof(struct sockaddr_in);
  if ((new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size)) == -1) {perror("accept");continue;}
  printf("serveur: Reçu connection de %s\n", my_ntoa(their_addr.sin_addr.s_addr));

  if (!fork())  /* processus fils */
  {if (send(new_fd, "Hello, world!\n", 14, 0) == -1) perror("send");
   close(new_fd);
   exit(0);
  }

  close(new_fd);  /* Le parent n'a pas besoin de cela */

  while(waitpid(-1,NULL,WNOHANG) > 0); /* Nettoyage des processus fils */
}
}
 
Dernière édition par un modérateur:
C:
char* my_ntoa(long adr)
{unsigned char *s; static unsigned char out[10];
s = (unsigned char *) &adr;
sprintf(out,"%d.%d.%d.%d",s[0],s[1],s[2],s[3]);
return(out);
}

La taille max d'une IPv4 c'est XXX.XXX.XXX.XXX, soit 15 chars (12 + 3 séparateurs)

-> Donc ton buffer de 10 est trop petit.

Sinon pour pas te prendre la tête y a des fonctions qui existent pour faire ça, inet_ntoa, inet_ntop, inet_aton, inet_pton
 
Oups ! Je répond à mon propre post, puisque 3 minutes après l'avoir posté j'ai compris ce qui ce passait :$

En faut ce n'est pas accept() qui crache mais l'affreuse fonction my_ntoa() que j'ai écrite à la va-vite (le buffer out est trop petit, c'est ce qui faisait crasher) pour remplacer la fonction standart inet_ntoa() qui, elle, refuse de marcher...

Cela m'amène d'ailleurs à reformuler ma demande d'aide : pourquoi diable inet_ntoa() refuse de marcher ??

le compilateur C me fait le warning :

Bloc de code:
server1.c:44:47: warning: format specifies type 'char *' but the argument has type 'int' [-Wformat]
  printf("serveur: Reçu connection de %s\n", inet_ntoa(their_addr.sin_addr));
                                      ~~     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                                      %d

et bien entendu à l'éxécution ça plante avec une : "Segmentation fault: 11" (ce qui ne m'étonne pas trop si on essaye d'afficher un entier comme une string)

Mais pourquoi diable inet_ntoa() retourne-t-elle un entier et non une string comme le précise la doc ??
cf le man inet_ntoa :
char *
inet_ntoa(struct in_addr in);
 
Oups ! Je répond à mon propre post, puisque 3 minutes après l'avoir posté j'ai compris ce qui ce passait :$

En faut ce n'est pas accept() qui crache mais l'affreuse fonction my_ntoa() que j'ai écrite à la va-vite (le buffer out est trop petit, c'est ce qui faisait crasher) pour remplacer la fonction standart inet_ntoa() qui, elle, refuse de marcher...

Cela m'amène d'ailleurs à reformuler ma demande d'aide : pourquoi diable inet_ntoa() refuse de marcher ??

le compilateur C me fait le warning :

Bloc de code:
server1.c:44:47: warning: format specifies type 'char *' but the argument has type 'int' [-Wformat]
  printf("serveur: Reçu connection de %s\n", inet_ntoa(their_addr.sin_addr));
                                      ~~     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                                      %d

et bien entendu à l'éxécution ça plante avec une : "Segmentation fault: 11" (ce qui ne m'étonne pas trop si on essaye d'afficher un entier comme une string)

Mais pourquoi diable inet_ntoa() retourne-t-elle un entier et non une string comme le précise la doc ??
cf le man inet_ntoa :
char *
inet_ntoa(struct in_addr in);

inet_ntoa est défini dans <arpa/inet.h> inclus le header et ça devrait être bon.