Vous êtes sur la page 1sur 8

TP 5 – Programmation IP (I) while ((nb_lu = lecture_socket (socket_cliente, buf)) > 0)

{
/* Si probleme de lecture sur la socket (fermee brutalement
Documentation : lire les pages de manuel suivantes : (r)syslogd, (r)syslog.conf
* par exemple) */
if (nb_lu == -1 || nb_lu == 0)
{
Créer un répertoire /local/TP5 et mettez les fichiers suivants :
return ;
}
– repeteur.c;
– Makefile
/* On repete ce qui a ete dit et on renvoie au client : si ça marche pas met
repeteur.c est un programme démon "répétant" tout ce qu’on lui dit. Il tourne sur le port « return » à la place du code en bleu (les 4 lignes en bleu */
6666 et reste à l’écoute d’une éventuelle connexion. Le protocole utilisé est du TCP. if (strncmp("stop\r\n",buf,6)==0)
{ openlog(“repeater”, LOG_PID | LOG_CONS, LOG_LOCAL0);
– création du démon : duplication et détachement du processus parent, changement du syslog(LOG_INFO |LOG__ERROR, “deconnexion” );
masque, et du répertoire racine, fermeture des entrées, sorties et erreurs standards... closelog();
– initialisation des variables utilisées pour la partie réseau, attente sur le port 6666. kill(getpid(), SIGTERM);
– lorsqu’il y a demande de connexion, le processus est dupliqué et se charge du client: }
tant que le client ne se déconnecte pas, tout ce que le client enverra via cette socket write (socket_cliente, buf, nb_lu) ;
au serveur sera renvoyé à ce même client. }
}
***

Exercice 1 : Puis, par l’appel syslog, demande à syslogd d’enregistrer l’adresse IP du client ayant
effectué cette demande de fin de connexion, ainsi qu’une phrase indiquant que la
Compilez et lancez le programme repeteur.c, vérifier sa bonne marche en lançant dans connexion a été interrompue à la demande du client.
Plusieurs terms des telnet contactant le serveur. Vous aurez à modifier le fichier /etc/rsyslog.conf. Pour cela, vous rajouterez une facilité de
type local0 qui trace tous les messages quelque soit le niveau dans un fichier
Recopier les fichiers repeteur..c et Makefile dans le même répertoire /var/log/local0.log1
Puis faire make ou make all
Lancer ./repeteur Analysez l’affichage de netstat -ap
Appeler telnet localhost (ou chez le voisin) 6666 après écrire une chaîne et taper entrer,
la chaîne sera réaffichée Création d’un fichier lolal0.log dans /var/log
chmod local0.log 700

ouvrir le fichier syslog.conf dans le répertoire /etc/


ajouter la ligne suivante
Exercice 2 :
local0.* /var/log/local0.log
Le démon syslogd permet de tracer les messages sur la console ou vers des fichiers de Modifier les lignes suivantes (en gras bleu) du programme repeteur
trace. Pour cela, il s’appuie sur le fichier de configuration /etc/rsyslog.conf afin de savoir ***
l’action à effectuer suivant le type du service (facility) lui ayant transmis le message /*
mais aussi suivant la priorité (level) du message. * Fichier 'repeteur.c' utilise pour le TD 5 de programmation IP.
* Le programme 'repeteur' est un programme demon "repetant" tout
Modifiez le programme repeteur.c de telle sorte que la réception par le serveur de la * ce qu'on lui dit. Il tourne sur le port 6666 et reste à l'ecoute
chaîne "stop", coupe la connexion avec le client qui lui a envoyé cette chaîne. * d'une eventuelle connexion.
*
*** void repeter (int socket_cliente) * Historique
{ * creation
int nb_lu ;
char buf [MAXLEN] ; 1
Vous aurez peut-être à créer ce fichier et à lui donner les droits adéquats

1 2
*/ setsid () ;

#include <unistd.h> /* 2 - le repertoire courant est change a la racine afin de ne pas


#include <stdlib.h> * causer de probleme lors de demontage eventuel de partition
#include <sys/stat.h> */
#include <string.h> chdir ("/") ;
#include <stdio.h>
#include <sys/types.h> /* 3 - Le masque sur les droits lors de creation de fichiers */
#include <sys/socket.h> umask (0) ;
#include <sys/wait.h>
#include <netinet/in.h> /* 4 - Comme c'est un demon qui est lance et qui est "detache" du
#include <netdb.h> * term, l'entree, la sortie et l'erreur standard n'ont pas de
#include <syslog.h> * terminal ou s'afficher. On peut donc les fermer.
*/
#include <signal.h> /*close (0) ;*/ /*RHA mettre close en comment*/
/*close (1) ;*/
#define MAXLEN 1024 /*close (2) ;*/
#define PORT_REPETEUR 6666
#define NB_CONN_MAX 5
/* 6 - On lance le demon proprement dit */
void demon () ; demon () ;

void repeter (int socket_cliente, struct sockaddr_in ) ; /*RHA add param struct /* 7 - Si le demon s'arrete, alors on sort du processus fils. Le
sockaddr_in */ * programme est alors termine. */
int lecture_socket (int socket_cliente, char *buf) ; exit (1) ;

default :
/*********************************************************************** /* Le processus pere est tue. On rend la main au shell appelant. */
* exit (0) ;
* }
* Fonction principale : return 0 ;
* On cree le demon en dupliquant le processus afin de detacher le }
* programme du processus pere
* /***********************************************************************
*
************************************************************************/ *
int main () * Le programme 'demon'
{ *
switch (fork ()) * Structure
{ * sockaddr_in : /usr/include/netinet/in.h
case -1 : *
perror ("*** erreur : fork impossible : demon non cree") ; *
exit (1) ; *

case 0 : ************************************************************************/
/* void demon ()
* Ce processus fils est celui qui deviendra le demon. {
* Ingredients pour en faire un vrai et bon demons : int socket_ecoute ;
*/ int socket_cliente ;
/* 1 - On cree une nouvelle session. Pas de terminal de controle */ int valeur_retour ;

3 4
int salong ; break ;
int opt = 1 ;
struct sockaddr_in monadr, sonadr ; case 0 :
int status ;
repeter (socket_cliente, sonadr) ; /*RHA add param sonadr*/
close (socket_cliente) ;
/* kill (getpid(),SIGTERM);
* Creation de la socket d'ecoute
*/ default :
socket_ecoute = socket (PF_INET, SOCK_STREAM, 0) ; waitpid (-1, &status, WNOHANG);
close (socket_cliente) ;
/* }
* Modification des options associees a la socket d'ecoute. }
*/ }
setsockopt (socket_ecoute, SOL_SOCKET, SO_REUSEADDR, (char *) &opt, \
sizeof (opt)) ; /***********************************************************************
*
/* *
* Initialisation des parametres internet de la socket d'ecoute. * La fonction qui repete
*/ *
bzero ((char *) &monadr, sizeof monadr) ; *
monadr.sin_family = AF_INET ; *
monadr.sin_port = htons (PORT_REPETEUR) ;
monadr.sin_addr.s_addr = INADDR_ANY ; ************************************************************************/
valeur_retour = bind (socket_ecoute, (struct sockaddr *) &monadr, \ void repeter (int socket_cliente, struct sockaddr_in sock_addr) /*RHA add 2nd
(int) sizeof monadr) ; param*/
{
/* int nb_lu ;
* Socket mise en position d'ecoute ('listen'). On specifie aussi le char buf [MAXLEN] ;
* nombre de connexions simultanees acceptees. char * addr; /*RHA declare addr*/
*/
valeur_retour = listen (socket_ecoute, NB_CONN_MAX) ;
addr = inet_ntoa(sock_addr.sin_addr);
/**
* Le demon tourne indefiniment a l'ecoute d'eventuelles connections while ((nb_lu = lecture_socket (socket_cliente, buf)) > 0)
* 'accept' {
* Lorsqu'un client se connecte, une socket est cree (socket_cliente). /* Si probleme de lecture sur la socket (fermee brutalement
* on duplique le processus et le processus fils prend en charge * par exemple) */
* cette socket par la fonction 'repeter'. if (nb_lu == -1 || nb_lu == 0)
*/ {
while (1) return ;
{ }
salong = sizeof sonadr ;
/* On repete ce qui a ete dit et on renvoie au client */
socket_cliente = accept (socket_ecoute, (struct sockaddr *) &sonadr, \
(socklen_t *) &salong) ; if (strncmp("stop\r\n",buf,6)==0){
syslog(LOG_LOCAL0, addr);
switch (fork ()) return;
{ }
case -1 :

5 6
write (socket_cliente, buf, nb_lu) ;
} int main(int argc, char **argv){
FILE *fp;
}

int lecture_socket (int socket_cliente, char *buf) int sockfd, portno, n;


{ struct sockaddr_in serv_addr;
struct hostent *server;
int nb_lu ;

nb_lu = read (socket_cliente, buf, MAXLEN) ;


return (nb_lu) ;
} /* ouverture fichier */
*** fp=fopen(argv[3],"r");

/* ouverture socket */
portno = atoi(argv[2]);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
Exercice 3 : if (sockfd < 0)
error("ERROR opening socket");
Ecrivez un programme client parleur.c qui lit la première ligne d’un fichier, l’envoie au serveur,
attend la réponse du serveur et l’affiche, puis passe à la ligne suivante. //recuperer l'@ ip via le premier argument
server = gethostbyname(argv[1]);
if (server == NULL) {
Il y a deux codes que je n’ai pas testé fprintf(stderr,"ERROR, no such host\n");
Il faut faire en principe : exit(0);
Lancer le ./repeteur }
./parleur ip-de_serveur_repeteur port_du_serveur_nom_du_fichier
// initialisation a zero du buffer
./parleur
bzero((char *) &serv_addr, sizeof(serv_addr));
Premier code :
/************************************************************************** // remplir ip et port
*/ serv_addr.sin_family = AF_INET;
// bcopy((char *)server->h_addr, (char *)&serv_addr.sin_addr.s_addr,server-
// usage: >h_length);
// serv_addr.sin_port = htons(portno);
// ./parleur ip port nomfichier
// // socket connect
// ip : ip du serveur "repeteur" if (connect(sockfd, (stuct sockaddr *)&serv_addr,sizeof(serv_addr)) < 0)
// port : port du serveur error("ERROR connecting");
// nomfichier: nom du fichier a envoyer
/**************************************************************************
***/ if ( fp != NULL )
#include <unistd.h>
#include <stdlib.h> {
#include <sys/stat.h>
#include <string.h> char line [ 128 ]; /* or other suitable maximum line size */
#include <stdio.h>

#include <sys/types.h> // boucle de lecture de lignes


#include <sys/socket.h> while ( fgets ( line, sizeof line, fp ) != NULL ) /* read a line */
#include <sys/wait.h>
#include <netinet/in.h> {
#include <netdb.h> // ecriture dans le socket
#include <syslog.h> n = write(sockfd,line,strlen(line));
#include <signal.h> if (n < 0)
error("ERROR writing to socket");
#define MAXLEN 1024 printf(" j'ai envoye : %s \n",line);
#define PORT_REPETEUR 6666 bzero(line,128);
#define NB_CONN_MAX 5

7 8
printf("entre temps : %s \n",line); #include <syslog.h>
#include <signal.h>
// lecture du socket
n = read(sockfd,line,128);
if (n < 0) #define MAXLEN 1024
error("ERROR reading from socket"); #define PORT_REPETEUR 6666
#define NB_CONN_MAX 5
printf(" j'ai reçu : %s \n",line);
//printf("ligne : %s",line);
int main(int argc, char **argv){
FILE *fp;
}
fclose ( fp);
}
int sockfd, portno, n;
struct sockaddr_in serv_addr;
struct hostent *server;
return 0;
}

/* ouverture fichier */

fp=fopen(argv[3],"r");

Fin code 1 /* ouverture socket */


portno = atoi(argv[2]);
Deuxième code sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
/*********************************************************************** error("ERROR opening socket");
****/
// //recuperer l'@ ip via le premier argument
// usage: server = gethostbyname(argv[1]);
// if (server == NULL) {
// fprintf(stderr,"ERROR, no such host\n");
// exit(0);
// ip : ip du serveur "repeteur" }
// port : port du serveur
// nomfichier: nom du fichier a envoyer // initialisation a zero du buffer
/*********************************************************************** bzero((char *) &serv_addr, sizeof(serv_addr));
******/
#include <unistd.h> // remplir ip et port
#include <stdlib.h> serv_addr.sin_family = AF_INET;
#include <sys/stat.h> bcopy((char *)server->h_addr, (char *)&serv_addr.sin_addr.s_addr,server->h_length);
#include <string.h> serv_addr.sin_port = htons(portno);
#include <stdio.h>
// socket connect
#include <sys/types.h> if (connect(sockfd, (stuct sockaddr *)&serv_addr,sizeof(serv_addr)) < 0)
#include <sys/socket.h> error("ERROR connecting");
#include <sys/wait.h>
#include <netinet/in.h>
#include <netdb.h> if ( fp != NULL )

9 10
{

char line [ 128 ]; /* or other suitable maximum line size */ /*


* Fichier 'repeteur.c' utilise pour le TD 5 de programmation IP.
* Le programme 'repeteur' est un programme demon "repetant" tout
// boucle de lecture de lignes * ce qu'on lui dit. Il tourne sur le port 6666 et reste à l'ecoute
while ( fgets ( line, sizeof line, fp ) != NULL ) /* read a line */ * d'une eventuelle connexion.
*
{ * Historique
// ecriture dans le socket * 1999/10/15 : dntt : creation
n = write(sockfd,line,strlen(line)); */
if (n < 0)
error("ERROR writing to socket"); #include <unistd.h>
printf(" j'ai envoye : %s \n",line); #include <stdlib.h>
bzero(line,128); #include <sys/stat.h>
printf("entre temps : %s \n",line); #include <string.h>
#include <stdio.h>
// lecture du socket
n = read(sockfd,line,128); #include <sys/types.h>
if (n < 0) #include <sys/socket.h>
error("ERROR reading from socket"); #include <sys/wait.h>
#include <netinet/in.h>
printf(" j'ai reçu : %s \n",line); #include <netdb.h>
//printf("ligne : %s",line); #include <syslog.h>

#include <signal.h>
}
fclose ( fp); #include <arpa/inet.h> /* inclusion de la biblio nécessaire à l'usage des fonctions inet*/
} #define MAXLEN 1024
#define PORT_REPETEUR 6666
#define NB_CONN_MAX 5

void demon () ;
return 0;
} void repeter (int socket_cliente, struct sockaddr_in sock_addr) ;
Fin code 2 int lecture_socket (int socket_cliente, char *buf) ;
void signal_contrC(int sig); /* EXERCICE4 */

/************************************************************************
*
* Fonction principale :
* On cree le demon en dupliquant le processus afin de detacher le
* programme du processus pere
Exercice 4 : *

Modifiez le programme repeteur.c afin qu’une interruption par l’administrateur du serveur soit ************************************************************************/
récupérée, tracée par syslog et coupe proprement la connexion avec chacun des clients en cours int main ()
avant de s’arrêter. {
signal(SIGTERM,signal_contrC); /* EXERCICE 4 */

11 12
switch (fork ()) * sockaddr_in : /usr/include/netinet/in.h
{ *
case -1 : *
perror ("*** erreur : fork impossible : demon non cree") ; *
exit (1) ;
************************************************************************/
case 0 : void demon ()
/* {
* Ce processus fils est celui qui deviendra le demon. int socket_ecoute ;
* Ingredients pour en faire un vrai et bon demons : int socket_cliente ;
*/ int valeur_retour ;
/* 1 - On cree une nouvelle session. Pas de terminal de controle */ int salong ;
setsid () ; int opt = 1 ;
struct sockaddr_in monadr, sonadr ;
/* 2 - le repertoire courant est change a la racine afin de ne pas int status ;
* causer de probleme lors de demontage eventuel de partition
*/
chdir ("/") ; /*
* Creation de la socket d'ecoute
/* 3 - Le masque sur les droits lors de creation de fichiers */ */
umask (0) ; socket_ecoute = socket (PF_INET, SOCK_STREAM, 0) ;

/* 4 - Comme c'est un demon qui est lance et qui est "detache" du /*


* term, l'entree, la sortie et l'erreur standard n'ont pas de * Modification des options associees a la socket d'ecoute.
* terminal ou s'afficher. On peut donc les fermer. */
*/ setsockopt (socket_ecoute, SOL_SOCKET, SO_REUSEADDR, (char *) &opt, \
close (0) ; sizeof (opt)) ;
close (1) ;
close (2) ; /*
* Initialisation des parametres internet de la socket d'ecoute.
*/
/* 6 - On lance le demon proprement dit */ bzero ((char *) &monadr, sizeof monadr) ;
demon () ; monadr.sin_family = AF_INET ;
monadr.sin_port = htons (PORT_REPETEUR) ;
/* 7 - Si le demon s'arrete, alors on sort du processus fils. Le monadr.sin_addr.s_addr = INADDR_ANY ;
* programme est alors termine. */ valeur_retour = bind (socket_ecoute, (struct sockaddr *) &monadr, \
exit (1) ; (int) sizeof monadr) ;

default : /*
/* Le processus pere est tue. On rend la main au shell appelant. */ * Socket mise en position d'ecoute ('listen'). On specifie aussi le
exit (0) ; * nombre de connexions simultanees acceptees.
} */
return 0 ; valeur_retour = listen (socket_ecoute, NB_CONN_MAX) ;
}
/**
/************************************************************************ * Le demon tourne indefiniment a l'ecoute d'eventuelles connections
* * 'accept'
* Le programme 'demon' * Lorsqu'un client se connecte, une socket est cree (socket_cliente).
* * on duplique le processus et le processus fils prend en charge
* Structure * cette socket par la fonction 'repeter'.

13 14
*/ {/*syslog(LOG_LOCAL0, addr);*/
while (1)
{
salong = sizeof sonadr ; //On spécifie l'information à l'utilisateur
write (socket_cliente, "\nFermeture de la connexion a la demande du client\n", 50);
socket_cliente = accept (socket_ecoute, (struct sockaddr *) &sonadr, \ //On récupère son adresse IP
(socklen_t *) &salong) ;
char* addr = inet_ntoa(sock_addr.sin_addr);
switch (fork ()) //On logue le tout dans le fichier /var/log/local0.log
{ openlog("repeteur",0,LOG_LOCAL0);
case -1 : syslog(LOG_LOCAL0,"arret de la connexion par %s",addr);
break ; closelog();
return;
case 0 : }
repeter (socket_cliente, sonadr) ;
close (socket_cliente) ;
//kill (getpid(),SIGTERM);

default :
waitpid (-1, &status, WNOHANG); /* On repete ce qui a ete dit et on renvoie au client */
close (socket_cliente) ; write (socket_cliente, buf, nb_lu) ;
} }
} } /* Solution EXERCICE 2 pour le log */
}
int lecture_socket (int socket_cliente, char *buf)
/************************************************************************ {
* int nb_lu ;
* La fonction qui repete
* nb_lu = read (socket_cliente, buf, MAXLEN) ;
*
* return (nb_lu) ;
}
************************************************************************/ //procedure signal /* Solution EXERCICE 4 pour coupure */
void repeter (int socket_cliente, struct sockaddr_in sock_addr) void signal_contrC(int sig)
{ {
int nb_lu ; openlog("repeteur",0,LOG_LOCAL0);
char buf [MAXLEN] ; syslog(LOG_LOCAL0,"coupure de la connexion par l'administrateur \n");
char *addr; closelog();
printf("\ncoupure de la connexion par l'administrateur, dsl.\n");
while ((nb_lu = lecture_socket (socket_cliente, buf)) > 0) exit(EXIT_SUCCESS);
{ } /* Solution EXERCICE 4 pour coupure */
/* Si probleme de lecture sur la socket (fermee brutalement
* par exemple) */
if (nb_lu == -1 || nb_lu == 0)
{
return ;
}
/*on caompare sur 6 caracteère la chaine que l'utilisateur envoie à la taille du buffeur*/
/* Solution EXERCICE 2 pour le log */
if (strncmp("stop\r\n",buf,6)==0)

15 16

Vous aimerez peut-être aussi