diff options
Diffstat (limited to 'app/v3_c/src/tcpserver.c')
-rw-r--r-- | app/v3_c/src/tcpserver.c | 118 |
1 files changed, 118 insertions, 0 deletions
diff --git a/app/v3_c/src/tcpserver.c b/app/v3_c/src/tcpserver.c new file mode 100644 index 0000000..53b86a9 --- /dev/null +++ b/app/v3_c/src/tcpserver.c @@ -0,0 +1,118 @@ +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <stdio.h> +#include <stdlib.h> +#include <strings.h> +#include <errno.h> +#include <unistd.h> +#include <signal.h> + +#include "utils.h" +#include "tcpserver.h" +#include "dispatcher.h" + +int end=0; + +void _signals(int signum) { + static int force=0; + + if (0) printf("signal %i\n", signum); + + if(!force) { + end=1; + force=1; + logs("Tentative d'arrêt soft du serveur..."); + } else { + logs("Arrêt d'urgence du serveur"); + exit(1); + } +} + + +int tcpserver() { + int res; + int sockServ, sockCli; + struct sockaddr_in servAddr, cliAddr; + socklen_t cliAddrLen; + + // Création socket + sockServ = socket(AF_INET, SOCK_STREAM, 0); + if (sockServ < 0) { perror("socket"); return(2); } + + // Accrochage du socket (adresse et port locaux) + bzero((char *) &servAddr, sizeof(servAddr)); + servAddr.sin_family = AF_INET; + servAddr.sin_addr.s_addr = INADDR_ANY; + servAddr.sin_port = htons(LISTEN_PORT); + res=bind(sockServ, (struct sockaddr *) &servAddr, sizeof(servAddr)); + if (res < 0) { perror("bind"); return(3); } + + // On lance l'écoute + listen(sockServ,LISTEN_BACKLOG); + if (res < 0) { perror("listen"); return(4); } + + // On active la gestion des signaux + signal(2,_signals); + + res=initDispatcher(); + if (res != 0 ) { +#ifdef DEBUG + logs("initDispatcher() error"); +#endif + return(5); + } + + // Boucle d'acceptation des clients + cliAddrLen = sizeof(cliAddr); + while ( ! end ) { + // Appel bloquant d'acceptation d'un nouveau client + sockCli=accept(sockServ, (struct sockaddr *) &cliAddr, &cliAddrLen); + + // Il y plein de raisons pour qu'un accept echoue + if (sockCli < 0) { + switch(errno) { + case EAGAIN: + case EINTR: + // Cas qui ne sont pas des erreurs, mais nécessitent de rappeler accept +#ifdef DEBUG + perror("accept (info)"); +#endif + break; + case EMFILE: + case ENFILE: + case ENOBUFS: + case ENOMEM: + // Cas d'erreur transitoire (attente d'une seconde histoire d'attendre un peu si ressources fichiers, ram épuisés +#ifdef DEBUG + perror("accept (warn)"); + sleep(1); +#endif + break; + default: + // Cas d'erreur fatales + perror("accept (err)"); + end=2; + } + } else { + // Cas nominal : un nouveau socket est disponible avec un client au bout +#ifdef HEAVYDEBUG + logs("Client accepté"); +#endif + end=requestDispatcher(sockCli, &cliAddr, &cliAddrLen); + } + } + + freeDispatcher(); + + if ( end != 1 ) { +#ifdef DEBUG + logs("Fin anormale du serveur"); +#endif + return(6); + } + + return 0; +} + |