/*****************************/ /* serveurUDP_corrige_Q3.2.c */ /*****************************/ #include #include #include #include #include #include #include #include #include #include #include #include "redblack.h" #include "initCommunication.h" #include "client-serveur.h" // // Constantes de fonctionnement du programme // // #define NB_MAX_REPONSES 10 // Nombre maximum de reponses que le serveur fait // a un client (avant de lui repondre REPONSE_KO) #define NB_THREADS_DANS_POOL 1000 // Nombre de threads dans le pool // Structure permettant de passer un entier en parametre lors // d'un pthread_create union IntPtr { int entier; void *ptr; }; // // Structure pour les noeuds du red-black tree // typedef struct{ char key[NI_MAXHOST + sizeof(':') + NI_MAXSERV]; // Le "+ 1" est la pour le ":" qui sert de separateur int nbReponsesAuClient; } node_t; // // Mutex // pthread_mutex_t mutexRangClient; // Mutex evitant les race conditions sur rangClient pthread_mutex_t mutexRbtree; // Mutex pour l'arbre red-black // Arbre red-black; struct rbtree *rbtree = NULL; // // Macros ameliorant la lisibilite des fonctions utilisant des mutex // #define MUTEX_LOCK(m) \ { \ int rc=pthread_mutex_lock(&(m)); \ if (rc < 0) \ error_at_line(EXIT_FAILURE,rc,__FILE__,__LINE__,"pthread_mutex_lock"); \ } #define MUTEX_UNLOCK(m) \ { \ int rc=pthread_mutex_unlock(&(m)); \ if (rc < 0) \ error_at_line(EXIT_FAILURE,rc,__FILE__,__LINE__,"pthread_mutex_unlock"); \ } int compare(const void *pa, const void *pb, const void *config) { node_t *pnodeA = (node_t *)pa; node_t *pnodeB = (node_t *)pb; return strcmp(pnodeA->key, pnodeB->key); } void gestionRequete(int fdPointDAcces, struct sockaddr_storage addrEmetteur, socklen_t addrEmetteur_len, message_t requete) { static int rangClient = 0; message_t reponse; // On determine l'emetteur du message char host[NI_MAXHOST], service[NI_MAXSERV]; int rc = getnameinfo((struct sockaddr *) &addrEmetteur, addrEmetteur_len, host, NI_MAXHOST, service, NI_MAXSERV, NI_NUMERICSERV); if (rc != 0) error_at_line(EXIT_FAILURE, errno, __FILE__, __LINE__, "getnameinfo"); // On traite la requete char key[NI_MAXHOST + sizeof(':') + NI_MAXSERV]; // Le "+ 1" est la pour le ":" qui sert de separateur sprintf(key, "%s:%s", host, service); MUTEX_LOCK(mutexRbtree); node_t *pnode = (node_t *)rbfind(key, rbtree); MUTEX_UNLOCK(mutexRbtree); if (pnode == NULL) { // C'est un nouveau client pnode = malloc(sizeof(node_t)); assert(pnode != NULL); strcpy(pnode->key, key); pnode->nbReponsesAuClient = 0; MUTEX_LOCK(mutexRbtree); (void)rbsearch(pnode, rbtree); MUTEX_UNLOCK(mutexRbtree); MUTEX_LOCK(mutexRangClient); rangClient++; printf("%6d-ieme client a traiter (%s:%s)\n", rangClient, host, service); MUTEX_UNLOCK(mutexRangClient); } if (pnode->nbReponsesAuClient < NB_MAX_REPONSES) { reponse.typ = REQUETE_OK; pnode->nbReponsesAuClient++; CALCUL_PAYLOAD(reponse.infoSup.payload, pnode->nbReponsesAuClient); //usleep(100000); } else { reponse.typ = REQUETE_KO; } ssize_t nbWrite = sendto(fdPointDAcces, &reponse, sizeof(reponse), 0, (struct sockaddr *) &addrEmetteur, addrEmetteur_len); if (nbWrite != sizeof(reponse)) error_at_line(EXIT_FAILURE, errno, __FILE__, __LINE__, "sendto"); } void *gestionPointDAcces(void *arg) { union IntPtr ip; ip.ptr = arg; int fdPointDAcces = ip.entier; do { // Attente message struct sockaddr_storage addrEmetteur; socklen_t addrEmetteur_len = sizeof(addrEmetteur); message_t requete; ssize_t nbRead = recvfrom(fdPointDAcces, &requete, sizeof(requete), 0, (struct sockaddr *) &addrEmetteur, &addrEmetteur_len); if (nbRead != sizeof(requete)) error_at_line(EXIT_FAILURE, errno, __FILE__, __LINE__, "recvfrom"); // Gestion de cette requete gestionRequete(fdPointDAcces, addrEmetteur, addrEmetteur_len, requete); } while (1); } int main() { int fdPointDAcces = creationPointDAcces(); int i; // Initialisation des mutex pthread_mutex_init(&mutexRangClient, NULL); pthread_mutex_init(&mutexRbtree, NULL); // Initialisation red-black tree if ((rbtree=rbinit(compare, NULL))==NULL) { fprintf(stderr, "insufficient memory\n"); exit(EXIT_FAILURE); } // Creation du pool de threads for (i = 0 ; i < NB_THREADS_DANS_POOL-1 ; i++) { pthread_t thread; union IntPtr ip; ip.entier = fdPointDAcces; int rc = pthread_create(&thread, NULL, gestionPointDAcces, ip.ptr); if (rc < 0) error_at_line(EXIT_FAILURE, rc, __FILE__, __LINE__, "pthread_create"); rc = pthread_detach(thread); if (rc < 0) error_at_line(EXIT_FAILURE, rc, __FILE__, __LINE__, "pthread_detach"); } // Le thread du main est aussi un thread du pool union IntPtr ip; ip.entier = fdPointDAcces; gestionPointDAcces(ip.ptr); return EXIT_SUCCESS; }