#include "central-manager.h" /* * * @argv : {0:program name} * * @history * [1] Lancement des THREADS d'écoute * 1. On démarre le SERVEUR TCP d'écoute globale * 2. On démarre le SERVEUR UDP d'écoute globale * [2] On attends la fin de tous les THREADS * [3] On ferme la SOCKET d'écoute globale * */ int main(int argc, char* argv[]){ /* [1] Lancement des THREADS d'écoute =========================================================*/ /* (1) Ecoute TCP */ pthread_create(&listenManagers[0], NULL, LISTEN_TCP, NULL); if( DEBUGMOD&THR ) printf("[main][TCP_LISTEN_THREAD] démarré\n"); /* (2) Ecoute UDP */ pthread_create(&listenManagers[1], NULL, LISTEN_UDP, NULL); if( DEBUGMOD&THR ) printf("[main][UDP_LISTEN_THREAD] démarré\n"); /* [2] On attends la fin de tous les THREADS ==========================================================*/ pthread_join(listenManagers[0], NULL); pthread_join(listenManagers[1], NULL); /* [3] On ferme la SOCKET d'écoute globale ==========================================================*/ printf("[main] FERMETURE DE TOUTES LES CONNECTIONS!\n"); } /* Attente de connection TCP * * @history * [0] Initialisation des variables * [1] On démarre le SERVEUR TCP d'écoute globale * [2] Attente d'une demande de connection TCP -> création d'un THREAD * [3] On attends la fin de tous les THREADS * [4] On ferme la SOCKET d'écoute TCP globale * */ void* LISTEN_TCP(){ /* [0] Initialisation des variables ==========================================================*/ int CLIENT_SOCKET; // contiendra la socket TCP à envoyer sur un THREAD struct sockaddr_in clientInfo; // contiendra les infos client socklen_t len; // taille de la socket int index, i; // compteurs // retour de @DROP_TCP_SERVER int LISTENSOCK; // contiendra la socket d'écoute TCP /* [1] On démarre le SERVEUR TCP d'écoute globale ==========================================================*/ if( DROP_TCP_SERVER(TCP_PORT, &LISTENSOCK) < 0 ){ if( DEBUGMOD&SCK ) printf("\tErreur de mise en place de la socket d'écoute TCP\n"); // On ferme la SOCKET d'écoute globale printf("\tFERMETURE DE L'ECOUTE TCP!\n"); close(LISTENSOCK); return NULL; } printf("[main][TCP_LISTEN_THREAD] Listen Port: %d\n", TCP_PORT); /* [2] Attente d'une demande de connection, pour création d'un THREAD ============================================================================*/ while( 1 ){ /* 1. On initialise les SOCKET en attendant la connexion et le rang du "manager" inactif */ CLIENT_SOCKET = -1; index = -1; /* 2. On attends une connection TCP */ CLIENT_SOCKET = accept(LISTENSOCK, (struct sockaddr*) &clientInfo, &len); /* 3. Si erreur, on attend une nouvelle connection */ if( CLIENT_SOCKET < 0 ){ if( DEBUGMOD&SCK ) printf("[main][TCP_LISTEN_THREAD] Erreur connection\n"); break; } /* 4. On cherche un "manager" libre (inactif) */ for( i = 0 ; i < MAX_TCP_THR ; i++ ) if( activeTCPManagers[i] == 0 ){ index = i; break; } // si on a trouvé un "manager" libre if( index != -1 ){ /* 5. On lance un thread pour le traitement de ce client */ pthread_create(&TCPManagers[index], NULL, managePlane, (void*)(intptr_t) CLIENT_SOCKET); if( DEBUGMOD&THR ) printf("[main][TCP_LISTEN_THREAD][COM_THREAD][%d] démarré\n", index); /* 6. On signale que ce "manager" est maintenant actif */ activeTCPManagers[index] = 1; }else if( DEBUGMOD&THR ) printf("[main][TCP_LISTEN_THREAD] Aucun thread libre!\n"); } /* [3] On attends la fin de tous les THREADS ==========================================================*/ for( i = 0 ; i < MAX_TCP_THR ; i++ ) pthread_join(TCPManagers[i], NULL); /* [4] On ferme la SOCKET d'écoute globale ==========================================================*/ printf("[main][TCP_LISTEN_THREAD] FERMETURE DE L'ECOUTE TCP!\n"); close(LISTENSOCK); return NULL; } /* Attente de connection UDP * * @history * [0] Initialisation des variables * [1] On démarre le SERVEUR UDP d'écoute globale * [2] On attends un client * [3] On gère la requête * [4] On ouvre une socket client sur un nouveau port (si ok) * [5] On envoie la réponse * [6] On démarre un thread de gestion avec timeout (en attente du client redirigé) * */ void* LISTEN_UDP(){ /* [0] Initialisation des variables ==========================================================*/ int CLIENT_SOCKET; // contiendra la socket UDP à envoyer sur un THREAD struct sockaddr_in serverInfo; // contiendra les infos serveur struct sockaddr_in clientInfo; // contiendra les infos client char client_ip[20]; // IP du client socklen_t len; // taille de la socket int read; // compteurs char buffer[MAX_BUF_LEN]; // buffer requête struct bind_header request; // requête parsée int i, index; // compteurs // retour de @DROP_UDP_SERVER int SOCKET; /* [1] On démarre le SERVEUR UDP d'écoute globale ==========================================================*/ if( DROP_UDP_SERVER(UDP_PORT, &SOCKET) < 0 ){ if( DEBUGMOD&SCK ) printf("[main][UDP_LISTEN_THREAD] Erreur de mise en place de la socket d'écoute\n"); // On ferme la SOCKET d'écoute globale printf("[main][UDP_LISTEN_THREAD] FERMETURE DE LA SOCKET D'ECOUTE UDP!\n"); close(SOCKET); return NULL; } printf("[main][UDP_LISTEN_THREAD] Listen Port: %d\n", UDP_PORT); /* [2] Attente de connection ============================================================================*/ while( 1 ){ /* 0. On initialise les SOCKET en attendant la connexion et le rang du "manager" inactif */ CLIENT_SOCKET = -1; index = -1; /* 1. On attends une connection UDP */ read = recvfrom(SOCKET, buffer, MAX_BUF_LEN, 0, (struct sockaddr*) &clientInfo, &len); /* 2. Si erreur reception ou taille incorrecte */ if( read != sizeof(char)+sizeof(unsigned short) ){ if( DEBUGMOD&BUF ) printf("[main][UDP_LISTEN_THREAD] read('%s') = %d bytes (expected: %d)\n", buffer, read, (int) (sizeof(char)+sizeof(unsigned short)) ); continue; } /* 3. On récupère l'adresse IP du client */ inet_ntop(AF_INET, &(clientInfo.sin_addr), client_ip, 20); if( DEBUGMOD&SCK ) printf("[main][UDP_LISTEN_THREAD] '%s' connecté\n", client_ip); /* 4. On parse la requête*/ memcpy(&request, buffer, sizeof(struct bind_header)); printf("[main][UDP_LISTEN_THREAD] received: {flag = %d; port = %d}\n", (int) request.flags, request.port); /* 5 Si on veut un port de communicatin */ if( request.flags&BINDHEAD_PRT ){ /* 5.1 On bind une socket sur un port random */ if( DROP_UDP_SERVER(0, &CLIENT_SOCKET) < 0 ){ if( DEBUGMOD&SCK ) printf("[main][UDP_LISTEN_THREAD] Erreur de création de la socket COM\n"); // On ferme la SOCKET CLIENT close(CLIENT_SOCKET); // On retire le flags PORT pour dire qu'on a pas pu ouvrir une socket de comm. request.flags -= BINDHEAD_PRT; } } /* 5.2 Si on veut on port de communication */ if( request.flags&BINDHEAD_PRT ){ /* On récupère le port de la socket de communication */ len = sizeof(struct sockaddr_in); if( getsockname(CLIENT_SOCKET, (struct sockaddr*) &serverInfo, &len) < 0 ){ if( DEBUGMOD&SCK ) printf("[main][UDP_LISTEN_THREAD] Erreur de recherche du port COM ouvert\n"); close(CLIENT_SOCKET); // On retire le flags PORT pour dire qu'on a pas pu ouvrir une socket de comm. request.flags -= BINDHEAD_PRT; // Si on a le port -> on le met dans la reponse }else request.port = serverInfo.sin_port; } if( DEBUGMOD&SCK ) printf("[main][UDP_LISTEN_THREAD] { port: %d }\n", serverInfo.sin_port); /* 8. On envoie la réponse */ memcpy(buffer, &request, sizeof(struct bind_header)); if( send(SOCKET, buffer, strlen(buffer), 0) < 0 ){ printf("[main][UDP_LISTEN_THREAD] Impossible de répondre au client!\n"); continue; } /* 4. On cherche un "manager" libre (inactif) */ for( i = 0 ; i < MAX_UDP_THR ; i++ ) if( activeUDPManagers[i] == 0 ){ index = i; break; } // si on a trouvé un "manager" libre if( index != -1 ){ /* 5. On lance un thread pour le traitement de ce client */ pthread_create(&UDPManagers[index], NULL, manageTerminal, (void*)(intptr_t) CLIENT_SOCKET); if( DEBUGMOD&THR ) printf("[main][UDP_LISTEN_THREAD][COM_THREAD][%d] démarré\n", index); /* 6. On signale que ce "manager" est maintenant actif */ activeUDPManagers[index] = 1; }else if( DEBUGMOD&THR ) printf("[main][UDP_LISTEN_THREAD] Aucun thread UDP libre!\n"); } /* [n] On ferme la SOCKET d'écoute globale ==========================================================*/ printf("[main][UDP_LISTEN_THREAD] FERMETURE DE LA SOCKET UDP!\n"); close(SOCKET); return NULL; } /* Gestion d'une connexion PLANE * * @THREADABLE_SOCKET SOCKET de la connexion client * * @history * [1] Initialisation des variables * [2] Récupération de la requête * [3] Traitement de la requête * [4] Création de la réponse * [5] Envoi de la réponse * [6] On vide les buffers * [7] Fermeture de la connection (SOCKET) * [n] Arrêt du THREAD * 1. On récupère le rang dans les "managers" * 2. On met à jour "activeManagers" * 3. On arrête le THREAD * */ void* managePlane(void* THREADABLE_SOCKET){ /* [1] Initialisation des variables =========================================================*/ int read; // compteur int TCP_SOCKET = (intptr_t) THREADABLE_SOCKET; // Socket client char request[MAX_BUF_LEN]; // Requête // char response[MAX_BUF_LEN]; // Réponse do{ /* [2] Récupération de la requête =========================================================*/ /* 1. On lit sur la socket */ read = recv(TCP_SOCKET, request, MAX_BUF_LEN, 0); /* 2. Si erreur reception */ if( read < 0 ){ if( DEBUGMOD&BUF ) printf("[main][TCP_LISTEN_THREAD][COM_THREAD] READ = %d\n", read); break; } /* 3. On désérialise la requête*/ printf("[main][TCP_LISTEN_THREAD][COM_THREAD] PLANE Request(%d bytes) : '%s'\n", read, request); /* [3] Gestion de la requête =========================================================*/ }while( 0 ); /* [n] Arrêt du THREAD ============================================================================*/ /* 1. On récupère le rang dans les "managers" */ int i, index = -1; for( i = 0 ; i < MAX_TCP_THR ; i++ ) if( TCPManagers[i] == pthread_self() ){ index = i; break; } /* 2. On met à jour "activeManagers" */ if( index != -1 ) activeTCPManagers[index] = 0; /* 3. On arrête le THREAD */ if( DEBUGMOD&THR ) printf("[main][UDP_LISTEN_THREAD][COM_THREAD][%d] libéré\n", index); pthread_exit(NULL); } /* Gestion d'une connexion TERMINAL * * @THREADABLE_SOCKET SOCKET de la connexion client * * @history * [1] Initialisation des variables * [2] Récupération de la requête * [3] Traitement de la requête * [4] Création de la réponse * [5] Envoi de la réponse * [6] On vide les buffers * [7] Fermeture de la connection (SOCKET) * [n] Arrêt du THREAD * 1. On récupère le rang dans les "managers" * 2. On met à jour "activeManagers" * 3. On arrête le THREAD * */ void* manageTerminal(void* THREADABLE_SOCKET){ /* [1] Initialisation des variables =========================================================*/ int read; // compteur struct sockaddr_in clientInfo; socklen_t len; int UDP_SOCKET = (intptr_t) THREADABLE_SOCKET; // Socket client char request[MAX_BUF_LEN]; // Requête // char response[MAX_BUF_LEN]; // Réponse do{ printf("[main][UDP_LISTEN_THREAD][COM_THREAD] waiting for terminal request\n"); /* [2] Récupération de la requête =========================================================*/ /* 1. On lit sur la socket */ len = sizeof(struct sockaddr_in); read = recvfrom(UDP_SOCKET, request, MAX_BUF_LEN, 0, (struct sockaddr*) &clientInfo, &len); /* 2. Si erreur reception */ if( DEBUGMOD&BUF ) printf("[main][UDP_LISTEN_THREAD][COM_THREAD] READ = %d\n", read); if( read < 0 ) continue; /* 3. On désérialise la requête*/ printf("[main][UDP_LISTEN_THREAD][COM_THREAD] TERMINAL Request(%d bytes) : '%s'\n", read, request); /* [3] Gestion de la requête =========================================================*/ /* [4] Envoi reponse =========================================================*/ strcpy(request+strlen(request), "-bla\0"); send(UDP_SOCKET, request, strlen(request), 0); }while( 0 ); /* [n] Arrêt du THREAD ============================================================================*/ /* 1. On récupère le rang dans les "managers" */ int i, index = -1; for( i = 0 ; i < MAX_TCP_THR ; i++ ) if( TCPManagers[i] == pthread_self() ){ index = i; break; } /* 2. On met à jour "activeManagers" */ if( index != -1 ) activeTCPManagers[index] = 0; /* 3. On arrête le THREAD */ if( DEBUGMOD&THR ) printf("[main][UDP_LISTEN_THREAD][COM_THREAD][%d] libéré\n", index); pthread_exit(NULL); }