/*
 * b_sample.c -- Sample program using the blocking API
 *
 * Copyright (C) 2005, Ranch Networks, Inc.
 *
 * 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.
 *
 * 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 General Public License for more details.
 *
 * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 *
 * Author : Srivatsa Chivukula <srivatsa@ranchnetworks.com>
 *
 */

/*
 * The flow of the program is as follows:
 *  1. Initialize the library.
 *  2. Open the notification channel to the middlebox, on which the SIMCO service is running.
 *  3. Do notification session establish (NE).
 *  4. Do notification session authenticate (NA).
 *  5. Open the SIMCO communication channel to the middlebox.
 *  6. Do SIMCO session establish (SE).
 *  7. Do SIMCO session authenticate (SA).
 *  8. Do policy enable rule (PER) request.
 *  9. Do policy lifetime change (PLC) for the rule set in step 8.
 * 10. Do policy reserve rule (PRR).
 * 11. Do policy enable rule after reservation (PEA) for the rule reserved in step 10.
 * 12. Do policy rule status (PRS) for the rule set in steps 10 and 11.
 * 13. Do policy rule list (PRL) for all the rules set on the middlebox.
 * 14. Do session terminate request on communication (ST) and notification (NT) channels.
 *
 * The program will wait in an infinite loop to listen for notifications.
 */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <pthread.h>

#include "simco_client.h"

static int done = 0;
static char *cert = "/home/srivatsa/certificate/server.pem";

static void *notify_thread(void *);

int main(int argc, char** argv)
{
  int con = -1, notif_con = -1;
  char *host = "192.162.162.215";
  int ret, temp = 0;  
  simcoPacket_t spacket;

  int *rules, nrules, i;

  pthread_t thread;
  void *thread_result;

  char *login = "root";
  char *password = "ranchroot";

  if (argc >= 3)
    {
      login = argv[1];
      password = argv[2];
    }

  /* Initialize the library */
  if (!mc_init(cert))
    {
      return -1;
    }
  printf("Trying to CONNECT to host %s\n", host);  
  /*  Get the notification channel */
  if ((notif_con = mc_notif_connect(host)) == -1)
    {
      mc_close();
      return -1;
    }
  printf("CONNECTED to host %s\n", host);  
  /* Notification session establish */
  if ((ret = simco_ne_b(notif_con)) != 0)
    {
      printf("Could not establish SIMCO connection\n");
      mc_notif_disconnect(notif_con);
      mc_close();
      return -1;
    }

  /* Notification session authenticate */
  if ((ret = simco_na_b(notif_con, login, password)) != 0)
    {
      printf("Could not authenticate with Login: %s Passsword: %s \n", login, password);
      simco_nt_b(notif_con);
      mc_notif_disconnect(notif_con);
      mc_close();
      return -1;
    }

  /* Create a thread to continously read on notification channel */
  if (pthread_create(&thread, NULL, notify_thread, (void*)notif_con) != 0)
    {
      printf("Tread creation failed. Exiting\n");
      simco_nt_b(notif_con);
      mc_notif_disconnect(notif_con);
      mc_close();
      return -1;
    }  

  /* Get the SIMCO communication channel */
  if ((con = mc_comm_connect(host)) == -1)
    {
      printf("CONNECTION to host %s failed\n", host);  
      goto end;
    }
  printf("CONNECTED to host %s\n", host);  

  /* SIMCO ping */
  if ((ret = simco_ping_b(con)) != 0)
    {
      printf("Could not ping\n");
      mc_comm_disconnect(con);
      goto end;
    }

  /* SIMCO session establish */
  if ((ret = simco_se_b(con)) != 0)
    {
      printf("Could not establish session\n");
      mc_comm_disconnect(con);
      goto end;
    }
  
  /* session authenticate */
  if ((ret = simco_sa_b(con, login, password)) != 0)
    {
      printf("Could not authenticate with Login: %s Passsword: %s \n", login, password);
      simco_st_b(con);
      mc_comm_disconnect(con);
      goto end;
    }

  /* PER */
  memset((void*)&spacket, 0, sizeof(simcoPacket_t));
  strcpy(spacket.internal_ip, "192.2.1.1");
  strcpy(spacket.external_ip, "192.2.1.2");
  spacket.internal_port = 1;
  spacket.external_port = 2;
  spacket.lifetime = 60;
  if ((ret = simco_per_b(con, &spacket)) != 0)
    {
      fprintf(stderr, "Error - simco_per_b: 0x%x\n", ret);
      simco_st_b(con);
      mc_comm_disconnect(con);
      goto end;
    }
  fprintf(stderr, "RuleId:%d GroupId:%d Lifetime:%d Outside_IP: %s Outside_Port:%d Status: %d\n",
          spacket.ruleId, spacket.groupId, spacket.lifetime, spacket.outside_ip, spacket.outside_port, spacket.status);

  temp = spacket.ruleId;

  /*  PLC */
  memset((void*)&spacket, 0, sizeof(simcoPacket_t));
  spacket.ruleId = temp;
  spacket.lifetime = 60;
  if ((ret = simco_plc_b(con, &spacket)) != 0)
    {
      fprintf(stderr, "Error - simco_plc_b: 0x%x\n", ret);
      simco_st_b(con);
      mc_comm_disconnect(con);
      goto end;
    }
  fprintf(stderr, "RuleId:%d Lifetime:%d Status: %d\n", spacket.ruleId, spacket.lifetime, spacket.status);
  
  /* PRR */
  memset((void*)&spacket, 0, sizeof(simcoPacket_t));
  spacket.lifetime = 60;
  if ((ret = simco_prr_b(con, &spacket)) != 0)
    {
      fprintf(stderr, "Error - simco_prr_b: 0x%x\n", ret);
      simco_st_b(con);
      mc_comm_disconnect(con);
      goto end;
    }
  fprintf(stderr, "RuleId:%d GroupId:%d Lifetime:%d Outside_IP: %s Outside_Port:%d Status: %d\n",
          spacket.ruleId, spacket.groupId, spacket.lifetime, spacket.outside_ip, spacket.outside_port, spacket.status);

  /* PEA */
  strcpy(spacket.internal_ip, "192.2.3.1");
  strcpy(spacket.external_ip, "192.2.1.2");
  spacket.internal_port = 3;
  spacket.external_port = 4;
  spacket.lifetime = 60;
  if ((ret = simco_pba_b(con, &spacket)) != 0)
    {
      fprintf(stderr, "Error - simco_pba_b: 0x%x\n", ret);
      simco_st_b(con);
      mc_comm_disconnect(con);
      goto end;
    }
  fprintf(stderr, "RuleId:%d GroupId:%d Lifetime:%d Outside_IP: %s Outside_Port:%d Status: %d\n",
          spacket.ruleId, spacket.groupId, spacket.lifetime, spacket.outside_ip, spacket.outside_port, spacket.status);
  
  temp = spacket.ruleId;

  /* PRS */
  memset((void*)&spacket, 0, sizeof(simcoPacket_t));
  spacket.ruleId = temp;
  if ((ret = simco_prs_b(con, &spacket)) != 0)
    {
      fprintf(stderr, "Error - simco_prs_b: 0x%x\n", ret);
      simco_st_b(con);
      mc_comm_disconnect(con);
      goto end;
    }
  fprintf(stderr, "RuleId:%d GroupId:%d Lifetime:%d Outside_IP: %s Outside_Port:%d Status: %d\n",
          spacket.ruleId, spacket.groupId, spacket.lifetime, spacket.outside_ip, spacket.outside_port, spacket.status);

  /* PRL */
  nrules = 128;
  rules = (int *)malloc(nrules*sizeof(int));
  if ((ret = simco_prl_b(con, &rules, &nrules)) != 0)
    {
      fprintf(stderr, "Error - simco_prl_b: 0x%x\n", ret);
      simco_st_b(con);
      mc_comm_disconnect(con);
      free(rules);
      goto end;
    }
  printf("Number of rules returned: %d\n", nrules);
  for (i = 0; i < nrules; i++)
    printf("Rule Id: %d\n", rules[i]);
  free(rules);

  simco_st_b(con);
  mc_comm_disconnect(con);

 end:

  /* Waiting for notifications. Type ctrl-c to end the program */
  while (1);

  done = 1;
  pthread_join(thread, &thread_result);

  simco_nt_b(notif_con);
  mc_notif_disconnect(notif_con);

  mc_close();
  return ret;
}


static void *notify_thread(void *ncon)
{
  int ret;
  simcoPacket_t notif;

  while (!done)
    {
      /* Keep reading on the notification channel */
      memset((void*)&notif, 0, sizeof(simcoPacket_t));
      if ((ret = simco_notif_read((int)ncon, &notif)) < 0)
	{
	  fprintf(stderr, "Error - simco_notif_read: 0x%x\n", ret);
	  break;
	}
      if (notif.status)
	fprintf(stderr, "NOTIFICATION:- RuleId:%d Lifetime:%d Type: %d\n", notif.ruleId, notif.lifetime, notif.status);
      //else
      //fprintf(stderr, "read timed-out. listening again...\n");
    }
  return NULL;
}

