/* modem guardian angel deamon */

#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>

#define FALSE 0
#define TRUE 1
#define BOOL int

/* Indiqués en secondes, >= 1 */
unsigned int intervalle_ping = 2;
unsigned int intervalle_ping_apres_abandon = 10;

unsigned int max_perdu = 5;
unsigned int max_attente = 15;

unsigned int tab_attente_critique[] =
  {2, 10, 60, 360, 360, 360, 360};

/* Indiqués en occurences, >= 1 */
unsigned int max_reset_rate_consecutifs = 3;
unsigned int abandon_reset_rate_consecutifs = 10;

/* #tab_attente_critique =
   abandon_reset_rate_consecutifs
   - max_reset_rate_consecutifs */
   
char *ip = "192.168.2.254";
char *cmd_abandon = "poff -a";
char *cmd_reprise = "pon dsl-provider";
char *portcom = "/dev/ttyS0";

char *flog = "/var/log/mgad.log";

BOOL recu_SIGTERM = FALSE;

BOOL debug = FALSE;

#define DEBUG(msg) if (debug) fprintf(stderr, "%d: %s\n", __LINE__, msg);

void logmesg(char *flog, char *s) {
  FILE *f;
  time_t tt = time(NULL);
  struct tm t = *localtime(&tt);

  f = fopen(flog, "a");
  fprintf(f, "[%02d:%02d:%02d %04d-%02d-%02d] %s\n", t.tm_hour, t.tm_min, t.tm_sec, 1900+t.tm_year, t.tm_mon+1, t.tm_mday, s);
  fclose(f);
}

int parse_options(int argc, char **argv) {
  int i = 0;
  
  while (i < argc) {

    i++;
  }
  
  return TRUE;
}

void SIGTERM_handler(int foo) {
  recu_SIGTERM = TRUE;
}

BOOL pingmodem(char *ip, unsigned int temps) {
  char *cmdf = "fping -c 1 -t %d %s >/dev/null 2>/dev/null";
  char *cmd;
  int reponse;
  
  cmd = malloc(sizeof(char) * (strlen(ip) + strlen(cmdf) + 128));

  sprintf(cmd, cmdf, temps * 1000, ip);
  reponse = system(cmd);
  
  free(cmd);
  
  return (reponse == 0);
}

void resetmodem() {
  FILE *f;
  
  DEBUG("reset modem...");
  f = fopen(portcom, "r");
  sleep(2);
  fclose(f);
  DEBUG("reset effectué");
}

int main(int argc, char **argv) {
  int compteur_perdu;
  int attente_allumage;
  int reset_rate_consecutifs;
  int ready;
  
  logmesg(flog, "Démarrage de mgad");
  
  if (!parse_options(argc, argv)) {
    /*usage();*/
  }
  
  DEBUG("signal handling");
  if (signal(SIGTERM, SIGTERM_handler) == SIG_ERR) {
    printf("Impossible de capter le signal SIGTERM\n");
  }
  
  do {
    DEBUG("init début boucle principale");
    compteur_perdu = 0;
    attente_allumage = 0;
    reset_rate_consecutifs = 0;
    ready = FALSE;
    
    do {
      do {
        DEBUG("pingmodem...");
        if (pingmodem(ip, intervalle_ping)) {
          DEBUG("réponse");
          compteur_perdu = 0;
          reset_rate_consecutifs = 0;
          if (!ready) {
            logmesg(flog, "Le modem est fonctionnel");
            ready = TRUE;
          }
        } else {
          DEBUG("sans réponse");
          if (ready) {
            DEBUG("compteur_perdu++");
            compteur_perdu += intervalle_ping;
          } else {
            DEBUG("attente_allumage++");
            attente_allumage += intervalle_ping;
          }
        }
      } while ((compteur_perdu < max_perdu)
        && (attente_allumage < max_attente)
        && (!recu_SIGTERM));
      
      if (!recu_SIGTERM) {
         logmesg(flog, "Problème détecté...");
         DEBUG("problème détecté");

        if (!ready) {
          DEBUG("reset raté");
          logmesg(flog, "Il s'agit d'un reset raté");
          reset_rate_consecutifs++;
        } else {
          DEBUG("plantage modem");
          logmesg(flog, "Il s'agit d'un plantage modem");
        }

        if (reset_rate_consecutifs < abandon_reset_rate_consecutifs) {
          if (reset_rate_consecutifs >= max_reset_rate_consecutifs) {
            logmesg(flog, "Le modem ne répond plus aux resets, entrée en attente critique");
            DEBUG("attente critique");
            sleep(60 * tab_attente_critique[
              reset_rate_consecutifs - max_reset_rate_consecutifs]);
          }

          logmesg(flog, "Reset du modem");
          resetmodem();

          attente_allumage = 0;
          compteur_perdu = 0;
          ready = FALSE;
        }
      }
    } while ((reset_rate_consecutifs < abandon_reset_rate_consecutifs)
      && (!recu_SIGTERM));

  if (!recu_SIGTERM) {
    logmesg(flog, "Abandon");
    DEBUG("abandon");

    DEBUG("appel cmd_abandon");
    logmesg(flog, "Lancement de la commande d'abandon");
    system(cmd_abandon);

    DEBUG("boucle lente");
    logmesg(flog, "Entree en boucle lente");
    do {} while ((!pingmodem(ip, intervalle_ping_apres_abandon)) && (!recu_SIGTERM));

    if (!recu_SIGTERM) {
      logmesg(flog, "Reprise");
      DEBUG("appel cmd_reprise");
      system(cmd_reprise);    
    }
  }

  } while (!recu_SIGTERM);
  
  logmesg(flog, "Arrêt de mgad");
  DEBUG("recu SIGTERM");
}
