/* * tools * Creation et manipulation de sockets * Thomas Nemeth -- le 15 juin 2001 * */ #include #include #include #include #include #include #include #include #include #include #include #include #include "defines.h" #include "xmem.h" #include "tools.h" /* * Ouverture d'une socket de type flot de donnees * * creation d'une socket serveur : port != 0 * */ int ouvre_socket (int port, char *adr_ip, struct sockaddr_in *ptr_adresse) { int desc_soc; int lg_adresse = sizeof (struct sockaddr_in); int lg_linger = sizeof (struct linger); struct sockaddr_in adresse; struct linger ling; /* * Creation de la socket * */ if ( (desc_soc = socket (AF_INET, SOCK_STREAM, 0) ) == -1) { #ifdef DEBUG fprintf (stderr, "Ne peut pas ouvrir la socket de connexion.\n"); #endif perror (__FILE__ " socket"); return -1; } /* * Affectation des options * */ if (port != 0) { int opt = 1; if (setsockopt (desc_soc, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof (int) ) == -1) { #ifdef DEBUG fprintf (stderr, "Impossible de positionner REUSEADDR.\n"); #endif perror (__FILE__ " setsockopt -- REUSEADDR"); return -1; } } ling.l_onoff = 0; ling.l_linger = 0; if (setsockopt (desc_soc, SOL_SOCKET, SO_LINGER, &ling, lg_linger) == -1) { #ifdef DEBUG fprintf (stderr, "Impossible de positionner LINGER.\n"); #endif perror (__FILE__ " setsockopt -- LINGER"); return -1; } /* * Preparation de l'adresse d'attachement * */ memset (&adresse, 0, sizeof (adresse) ); adresse.sin_family = AF_INET; if (adr_ip) { struct in_addr ia; if (inet_aton(adr_ip, &ia)) { adresse.sin_addr = ia; } else { struct hostent *h; h = gethostbyname(adr_ip); if (!h) { fprintf (stderr, "Adresse %s inconnue.\n", adr_ip); return -1; } memcpy (&adresse.sin_addr.s_addr, h->h_addr, h->h_length); } } else adresse.sin_addr.s_addr = htonl (INADDR_ANY); adresse.sin_port = htons (port); /* * Demande d'attachement de la socket * */ if (bind (desc_soc, (struct sockaddr*) &adresse, lg_adresse) == -1) { #ifdef DEBUG fprintf (stderr, "Ne peut donner de nom a la socket de connexion.\n" "Attendez quelques minutes avant de relancer.\n"); #endif perror (__FILE__ " bind"); close (desc_soc); return -1; } /* * Recuperation de l'adresse effective d'attachement * */ if (ptr_adresse != NULL) getsockname (desc_soc, (struct sockaddr *) ptr_adresse, &lg_adresse); return desc_soc; } int connect_server (const char *machine, int port) { struct hostent *serveur; struct sockaddr_in adresse_serveur, adresse_client; int socket_client; /* Recherche de la machine ou se trouve le serveur */ if ( (serveur = gethostbyname (machine) ) == NULL) { #ifdef DEBUG fprintf (stderr, "Machine %s inconnue...\n", machine); #endif return -1; } /* Creation et attachement de la socket du client -- * port quelconque => 0 */ if ( (socket_client = ouvre_socket (0, NULL, (struct sockaddr_in *) &adresse_client)) == -1) { #ifdef DEBUG fprintf (stderr, "Creation de la socket du client impossible.\n"); #endif return -1; } /* Preparation de l'adresse du serveur */ adresse_serveur.sin_family = AF_INET; adresse_serveur.sin_port = htons (port); memcpy (&adresse_serveur.sin_addr.s_addr, serveur->h_addr, serveur->h_length); /* Demande de connexion au serveur */ if (connect (socket_client, (struct sockaddr *) &adresse_serveur, sizeof (adresse_serveur) ) == -1) { #ifdef DEBUG fprintf (stderr, "Impossible de se connecter au serveur.\n"); #endif perror (__FILE__ " connect"); return -1; } return socket_client; } int install_server (int port, char *adr_ip, struct sockaddr_in *ecoute) { int socket_ecoute; /* Ouverture de la socket */ if ( (socket_ecoute = ouvre_socket (port, adr_ip, ecoute)) == -1) { #ifdef DEBUG fprintf (stderr, "Creation de la socket du serveur impossible.\n"); #endif return -1; } /* Declaration d'ouverture du service */ if (listen (socket_ecoute, 10) == -1) { #ifdef DEBUG fprintf (stderr, "Impossible d'enregistrer le service.\n"); #endif perror (__FILE__ " listen"); return -1; } return socket_ecoute; } /* * Fonction de reception de donnees * */ int read_infos (int socket_data, char *infos) { int nb; /* SSIZE_MAX = 2147483647 */ memset (infos, 0, MAXSTRLEN); nb = read (socket_data, infos, MAXSTRLEN - 1); if ( (nb == -1) || (nb == 0) ) { #ifdef DEBUG fprintf (stderr, "Erreur de connexion reception !\n"); #endif if ( (errno == EPIPE) || (nb == 0) ) return FALSE; /* cont = FALSE; */ } #ifdef DEBUG printf ("Recu : [%s] lg = %d/%d\n", infos, strlen (infos), nb); #endif return TRUE; } /* * Fonction d'emisson de donnees * */ int send_infos (int socket_data, const char *infos) { #ifdef DEBUG printf ("Emission de : %s [%d]\n", infos, strlen (infos)); #endif if (write (socket_data, (void *) infos, strlen (infos) + 1) == -1) { /* Erreur : plus de socket ! */ #ifdef DEBUG fprintf (stderr, "Erreur de connexion emission !\n"); #endif if (errno == EPIPE) return FALSE; /*cont = FALSE;*/ } #ifdef DEBUG fprintf (stderr, "Emission ok !\n"); #endif return TRUE; } void get_sock_infos (int sock, char **nom, char **adr, int *prl, int *prd) { struct sockaddr_in name; #ifdef OpenBSD int namelen; #else socklen_t namelen; #endif struct hostent *machine; /* Initialisations en cas d'echecs */ *nom = NULL; *adr = NULL; *prd = 0; /* Infos locales (port) */ namelen = sizeof (name); if (getsockname (sock, (struct sockaddr *) &name, &namelen) == 0) *prl = ntohs (name.sin_port); else { perror ("getsockname() "); *prl = 0; } /* Port et adresse IP distants */ namelen = sizeof (name); if (getpeername (sock, (struct sockaddr *) &name, &namelen) != 0) { #ifdef DEBUG perror ("Erreur de recuperation d'information sur pair !\n" "getpeername() "); #else perror ("Impossible d'obtenir les infos distantes "); #endif return; } *adr = xstrdup (inet_ntoa (name.sin_addr)); *prd = ntohs (name.sin_port); /* Nom de machine distante */ machine = gethostbyaddr ((char *)&name.sin_addr, sizeof name.sin_addr, name.sin_family); if (machine == NULL) { #ifdef DEBUG perror ("Erreur de recuperation de nom de pair.\n" "gethostbyaddr() "); fprintf (stderr, "Adresse : %s (%s)\tFamille : %d (2 == AF_INET)\n", *adr, (char *)&name.sin_addr, name.sin_family); #else perror ("Impossible d'obtenir le nom d'hote distant "); #endif return; } *nom = xstrdup (machine->h_name); }