#include #include #include #include #include #include #include #ifdef LINUX #include #include #else #include #include #endif #include #include #define ND_MODE 1 #include #define MSG_MODE 1 #include #include extern int sigignore(int sig); VER_INFO_EXPORT (logsupervisor, "$Revision: 1.1 $", "$Name: $", __FILE__, "$Author: smas $") /*--------------------------------------------------------------------------------------------------*/ #define Date_IsSet(tvp) ((tvp).tv_sec || (tvp).tv_usec) #define Date_Compare(tvp, uvp) ((tvp).tv_sec < (uvp).tv_sec || ((tvp).tv_sec == (uvp).tv_sec && (tvp).tv_usec < (uvp).tv_usec)) /* Tableau permettant de référéncer les agents suivis par le superviseur */ typedef struct { pid_t Pid; /* Identifiant du processus */ short int Restarted; /* Indique si l'agent est déjà tombé puis a été redémarré */ short int GivenUp; /* Indique si l'agent a été abandonné (car tombé plusieur fois) */ } Agent_Ref; Agent_Ref * Tab_Agent; /* Requêtes à traiter par le superviseur (classées par type de message système) */ typedef struct { struct timeval Request_Date; /* Date de début de la requête */ unsigned int Nb_Reply; /* Nombre de réponses recues de la part des agents */ Agent_Stat Reply_Stat [NB_MAX_AGENT]; /* Statistiques des agents ayant répondu */ NDT_Root * Msg_List; /* Liste chaînée des messages en attente sur cette requête */ } Waiting_Request; Waiting_Request Tab_Request [MSGD_NB_SYSTEM_MESSAGE]; char Debug_Trace [256]; unsigned int Timeout; /*--------------------------------------------------------------------------------------------------*/ #define AGENT_PATH "logagent" #define SUPERVISOR_START 1 #define SUPERVISOR_PING 2 #define SUPERVISOR_STATUS_GET 3 #define SUPERVISOR_INFO_GET 4 #define SUPERVISOR_STOP_AGENT 5 #define SUPERVISOR_CONTINUE_AGENT 6 #define SUPERVISOR_TRACEON 7 #define SUPERVISOR_TRACEOFF 8 #define SUPERVISOR_SHUTDOWN 9 void Parse_Arg ( int, char ** ); void Supervisor_Start ( void ); void Supervisor_Request (unsigned int, size_t, int); void Supervisor_Ping ( void ); void Supervisor_Status_Get ( void ); void Supervisor_Info_Get ( void ); void Supervisor_Agent_Stop ( void ); void Supervisor_Agent_Continue ( void ); void Supervisor_Shutdown ( void ); void System_Msg_Process ( MSGT_Message * ); int Agent_Msg_Send ( unsigned int, unsigned int, int ); int Agent_Start ( unsigned int ); void Agent_Restart ( int signum ); char * Agent_Status_Get ( unsigned int Agent_Status, unsigned int Agent_Debug ); void Request_Answer ( unsigned int Idx ); void Timeout_Handle ( int signum ); void Info_Trace ( void ); char * Status_Get ( void ); NDT_Status Request_List_Manager ( va_list ); unsigned int Nb_Agent, Nb_GivenUp, End_Supervisor, Status, Debug, Action; MSGT_Port * Supervisor_Port, * System_Port; /*--------------------------------------------------------------------------------------------------*/ int main ( int argc , char ** argv ) { /* Récupération des arguments de la ligne de commande */ Parse_Arg (argc, argv); /* Lancement de l'action sur le superviseur */ switch (Action) { case SUPERVISOR_START: Supervisor_Start (); break; case SUPERVISOR_PING: Supervisor_Request (MSGD_SYSTEM_PING_REQUEST, sizeof (MSGT_PingData), MSGD_SYSTEM_HIGH_PRIORITY); break; case SUPERVISOR_STATUS_GET: Supervisor_Request (MSGD_SYSTEM_STATUS_REQUEST, ANSWER_SIZE, MSGD_SYSTEM_HIGH_PRIORITY); break; case SUPERVISOR_INFO_GET: Supervisor_Request (MSGD_SYSTEM_INFO_REQUEST, ANSWER_SIZE, MSGD_SYSTEM_HIGH_PRIORITY); break; case SUPERVISOR_STOP_AGENT: Supervisor_Request (MSGD_SYSTEM_STOP_REQUEST, ANSWER_SIZE, MSGD_SYSTEM_HIGH_PRIORITY); break; case SUPERVISOR_CONTINUE_AGENT: Supervisor_Request (MSGD_SYSTEM_CONTINUE_REQUEST, ANSWER_SIZE, MSGD_SYSTEM_HIGH_PRIORITY); break; case SUPERVISOR_TRACEON: Supervisor_Request (MSGD_SYSTEM_TRACEON_REQUEST, ANSWER_SIZE, MSGD_SYSTEM_HIGH_PRIORITY); break; case SUPERVISOR_TRACEOFF: Supervisor_Request (MSGD_SYSTEM_TRACEOFF_REQUEST, ANSWER_SIZE, MSGD_SYSTEM_HIGH_PRIORITY); break; case SUPERVISOR_SHUTDOWN: Supervisor_Request (MSGD_SYSTEM_SHUTDOWN_REQUEST, ANSWER_SIZE, MSGD_SYSTEM_HIGH_PRIORITY); break; default: break; } return OK; } /*--------------------------------------------------------------------------------------------------*/ /* Récupération de la ligne de commande */ /*--------------------------------------------------------------------------------------------------*/ void Parse_Arg (int argc, char ** argv) { int i; Debug = FALSE; Nb_Agent = 0; Timeout = 0; for (i = 1; i < argc; i++) { if (!strcmp (argv[i], "--help") || !strcmp (argv[i], "-h")) { char Usage [1000]; sprintf (Usage, "Usage : %s \nOptions :\n\t%-50s\t%s\n\t%-50s\t%s\n\t%-50s\t%s\n\t%-50s\t%s\n\t%-50s\t%s\n\t%-50s\t%s\n\t%-50s\t%s\n\t%-50s\t%s\n\t%-50s\t%s\n\t%-50s\t%s\n\t%-50s\t%s\n", argv [0], "--help | -h", "-> Affiche l'aide courante", "--version [-v]", "-> Affiche le numéro de version", "--start [--debug] [--timeout ]", "-> Démarre le superviseur et agents", "--ping", "-> Ping le superviseur", "--status", "-> Affiche le status de tous les agents et du superviseur", "--info", "-> Affiche des informations statistiques de tous les agents", "--stop", "-> Stoppe tous les agents", "--continue", "-> Continue tous les agents stoppés", "--traceon", "-> Active le mode trace du superviseur et des agents", "--traceoff", "-> Désactive le mode trace du superviseur et des agents", "--shutdown", "-> Tue tous les agents et le superviseur"); fprintf (stderr, Usage); exit (1); } if (!strcmp (argv[i], "--version")) { if (i+1 < argc && !strcmp (argv[i+1], "-v")) { VER_Object_Print (stdout, VERD_VERBOSE); exit (0); } else { VER_Object_Print (stdout, VERD_MINIMAL); exit (0); } } if (!strcmp (argv[i], "--start")) { Action = SUPERVISOR_START; i++; if (i == argc) { fprintf (stderr, "Missing argument after %s\n", argv[i - 1]); exit (0); } if ((Nb_Agent = atoi (argv[i])) <= 0) { fprintf (stderr, "Bad value (%s) after %s\n", argv[i], argv[i - 1]); exit (0); } continue; } if (!strcmp (argv[i], "--ping")) { Action = SUPERVISOR_PING; continue; } if (!strcmp (argv[i], "--status")) { Action = SUPERVISOR_STATUS_GET; continue; } if (!strcmp (argv[i], "--info")) { Action = SUPERVISOR_INFO_GET; continue; } if (!strcmp (argv[i], "--stop")) { Action = SUPERVISOR_STOP_AGENT; continue; } if (!strcmp (argv[i], "--continue")) { Action = SUPERVISOR_CONTINUE_AGENT; continue; } if (!strcmp (argv[i], "--traceon")) { Action = SUPERVISOR_TRACEON; continue; } if (!strcmp (argv[i], "--traceoff")) { Action = SUPERVISOR_TRACEOFF; continue; } if (!strcmp (argv[i], "--shutdown")) { Action = SUPERVISOR_SHUTDOWN; continue; } if (!strcmp (argv[i], "--debug")) { Debug = TRUE; continue; } if (!strcmp (argv[i], "--timeout")) { i++; if (i == argc) { fprintf (stderr, "Missing argument after %s\n", argv[i - 1]); exit (0); } if ((Timeout = atoi (argv[i])) <= 0) { fprintf (stderr, "Bad value (%s) after %s\n", argv[i], argv[i - 1]); exit (0); } continue; } fprintf (stderr, "Option invalide \"%s\"\n", argv[i]); exit (0); } if (Timeout == 0) Timeout = DEFAULT_TIMEOUT; } /*--------------------------------------------------------------------------------------------------*/ /*--------------------------------------- SUPERVISEUR ----------------------------------------------*/ /*--------------------------------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------------------------------*/ /* Envoie une requête au superviseur */ /*--------------------------------------------------------------------------------------------------*/ void Supervisor_Request (unsigned int Type, size_t Size, int Priority) { MSGT_Message * Msg; Debug = TRUE; /* Ouverture de la librairie LIBLOG */ if (MSG_Library_Open (0, NULL, MSGD_OPEN | MSGD_DEBUG_ALL) != MSGS_OK) { fprintf (stderr, "=> Impossible d'ouvrir la librairie LIBMSG\n"); return; } /* Ouverture du port de messages du superviseur */ if (MSG_Port_Open (MSGD_SUPERVISOR_PORT_NAME, &Supervisor_Port, MSGD_OPEN) != MSGS_OK) { fprintf (stderr, "=> Impossible d'ouvrir le port de messages du superviseur\n"); MSG_Library_Close (MSGD_CLOSE); return; } /* Création / ouverture du port système dont on se sert pour les accusés réception */ if (MSG_Port_Open (MSGD_SYSTEM_PORT_NAME, &System_Port, MSGD_OPEN | MSGD_CREATE) != MSGS_OK) { fprintf (stderr, "=> Impossible d'ouvrir ou de créer le port de messages système\n"); MSG_Port_Close (Supervisor_Port, MSGD_CLOSE); MSG_Library_Close (MSGD_CLOSE); return; } /* Création du message */ if (MSG_Message_Alloc (&Msg, Size) != MSGS_OK) { fprintf (stderr, "=> Impossible de créer un message\n"); MSG_Port_Close (Supervisor_Port, MSGD_CLOSE); MSG_Port_Close (System_Port, MSGD_CLOSE); MSG_Library_Close (MSGD_CLOSE); return; } memset (Msg->Data, 0, Msg->Size); if (MSG_Message_Config (Msg, MSGD_CONFIG_TYPE, Type) != MSGS_OK) { fprintf (stderr, "=> Impossible de configurer le type du message\n"); MSG_Message_Free (Msg); MSG_Port_Close (System_Port, MSGD_CLOSE); MSG_Port_Close (Supervisor_Port, MSGD_CLOSE); MSG_Library_Close (MSGD_CLOSE); return; } if (MSG_Message_Config (Msg, MSGD_CONFIG_PRIORITY, Priority) != MSGS_OK) { fprintf (stderr, "=> Impossible de configurer la priorité du message\n"); MSG_Message_Free (Msg); MSG_Port_Close (System_Port, MSGD_CLOSE); MSG_Port_Close (Supervisor_Port, MSGD_CLOSE); MSG_Library_Close (MSGD_CLOSE); return; } /* Envoi du message avec demande d'accusé réception dans le port système */ if (MSG_Message_Send (MSGD_SYSTEM_PORT_NAME, Supervisor_Port, Msg) != MSGS_OK) { fprintf (stderr, "=> Impossible d'envoyer le message\n"); MSG_Port_Close (System_Port, MSGD_CLOSE); MSG_Port_Close (Supervisor_Port, MSGD_CLOSE); MSG_Library_Close (MSGD_CLOSE); return; } /* Fermeture du port de messages du superviseur */ if (MSG_Port_Close (Supervisor_Port, MSGD_CLOSE) != MSGS_OK) { fprintf (stderr, "=> Impossible de fermer le port de messages du superviseur\n"); MSG_Port_Close (Supervisor_Port, MSGD_CLOSE); MSG_Library_Close (MSGD_CLOSE); return; } /* Ecoute du port de messages système */ if (MSG_Message_Receive (System_Port, MSGD_NO_TYPE, &Msg, MSGD_WAIT) != MSGS_OK) { fprintf (stderr, "=> Impossible de réceptionner un message dans le port système\n"); MSG_Message_Free (Msg); MSG_Library_Close (MSGD_CLOSE); return; } if (Msg->Type == MSGD_SYSTEM_PING_REPLY) { double send_delay, rcv_delay, ping_delay; struct timeval t1, t2, t3, t4; t1 = ((MSGT_PingData *)(Msg->Data))->Snd1; t2 = ((MSGT_PingData *)(Msg->Data))->Rcv1; t3 = ((MSGT_PingData *)(Msg->Data))->Snd2; t4 = ((MSGT_PingData *)(Msg->Data))->Rcv2; send_delay = (double)(t2.tv_sec) - (double)(t1.tv_sec) + ((double)(t2.tv_usec) - (double)(t1.tv_usec)) / 1000000; rcv_delay = (double)(t4.tv_sec) - (double)(t3.tv_sec) + ((double)(t4.tv_usec) - (double)(t3.tv_usec)) / 1000000; ping_delay = (double)(t4.tv_sec) - (double)(t1.tv_sec) + ((double)(t4.tv_usec) - (double)(t1.tv_usec)) / 1000000; fprintf (stdout, "Ping = %.4f sec (Aller = %.4f sec / Retour = %.4f sec)\n", ping_delay, send_delay, rcv_delay); } else { /* Autres messages système */ fprintf (stdout, (char *)(Msg->Data)); } /* Désallocation du message */ if (MSG_Message_Free (Msg) != MSGS_OK) { fprintf (stderr, "=> Impossible de supprimer le message\n"); MSG_Port_Close (System_Port, MSGD_CLOSE); MSG_Library_Close (MSGD_CLOSE); return; } /* Fermeture du port de messages système */ if (MSG_Port_Close (System_Port, MSGD_CLOSE) != MSGS_OK) { fprintf (stderr, "=> Impossible de fermer le port de messages système\n"); MSG_Library_Close (MSGD_CLOSE); return ; } MSG_Library_Close (MSGD_CLOSE); } /*--------------------------------------------------------------------------------------------------*/ /* Procédure de démarrage du superviseur */ /*--------------------------------------------------------------------------------------------------*/ void Supervisor_Start ( void ) { MSGT_Message * Msg; unsigned int i; Nb_GivenUp = 0; End_Supervisor = FALSE; Status = ACTIVE; /* Allocation d'un tableau pour référencer les agents */ Tab_Agent = (Agent_Ref *)malloc (Nb_Agent * sizeof (Agent_Ref)); if (!Tab_Agent) { strcpy (Debug_Trace, "impossible d'allouer de la mémoire pour référencer les agents"); Info_Trace (); return; } /* Initialisation du tableau des requêtes soumises au superviseur */ for (i = 0; i < MSGD_NB_SYSTEM_MESSAGE; i++) { memset (&(Tab_Request [i]), 0, sizeof (Waiting_Request)); ND_DataStruct_Open (&(Tab_Request [i].Msg_List), NDD_DS_LIST | NDD_MN_FIFO, NULL, NULL, NULL, TRUE); strcpy (Tab_Request [i].Msg_List->Manager, "Request_List_Manager"); } /* Ouverture de la librairie LIBMSG */ if (MSG_Library_Open (0, NULL, MSGD_OPEN) != MSGS_OK) { strcpy (Debug_Trace, "impossible d'ouvrir la librairie LIBMSG"); Info_Trace (); return; } /* Ouverture / création du port de messages du superviseur */ if (MSG_Port_Open (MSGD_SUPERVISOR_PORT_NAME, &Supervisor_Port, MSGD_OPEN | MSGD_CREATE) != MSGS_OK) { strcpy (Debug_Trace, "impossible d'ouvrir mon port de messages privé"); Info_Trace (); MSG_Library_Close (MSGD_CLOSE); return; } /* On trappe le signal SIGCHLD pour détecter les agents qui tombent */ signal (SIGCHLD, Agent_Restart); /* Lancement des agents */ for (i = 1; i <= Nb_Agent; i++) Agent_Start (i); /* Boucle principale du superviseur */ while (End_Supervisor == FALSE) { /* Ecoute du port de messages du superviseur */ int rc = MSG_Message_Receive (Supervisor_Port, MSGD_NO_TYPE, &Msg, MSGD_WAIT); switch (rc) { case MSGS_OK: /* Traitement des messages envoyés au superviseur */ System_Msg_Process (Msg); break; case MSGS_ERRSIG: /* On continue à boucler sur l'écoute */ break; default: strcpy (Debug_Trace, "impossible de réceptionner un message dans mon port du messages privé"); Info_Trace (); MSG_Message_Free (Msg); MSG_Port_Close (Supervisor_Port, MSGD_CLOSE); MSG_Library_Close (MSGD_CLOSE); return; } } /* Fermeture du port de messages du superviseur */ if (MSG_Port_Close (Supervisor_Port, MSGD_CLOSE) != MSGS_OK) { strcpy (Debug_Trace, "impossible de fermer mon port de messages privé"); Info_Trace (); MSG_Library_Close (MSGD_CLOSE); return; } /* Fermeture de la librairie LIBMSG */ MSG_Library_Close (MSGD_CLOSE); /* Désallocation des ressources locales */ for (i = 0; i < MSGD_NB_SYSTEM_MESSAGE; i++) { if (Tab_Request [i].Msg_List) ND_DataStruct_Close (Tab_Request [i].Msg_List); } strcpy (Debug_Trace, "terminé"); Info_Trace (); } /*--------------------------------------------------------------------------------------------------*/ /* Traitement d'un message système par le superviseur */ /*--------------------------------------------------------------------------------------------------*/ void System_Msg_Process (MSGT_Message * Msg) { unsigned int Idx; unsigned int i; /* S'agit-il d'un message de type REQUEST ou REPLY ? */ if (MSGD_IS_SYSTEM_REQUEST (Msg->Type)) { Idx = (Msg->Type - 1) / 2; /* Le message est-il de taille suffisante pour que l'on y réponde ? */ if (Msg->Size < ANSWER_SIZE) { /* On le supprime : tant pis pour l'envoyeur ! */ MSG_Message_Free (Msg); sprintf (Debug_Trace, "la requête envoyée par \"%s\" ne sera pas prise en compte car le message est de taille insuffisante (%d octets minimum)", Msg->From, ANSWER_SIZE); Info_Trace (); return; } /* Mise du message en attente : on y répondra lorque tous les agents y auront répondu ou bien lorsque le timeout aura expiré. */ ND_Value_Add (Tab_Request [Idx].Msg_List, Msg); /* On regarde si une requête du même type était déjà en cours */ if (Tab_Request [Idx].Msg_List->Node_Number == 1) { /* S'il s'agit d'une requête SHUTDOWN_REQUEST, il faut désormais ignorer les signaux de type SIGCHLD */ if (Msg->Type == MSGD_SYSTEM_SHUTDOWN_REQUEST) sigignore (SIGCHLD); /* On prend en compte les requêtes TRACEON_REQUEST et TRACEOFF_REQUEST */ if (Msg->Type == MSGD_SYSTEM_TRACEON_REQUEST) { Debug = TRUE; sprintf (Debug_Trace, "activation du mode trace"); Info_Trace (); } if (Msg->Type == MSGD_SYSTEM_TRACEOFF_REQUEST) { sprintf (Debug_Trace, "désactivation du mode trace"); Info_Trace (); Debug = FALSE; } /* On mémorise la date de la requête */ gettimeofday (&(Tab_Request [Idx].Request_Date), NULL); if (Nb_Agent - Nb_GivenUp == 0) { /* S'il n'y a plus d'agent valide, on répond tout de suite à la requête */ Request_Answer (Idx); } else { /* Sinon, on initie une alarme ... */ signal (SIGALRM, Timeout_Handle); alarm (Timeout); /* ... et on transmet la requête à tous les agents qui devront y répondre avant le timeout */ for (i = 1; i <= Nb_Agent; i++) { if (Tab_Agent [i -1].GivenUp == FALSE) { if (Agent_Msg_Send (i, Msg->Type, MSGD_SYSTEM_HIGH_PRIORITY) != OK) { sprintf (Debug_Trace, "impossible de transmettre la requête à l'agent n°%d", i); Info_Trace (); } } } } } } else if (MSGD_IS_SYSTEM_REPLY (Msg->Type)) /* Il s'agit d'une réponse d'un agent */ { Idx = (Msg->Type / 2) - 1; /* Une requête de ce type a-t'elle déjà été lancée ? */ if (Tab_Request [Idx].Msg_List->Node_Number > 0) { int Num_Agent; Agent_Stat * Stat; Tab_Request [Idx].Nb_Reply++; /* Mise à jour de statistiques : on recopie celles renvoyés par l'agent dans notre tableau */ Stat = (Agent_Stat *)(Msg->Data); Num_Agent = Stat->Num_Agent; Tab_Request [Idx].Reply_Stat [Num_Agent - 1].Num_Agent = Stat->Num_Agent; Tab_Request [Idx].Reply_Stat [Num_Agent - 1].Pid = Stat->Pid; Tab_Request [Idx].Reply_Stat [Num_Agent - 1].Cpt_Event = Stat->Cpt_Event; Tab_Request [Idx].Reply_Stat [Num_Agent - 1].Cpt_System = Stat->Cpt_System; Tab_Request [Idx].Reply_Stat [Num_Agent - 1].Status = Stat->Status; Tab_Request [Idx].Reply_Stat [Num_Agent - 1].Debug = Stat->Debug; Tab_Request [Idx].Reply_Stat [Num_Agent - 1].Answer = Stat->Answer; /* Tous les agents ont-ils répondu à la requête ? */ if (Tab_Request [Idx].Nb_Reply == Nb_Agent - Nb_GivenUp) { /* On répond à la requête */ Request_Answer (Idx); } else { /* Tous les agents n'ont pas encore répondu : on attend encore */ } } else { /* L'agent a répondu trop tard : tant pis pour lui, on ne tient pas compte de cette réponse */ } /* On supprime le message */ MSG_Message_Free (Msg); } } /*--------------------------------------------------------------------------------------------------*/ /* Réponse à une requête (procédure exécutée au timeout ou bien lorsque tous les agents ont répondu)*/ /*--------------------------------------------------------------------------------------------------*/ void Request_Answer ( unsigned int Idx ) { char Answer [ANSWER_SIZE]; unsigned int i, j; unsigned int Type = 2 * Idx + 1; NDT_Node * Node, * Next_Node; NDT_Root * Msg_List; char str [256]; Answer [0] = (char)0; /* Réponse concernant le superviseur lui-même */ switch (Type) { case MSGD_SYSTEM_TRACEON_REQUEST: sprintf (str, "Superviseur : mode trace activé\n"); strcat (Answer, str); break; case MSGD_SYSTEM_TRACEOFF_REQUEST: sprintf (str, "Superviseur : mode trace désactivé\n"); strcat (Answer, str); break; case MSGD_SYSTEM_STATUS_REQUEST: sprintf (str, "Superviseur : %s\n", Status_Get ()); strcat (Answer, str); break; case MSGD_SYSTEM_INFO_REQUEST: /* Informations concernant les agents suivis */ sprintf (str, "Superviseur :\n\t- %d agent(s) suivi(s)\n\t- %d agent(s) abandonné(s)\n", Nb_Agent - Nb_GivenUp, Nb_GivenUp); strcat (Answer, str); /* On compte le nombre de requêtes en attente */ j = 0; for (i = 0; i < MSGD_NB_SYSTEM_MESSAGE; i++) if (i != Idx && Tab_Request [i].Msg_List->Node_Number > 0) j++; sprintf (str, "\t- %d requête(s) en attente de réponse de la part des agents\n", j); strcat (Answer, str); /* On consolide les statistiques des agents concernant le nombre d'événements traités */ j = 0; for (i = 0; i < MSGD_NB_SYSTEM_MESSAGE; i++) j += Tab_Request [Idx].Reply_Stat [i].Cpt_Event; sprintf (str, "\t- %d événement(s) traité(s) par l'ensemble des agents ayant répondu\n\n", j); strcat (Answer, str); break; case MSGD_SYSTEM_SHUTDOWN_REQUEST: End_Supervisor = TRUE; strcpy (Debug_Trace, "terminaison en cours..."); Info_Trace (); break; default: break; } /* Réponse concernant les agents auxquels la requête a été transmise */ sprintf (str, "%d/%d agent(s) ont répondu à la requête%s\n", Tab_Request [Idx].Nb_Reply, Nb_Agent - Nb_GivenUp, Tab_Request [Idx].Nb_Reply > 0 ? " :" : "."); strcat (Answer, str); for (i = 0; i < Nb_Agent; i++) { if (Tab_Agent [i].GivenUp == TRUE) continue; sprintf (str, "\t- Agent n°%d (process %ld) : ", i + 1, Tab_Agent [i].Pid); strcat (Answer, str); if (Tab_Request [Idx].Reply_Stat [i].Num_Agent == 0) strcat (Answer, "pas de réponse\n"); else { switch (Type) { case MSGD_SYSTEM_STOP_REQUEST: sprintf (str, "%s\n", Tab_Request [Idx].Reply_Stat [i].Answer == TRUE ? "stoppé" : "déjà stoppé"); strcat (Answer, str); break; case MSGD_SYSTEM_CONTINUE_REQUEST: sprintf (str, "%s\n", Tab_Request [Idx].Reply_Stat [i].Answer == TRUE ? "repris" : "déjà actif"); strcat (Answer, str); break; case MSGD_SYSTEM_SHUTDOWN_REQUEST: strcat (Answer, "arrêté\n"); break; case MSGD_SYSTEM_STATUS_REQUEST: sprintf (str, "%s\n", Agent_Status_Get (Tab_Request [Idx].Reply_Stat [i].Status, Tab_Request [Idx].Reply_Stat [i].Debug)); strcat (Answer, str); break; case MSGD_SYSTEM_INFO_REQUEST: sprintf (str, "%d événement(s) traité(s) / %d message(s) système(s) reçu(s)\n", Tab_Request [Idx].Reply_Stat [i].Cpt_Event, Tab_Request [Idx].Reply_Stat [i].Cpt_System); strcat (Answer, str); break; case MSGD_SYSTEM_TRACEON_REQUEST: strcat (Answer, "mode trace activé\n"); break; case MSGD_SYSTEM_TRACEOFF_REQUEST: strcat (Answer, "mode trace désactivé\n"); break; default: break; } } } if (Type == MSGD_SYSTEM_SHUTDOWN_REQUEST) strcat (Answer, "Superviseur terminé.\n"); /* On répond à tous les messages en attente sur cette requête */ Msg_List = Tab_Request [Idx].Msg_List; ND_Node_First_Get (Msg_List, &Node); while (Node) { MSGT_Message * Msg = (MSGT_Message *)(Node->Value); char * Msg_Data = Msg->Data; ND_Node_Next_Get (Node, &Next_Node); ND_Node_Remove (Node); /* On remplit le champ de données du message */ if (strlen (Answer) >= Msg->Size) { sprintf (Debug_Trace, "attention, le message (%d octets) n'est pas assez long pour contenir toute la réponse (%d caractères)\n", Msg->Size, strlen (Answer)); Info_Trace (); strncpy (Msg_Data, Answer, Msg->Size - 1); Msg_Data [Msg->Size - 1] = (char)0; } else strcpy (Msg_Data, Answer); /* On renvoie le message à son envoyeur */ MSG_Message_Reply (Msg); /* Message suivant */ Node = Next_Node; } /* On réinitialise les données concernant la requête */ memset (&(Tab_Request [Idx]), 0, sizeof (Waiting_Request)); Tab_Request [Idx].Msg_List = Msg_List; } /*--------------------------------------------------------------------------------------------------*/ /* Procédure appelée lorsqu'un timeout expire */ /*--------------------------------------------------------------------------------------------------*/ void Timeout_Handle ( int signum ) { unsigned int i, Older; int Found = FALSE; /* On recherche la requête la plus ancienne */ for (i = 0; i < MSGD_NB_SYSTEM_MESSAGE; i++) { if (Date_IsSet (Tab_Request [i].Request_Date) && (Found == FALSE || Date_Compare (Tab_Request [i].Request_Date, Tab_Request [Older].Request_Date))) { Found = TRUE; Older = i; } } /* On répond à la requête */ if (Found == TRUE) { strcpy (Debug_Trace, "timeout expiré => réponse à la requête la plus ancienne"); Info_Trace (); Request_Answer (Older); } } /*--------------------------------------------------------------------------------------------------*/ /* Redémarrage automatique d'un agent tombé */ /*--------------------------------------------------------------------------------------------------*/ void Agent_Restart ( int signum ) { unsigned int Found, i; pid_t Child_Pid; #ifdef LINUX int Child_Info; #else siginfo_t Child_Info; #endif unsigned int Restart; /* On réinitialise le trap du signal SIGCHLD */ signal (SIGCHLD, Agent_Restart); /* On récupère les informations concernant le processus fils qui est tombé */ #ifdef LINUX Child_Pid = waitpid (-1, &Child_Info, WNOHANG); if (Child_Pid == -1) { sprintf (Debug_Trace, "impossible de récupérer les informations concernant un processus fils tombé"); Info_Trace (); return; } #else if (waitid (P_ALL, 0, &Child_Info, WEXITED) == -1) { sprintf (Debug_Trace, "impossible de récupérer les informations concernant un processus fils tombé"); Info_Trace (); return; } Child_Pid = Child_Info.si_pid; #endif /* On recherche l'agent correspondant au process fils tombé */ Found = FALSE; i = 0; while (i < Nb_Agent && Found == FALSE) { if (Tab_Agent [i].GivenUp == FALSE) { if (Tab_Agent [i].Pid == Child_Pid) Found = TRUE; else i++; } else i++; } if (Found == FALSE) { sprintf (Debug_Trace, "impossible de trouver l'agent correspondant au processus fils %ld tombé", Child_Pid); Info_Trace (); return; } /* Analyse de la raison pour laquelle le fils est tombé */ #ifdef LINUX if (WIFEXITED(Child_Info)) #else if (Child_Info.si_code == CLD_EXITED) #endif { /* L'agent s'est terminé tout seul (comme un grand !!!) : on ne le relance pas */ Restart = FALSE; #ifdef LINUX sprintf (Debug_Trace, "détection agent n°%d terminé avec code retour %d", i + 1, WEXITSTATUS(Child_Info)); #else sprintf (Debug_Trace, "détection agent n°%d terminé avec code retour %d", i + 1, Child_Info.si_status); #endif Info_Trace (); } #ifdef LINUX else if (WIFSIGNALED(Child_Info) && WTERMSIG(Child_Info) == SIGKILL) #else else if (Child_Info.si_code == CLD_KILLED) #endif { /* L'agent a à priori été tué volontairement : on ne le relance donc pas */ Restart = FALSE; sprintf (Debug_Trace, "détection agent n°%d tué", i + 1); Info_Trace (); } #ifdef LINUX else if WIFSIGNALED(Child_Info) #else else if (Child_Info.si_code == CLD_DUMPED) #endif { /* L'agent s'est terminé anormallement : on essaie de relancer l'agent */ Restart = TRUE; #ifdef LINUX sprintf (Debug_Trace, "détection agent n°%d tombé suite à signal %d", i + 1, WTERMSIG(Child_Info)); #else sprintf (Debug_Trace, "détection agent n°%d tombé suite à signal %d", i + 1, Child_Info.si_status); #endif Info_Trace (); } else Restart = TRUE; if (Restart == TRUE) { /* Une tentative de relance a-t'elle déjà été lancée ? */ if (Tab_Agent [i].Restarted == TRUE) { sprintf (Debug_Trace, "abandon de l'agent n°%d", i + 1); Info_Trace (); Tab_Agent [i].GivenUp = TRUE; Nb_GivenUp ++; } else { /* On redémarre l'agent */ sprintf (Debug_Trace, "relance de l'agent n°%d", i + 1); Info_Trace (); Agent_Start (i + 1); Tab_Agent [i].Restarted = TRUE; } } else { sprintf (Debug_Trace, "abandon de l'agent n°%d", i + 1); Info_Trace (); Tab_Agent [i].GivenUp = TRUE; Nb_GivenUp ++; } } /*--------------------------------------------------------------------------------------------------*/ /* Envoi d'un message à un agent */ /*--------------------------------------------------------------------------------------------------*/ int Agent_Msg_Send ( unsigned int Num_Agent, unsigned int Type, int Priority ) { MSGT_Message * Msg; char Agent_Port_Name [256]; MSGT_Port * Agent_Port; /* Ouverture du port de messages privé d'un agent dont on connait le numéro */ sprintf (Agent_Port_Name, "Agent_%d_port", Num_Agent); if (MSG_Port_Open (Agent_Port_Name, &Agent_Port, MSGD_OPEN) != MSGS_OK) { sprintf (Debug_Trace, "impossible d'ouvrir le port de messages \"%s\"", Agent_Port_Name); Info_Trace (); return KO; } /* Création du message (de la taille d'un message système standard du superviseur aux agents) */ if (MSG_Message_Alloc (&Msg, sizeof (Agent_Stat)) != MSGS_OK) { sprintf (Debug_Trace, "impossible de créer un message destiné à l'agent n°%d", Num_Agent); Info_Trace (); MSG_Port_Close (Agent_Port, MSGD_CLOSE); return KO; } /* Initialisation des données du message */ memset (Msg->Data, 0, Msg->Size); /* Configuration du type de message */ if (MSG_Message_Config (Msg, MSGD_CONFIG_TYPE, Type) != MSGS_OK) { sprintf (Debug_Trace, "impossible de configurer le type du message destiné à l'agent n°%d", Num_Agent); Info_Trace (); MSG_Message_Free (Msg); MSG_Port_Close (Agent_Port, MSGD_CLOSE); return KO; } /* Configuration de la priorité du message */ if (MSG_Message_Config (Msg, MSGD_CONFIG_PRIORITY, Priority) != MSGS_OK) { sprintf (Debug_Trace, "impossible de configurer la priorité du message destiné à l'agent n°%d", Num_Agent); Info_Trace (); MSG_Message_Free (Msg); MSG_Port_Close (Agent_Port, MSGD_CLOSE); return KO; } /* Envoi du message avec demande d'accusé réception dans le port du superviseur */ if (MSG_Message_Send (MSGD_SUPERVISOR_PORT_NAME, Agent_Port, Msg) != MSGS_OK) { sprintf (Debug_Trace, "impossible d'envoyer le message destiné à l'agent n°%d", Num_Agent); Info_Trace (); MSG_Message_Free (Msg); MSG_Port_Close (Agent_Port, MSGD_CLOSE); return KO; } /* Fermeture du port de messages d'envoi */ if (MSG_Port_Close (Agent_Port, MSGD_CLOSE) != MSGS_OK) { sprintf (Debug_Trace, "impossible de fermer le port de messages de l'agent n°%d", Num_Agent); Info_Trace (); MSG_Message_Free (Msg); MSG_Port_Close (Agent_Port, MSGD_CLOSE); return KO; } return OK; } /*--------------------------------------------------------------------------------------------------*/ /* Démarrage d'un agent */ /*--------------------------------------------------------------------------------------------------*/ int Agent_Start ( unsigned int Num_Agent ) { pid_t Agent_Pid; if (Num_Agent > NB_MAX_AGENT) { strcpy (Debug_Trace, "Limite maximale du nombre d'agents atteinte"); Info_Trace (); return KO; } /* On crée un process fils */ #ifdef LINUX Agent_Pid = fork (); #else /* Sous Solaris, il faut utiliser la fonction fork1() pour supporter le multi-thread */ Agent_Pid = fork1 (); #endif if (Agent_Pid != 0) { /* Code pour le processus père (superviseur) : on référence le processus fils comme nouvel agent */ Tab_Agent [Num_Agent - 1].Pid = Agent_Pid; Tab_Agent [Num_Agent - 1].Restarted = FALSE; Tab_Agent [Num_Agent - 1].GivenUp = FALSE; sprintf (Debug_Trace, "lancement de l'agent n°%d", Num_Agent); Info_Trace (); } else { char sNum_Agent [10]; sprintf (sNum_Agent, "%d", Num_Agent); /* Code pour le processus fils (agent) */ if (Debug == TRUE) execlp (AGENT_PATH, AGENT_PATH, "-id", sNum_Agent, "--debug", NULL, NULL); else execlp (AGENT_PATH, AGENT_PATH, "-id", sNum_Agent, NULL, NULL); sprintf (Debug_Trace, "erreur lors du lancement de l'agent n°%d (execl: errno %d)", Num_Agent, errno); Info_Trace (); exit (KO); } return OK; } /*--------------------------------------------------------------------------------------------------*/ /* Affichage sur la sortie standard d'erreur d'un message généré par le superviseur */ /*--------------------------------------------------------------------------------------------------*/ void Info_Trace ( void ) { time_t dts; struct tm * dt; char Current_Date [25]; if (Debug) { /* Récupère la date courante */ time (&dts); dt = localtime (&dts); sprintf (Current_Date, "%02d/%02d/%04d %02d:%02d:%02d", dt->tm_mday, dt->tm_mon + 1, dt->tm_year + 1900, dt->tm_hour, dt->tm_min, dt->tm_sec); fprintf (stderr, "[%s] Superviseur : %s\n", Current_Date, Debug_Trace); } } /*--------------------------------------------------------------------------------------------------*/ /* Affiche le statut du superviseur */ /*--------------------------------------------------------------------------------------------------*/ char * Status_Get ( void ) { static char Status_Str [256]; sprintf (Status_Str, "Timeout = %d sec / Trace = %s", Timeout, Debug == TRUE ? "On" : "Off"); return Status_Str; } /*--------------------------------------------------------------------------------------------------*/ /* Affiche le statut d'un agent */ /*--------------------------------------------------------------------------------------------------*/ char * Agent_Status_Get ( unsigned int Agent_Status, unsigned int Agent_Debug ) { static char Status_Str [256]; sprintf (Status_Str, "Statut = %s / Trace = %s", Agent_Status == ACTIVE ? "actif" : "stoppé", Agent_Debug == TRUE ? "On" : "Off"); return Status_Str; } /*--------------------------------------------------------------------------------------------------*/ /* Manager d'une liste de messages en attente sur une requête */ /*--------------------------------------------------------------------------------------------------*/ NDT_Status Request_List_Manager (va_list Args) { return NDS_OK; }