/************************** * Central-Manager * *************************** * Designed & Developed by * * Adrien Marquès * * * *************************** * doowap31@gmail.com * **************************/ #include "central-manager.h" /* * * @argv : {0:program name} * * @history * [0] Initialisation des variables * [1] Lancement des THREADS d'écoute * 1. On démarre le SERVEUR TCP d'écoute globale * 2. On récupère l'IP locale * 3. On démarre le SERVEUR UDP d'écoute globale * [2] On attends la fin de tous les THREADS * [3] On libère les variables globale * */ int main(int argc, char* argv[]){ printf("[Copyright (R) 2017]\n"); printf(" - Adrien Marquès aka. xdrm-brackets (C shit)\n"); printf(" - Lucas Mascaro aka. SeekDaSky (java shit)\n"); printf("* From the developers of the 'WebSocket' library for the UPPA University\n\n\n"); printf("Notice: {threadName}{subThread}(subThreadId)\n\n"); printf("**** Execution tree\n"); /* [0] Initialisation des variables =========================================================*/ /* 1. Variables globales */ sgca.n = 0; sgca.unit = (struct context_unit*) malloc( sizeof(struct context_unit) ); struct in_addr* SERV_HOST; /* 2. On récupère l'IP locale' */ SERV_HOST = GET_LOCAL_IP(); if( SERV_HOST == NULL ){ printf("/!\\ Cannot fetch local ip address. Aborting!\n"); free(sgca.unit); return EXIT_FAILURE; } printf("LOCAL IP: %s\n", inet_ntoa(*SERV_HOST)); /* 3. Variables locales */ struct listen_arg tcp_listn_arg = { SERV_HOST->s_addr, TCP_LIST, NULL, &managePlane }; struct listen_arg udp_mcast_arg = { inet_addr(MCST_HOST), UDP_MCST, NULL, NULL }; struct listen_arg udp_vterm_arg = { inet_addr(MCST_VTER), UDP_VTER, &multicastTerminal, &manageViewTerm }; struct listen_arg udp_cterm_arg = { inet_addr(MCST_CTER), UDP_CTER, &multicastTerminal, &manageCtrlTerm }; /* [1] Lancement des THREADS d'écoute =========================================================*/ /* (1) Ecoute TCP */ pthread_create(&listenManagers[0], NULL, LISTEN_TCP, (void*) &tcp_listn_arg); if( DEBUGMOD&THR ) printf("{tcp_listn} started\n"); /* (2) Ecoute UDP multicast */ pthread_create(&listenManagers[1], NULL, MCAST_PUBLISH, (void*) &udp_mcast_arg); if( DEBUGMOD&THR ) printf("{udp_mcast} started\n"); /* (3) Ecoute UDP viewTerm */ pthread_create(&listenManagers[2], NULL, LISTEN_UDP, (void*) &udp_vterm_arg); if( DEBUGMOD&THR ) printf("{udp_vterm} started\n"); /* (4) Ecoute UDP ctrlTerm */ pthread_create(&listenManagers[3], NULL, LISTEN_UDP, (void*) &udp_cterm_arg); if( DEBUGMOD&THR ) printf("{udp_cterm} started\n"); /* [2] On attends la fin de tous les THREADS ==========================================================*/ for( char i = 0 ; i < 4 ; i++ ) pthread_join(listenManagers[(int)i], NULL); /* [3] On libère les variables globales ==========================================================*/ free(sgca.unit); return EXIT_SUCCESS; } /* 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(void* THREADABLE_ARGS){ /* [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 struct listen_arg* arg = THREADABLE_ARGS; // Addr + Port serveur struct in_addr ip; // Pour afficher l'IP en dot notation int rtnPort; // Port utilisé par le serveur ip.s_addr = arg->addr; // retour de @DROP_TCP_SERVER int LISTENSOCK; // contiendra la socket d'écoute TCP /* [1] On démarre le SERVEUR TCP d'écoute globale ==========================================================*/ rtnPort = DROP_TCP_SERVER(arg->port, &LISTENSOCK); if( rtnPort < 0 ){ if( DEBUGMOD&SCK ) printf("{tcp_listn} Error creating listener socket\n"); // On ferme la SOCKET d'écoute globale printf("{tcp_listn} Closing listener socket!\n"); close(LISTENSOCK); return NULL; } printf("{tcp_listn} listen on %s:%d\n", inet_ntoa(ip), rtnPort); if( rtnPort != arg->port ) printf("{tcp_listn} /!\\ Another SGCA might be running, port %d is already used\n", arg->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 */ len = sizeof(struct sockaddr_in); CLIENT_SOCKET = accept(LISTENSOCK, (struct sockaddr*) &clientInfo, &len); /* 3. Si erreur, on attend une nouvelle connection */ if( CLIENT_SOCKET < 0 ){ if( DEBUGMOD&SCK ) printf("{tcp_listn} accept: Erreur connection\n"); break; } if( DEBUGMOD&SCK ) printf("{tcp_listn} %s:%d connected\n", inet_ntoa(clientInfo.sin_addr), ntohs(clientInfo.sin_port)); /* 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 ){ // Construction arguments thread struct handler_arg thread_args = { TCPManagers, UDPManagers, activeTCPManagers, activeUDPManagers, CLIENT_SOCKET, &sgca }; /* 5. On lance un thread pour le traitement de ce client */ pthread_create(&TCPManagers[index], NULL, arg->handler, (void*) &thread_args); if( DEBUGMOD&THR ) printf("{tcp_listn}{com}(%d) started\n", index); /* 6. On signale que ce "manager" est maintenant actif */ activeTCPManagers[index] = 1; }else if( DEBUGMOD&THR ) printf("{tcp_listn} No available thread\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("{tcp_listn} Closing listener socket\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 * 1. On parse la requête * 2. Si demande de socket de communication * 1. Création socket port random * 2. On récupère le port en question * 3. On envoie la réponse * [4] On envoie la réponse * [5] On démarre un thread de gestion * [N] On ferme la SOCKET d'écoute globale * */ void* LISTEN_UDP(void* THREADABLE_ARGS){ /* [0] Initialisation des variables ==========================================================*/ /* 1. On initialise les variables */ int CLIENT_SOCKET; // contiendra la socket UDP à envoyer sur un THREAD struct sockaddr_in listenInfo; // contiendra les infos de la socket LISTEN int i, index; // compteurs char entity[10]; // identifiant pour debug int returned; // Contrôle d'exécution middleware struct middleware_arg marg; // paramètres pour middleware struct in_addr ip; // Permet d'afficher les IP en dot notation int rtnPort; // Returned port (if already used) /* 2. On parse les arguments */ struct listen_arg* arg = THREADABLE_ARGS; // Addr + Port serveur if( arg->port == UDP_VTER ) strcpy(entity, "udp_vterm"); if( arg->port == UDP_CTER ) strcpy(entity, "udp_cterm"); if( arg->port == UDP_MCST ) strcpy(entity, "udp_mcast"); // retour de @DROP_UDP_SERVER int SOCKET; ip.s_addr = arg->addr; /* [1] On démarre le SERVEUR UDP d'écoute globale ==========================================================*/ /* 1. On crée la socket */ rtnPort = DROP_UDP_SERVER(arg->addr, arg->port, &SOCKET, &listenInfo, 1); if( rtnPort < 0 ){ if( DEBUGMOD&SCK ) printf("{%s} Error creating listener socket\n", entity); // On ferme la SOCKET d'écoute globale printf("{%s} Closing listener socket!\n", entity); close(SOCKET); return NULL; } /* 2. On définit un timeout d'envoi */ setTimeout(SOCKET, SOCK_TIMEOUT, TIMEOUT_SEND); if( DEBUGMOD&SCK ) printf("{%s} SEND timeout set to %d\n", entity, SOCK_TIMEOUT); printf("{%s} listen on %s:%d\n", entity, inet_ntoa(ip), rtnPort); if( rtnPort != arg->port ) printf("{%s} /!\\ Another SGCA might be running, port %d is already used\n", entity, arg->port); /* [2] Attente de connection ============================================================================*/ while( 1 ){ /* On initialise les SOCKET en attendant la connexion d'un client */ CLIENT_SOCKET = -1; index = -1; /* [2] Appel middleware si existe =========================================================*/ if( arg->middleware != NULL ){ /* 1. Construction des arguments */ marg.listenSock = SOCKET; marg.comSock = &CLIENT_SOCKET; strcpy(marg.entity, entity); /* 2. Exécution middleware */ returned = -1; returned = (*arg->middleware)( &marg ); /* 3. Gestion erreur FATALE */ if( returned == -2 ) break; /* 4. Gestion erreur non FATALE */ if( returned == -1 ) continue; } /* [5] On démarre la tache sur un thread dédié -> si handler =========================================================*/ if( arg->handler == NULL ) continue; /* 1. On cherche un "manager" libre (inactif) */ for( i = 0 ; i < MAX_UDP_THR ; i++ ) if( activeUDPManagers[i] == 0 ){ index = i; break; } /* 2. si on a trouvé un "manager" libre */ if( index != -1 ){ // Construction arguments thread struct handler_arg thread_args = { TCPManagers, UDPManagers, activeTCPManagers, activeUDPManagers, CLIENT_SOCKET, &sgca }; /* 2.1. On lance un thread pour le traitement de ce client */ pthread_create(&UDPManagers[index], NULL, arg->handler, (void*) &thread_args); if( DEBUGMOD&THR ) printf("{%s}{com}(%d) started\n", entity, index); /* 2.2. On signale que ce "manager" est maintenant actif */ activeUDPManagers[index] = 1; }else if( DEBUGMOD&THR ) printf("{%s} No available thread\n", entity); } /* [n] On ferme la SOCKET d'écoute globale ==========================================================*/ printf("{%s} Closing listener socket\n", entity); close(SOCKET); return NULL; } /* Publication de la socket TCP sur un groupe multicast * * @history * [0] Initialisation des variables * [1] On initialise la socket CLIENT UDP * [2] On construit la requête à envoyer * @loop * [3] On attends un délai fixé (2s par défaut) * [4] On envoie les information de la socket TCP * [N] On ferme la SOCKET * */ void* MCAST_PUBLISH(void* THREADABLE_ARGS){ /* [0] Initialisation des variables ==========================================================*/ /* 1. On initialise les variables */ struct sockaddr_in targetInfo; // contiendra les infos de la cible de la socket client char buffer[MAX_BUF_LEN]; // buffer de requêtes (envois) struct bind_header request; // requête brute struct in_addr ip; // Permet d'afficher les IP en dot notation /* 2. On parse les arguments */ struct listen_arg* arg = THREADABLE_ARGS; // Addr + Port serveur // retour de @UDP_SOCKET int SOCKET; ip.s_addr = arg->addr; /* [1] On initialise la socket CLIENT UDP ==========================================================*/ if( UDP_SOCKET(&SOCKET, arg->addr, arg->port, &targetInfo) < 0 ){ if( DEBUGMOD&SCK ) printf("{udp_mcast} Erreur de création socket UDP client\n"); // On ferme la SOCKET d'écoute globale printf("{udp_mcast} FERMETURE SOCKET CLIENT UDP!\n"); close(SOCKET); return NULL; } printf("{udp_mcast} bound to %s:%d\n", inet_ntoa(ip), arg->port); /* [2] On construit la requête à envoyer =========================================================*/ /* 1. Initialisation du buffer */ bzero(buffer, MAX_BUF_LEN*sizeof(char)); /* 2. On récupère l'IP locale */ struct in_addr* servip = GET_LOCAL_IP(); if( servip == NULL ){ printf("{udp_mcast} /!\\ Cannot fetch local ip address. Aborting!\n");// On ferme la SOCKET d'écoute globale printf("{udp_mcast} Closing publisher socket!\n"); close(SOCKET); return NULL; } /* 3. Remplissage de la requête brute */ request.flags = BINDHEAD_TCP; request.addr = htonl(servip->s_addr); request.port = htons(TCP_LIST); /* 4. Copie dans le buffer */ memcpy(buffer, &request.flags, sizeof(char) ); memcpy(buffer+sizeof(char), &request.addr, sizeof(in_addr_t) ); memcpy(buffer+sizeof(char)+sizeof(in_addr_t), &request.port, sizeof(unsigned short) ); while( 1 ){ /* [3] On attends un délai fixé (2s par défaut) =========================================================*/ sleep(PUBL_TIMEOUT); /* [4] On envoie les information de la socket TCP =========================================================*/ if( sendto(SOCKET, buffer, BINDHDR_LEN / sizeof(char) + 1, 0, (struct sockaddr*) &targetInfo, sizeof(struct sockaddr_in)) < 0 ){ printf("{udp_mcast} Cannot publish credentials\n"); break; } } /* [n] On ferme la SOCKET CLIENT UDP ==========================================================*/ printf("{udp_mcast} Closing publisher socket\n"); close(SOCKET); return NULL; }