projet-multitaches/src/server.c

183 lines
5.9 KiB
C
Raw Normal View History

2022-09-13 15:43:49 +02:00
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <signal.h>
#include <sys/wait.h>
2022-09-13 21:40:23 +02:00
#include "server.h"
2022-09-13 15:43:49 +02:00
#include "common.h"
2022-09-13 21:59:52 +02:00
/* booléen pour la boucle d'acceptation */
2022-09-13 21:40:23 +02:00
int RUN = 1;
2022-09-13 15:43:49 +02:00
2022-09-13 21:40:23 +02:00
int main(void) {
2022-09-14 10:08:51 +02:00
int serv_sock_fd, child_sock_fd; // socket id = file descriptor
struct sockaddr_in server_socket;
2022-09-14 10:08:51 +02:00
struct sockaddr_in child_socket; // on définit juste, les valeurs seront récuperées dans accept()
2022-09-13 15:43:49 +02:00
pid_t pid;
2022-09-14 10:08:51 +02:00
long addr_len; // pour récuperer la longueur de l'adresse dans accept()
2022-09-13 15:43:49 +02:00
/* Gestion des signaux */
2022-09-13 15:43:49 +02:00
signal(SIGCHLD, interrupt);
signal(SIGINT, interrupt);
signal(SIGTERM, interrupt);
/* Initialisation des valeurs par défaut du socket */
server_socket.sin_family = AF_INET;
2022-09-14 10:12:10 +02:00
#ifdef PORT
2022-09-14 10:08:51 +02:00
server_socket.sin_port = htons(PORT); // port dans l'ordre des octets réseau
#else
server_socket.sin_port = 0;
2022-09-14 10:12:10 +02:00
#endif
2022-09-14 10:08:51 +02:00
server_socket.sin_addr.s_addr = makeip4(127, 0, 0, 1);
// server_socket.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
2022-09-13 15:43:49 +02:00
2022-09-14 10:27:02 +02:00
/* Définition du socket */
2022-09-14 10:08:51 +02:00
if ((serv_sock_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
2022-09-13 15:43:49 +02:00
perror("socket");
return EXIT_FAILURE;
}
2022-09-14 10:27:02 +02:00
/* bind() avec un cast d'un struct générique, le type de struct sera découvert dans sa_family */
2022-09-14 10:08:51 +02:00
if (bind(serv_sock_fd, (struct sockaddr *) &server_socket, sizeof(server_socket)) == -1) {
2022-09-13 15:43:49 +02:00
perror("bind");
return EXIT_FAILURE;
}
/* On récupere le port d'attache */
2022-09-14 10:08:51 +02:00
addr_len = sizeof(server_socket);
if (getsockname(serv_sock_fd, (struct sockaddr *) &server_socket, (socklen_t *) &addr_len) < 0) {
2022-09-13 15:43:49 +02:00
perror("getsockname");
return EXIT_FAILURE;
} else {
printf("Connexion de %s !\n", ip4tostring(ntohl(makeip4(127, 0, 0, 1))));
2022-09-14 10:08:51 +02:00
printf("Le serveur est attaché au port %d\n", ntohs(server_socket.sin_port));
2022-09-13 15:43:49 +02:00
}
/* On définit le nombre d'écoutes simultanées */
2022-09-14 10:08:51 +02:00
if (listen(serv_sock_fd, 10) == -1) {
2022-09-13 15:43:49 +02:00
perror("listen");
return EXIT_FAILURE;
}
/* On laisse le serveur accepter des connexions
* A chaque connexion établie, le serveur crée un fils pour gérer celle-ci. */
while (RUN) {
2022-09-14 10:08:51 +02:00
if ((child_sock_fd = accept(serv_sock_fd, (struct sockaddr *) &child_socket, (socklen_t *) &addr_len)) < 0) {
2022-09-13 15:43:49 +02:00
perror("accept");
} else {
2022-09-14 10:08:51 +02:00
printf("Connexion de %s !\n", ip4tostring(ntohl(child_socket.sin_addr.s_addr)));
2022-09-13 15:43:49 +02:00
/* Création d'un processus dédié au client */
if ((pid = fork()) == -1) {
perror("fork");
2022-09-14 10:08:51 +02:00
write(child_sock_fd, "Erreur serveur !\n", 18);
2022-09-13 15:43:49 +02:00
} else {
if (pid == 0) { // code du fils
2022-09-14 10:08:51 +02:00
service(child_sock_fd); // Regroupe le code pour le fils
2022-09-13 15:43:49 +02:00
return 0;
}
}
2022-09-14 10:08:51 +02:00
close(child_sock_fd); // On ferme le file descriptor qu'on vient de créer puisque c'est le fils qui s'en occupe
2022-09-13 15:43:49 +02:00
}
}
return EXIT_SUCCESS;
}
2022-09-13 21:40:23 +02:00
void service(int fd) {
2022-09-13 15:43:49 +02:00
int i, n, t;
pid_t pid2;
2022-09-13 21:59:52 +02:00
char buf[BUF_LEN], buf2[BUF_LEN], eot = EOT;
2022-09-13 15:43:49 +02:00
void *memory = NULL;
char **command_line;
char delim[4];
char *token, *text;
delim[0] = ' ';
delim[1] = '\t';
delim[2] = '\n';
delim[3] = '\0';
while (1) {
/* Lecture du répertoire */
2022-09-13 21:59:52 +02:00
if ((n = readline(fd, buf, BUF_LEN)) == -1) {
2022-09-13 15:43:49 +02:00
sprintf(buf, "Erreur réception message : sans doute trop long !\n");
write(fd, buf, strlen(buf) + 1);
} else {
/* Exécution de ls vers le pipe */
if ((pid2 = fork()) == -1) {
sprintf(buf, "Erreur système ! Revenez plus tard !\n");
write(fd, buf, strlen(buf) + 1);
close(fd);
return;
} else {
if (pid2 == 0) { // code du fils qui execute la commande
/* Il a dans buf la commande a executer */
/* Redirection de stdout et stderr vers le socket */
dup2(fd, STDOUT_FILENO);
dup2(fd, STDERR_FILENO);
strcpy(buf2, buf);
text = buf;
t = 0;
while ((token = strtok_r(text, delim, &text)) != NULL) {
t++;
}
t++; // Pour ajouter le NULL à la fin
if ((memory = malloc(t * sizeof(memory))) == NULL) {
sprintf(buf, "Erreur mémoire ! Revenez plus tard !\n");
write(fd, buf, strlen(buf) + 1);
close(fd);
return;
}
command_line = (char**) memory;
text = buf2;
for (i = 0; ((token = strtok_r(text, delim, &text)) != NULL); i++) {
command_line[i] = token;
}
command_line[i] = NULL;
execvp(command_line[0], command_line);
/* Si le execvp a marché le code suivant ne sera jamais executé.
* Pas besoin donc de faire un test */
perror("execvp");
exit(1);
}
/* Suite du pere */
wait(NULL); // Attend la fin du fils
write(fd, &eot, 1);
}
}
}
close(fd);
}
2022-09-13 21:40:23 +02:00
2022-09-13 21:59:52 +02:00
void interrupt(int signal) {
switch (signal) {
2022-09-13 21:40:23 +02:00
case SIGCHLD:
while (waitpid(-1, NULL, WNOHANG) != -1);
break;
case SIGINT:
RUN = 0;
exit(EXIT_FAILURE);
break;
case SIGTERM:
fprintf(stderr, "Arret du serveur !\n");
exit(0);
break;
default:
2022-09-13 21:59:52 +02:00
fprintf(stderr, "Reçu signal %d !?!\n", signal);
2022-09-13 21:40:23 +02:00
break;
}
}