#include #include #include #include #include #include #include #include #include #include "tcpserver.h" #include "utils.h" #include "dispatcher.h" int end=0; 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); } 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; }