/* ***********************IMPORTANT *********************************************
 *  Copyright (C) 2004-2007 Thierry Lagarde <tlagarde@users.sourceforge.net>
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License.
 *
 *
 *                      ********************
 *
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Library General Public License for more details.
 *
 *
 *                      ********************
 *
 *
 * You are highly encouraged to send your changes to <tlagarde@users.sourceforge.net>
 * for possible incorporation into the main distribution.
 * By sending these changes to <tlagarde@users.sourceforge.net>,
 * it is assumed that you are offering <tlagarde@users.sourceforge.net>
 * the unlimited, non-exclusive right to reuse, modify, and relicense the code.
 *
 *
 *                      ********************
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 **************************************************************************************/
#include <glib.h>
#include <errno.h>
#include <stdlib.h>
#include "Communication.h"
#include "Commun.h"
#include "../Debug.h"
#include "../Thread.h"
#include "../Intrus.h"
#include "../Notification_Port.h"
#include "Socket.h"
#include "Quit.h"
#include "Semaphore.h"
#include "Scan_Port.h"
#include "Scan_Signature.h"
#include "Sous_Reseau_Autorise.h"
#include "Initialisation_Com.h"
#include "Notification_Equipement.h"
#include "../Restoration.h"
#include "../Nessus.h"
#include "Declaration_Constante.h"
#include "../Scan_Equipement.h"
#include "../Snmp.h"
#include "Macro.h"

struct Struct_Modele_Communication Liste_Communication[] = {
	{AGENT_VERSION, NULL,"AGENT_VERSION",0},
	{AJOUT_PORT, &Ajout_Un_Port,"AJOUT_PORT",sizeof(struct struct_Ajout_Port)},
	{AJOUT_SIGNATURE, NULL,"AJOUT_SIGNATURE",0},
	{RESTAURATION_MACHINE, &Ajout_Equipement_Restoration,"RESTAURATION_MACHINE",sizeof(struct struct_Restauration_Machine)},
	{AJOUT_RESEAU_PRIVEE, &Ajout_Sous_Reseau_Autorise,"AJOUT_RESEAU_PRIVEE",sizeof(struct struct_Ajout_Reseau_Privee)},
	{DEMANDE_LISTE_INTERFACE, &Envoie_Liste_Interface,"DEMANDE_LISTE_INTERFACE",sizeof(struct struct_Demande_Liste_Interface)},
	{NOUVELLE_INTERFACE, NULL,"NOUVELLE_INTERFACE",0},
	{FIN_LISTE_INTERFACE, NULL,"FIN_LISTE_INTERFACE",0},
	{DEMARRAGE_AGENT, &Demarrage_Agent,"DEMARRAGE_AGENT",sizeof(struct struct_Demarrage_Agent)},
	{DEMANDE_ARRET_AGENT, &Arret_Demande,"DEMANDE_ARRET_AGENT",sizeof(struct struct_Demande_Arret_Agent)},
	{RETOUR_MESSAGE, NULL,"RETOUR_MESSAGE",0},
	{RETOUR_ERREUR_CRITIQUE, NULL,"RETOUR_ERREUR_CRITIQUE",0},
	{INFO_AGENT, NULL,"INFO_AGENT",0},
	{NOUVEAU_EQUIPEMENT, NULL,"NOUVEAU_EQUIPEMENT",0},
	{DEMANDE_NESSUS, &Initialisation_Nessus,"DEMANDE_NESSUS",sizeof(struct struct_Demande_Nessus)},
	{DEMARRAGE_NESSUS, NULL,"DEMARRAGE_NESSUS",0},
	{RETOUR_NESSUS_INFO, NULL,"RETOUR_NESSUS_INFO",0},
	{RETOUR_NESSUS_DONNEE, NULL,"RETOUR_NESSUS_DONNEE",0},
	{RETOUR_NESSUS_FIN, NULL,"RETOUR_NESSUS_FIN",0},
	{DEMANDE_RAFRAICHIR_ETAT_EQUIMEMENT, &Rafraichir_Etat_Equipement,"DEMANDE_RAFRAICHIR_ETAT_EQUIMEMENT",sizeof(struct struct_Demande_Rachaichir_Etat_Equipement)},
	{RETOUR_RAFRAICHIR_ETAT_EQUIMEMENT, NULL,"RETOUR_RAFRAICHIR_ETAT_EQUIMEMENT",0},
	{DEMANDE_RAFRAICHIR_LISTE_PORTS, NULL,"DEMANDE_RAFRAICHIR_LISTE_PORTS",0},
	{RETOUR_RAFRAICHIR_LISTE_PORTS, NULL,"RETOUR_RAFRAICHIR_LISTE_PORTS",0},
	{DEMANDE_RAFRAICHIR_ENREGISTREMENT_SAMBA, NULL,"DEMANDE_RAFRAICHIR_ENREGISTREMENT_SAMBA",0},
	{RETOUR_RAFRAICHIR_ENREGISTREMENT_SAMBA, NULL,"RETOUR_RAFRAICHIR_ENREGISTREMENT_SAMBA",0},
	{DEMANDE_RAFRAICHIR_SIGNATURE, NULL,"DEMANDE_RAFRAICHIR_SIGNATURE",0},
	{RETOUR_RAFRAICHIR_SIGNATURE, NULL,"RETOUR_RAFRAICHIR_SIGNATURE",0},
	{DEMANDE_NOTIFICATION_WARNING_ETAT_EQUIPEMENT, NULL,"DEMANDE_NOTIFICATION_WARNING_ETAT_EQUIPEMENT",0},
	{DEMANDE_NOTIFICATION_WARNING_ETAT_PORT, NULL,"DEMANDE_NOTIFICATION_WARNING_ETAT_PORT",0},
	{DEMANDE_NOTIFICATION_CRITIQUE_ETAT_EQUIPEMENT, &Ajout_Notification_Equipement,"DEMANDE_NOTIFICATION_CRITIQUE_ETAT_EQUIPEMENT",sizeof(struct struct_Demande_Notication_Critique_Etat_Equipement)},
	{DEMANDE_NOTIFICATION_CRITIQUE_ETAT_PORT, &Ajout_Notification_Port,"DEMANDE_NOTIFICATION_CRITIQUE_ETAT_PORT",sizeof(struct struct_Demande_Notication_Critique_Etat_Port)},
	{RETOUR_NOTIFICATION_CHANGEMENT_ETAT_EQUIPEMENT, NULL,"RETOUR_NOTIFICATION_CHANGEMENT_ETAT_EQUIPEMENT",0},
	{RETOUR_NOTIFICATION_CHANGEMENT_ETAT_PORT, NULL,"RETOUR_NOTIFICATION_CHANGEMENT_ETAT_PORT",0},
	{ANNULATION_NOTIFICATION_ETAT_EQUIPEMENT, &Enlever_Notification_Equipement,"ANNULATION_NOTIFICATION_ETAT_EQUIPEMENT",sizeof(struct struct_Annulation_Notification_Etat_Equipement)},
	{ANNULATION_NOTIFICATION_ETAT_PORT, &Enlever_Notification_Port,"ANNULATION_NOTIFICATION_ETAT_PORT",sizeof(struct struct_Annulation_Notification_Etat_Port)},
	{ACTIVE_ALERTE_INTRUS, &Active_Alerte_Intrusion,"ACTIVE_ALERTE_INTRUS",sizeof(struct struct_Active_Alerte_Intrus)},
	{DESACTIVE_ALERTE_INTRUS, &Desactive_Alerte_Intrusion,"DESACTIVE_ALERTE_INTRUS",sizeof(struct struct_Desactive_Alerte_Intrus)},
	{ALERTE_INTRUS, NULL,"ALERTE_INTRUS",0},
	{DEMANDE_MODIFIE_NIVEAU_DEBUG, NULL,"DEMANDE_MODIFIE_NIVEAU_DEBUG",0},
	{RETOUR_LISTE_SNMP, NULL,"RETOUR_LISTE_SNMP",0},
	{DEMANDE_LANCEMENT_SCRIPT, NULL,"DEMANDE_LANCEMENT_SCRIPT",0},
	{RETOUR_SCRIPT, NULL,"RETOUR_SCRIPT",0},
	{RETOUR_SCRIPT_TERMINER, NULL,"RETOUR_SCRIPT_TERMINER",0},
	{DEMANDE_RAFRAICHIR_EQUIPEMENT, &Demande_Rafraichir_Equipement,"DEMANDE_RAFRAICHIR_EQUIPEMENT",sizeof(struct struct_Demande_Rafraichir_Equipement)},
	{RETOUR_RAFRAICHIR_EQUIPEMENT, NULL,"RETOUR_RAFRAICHIR_EQUIPEMENT",0},
	{IP_RETROUVER, NULL,"IP_RETROUVER",0},
	{IP_PERDU, NULL,"IP_PERDU",0},
	{IP_MODIFIER, NULL,"IP_MODIFIER",0},
	{DEMANDE_LISTE_SNMP, &Demande_Envoie_Liste_Snmp,"DEMANDE_LISTE_SNMP",sizeof(struct struct_Demande_Liste_SNMP)},	
	{DEL_GLIST_SNMP, NULL,"DEL_GLIST_SNMP",0},	
	{DEMANDE_LISTE_SNMP_ALL, &Demande_Envoie_Liste_Snmp_All ,"DEMANDE_LISTE_SNMP_ALL",sizeof(struct struct_Demande_Liste_SNMP_All)},
	{DEMANDE_WAKE_UP, &Demande_WakeUp ,"DEMANDE_WAKE_UP",sizeof(struct struct_Demande_WakeUp)},
	{DEMANDE_LOG_EQUIPEMENT, &Envoie_Log_Equipement ,"DEMANDE_LOG_EQUIPEMENT",sizeof(struct struct_Demande_Log_Equipement)},
	{RETOUR_LOG_EQUIPEMENT, NULL ,"RETOUR_LOG_EQUIPEMENT",0},
	{RETOUR_RAFRAICHIR_NOM_UTILISATEUR, NULL ,"RETOUR_RAFRAICHIR_NOM_UTILISATEUR",0},
	{AFFICHE_NOUVEAU_EQUIPEMENT, NULL ,"AFFICHE_NOUVEAU_EQUIPEMENT",0},
	{DEMANDE_SNMP_SCALAIRE, &Demande_Envoie_Snmp_Scalaire,"DEMANDE_SNMP_SCALAIRE",sizeof(struct struct_Demande_SNMP_Scalaire)},
	{RETOUR_SNMP_SCALAIRE, NULL,"DEMANDE_LISTE_SCALAIRE",}	

};

#ifdef __DEBUG_COM
void Log_Reception_Transmission(struct struct_Cle_Privee *Donnee_Cle,gchar *Texte_Log){
	if (Donnee_Cle!=NULL)
		Log(Donnee_Cle,Texte_Log);
	MYFREE(Texte_Log);
}
#endif


void     *Communication_Reception_Donnee_Boucle (void)
{
	struct struct_Info_Entete Entete;
	gint      Taille_Donnee_Recue,Ckecksum;
	gchar     Donnee_Brut[TAILLE_MAX_DONNEE_BRUT],*pEntete = NULL;
	guint     Tentative,Taille_Donnee_Recue_Part;
	
#ifdef __LOG_ENABLE
	Create_Log(CATEG_BOUCLE_COMMUNIC,NULL,NULL,TRUE);
#endif
	pEntete = &Entete; 
	while (1) {
	
		
		Tentative = 0;
		Taille_Donnee_Recue = 0;
		do{
			Tentative++;
			Taille_Donnee_Recue_Part = recvfrom (client_id, &pEntete[Taille_Donnee_Recue], sizeof (struct struct_Info_Entete)-Taille_Donnee_Recue, 0, NULL, 0);
			if (Taille_Donnee_Recue_Part == -1){
#ifdef __DEBUG_COM
				Log_Reception_Transmission(Log_Recv,g_strdup_printf("[%s] Tentative(%d) Taille_Donnee_Recue_Part == -1   %s\n",Liste_Communication[Entete.ID_Info].Debug, Tentative, strerror (errno)));
#endif		
				debug_printf (D_WARN, __FILE__, __PRETTY_FUNCTION__, __LINE__, "Taille_Donnee_Recue_Part == -1   %s  Socket (%d)", strerror (errno),client_id);
				if (!(errno == EINTR || errno == EAGAIN))
					debug_printf (D_ERRO, __FILE__, __PRETTY_FUNCTION__, __LINE__, "%s nSocket ouvert[%d]  Thread[%d][%d] Nb equipement (%d)", strerror (errno), Nb_Socket_Ouverte, Info_Demarrage.Nb_Thread_Max, Info_Demarrage.Nb_Thread_Max - Valeur_Semaphore (&Semaphore_Thread_Scan), g_list_length (GList_Equipement));
				usleep(400000);
			}
			else {
				if (Taille_Donnee_Recue_Part==0)
					debug_printf (D_WARN, __FILE__, __PRETTY_FUNCTION__, __LINE__, "Taille_Donnee_Recue_Part == 0   %s  Socket (%d)", strerror (errno),client_id);
				Taille_Donnee_Recue = Taille_Donnee_Recue + Taille_Donnee_Recue_Part;
			}
		}while ((sizeof (struct struct_Info_Entete)!=Taille_Donnee_Recue)&&(Tentative!=10));
#ifdef __DEBUG_COM					
			Log_Reception_Transmission(Log_Recv,g_strdup_printf("[%s] %d\n",Liste_Communication[Entete.ID_Info].Debug,Entete.Taille_Donnee));
#endif		
	
		if (sizeof (struct struct_Info_Entete) != Taille_Donnee_Recue)
			debug_printf (D_ERRO, __FILE__, __PRETTY_FUNCTION__, __LINE__, "[%s] [%d]!=[%d]", Liste_Communication[Entete.ID_Info].Debug,sizeof (struct struct_Info_Entete), Taille_Donnee_Recue);
		if (Taille_Donnee_Recue>0){
		
		
			if (Entete.Taille_Donnee != Liste_Communication[Entete.ID_Info].Taille_Structure)
				debug_printf (D_ERRO, __FILE__, __PRETTY_FUNCTION__, __LINE__, "[%d]!=[%d]", Liste_Communication[Entete.ID_Info].Taille_Structure, Entete.Taille_Donnee);
			if (Entete.Taille_Donnee > TAILLE_MAX_DONNEE_BRUT)
				debug_printf (D_ERRO, __FILE__, __PRETTY_FUNCTION__, __LINE__, "[%s]  Taille:[%d]", Liste_Communication[Entete.ID_Info].Debug, Entete.Taille_Donnee);
		
			Tentative = 0;
			Taille_Donnee_Recue = 0;
			do{
				Tentative++;
				Taille_Donnee_Recue_Part = recvfrom (client_id, &Donnee_Brut[Taille_Donnee_Recue], Entete.Taille_Donnee-Taille_Donnee_Recue, 0, NULL, 0);
				if (Taille_Donnee_Recue_Part == -1){
#ifdef __DEBUG_COM		
					Log_Reception_Transmission(Log_Recv,g_strdup_printf("[%s] Tentative(%d) Taille_Donnee_Recue_Part == -1   %s\n",Liste_Communication[Entete.ID_Info].Debug, Tentative, strerror (errno)));
#endif	
					debug_printf (D_WARN, __FILE__, __PRETTY_FUNCTION__, __LINE__, "Taille_Donnee_Recue_Part == -1   %s  Socket (%d)", strerror (errno),client_id);
					if (!(errno == EINTR || errno == EAGAIN))
						debug_printf (D_ERRO, __FILE__, __PRETTY_FUNCTION__, __LINE__, "%s nSocket ouvert[%d]  Thread[%d][%d] Nb equipement (%d)", strerror (errno), Nb_Socket_Ouverte, Info_Demarrage.Nb_Thread_Max, Info_Demarrage.Nb_Thread_Max - Valeur_Semaphore (&Semaphore_Thread_Scan), g_list_length (GList_Equipement));
					usleep(400000);
				}
				else {
					if (Taille_Donnee_Recue_Part==0)
						debug_printf (D_WARN, __FILE__, __PRETTY_FUNCTION__, __LINE__, "Taille_Donnee_Recue_Part == 0   %s  Socket (%d)", strerror (errno),client_id);
					Taille_Donnee_Recue = Taille_Donnee_Recue + Taille_Donnee_Recue_Part;
				}
			}while ((Entete.Taille_Donnee!=Taille_Donnee_Recue)&&(Tentative!=10));
		
			if ((Taille_Donnee_Recue == -1)||(Taille_Donnee_Recue == 0))
				debug_printf (D_ERRO, __FILE__, __PRETTY_FUNCTION__, __LINE__, "[%s] Taille Recupere Entete : (%d)", strerror (errno),Taille_Donnee_Recue);
			if (Entete.Taille_Donnee!=Taille_Donnee_Recue)
				debug_printf (D_ERRO, __FILE__, __PRETTY_FUNCTION__, __LINE__, "Entete.Taille_Donnee!=Taille_Donnee_Recue [%d!=%d]  Tentative(%d) [%s]", Entete.Taille_Donnee,Taille_Donnee_Recue,Tentative,Liste_Communication[Entete.ID_Info].Debug);
			Ckecksum = Calculer_Ckecksum(Donnee_Brut,Taille_Donnee_Recue);
			if (Ckecksum!=Entete.Ckecksum)
				debug_printf (D_ERRO, __FILE__, __PRETTY_FUNCTION__, __LINE__, "Ckecksum!=Entete.Ckecksum [%08X!=%08X]", Ckecksum, Entete.Ckecksum);
#ifdef __DEBUG_COM					
					Log_Reception_Transmission(Log_Recv,g_strdup_printf("[%s] Ckecksum %08X\n",Liste_Communication[Entete.ID_Info].Debug,Ckecksum));
#endif	
		
			if (Liste_Communication[Entete.ID_Info].Gestion_Communication != NULL)
				(*Liste_Communication[Entete.ID_Info].Gestion_Communication) ((gpointer *) &Donnee_Brut);
			else
				debug_printf (D_WARN_USER, __FILE__, __PRETTY_FUNCTION__, __LINE__, "Reception Message sans action defini");
		}
		else {
			if (Taille_Donnee_Recue == -1)
				debug_printf (D_WARN_USER, __FILE__, __PRETTY_FUNCTION__, __LINE__, "recvfrom : (%s)", strerror (errno));
		}
	}
}

void Communication_Initialisation (void)
{
#define NB_CARACTERE_IDENTIFICATION 25
	gchar     Identification[NB_CARACTERE_IDENTIFICATION];
	gint      NbOctet;

#ifdef         __WINDOWS_ENABLE
	int ret;
	WSADATA wsaData;
 
	if ((ret = WSAStartup(MAKEWORD(1,1),&wsaData)) != 0)
		 debug_printf (D_ERRO, __FILE__, __PRETTY_FUNCTION__, __LINE__, "Init Network : Failed\n");
	debug_printf (D_WARN, __FILE__, __PRETTY_FUNCTION__, __LINE__, "Init Network : OK\n");
#endif
	Mon_Pid = getpid ();

	Socket_Service = create_tcp_server (4555, 1);
	if (-1 == (client_id = accept (Socket_Service, NULL, 0)))
		debug_printf (D_ERRO, __FILE__, __PRETTY_FUNCTION__, __LINE__, "accept", strerror (errno));

	shutdown (Socket_Service, SHUT_RDWR);
  	close (Socket_Service);

	NbOctet = send (client_id, VERSION_AGENT, sizeof (VERSION_AGENT), 0);
	if (NbOctet == -1){
#ifdef __LOG_ENABLE
		Log ( Donnee_Cle_Main, "[ERROR] Communication.h  [send] NbOctet < 0");
		Log (Donnee_Cle_Main, strerror (errno));
#endif
		Arret_Demande(NULL);
	}
	if (NbOctet != sizeof (VERSION_AGENT)){
#ifdef __LOG_ENABLE
		Log ( Donnee_Cle_Main, "[ERROR] Communication.h  [send] NbOctet != sizeof (VERSION_AGENT)");
		Log (Donnee_Cle_Main, strerror (errno));
#endif
		Arret_Demande(NULL);
	}
	NbOctet = recvfrom (client_id, &Identification, sizeof (gchar) * NB_CARACTERE_IDENTIFICATION, 0, NULL, 0);
	if (NbOctet == -1){
#ifdef __LOG_ENABLE
		Log ( Donnee_Cle_Main, "[ERROR] Commun.h  [recvfrom] NbOctet == -1");
		Log (Donnee_Cle_Main, strerror (errno));
#endif
		Arret_Demande(NULL);
	}
	demmarrage_Thread (Communication_Reception_Donnee_Boucle, NULL);
}
