/*---------------------------------------------------------------------------
** INCLUDES SYSTEMES
**---------------------------------------------------------------------------
*/

#include <sys/wait.h>
#include <sys/time.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <math.h>



/*---------------------------------------------------------------------------
** INCLUDES APPLICATIFS
**---------------------------------------------------------------------------
*/

#include "Sondesplus-ajout.h"

/*---------------------------------------------------------------------------
**
** FONCTION : UsageProgramme
**
** DESCRIPTION :
**         Donne les arguments attendus
**
** PARAMETRES D'ENTREE :
**      char* prog : nom du binaire
**
** PARAMETRES DE SORTIE :
**  aucun
**
** VALEURS DE RETOUR :
**      0     : OK
**      Autre : ERREUR
**---------------------------------------------------------------------------
*/
static void UsageProgramme( void )
{

    fprintf( stdout,"\n");
    fprintf( stdout," \tusage: Sondes -a -i <Interval> -n <nbIteration> \n");
    //fprintf( stdout," \tusage: Sondes [-a] [-v <VM>] -i <Interval> -n <nbIteration> \n");

    fprintf( stdout,"\t\t -a => toutes les machines virtuelles \n");
    //fprintf( stdout,"\t\t ou \n");
    //fprintf( stdout,"\t\t -v => nom de la machine virtuelle \n");
    //fprintf( stdout,"\t\t et \n");
    fprintf( stdout,"\t\t -i => interval de temps en seconde entre deux mesures  \n" );
    fprintf( stdout,"\t\t -n => nombre d'iterations  \n" );
    fprintf( stdout,"\n");
    //fprintf( stdout,"\texemple: Sondes -v vmXen01 -i 2 -n 10  \n");
    fprintf( stdout,"\texemple: Sondes -a -i 2 -n 10  \n");
    fprintf( stdout,"\n");

    return;
}

/*---------------------------------------------------------------------------
**
** FONCTION : RecupererArguments
**
** DESCRIPTION :
**         recuperation de l'ensemble des arguments d'entree
**
** PARAMETRES D'ENTREE :
**
** PARAMETRES DE SORTIE :
**
** VALEURS DE RETOUR :
**      0     : OK
**      Autre : ERREUR
**---------------------------------------------------------------------------
*/
static int RecupererArguments(
    int                 argc,
    char                *argv[],
    virConnectPtr	conn,
    InfoMesure_t	*p_infoVM )
{
    int         id, Ivm;
    int         verif	= 0;
    int         option	= 0;


    /* Extrait le nom du fichier scenario des parametres*/
    if( ( argc < 6 ) || ( argc > MAX_ARGUMENTS ) )
    {
        UsageProgramme( );
        return( 1 );
    }

    /* distribution des arguments dans la structure des criteres */
    for( id = 1; id < argc; id++ )
    {
        if( !strcmp( argv[id], "-v" ) )
        {
	    if ( option == 1)
		break;
	    /* type d'information all */
	    p_infoVM->All = 0;
   	    memset( p_infoVM->MachVirt, 0x00, TAILLE_MAX_VM );
	    if( isalpha( argv[id+1][1] ) )
            {
                /* Nom de la VM */
                strcpy( p_infoVM->MachVirt, argv[id+1] );
                printf( "Nom de la VM a traiter <%s>\n", p_infoVM->MachVirt );
                p_infoVM->IdVM = 0;
                p_infoVM->typeInfo =0;
            }
            else
            {
                /* Id de la VM */
                p_infoVM->IdVM = atoi( argv[ id+1 ] );
                printf( "ID de la VM a traiter <%d>\n", p_infoVM->IdVM );
                p_infoVM->typeInfo =1;
            }

	    option=1;
            verif++;
        }

        if( !strcmp( argv[id], "-a" ) )
        {
	    if ( option == 1)
		break;
	    /* type d'information all */
	    p_infoVM->All = 1;
	    p_infoVM->InfoAll.tailleId = NBR_MAX_VM;
	    /* recuperation du nbre de VM total */
	    if ( ( p_infoVM->InfoAll.nbrVM = virConnectListDomains( conn, 
							p_infoVM->InfoAll.tabidVM,
							p_infoVM->InfoAll.tailleId ) ) == -1 )
	    {
		printf( "Impossible de recuperer les infos des VM\n" );
		return(1);
	    }
	/*
            printf( "Nbre de VMM a traiter <%d>\n", p_infoVM->InfoAll.nbrVM );
	    for( Ivm=0; Ivm < p_infoVM->InfoAll.nbrVM; Ivm++ )
	    { 
		printf( "Idvm <%d>\n", p_infoVM->InfoAll.tabidVM[Ivm] );
	    }
	*/

	    option=1;
	    id--;
            verif++;
        }

        else if( !strcmp( argv[id], "-i" ) )
        {
            p_infoVM->Interval = atoi( argv[ id+1 ] );
            //printf( "Interval entre deux messures <%d> secondes\n", p_infoVM->Interval );
            verif++;
        }

        else if( !strcmp( argv[id], "-n" ) )
        {
            p_infoVM->Iterations = atoi( argv[ id+1 ] );
            //printf( "Nombre d'iterations <%d>\n\n", p_infoVM->Iterations );
            verif++;
        }

        else
        {
            UsageProgramme( );
            return( 1 );
        }
        id++;
    }

    /* verification des parmatres obligatoires */
    if( verif != 3 )
    {
        printf( "Il manque des parametres obligatoires" );
        UsageProgramme( );
        return( 1 );
    }

    return( 0 );
}


/*---------------------------------------------------------------------------
**
** FONCTION : Error
**
** DESCRIPTION :
**         liberation des espaces alloués suite a une erreur
**
** PARAMETRES D'ENTREE :
**
** PARAMETRES DE SORTIE :
**
** VALEURS DE RETOUR :
**      0     : OK
**      Autre : ERREUR
**---------------------------------------------------------------------------
*/
static void Error( 
	virDomainPtr	dom,
	virDomainPtr	dom0,
	virConnectPtr	conn )
{
    if (dom != NULL)
        virDomainFree(dom);
    if (dom0 != NULL)
        virDomainFree(dom0);
    if (conn != NULL)
        virConnectClose(conn);
    
    return;

}


/*---------------------------------------------------------------------------
**
** FONCTION : LibStatIO
**
** DESCRIPTION :
**         liberation de l'ensemble des tableaux des sondes pour les IO disque
**
** PARAMETRES D'ENTREE :
**      InfoMesure_t infoVM : structure des tableaux pour l'ensemble des sondes
**
** PARAMETRES DE SORTIE :
**      Aucun
**
** VALEURS DE RETOUR :
**      0     : OK
**      Autre : ERREUR
**---------------------------------------------------------------------------
*/
void LibStatIO( 
	int		id,
	InfoAll_t	InfoVM )
{
    /* liberer les tableaux de stats IO */
    if( InfoVM.SondeVMIO[id].SondeVMIOAvant.p_StatIO != NULL )
    {
	if( InfoVM.SondeVMIO[id].SondeVMIOAvant.nbrDisk != 0 )
            free( InfoVM.SondeVMIO[id].SondeVMIOAvant.p_StatIO);
    }

    if( InfoVM.SondeVMIO[id].SondeVMIOApres.p_StatIO != NULL )
    {
	if( InfoVM.SondeVMIO[id].SondeVMIOApres.nbrDisk != 0 )
            free( InfoVM.SondeVMIO[id].SondeVMIOApres.p_StatIO);
    }
}


/*---------------------------------------------------------------------------
**
** FONCTION : LibStatEth
**
** DESCRIPTION :
**         liberation de l'ensemble des tableaux des sondes pour les IO reseau
**
** PARAMETRES D'ENTREE :
**      InfoMesure_t infoVM : structure des tableaux pour l'ensemble des sondes
**
** PARAMETRES DE SORTIE :
**      Aucun
**
** VALEURS DE RETOUR :
**      0     : OK
**      Autre : ERREUR
**---------------------------------------------------------------------------
*/
void LibStatEth( 
	int		id,
	InfoAll_t	InfoVM )
{
    /* liberer les tableaux de stats IO */
    if( InfoVM.SondeVMEth[id].SondeVMEthAvant.p_StatEth != NULL )
    {
	if( InfoVM.SondeVMEth[id].SondeVMEthAvant.nbrEth != 0)
	    free( InfoVM.SondeVMEth[id].SondeVMEthAvant.p_StatEth);
    }

    if( InfoVM.SondeVMEth[id].SondeVMEthApres.p_StatEth != NULL )
    {
	if( InfoVM.SondeVMEth[id].SondeVMEthApres.nbrEth != 0)
	   free( InfoVM.SondeVMEth[id].SondeVMEthApres.p_StatEth);
    }

}

/*---------------------------------------------------------------------------
**
** FONCTION : ToutLiberer
**
** DESCRIPTION :
**         liberation de l'ensemble des tableaux des sondes et des pointeurs
**		de l'ensemble des VM
**
** PARAMETRES D'ENTREE :
**      InfoMesure_t infoVM : structure des tableaux pour l'ensemble des sondes
**      virDomainPtr    dom0
** 	virConnectPtr   conn
**
** PARAMETRES DE SORTIE :
**      Aucun
**
** VALEURS DE RETOUR :
**      0     : OK
**      Autre : ERREUR
**---------------------------------------------------------------------------
*/
void ToutLiberer( 
	int		Id,
	InfoAll_t	InfoVM,
	virDomainPtr	dom0,
	virConnectPtr	conn )
{
    int nbr, idx;

/*
    for( nbr=0; nbr < Id; nbr++ )
    {
    	if ( InfoVM.tabDomPtr[nbr] != NULL)
        	virDomainFree(InfoVM.tabDomPtr[nbr]);
    }
*/
    if( InfoVM.tabDomPtr != NULL )
        free( InfoVM.tabDomPtr );

    /* libere les tableaux d'infos des VM */
    if ( InfoVM.tabInfoVMavant != NULL )
	free( InfoVM.tabInfoVMavant );

    if( InfoVM.tabInfoVMapres != NULL )
        free( InfoVM.tabInfoVMapres );

    /* liberer le tableau des sondes IO reseau et disque */
    if( InfoVM.SondeVMIO != NULL )
    {
	//for( idx=0; idx < InfoVM.nbrVM; idx++)
		//LibStatIO( idx, InfoVM );
       	free( InfoVM.SondeVMIO );
    }

    if( InfoVM.SondeVMEth != NULL )
    {
	//for( idx=0; idx < InfoVM.nbrVM; idx++)
	    //LibStatEth( idx, InfoVM );
        free( InfoVM.SondeVMEth );
    }

    if (dom0 != NULL)
        virDomainFree(dom0);

    
    return;

}


/*---------------------------------------------------------------------------
**
** FONCTION : AfficheResultat
**
** DESCRIPTION :
**         Affiche les resultats sur la sortie standard
**
** PARAMETRES D'ENTREE :
**      InfoMesure_t *p_infoVM : structure pour l'ensemble des sondes
**
** PARAMETRES DE SORTIE :
**  	info sur la sortie standard
**
** VALEURS DE RETOUR :
**      0     : OK
**      Autre : ERREUR
**---------------------------------------------------------------------------
*/
static int AfficheResultat(  InfoMesure_t	*p_infoVM,
			     virDomainInfo       infoDom0,
			     time_t		Interval )
{
	int		idv, nbdisk, nbEth;
        float		pourCentcpu;	/* Pourcentage de taux d'occupation */
	long long 	r_IoOctets;
	long long 	w_IoOctets;
	long long 	r_EthOctets;
	long long 	w_EthOctets;

        for( idv=0; idv < p_infoVM->InfoAll.nbrVM; idv++ )
        {
		/* coté CPU */
                pourCentcpu = (100.0 * (p_infoVM->InfoAll.tabInfoVMapres[idv].cpuTime - p_infoVM->InfoAll.tabInfoVMavant[idv].cpuTime))
                                        / (Interval * infoDom0.nrVirtCpu * pow(10,9) );
                printf("IdVM %d Interval %d  CPU %f", p_infoVM->InfoAll.tabidVM[idv], Interval, pourCentcpu );
		
		/* coté memoire */
                printf("  memory %d \n", p_infoVM->InfoAll.tabInfoVMapres[idv].memory );

		/* coté IO disque */
		//printf("nbdisk %d", p_infoVM->InfoAll.SondeVMIO[idv].SondeVMIOAvant.nbrDisk);
		for( nbdisk=0; nbdisk < p_infoVM->InfoAll.SondeVMIO[idv].SondeVMIOAvant.nbrDisk; nbdisk++ )
		{
		    r_IoOctets = ((p_infoVM->InfoAll.SondeVMIO[idv].SondeVMIOApres.p_StatIO[nbdisk].rd_bytes -
				p_infoVM->InfoAll.SondeVMIO[idv].SondeVMIOAvant.p_StatIO[nbdisk].rd_bytes ) / Interval) / 1024;
		    w_IoOctets = ((p_infoVM->InfoAll.SondeVMIO[idv].SondeVMIOApres.p_StatIO[nbdisk].wr_bytes -
				p_infoVM->InfoAll.SondeVMIO[idv].SondeVMIOAvant.p_StatIO[nbdisk].wr_bytes) / Interval) / 1024;
                    printf("                       IO  %s  Read  %ld Write %ld \n", 
				p_infoVM->InfoAll.SondeVMIO[idv].SondeVMIOApres.SondeIO.tabValeur[nbdisk],
				r_IoOctets ,  w_IoOctets );
                    //printf("                       IO disque : xx - Read : %ld Ko -  Write : xxx Ko\n", 
				//r_IoOctets );
		}
		
		/* coté IO reseau */
		//printf("nbEth %d", p_infoVM->InfoAll.SondeVMEth[idv].SondeVMEthAvant.nbrEth );
		for( nbEth=0; nbEth < p_infoVM->InfoAll.SondeVMEth[idv].SondeVMEthAvant.nbrEth; nbEth++ )
		{
		    r_EthOctets = ((p_infoVM->InfoAll.SondeVMEth[idv].SondeVMEthApres.p_StatEth[nbEth].rx_bytes -
				p_infoVM->InfoAll.SondeVMEth[idv].SondeVMEthAvant.p_StatEth[nbEth].rx_bytes) /Interval) / 1024;
		    w_EthOctets = ((p_infoVM->InfoAll.SondeVMEth[idv].SondeVMEthApres.p_StatEth[nbEth].tx_bytes -
				p_infoVM->InfoAll.SondeVMEth[idv].SondeVMEthAvant.p_StatEth[nbEth].tx_bytes) / Interval) / 1024;
                    printf("                       net %s  rcv %ld tx %ld \n", 
				p_infoVM->InfoAll.SondeVMEth[idv].SondeVMEthApres.SondeEth.tabValeur[nbEth],
				r_EthOctets, w_EthOctets );
                    //printf("                       IO reseau : xx  - Reçus : %ld Ko - Transmis : xxx Ko\n", 
				//r_EthOctets );
		}
		
		/* liberer les tableaux de stats IO disque */
		if( p_infoVM->InfoAll.SondeVMIO[idv].SondeVMIOApres.nbrDisk != 0 )
			LibStatIO( idv, p_infoVM->InfoAll );

		/* liberer les tableaux de stats IO reseau */
		if(  p_infoVM->InfoAll.SondeVMEth[idv].SondeVMEthApres.nbrEth != 0 )
			LibStatEth( idv, p_infoVM->InfoAll );
        }

}

/*---------------------------------------------------------------------------
**
** FONCTION : sd_SondeIO
**
** DESCRIPTION :
**         Recuperation des informations IO disque pour chaque disque d'une VM
**
** PARAMETRES D'ENTREE :
**	int	     idx 	: Index de la VM a traiter
**      InfoMesure_t *p_infoVM : structure pour l'ensemble des sondes
**
** PARAMETRES DE SORTIE :
**      InfoMesure_t *p_infoVM : allocation des tableaux pour chaque sonde
**                                 CPU, Memoire, IO disque et IO reseau
**
** VALEURS DE RETOUR :
**      0     : OK
**      Autre : ERREUR
**---------------------------------------------------------------------------
*/
static int sd_SondeIO(  int 		idx, 
			InfoMesure_t	*p_infoVM,
			sondeIOdisk_t	*p_SondeVMIO,
			sondeIOEth_t	*p_SondeVMEth )
{
    int				iter;
    int				ret;
    virDomainPtr		dom = NULL;	/* Domaine pris en compte */
    virDomainBlockStatsPtr	StatsIO;

    /* Pour simplifier l'ecriture */
    dom = p_infoVM->InfoAll.tabDomPtr[idx];

    ret = SondeIoEth( dom, &(p_SondeVMIO->SondeIO), &(p_SondeVMEth->SondeEth) );
    if( ret != 0 )
    {
      	//fprintf(stderr, "Recuperation des information IO de la VM %d impossible\n",
				//p_infoVM->InfoAll.tabidVM[idx] );
	p_SondeVMIO->nbrDisk = 0;
	p_SondeVMEth->nbrEth = 0;
	return(1);
    }

    /* allocation de la structure de reponse pour chaque disque en fonction du nombre de disque */
    p_SondeVMIO->nbrDisk = p_SondeVMIO->SondeIO.nbrValeur;
    p_SondeVMIO->p_StatIO = 
		//( virDomainBlockStatsPtr ) malloc( p_SondeVMIO->nbrDisk * sizeof( virDomainBlockStatsStruct ) );
		( virDomainBlockStatsPtr ) calloc( p_SondeVMIO->nbrDisk,  sizeof( virDomainBlockStatsStruct ) );
    if( p_SondeVMIO->p_StatIO == NULL )
    {
      	fprintf(stderr, "Allocation dynamique des stats par disque pour la VM %d  impossible\n", p_infoVM->InfoAll.tabidVM[idx] );
	p_SondeVMIO->nbrDisk = 0;
	p_SondeVMEth->nbrEth = 0;
	return(1);
    }

    /* Pour chaque disque de la VM, on recupere les infos IO disque */
    for( iter = 0; iter < p_SondeVMIO->nbrDisk; iter++)
    {
    	ret = virDomainBlockStats( dom, 
				   p_SondeVMIO->SondeIO.tabValeur[iter], 
				   &(p_SondeVMIO->p_StatIO[iter]), 
				   sizeof(virDomainBlockStatsStruct) );
    	if( ret != 0 )
    	{
      	    fprintf(stderr, "Recuperation des statsIO des disques de la VM %d impossible\n",
				p_infoVM->InfoAll.tabidVM[idx] );
	    free( p_SondeVMIO->p_StatIO);
	    p_SondeVMIO->nbrDisk = 0;
	    p_SondeVMEth->nbrEth = 0;
	    return(1);
	}
    }

    /* allocation de la structure de reponse pour chaque interface de la VM */
    p_SondeVMEth->nbrEth = p_SondeVMEth->SondeEth.nbrValeur;
    p_SondeVMEth->p_StatEth = 
		//( virDomainInterfaceStatsPtr ) malloc( p_SondeVMEth->nbrEth * sizeof( virDomainInterfaceStatsStruct ) );
		( virDomainInterfaceStatsPtr ) calloc( p_SondeVMEth->nbrEth,  sizeof( virDomainInterfaceStatsStruct ) );
    if( p_SondeVMEth->p_StatEth == NULL )
    {
      	fprintf(stderr, "Allocation dynamique des stats par disque pour la VM %d  impossible\n", p_infoVM->InfoAll.tabidVM[idx] );
	free( p_SondeVMIO->p_StatIO);
	p_SondeVMIO->nbrDisk = 0;
	p_SondeVMEth->nbrEth = 0;
	return(1);
    }
//printf(" malloc p_StatEth\n");

    /* Pour chaque disque de la VM, on recupere les infos IO reseau */
    for( iter = 0; iter < p_SondeVMEth->nbrEth; iter++)
    {
    	ret = virDomainInterfaceStats(  dom, 
					p_SondeVMEth->SondeEth.tabValeur[iter], 
					&(p_SondeVMEth->p_StatEth[iter]), 
					sizeof(virDomainInterfaceStatsStruct) );
    	if( ret != 0 )
    	{
      	    fprintf(stderr, "Recuperation des statEth IO de la VM %d impossible\n",
				p_infoVM->InfoAll.tabidVM[idx] );
	    free( p_SondeVMIO->p_StatIO );
	    free( p_SondeVMEth->p_StatEth );
	    p_SondeVMIO->nbrDisk = 0;
	    p_SondeVMEth->nbrEth = 0;
	    return(1);
	}
    }
	return(0);
}




/*---------------------------------------------------------------------------
**
** FONCTION : allocationInfo
**
** DESCRIPTION :
**         allocation dynamique des tableaux permettant la remontee d'informations
**		pour l'ensemble des VM du serveur
**
** PARAMETRES D'ENTREE :
**      InfoMesure_t *p_infoVM : structure pour l'ensemble des sondes
**
** PARAMETRES DE SORTIE :
**      InfoMesure_t *p_infoVM : allocation des tableaux pour chaque sonde
**				   CPU, Memoire, IO disque et IO reseau
**
** VALEURS DE RETOUR :
**      0     : OK
**      Autre : ERREUR
**---------------------------------------------------------------------------
*/
int allocationInfo( InfoMesure_t	*p_infoVM )
{
    /* Allocation dynamique pour la remontee d'infos de chaque VM */
    p_infoVM->InfoAll.tabDomPtr = ( virDomainPtr * ) malloc( p_infoVM->InfoAll.nbrVM * sizeof( virDomainPtr ) );
    if( p_infoVM->InfoAll.tabDomPtr == NULL )
    {
      	fprintf(stderr, "Allocation dynamique de la table d'infos des VM impossible\n" );
	return(1);
    }
//printf( "malloc virDomainPtr\n");

    /* Allocation dynamique pour la remontee d'infos de chaque VM */
    p_infoVM->InfoAll.tabInfoVMavant = ( virDomainInfo * ) malloc( p_infoVM->InfoAll.nbrVM * sizeof( virDomainInfo ) );
    if( p_infoVM->InfoAll.tabInfoVMavant == NULL )
    {
      	fprintf(stderr, "Allocation dynamique de la table d'infos des VM impossible\n" );
	return(1);
    }
//printf( "malloc tabInfoVMavant\n");

    p_infoVM->InfoAll.tabInfoVMapres = ( virDomainInfo * ) malloc( p_infoVM->InfoAll.nbrVM * sizeof( virDomainInfo ) );
    if( p_infoVM->InfoAll.tabInfoVMapres == NULL )
    {
      	 fprintf(stderr, "Allocation dynamique de la table d'infos des VM impossible\n" );
	 return(1);
    }
//printf( "malloc tabInfoVMapres\n");

    /* Allocation dynamique pour la remontee des IO pour chaque disque d'une VM */
    p_infoVM->InfoAll.SondeVMIO = ( sondeDisk_t * ) malloc( p_infoVM->InfoAll.nbrVM * sizeof( sondeDisk_t ) );
    if( p_infoVM->InfoAll.SondeVMIO == NULL )
    {
      	 fprintf(stderr, "Allocation dynamique pour la remontee des IO disque impossible\n" );
	 return(1);
    }
//printf( "malloc SondeVMIO\n");

    /* Allocation dynamique pour la remontee des IO pour chaque carte reseau d'une VM */
    p_infoVM->InfoAll.SondeVMEth = ( sondeEth_t * ) malloc( p_infoVM->InfoAll.nbrVM * sizeof( sondeEth_t ) );
    if( p_infoVM->InfoAll.SondeVMEth == NULL )
    {
      	 fprintf(stderr, "Allocation dynamique pour la remontee des IO disque impossible\n" );
	 return(1);
    }
//printf( "malloc SondeVMEth\n");
    return(0);
}



/*---------------------------------------------------------------------------
**
** FONCTION : getAllInfo
**
** DESCRIPTION :
**         recuperation de l'ensemble des metriques pour l'ensemble des VM
**
** PARAMETRES D'ENTREE :
**
** PARAMETRES DE SORTIE :
**
** VALEURS DE RETOUR :
**      0     : OK
**      Autre : ERREUR
**---------------------------------------------------------------------------
*/
int getAllInfo( 
	InfoMesure_t	*p_infoVM,
	virConnectPtr	conn )
{
    virDomainPtr	dom0 = NULL;	/* Domaine pris en compte */
    virDomainInfo	infoDom0;	/* Information du domaine 0 */
    struct timeval 	timeod0;	/* temps ecoulé en seconde  et micro */
    struct timeval 	timeod1;	/* temps ecoulé en seconde  et micro */
    unsigned long long	timecpu1;
    unsigned long long	timecpu2;
    time_t		Interval;	/* interval de temps en secondes */
    int			pourCentcpu;	/* Pourcentage de taux d'occupation */
    int			I=0, idv, ret=0, nbVM=0;

    /* Recupere le domaine a partir de son id */
    dom0 = virDomainLookupByID(conn, 0 );
    if (dom0 == NULL) {
        fprintf(stderr, "Le domaine 0 est introuvable \n");
	Error( NULL, NULL, conn);
	return(1);
    }
    ret = virDomainGetInfo(dom0, &infoDom0);
    if (ret < 0) {
      	fprintf(stderr, "Impossible de recuperer les info du domaine 0\n" );
	Error( NULL, dom0, conn);
	return(1);
    }

    /* Allocation dynamique des tableaux d'informations des VM */
    ret = allocationInfo(p_infoVM );
    if (ret < 0) {
      	fprintf(stderr, "Impossible d'allouer les tableaux de remonte des infos \n" );
	ToutLiberer( 0, p_infoVM->InfoAll, dom0, conn);
	return(1);
    }

    /* Recuperation du pointeur de connection de chaque VM a partir de l'hyperviseur */
    for( idv=0; idv < p_infoVM->InfoAll.nbrVM; idv++ )
    {
    	p_infoVM->InfoAll.tabDomPtr[idv] = virDomainLookupByID(conn, p_infoVM->InfoAll.tabidVM[idv] );
    	if( p_infoVM->InfoAll.tabDomPtr[idv] == NULL) {
        	fprintf(stderr, "Le domaine <%d> est introuvable \n", p_infoVM->InfoAll.tabidVM[idv] );
	 	ToutLiberer( idv, p_infoVM->InfoAll, dom0, conn);
	 	return(1);
    	}
    }

    while( I < p_infoVM->Iterations )
    { 
	/* Recuperation de la date/heure */
	gettimeofday(&timeod0, NULL);
printf("Iteration %d time %ld\n",I,timeod0.tv_sec);

	for( idv=0; idv < p_infoVM->InfoAll.nbrVM; idv++ )
	{
    		/* Remonte des infos du domaine */
    		ret = virDomainGetInfo( p_infoVM->InfoAll.tabDomPtr[idv], &(p_infoVM->InfoAll.tabInfoVMavant)[idv] );
    		if (ret < 0) {
			break;
        		//fprintf(stderr, "Impossible de recuperer les info du domaine %d\n", p_infoVM->InfoAll.tabidVM[idv] );
	 		//ToutLiberer( idv, p_infoVM->InfoAll, dom0, conn);
	 		//return(1);
    		}

    		/* Remonte des infos IO disques et reseau */
		ret = sd_SondeIO(  idv, 
				   p_infoVM, 
				   &p_infoVM->InfoAll.SondeVMIO[idv].SondeVMIOAvant,
				   &p_infoVM->InfoAll.SondeVMEth[idv].SondeVMEthAvant );
    		if (ret < 0) {
        		fprintf(stderr, "Impossible de recuperer les info du domaine %d\n", p_infoVM->InfoAll.tabidVM[idv] );
			break;
	 		//ToutLiberer( idv, p_infoVM->InfoAll, dom0, conn);
	 		//return(1);
    		}
	}

	/* Interval de temps entre deux mesures */
	sleep( p_infoVM->Interval );

    	/* Remonte des infos du domaine */
	for( idv=0; idv < p_infoVM->InfoAll.nbrVM; idv++ )
	{
    		/* Remonte des infos du domaine */
    		ret = virDomainGetInfo( p_infoVM->InfoAll.tabDomPtr[idv], &(p_infoVM->InfoAll.tabInfoVMapres)[idv] );
    		if (ret < 0) {
			break;
			/*
        		fprintf(stderr, "Impossible de recuperer les info du domaine %d\n", p_infoVM->InfoAll.tabidVM[idv] );
	 		ToutLiberer( idv, p_infoVM->InfoAll, dom0, conn);
	 		return(1);
			*/
    		}
    		/* Remonte des infos IO disques et reseau */
		ret = sd_SondeIO(  idv, 
				   p_infoVM, 
				   &p_infoVM->InfoAll.SondeVMIO[idv].SondeVMIOApres,
				   &p_infoVM->InfoAll.SondeVMEth[idv].SondeVMEthApres );
    		if (ret < 0) {
        		fprintf(stderr, "Impossible de recuperer les info du domaine %d\n", p_infoVM->InfoAll.tabidVM[idv] );
			break;
			/*
	 		ToutLiberer( idv, p_infoVM->InfoAll, dom0, conn);
	 		return(1);
			*/
    		}
	}
    	gettimeofday(&timeod1, NULL);

	/*Interval de temps entre deux mesures */
	Interval= timeod1.tv_sec - timeod0.tv_sec;
	
	AfficheResultat( p_infoVM, infoDom0, Interval );

	/* Une nouvelle VM a demarré ou c'est arrete */
        if ( ( nbVM = virConnectListDomains( conn,
                                             p_infoVM->InfoAll.tabidVM,
                                             p_infoVM->InfoAll.tailleId ) ) == -1 )
        {
            printf( "Impossible de recuperer les infos des VM\n" );
        }
	if ( nbVM != p_infoVM->InfoAll.nbrVM )
	{ 
		//il tout liberer et relancer 
		p_infoVM->Iterations -= I;
    		ToutLiberer( p_infoVM->InfoAll.nbrVM, p_infoVM->InfoAll, dom0, conn);
		p_infoVM->InfoAll.nbrVM = nbVM;

		//appel recurcif
		getAllInfo( p_infoVM, conn );
		return(0);
	}

    	I++;
	printf( "-----\n" );
	fflush(stdout);

    }

    ToutLiberer( p_infoVM->InfoAll.nbrVM, p_infoVM->InfoAll, dom0, conn);

    return(0);

}


/*---------------------------------------------------------------------------
**
** FONCTION : getDomainInfo
**
** DESCRIPTION :
**         recuperation de l'ensemble des metriques pour une VM donnée, 
**	    ATTENTIon en cours de chantier
**
** PARAMETRES D'ENTREE :
**
** PARAMETRES DE SORTIE :
**
** VALEURS DE RETOUR :
**      0     : OK
**      Autre : ERREUR
**---------------------------------------------------------------------------
*/
int getDomainInfo( 
	InfoMesure_t	*p_infoVM,
	virConnectPtr	conn )
{
    virDomainPtr	dom = NULL;	/* Domaine pris en compte */
    virDomainPtr	dom0 = NULL;	/* Domaine pris en compte */
    virDomainInfo	info;		/* Information du domaine */
    virDomainInfo	infoDom0;	/* Information du domaine 0 */
    struct timeval 	timeod0;	/* temps ecoulé en seconde  et micro */
    struct timeval 	timeod1;	/* temps ecoulé en seconde  et micro */
    time_t		Interval;	/* interval de temps en secondes */
    unsigned long long	timecpu1;
    unsigned long long	timecpu2;
    int 		nbrActifDom;	/* Nombre de domaines actifs */
    int			ret, tipCpu;
    int			pourCentcpu;	/* Pourcentage de taux d'occupation */

    if( !p_infoVM->typeInfo )
    {
        /* Recupere l'id du domain a partir de son nom */
        dom = virDomainLookupByName (conn, p_infoVM->MachVirt );
        if (dom == NULL) {
                fprintf(stderr, "Le domaine %d est introuvable \n", p_infoVM->IdVM );
		Error( dom, dom0, conn);
		return(1);
        }
    }
    else
    {
        /* Recupere le domaine a partir de son id */
        /*dom = virDomainLookupByID(conn,  p_infoVM->IdVM );*/
        dom = virDomainLookupByID(conn, p_infoVM->IdVM );
        if (dom == NULL) {
                fprintf(stderr, "L'ID %d est introuvable \n", p_infoVM->IdVM );
		Error( dom, dom0, conn);
		return(1);
        }
    }

    /* Recupere le domaine a partir de son id */
    dom0 = virDomainLookupByID(conn, 0 );
    if (dom0 == NULL) {
        fprintf(stderr, "Le domaine 0 est introuvable \n");
	Error( dom, dom0, conn);
	return(1);
    }
    ret = virDomainGetInfo(dom0, &infoDom0);
    if (ret < 0) {
      	 fprintf(stderr, "Impossible de recuperer les info du domaine 0\n" );
	 Error( dom, dom0, conn);
	 return(1);
    }

    int I = 0;
    /*struct timeval timeod0 = { 0, 0 }, timeod1 = { 0, 0 }; */
    while (I < p_infoVM->Iterations )
    { 
    	/* Remonte des infos du domaine */
    	ret = virDomainGetInfo(dom, &info);
    	if (ret < 0) {
        	fprintf(stderr, "Impossible de recuperer les info du domaine %d\n", p_infoVM->IdVM );
		Error( dom, dom0, conn);
		return(1);
    	}

	timecpu1 = info.cpuTime;
    	/*printf("Domains %d: %lld TimeCPUs\n", p_infoVM->IdVM , timecpu1);*/
	gettimeofday(&timeod0, NULL);

	/* Interval de temps entre deux mesures */
	sleep( p_infoVM->Interval );
    	/* Remonte des infos du domaine */
    	ret = virDomainGetInfo(dom, &info);
    	if (ret < 0) {
        	fprintf(stderr, "Impossible de recuperer les info du domaine %d\n", p_infoVM->IdVM );
		Error( dom, dom0, conn);
		return(1);
    	}
	timecpu2 = info.cpuTime;
    	gettimeofday(&timeod1, NULL);

	/* Interval de temps entre deux mesures */
	Interval= timeod1.tv_sec - timeod0.tv_sec;
	tipCpu = timecpu2 - timecpu1;
	
	pourCentcpu = (100 * (timecpu2 - timecpu1)) / (Interval * infoDom0.nrVirtCpu * pow(10,9) );
	printf("Pourcentage CPU :%d\n\n", pourCentcpu);
    	I++;

    }
    return(0);

}

/*---------------------------------------------------------------------------
**
** FONCTION : main
**
** DESCRIPTION :
**         fonction principale
**
** PARAMETRES D'ENTREE :
**
** PARAMETRES DE SORTIE :
**
** VALEURS DE RETOUR :
**      0     : OK
**      Autre : ERREUR
**---------------------------------------------------------------------------
*/
int main(int argc, char **argv) {

    InfoMesure_t        infoVM;		/* information sur la ou les VM */ 
    virConnectPtr	conn = NULL;	/* Connexion Hyperviseur */
    int			Ret=0;

    /* le param NULL permet de se connecter sur l'hyperviseur */
    conn = virConnectOpenReadOnly(NULL);
    if (conn == NULL) {
        fprintf(stderr, "Connexion sur l'hyperviseur Impossible\n");
        return(1);
    }

    /* Recuperation des arguments */
    Ret = RecupererArguments( argc, argv, conn, &infoVM );
    if ( Ret != 0 )
	return(1);

    if ( infoVM.All == 1 )
    {
    	getAllInfo( &infoVM, conn );
    }
    else
    {
    	getDomainInfo( &infoVM, conn );
    }

    if (conn != NULL)
        virConnectClose(conn);

    return(0);
}
