liblog-bdm/util/logsupervisor.c
2000-07-31 13:15:35 +00:00

1247 lines
40 KiB
C

#include <sys/types.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/times.h>
#include <signal.h>
#ifdef LINUX
#include <bits/siginfo.h>
#include <sys/wait.h>
#else
#include <sys/siginfo.h>
#include <wait.h>
#endif
#include <errno.h>
#include <ver.h>
#define ND_MODE 1
#include <node.h>
#define MSG_MODE 1
#include <msg.h>
#include <logagent.h>
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 <options>\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 <nb_agent> [--debug] [--timeout <nb_sec>]", "-> Démarre le superviseur et <nb_agent> 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;
}