#include #include #include #include #include #include #include #include #include #include "server.h" #include "common.h" /* booléen pour la boucle d'acceptation */ int RUN = 1; int main(void) { int serv_sockid, child_sockid; struct sockaddr_in server_socket; struct sockaddr_in child_socket; pid_t pid; long addr_len; /* Gestion des signaux */ signal(SIGCHLD, interrupt); signal(SIGINT, interrupt); signal(SIGTERM, interrupt); /* Initialisation des valeurs par défaut du socket */ server_socket.sin_family = AF_INET; #ifdef PORT server_socket.sin_port = htons(PORT); // port dans l'ordre des octets réseau #else server_socket.sin_port = 0; #endif server_socket.sin_addr.s_addr = makeip4(0, 0, 0, 0); // server_socket.sin_addr.s_addr = htonl(INADDR_LOOPBACK); /* Définition du socket */ if ((serv_sockid = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) { perror("socket"); return EXIT_FAILURE; } /* bind() avec un cast d'un struct générique, le type de struct sera découvert dans sa_family */ if (bind(serv_sockid, (struct sockaddr *) &server_socket, sizeof(server_socket)) == -1) { perror("bind"); return EXIT_FAILURE; } /* On récupere le port d'attache */ addr_len = sizeof(server_socket); if (getsockname(serv_sockid, (struct sockaddr *) &server_socket, (socklen_t *) &addr_len) < 0) { perror("getsockname"); return EXIT_FAILURE; } else { printf("serving connexions on %s:%d\n", ip4tostring(ntohl(server_socket.sin_addr.s_addr)), ntohs(server_socket.sin_port)); } if (listen(serv_sockid, SOMAXCONN) == -1) { 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) { if ((child_sockid = accept(serv_sockid, (struct sockaddr *) &child_socket, (socklen_t *) &addr_len)) < 0) { perror("accept"); } else { printf("received connection from %s\n", ip4tostring(ntohl(child_socket.sin_addr.s_addr))); /* Création d'un processus dédié au client */ if ((pid = fork()) == -1) { perror("fork"); write(child_sockid, "server error\n", 14); } else { if (pid == 0) { // code du fils service(child_sockid); // Regroupe le code pour le fils return EXIT_SUCCESS; } } close(child_sockid); // On ferme le file descriptor qu'on vient de créer puisque c'est le fils qui s'en occupe } } return EXIT_SUCCESS; } void service(int fd) { int i, n, t; pid_t pid; char buf[BUF_LEN], buf2[BUF_LEN], eot = EOT; void *memory = NULL; char **command_line; char delim[] = {' ', '\t', '\n', '\0'}; char *token, *text; while (1) { /* Lecture du répertoire */ if ((n = readline(fd, buf, BUF_LEN)) == -1) { sprintf(buf, "ERROR: receive message - probably too long\n"); write(fd, buf, strlen(buf) + 1); } else { if ((pid = fork()) == -1) { sprintf(buf, "ERROR: system\n"); write(fd, buf, strlen(buf) + 1); close(fd); return; } else { if (pid == 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, "ERROR: memory\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(EXIT_FAILURE); } /* Suite du pere */ wait(NULL); // Attend la fin du fils write(fd, &eot, 1); } } } close(fd); } void interrupt(int signal) { switch (signal) { case SIGCHLD: while (waitpid(-1, NULL, WNOHANG) != -1); break; case SIGINT: RUN = 0; exit(EXIT_FAILURE); break; case SIGTERM: fprintf(stderr, "server killed\n"); exit(EXIT_SUCCESS); break; default: fprintf(stderr, "received unexpected signal %d\n", signal); break; } }