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-16 09:57:31 +02:00
|
|
|
int serv_sockid, child_sockid;
|
2022-09-14 13:32:34 +02:00
|
|
|
struct sockaddr_in server_socket;
|
2022-09-16 09:57:31 +02:00
|
|
|
struct sockaddr_in child_socket;
|
2022-09-13 15:43:49 +02:00
|
|
|
pid_t pid;
|
2022-09-16 09:57:31 +02:00
|
|
|
long addr_len;
|
2022-09-13 15:43:49 +02:00
|
|
|
|
2022-09-14 13:32:34 +02:00
|
|
|
/* Gestion des signaux */
|
2022-09-13 15:43:49 +02:00
|
|
|
signal(SIGCHLD, interrupt);
|
|
|
|
signal(SIGINT, interrupt);
|
|
|
|
signal(SIGTERM, interrupt);
|
|
|
|
|
2022-09-14 13:32:34 +02:00
|
|
|
/* Initialisation des valeurs par défaut du socket */
|
|
|
|
server_socket.sin_family = AF_INET;
|
2022-10-14 18:16:46 +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
|
2022-10-14 18:16:46 +02:00
|
|
|
#else
|
2022-09-14 13:32:34 +02:00
|
|
|
server_socket.sin_port = 0;
|
2022-10-14 18:16:46 +02:00
|
|
|
#endif
|
|
|
|
server_socket.sin_addr.s_addr = makeip4(0, 0, 0, 0);
|
2022-09-14 10:08:51 +02:00
|
|
|
// 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-16 09:57:31 +02:00
|
|
|
if ((serv_sockid = 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-16 09:57:31 +02:00
|
|
|
if (bind(serv_sockid, (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);
|
2022-09-16 09:57:31 +02:00
|
|
|
if (getsockname(serv_sockid, (struct sockaddr *) &server_socket, (socklen_t *) &addr_len) < 0) {
|
2022-09-13 15:43:49 +02:00
|
|
|
perror("getsockname");
|
|
|
|
return EXIT_FAILURE;
|
|
|
|
} else {
|
2022-10-14 18:16:46 +02:00
|
|
|
printf("serving connexions on %s:%d\n", ip4tostring(ntohl(server_socket.sin_addr.s_addr)), ntohs(server_socket.sin_port));
|
2022-09-13 15:43:49 +02:00
|
|
|
}
|
|
|
|
|
2022-10-14 18:21:59 +02:00
|
|
|
if (listen(serv_sockid, SOMAXCONN) == -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-16 09:57:31 +02:00
|
|
|
if ((child_sockid = accept(serv_sockid, (struct sockaddr *) &child_socket, (socklen_t *) &addr_len)) < 0) {
|
2022-09-13 15:43:49 +02:00
|
|
|
perror("accept");
|
|
|
|
} else {
|
2022-09-19 11:13:07 +02:00
|
|
|
printf("received connexion from %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-19 11:13:07 +02:00
|
|
|
write(child_sockid, "server error\n", 14);
|
2022-09-13 15:43:49 +02:00
|
|
|
} else {
|
|
|
|
if (pid == 0) { // code du fils
|
2022-09-16 09:57:31 +02:00
|
|
|
service(child_sockid); // Regroupe le code pour le fils
|
2022-09-13 15:43:49 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
2022-09-16 09:57:31 +02:00
|
|
|
close(child_sockid); // 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;
|
2022-09-14 13:55:11 +02:00
|
|
|
pid_t pid;
|
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;
|
2022-09-14 13:55:11 +02:00
|
|
|
char delim[] = {' ', '\t', '\n', '\0'};
|
2022-09-13 15:43:49 +02:00
|
|
|
char *token, *text;
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
/* Lecture du répertoire */
|
2022-09-13 21:59:52 +02:00
|
|
|
if ((n = readline(fd, buf, BUF_LEN)) == -1) {
|
2022-09-19 11:13:07 +02:00
|
|
|
sprintf(buf, "ERROR: receive message - probably too long\n");
|
2022-09-13 15:43:49 +02:00
|
|
|
write(fd, buf, strlen(buf) + 1);
|
|
|
|
} else {
|
2022-09-14 13:55:11 +02:00
|
|
|
if ((pid = fork()) == -1) {
|
2022-09-19 11:13:07 +02:00
|
|
|
sprintf(buf, "ERROR: system\n");
|
2022-09-13 15:43:49 +02:00
|
|
|
write(fd, buf, strlen(buf) + 1);
|
|
|
|
close(fd);
|
|
|
|
return;
|
|
|
|
} else {
|
2022-09-14 13:55:11 +02:00
|
|
|
if (pid == 0) { // code du fils qui execute la commande
|
2022-09-13 15:43:49 +02:00
|
|
|
/* 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) {
|
2022-09-19 11:13:07 +02:00
|
|
|
sprintf(buf, "ERROR: memory\n");
|
2022-09-13 15:43:49 +02:00
|
|
|
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:
|
2022-09-19 11:13:07 +02:00
|
|
|
fprintf(stderr, "server killed\n");
|
2022-09-13 21:40:23 +02:00
|
|
|
exit(0);
|
|
|
|
break;
|
|
|
|
default:
|
2022-09-19 11:13:07 +02:00
|
|
|
fprintf(stderr, "received unexpected signal %d\n", signal);
|
2022-09-13 21:40:23 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|