/* **********************************************************************
 * *                                                                    *
 * *                                                                    *
 * *                                                                    *
 * **********************************************************************
 * File: utils/custom/iris_agl_svr.c
 *
 *               COPYRIGHT (c) 1998, 1999, 2000, 2001  BY
 *          SIGMET INCORPORATED, WESTFORD MASSACHUSETTS, U.S.A.
 * 
 * THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED AND  COPIED
 * ONLY  IN  ACCORDANCE WITH  THE  TERMS  OF  SUCH  LICENSE  AND WITH THE
 * INCLUSION OF THE ABOVE COPYRIGHT NOTICE.  THIS SOFTWARE  OR  ANY OTHER
 * COPIES  THEREOF MAY NOT BE PROVIDED OR OTHERWISE MADE AVAILABLE TO ANY
 * OTHER PERSON.  NO TITLE TO AND OWNERSHIP OF  THE  SOFTWARE  IS  HEREBY
 * TRANSFERED.
 */

/*****
   This program performs the following functions:
   1) Receives product notification socket messages from an IRIS server
   2) When notified in (1), reads in a product and looks at the IRIS mode
   3) Listens to 1 or 2 AGL servers via sockets and monitors the landing direction
   4) Sends a socket message to the IRIS server requesting a mode
*****/

#include <errno.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <fcntl.h>

#include <sys/socket.h>
#include <netdb.h>
#include <sys/time.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <signal.h>
#include <unistd.h>

#include "inetlib.h"
#include "sigtypes.h"
#include "headers.h"
#include "product.h"
#include "setup.h"

const char *labels [] = {"msgid", "data-valid", "land-dir#1", "REH#1", "RCL#1",
	"land-dir#2", "REH#2", "RCL#2"};

static void sighup_handler (int signal_a);
static void sigio_handler (int signal_a);
void Lprintf(const char *log_str);
int connected_iris_mode = 0;
int iris_mode_s;
int logging = 0;
char log_str[200];
struct sigaction action;
FILE *log_file;

/*
  The config file is organized as follows and must be in this order:
  LOG     <0 or 1>
  NOTIFY  <iris_notify_PORT> <iris_notify_DIR>  (we listen to PORT for notification of inbound files in DIR)
  MODE    <iris_mode_server_NAME> <iris_mode_server_PORT>  (NAME and PORT where we send mode changes)
  FDPS    <fdps_1_NAME> <fdps_1_PORT>  (NAME and PORT of where we send HWWS messages)
  FDPS    <fdps_2_NAME> <fdps_2_PORT>  (NAME and PORT of where we send HWWS messages - this line is optional)
  AGL     <server_1_NAME> <server_1_PORT>  (NAME and port of AGL server we listen to)
  AGL     <server_2_NAME> <server_2_PORT>  (NAME and port of AGL server we listen to - this line is optional)
*/

struct runwayutil 
{
  int  runway_flag;
  char input_agl_server[10];
  char input_runway_I_rep[10];
  char output_runway_I_cmd[10];
  char input_runway_II_rep[10];
  char output_runway_II_cmd[10];
} *runwayutil_data;

struct alert_status
{
  char runway[4];
  char arena[4];
  char type[4];
  char level[4];
};

struct adb
{
  char year[4];
  char month[2];
  char day[2];
  char hour[2];
  char minute[2];
  char second[2];
  struct alert_status alert_status[14];
};

struct hwws_msg
{
  unsigned short msg_counter;
  unsigned short req_id ;
  unsigned short adb_len;
  struct adb adb;
};

#define PI FPI_P
#define ACCESS (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP)

int main (int argc, char ** argv)
{
  char server[2][50];
  char port[2][50];
  short iris_mode_port_num;
  int servercount = 0;
  int nowserver = 0;
  int iris_mode_send_to = 0;
  int pri_land_dir = 0;
  int sec_land_dir = 0;
  int i, j, k, n, t, answer, nodata=0;
  int agl_to_counter, alen;
  int iris_ms, iris_ss, agl_s, connected_agl, connected_iris_prod;
  int iris_pending = 0, agl_pending = 0;
  int  iflag, ifamily, iaddrsize;
  short u[50];
  struct timeval tv, tv1;
  int count, offset;
  int year_int, month_int, day_int, hour_int, minu_int, seco_int;
  fd_set afds, bfds;
  int fdps_s;
  short fdps_port_num;
  int fdps_send_count = 0;
  float faxis, fstrength;
  int istrength, warn_strength[14];
  char fdps_name[2][200], fdps_port[2][20];
  int fdps_servers = 0;
  time_t warn_time = 0;
  char iris_mode_name[200], iris_mode_port[20];
  char iris_port[20], iris_dir[200], buf[1024] ;
  char prod_file_name[5][200], report_mode[200], del_string[200];
  char tmp_str[200];
  char log_str[200];
  unsigned short msg_counter;
  unsigned int hit_mask;
  struct hwws_msg fdps_msg;
  struct protect_setup protect_buf;
  struct warning_results warning_buf;
  struct sline_results sline_buf;
  struct product_hdr prod_hdr;
  struct sockaddr_in fsin, servaddr_in, sin;
  struct sockaddr *pservaddr;
  struct hostent *hostptr;
  struct in_addr *paddress;
  int runway_key;
  FILE *config_file, *prod_file;

  action.sa_handler = sighup_handler;
  sigemptyset( &action.sa_mask );
  action.sa_flags = SA_RESTART;
  answer = sigaction( SIGHUP, &action, NULL );

  if ( (runway_key = shmget(0x01020e00, sizeof(struct runwayutil), 
          IPC_CREAT | ACCESS)) <= 0 )
  {
    perror("shmget");
    exit(0);   
  }
  if ( (runwayutil_data = (struct runwayutil *)shmat(runway_key, NULL, 0)) ==
          (struct runwayutil *) -1 )
  {
    perror("shmat");
    exit(0);
  }
  runwayutil_data->input_agl_server[0]    = '\0' ;
  runwayutil_data->input_runway_I_rep[0]  = '\0' ;
  runwayutil_data->input_runway_II_rep[0] = '\0' ;

  msg_counter = 0;
  fdps_msg.msg_counter = htons(msg_counter);
  fdps_msg.req_id = htons(508);
  fdps_msg.adb_len = htons((short)(sizeof(struct adb)));

  /*****
    Process the configuration file
  *****/
  if (argc != 2)
  {
    printf("usage: iris_interface <config file name>\n");
    exit(0);
  }

  if ((config_file = fopen(argv[1], "r")) == NULL)
  {
    sprintf(log_str, "Can not open config file: %s\n", argv[1]);
    printf(log_str);
    exit(-1);
  }

  answer = fscanf(config_file, "%s%s", tmp_str, log_str);
  if (answer <= 0 || strcmp(tmp_str, "LOG"))
  {
    printf("No valid LOG line!\n");
    exit(-2);
  }
  if (log_str[0] == '1') 
  {
    if ((log_file = fopen("/tmp/iris_interface.dat", "w")) == NULL)
    {
      printf("Can not open log file: /tmp/iris_interface.dat!\n");
      exit(-2);
    }
    else 
    {
      logging = 1;
      printf("Logging to file: /tmp/iris_interface.dat.\n");
    }
  }

  answer = fscanf(config_file, "%s%s%s", tmp_str, iris_port, iris_dir);
  if (answer <= 0 || strcmp(tmp_str, "NOTIFY"))
  {
    printf("No valid IRIS product notification port or directory!\n");
    exit(-2);
  }
  sprintf(log_str, "Using IRIS product notification port %s with directory %s.\n", iris_port, iris_dir);
  Lprintf(log_str);
  sprintf(del_string, "rm -rf %s*", iris_dir);
  system(del_string); 

  answer = fscanf(config_file, "%s%s%s", tmp_str, iris_mode_name, iris_mode_port);
  if (answer <= 0 || strcmp(tmp_str, "MODE"))
  {
    Lprintf("No valid IRIS mode change server / port listed.\n");
    exit(-2);
  }
  sprintf(log_str, "Using IRIS mode change server and port: %s %s\n", iris_mode_name, iris_mode_port);
  Lprintf(log_str);

  answer = fscanf(config_file, "%s%s%s", tmp_str, fdps_name[0], fdps_port[0]);
  if (answer <= 0 || strcmp(tmp_str, "FDPS"))
  {
    Lprintf("No FDPS server / port listed!\n");
    exit(-2);
  }
  fdps_servers = 1;
  sprintf(log_str, "Using FDPS server and port: %s %s\n", fdps_name[0], fdps_port[0]);
  Lprintf(log_str);

  answer = fscanf(config_file, "%s", tmp_str);
  if (answer <= 0)
  {
    Lprintf("No valid AGL server / port listed!\n");
    exit(-2);
  }

  if (strcmp(tmp_str, "FDPS") && strcmp(tmp_str, "AGL"))
  {
    Lprintf("No valid AGL server / port listed!\n");
    exit(-2);
  }

  if (!strcmp(tmp_str, "FDPS"))
  {
    answer = fscanf(config_file, "%s%s", fdps_name[1], fdps_port[1]);
    if (answer <= 0)
    {
      Lprintf("Invalid FDPS server name / port number!\n");
      exit(-2);
    }
    fdps_servers = 2;
    sprintf(log_str, "Using FDPS server and port: %s %s\n", fdps_name[1], fdps_port[1]);
    Lprintf(log_str);
  }
  else
  {
    answer = fscanf(config_file, "%s%s", server[0], port[0]);
    if (answer <= 0)
    {
      Lprintf("No valid AGL server / port listed!\n");
      exit(-2);
    }
    sprintf(log_str, "Using AGL server and port: %s %s\n", server[0], port[0]);
    Lprintf(log_str);
    servercount = 1;
  }

  answer = fscanf(config_file, "%s%s%s", tmp_str, server[servercount], port[servercount]);
  if (answer > 0)
  {
    if (strcmp(tmp_str, "AGL"))
    {
      Lprintf("Invalid AGL server / port listed!\n");
      exit(-2);
    }
    sprintf(log_str, "Using AGL server and port: %s %s\n", server[servercount], port[servercount]);
    Lprintf(log_str);
    servercount++;
  }
  else
  {
    if (servercount == 0)
    {
      Lprintf("No AGL server listed!\n");
      exit(-2);
    }
  }

  tmp_str[0] = '\0' ;
  if (servercount == 1)
  {
    answer = fscanf(config_file, "%s%s%s", tmp_str, server[1], port[1]);
    if (answer > 0)
    {
      if (strcmp(tmp_str, "AGL"))
      {
        Lprintf("Invalid AGL server / port listed!\n");
        exit(-2);
      }
      servercount = 2;
      sprintf(log_str, "Using AGL server and port: %s %s\n", server[1], port[1]);
      Lprintf(log_str);
    }
  }

  fclose(config_file);

  /*****
    Establish a socket to listen to so an IRIS server can send us notification
    messages about the transfer of products.
  *****/
  iris_ss = 0;
  memset ((char *) &sin, 0, sizeof (sin));
  sin.sin_family = AF_INET;
  sin.sin_addr.s_addr = htonl(INADDR_ANY);
  sin.sin_port = htons(atoi(iris_port));
  while(iris_ss <= 0)
  {
    iris_ss = socket (PF_INET, SOCK_STREAM, 0);
    if (iris_ss < 0) 
    {
      sprintf(log_str, "Socket call for IRIS product notify failed with errno: %d\n", errno);
      Lprintf(log_str);
    }
    else 
    {
      if (bind (iris_ss, (struct sockaddr *) &sin, sizeof (sin)) < 0) 
      {
        sprintf(log_str, "Bind call for IRIS product notify failed with errno: %d\n", errno);
        Lprintf(log_str);
	iris_ss = -1;
        close(iris_ss);
      }
      else
      {
        if (listen (iris_ss, 5) < 0) 
        {
          sprintf(log_str, "Listen call for IRIS product notify failed with errno: %d\n", errno);
          Lprintf(log_str);
	  iris_ss = -1;
          close(iris_ss);
        }
        else
        {
          Lprintf("Socket open for listening for IRIS product notifications\n");
          break;
        }
      }
    }
    Lprintf("Will try again in 5 seconds.\n");
    sleep(5);
  }

  tv.tv_sec = 0;
  tv.tv_usec = 0;
  tv1.tv_sec = 1;
  tv1.tv_usec = 0;
  agl_to_counter = 0;
  connected_agl = 0;
  connected_iris_prod = 0;
  agl_s = 0;
  iris_ms = 0;

  /*****
    The main loop of the program.  The program will cycle once per second.
    In this cycle, if will do the following in the following order:
    1) If not connected via a socket to an IRIS server that we send mode
       change messages to, try to establish this connection.
    2) If connected to an IRIS server for mode changes, then check to see
       if we have a mode update to send it, or check to see if a timer has
       expired afte which we send anyways regardless of if a mode change
       is being signaled.
    3) See if any connections are pending on the IRIS server socket that we
       listen to for product notifications.  If so, then open a socket
       for this server.
    4) If we do not have a connection established to an AGL server, then try
       to establish one.
    5) Listen to both the AGL socket and the IRIS product notification
       socket to see if any messages are pending.  If so, then process them.
  *****/
  while (1) 
  {
    runwayutil_data->runway_flag = 1;
    if (!strcmp(runwayutil_data->output_runway_I_cmd,  "32R")) pri_land_dir = 0;
    if (!strcmp(runwayutil_data->output_runway_I_cmd,  "14L")) pri_land_dir = 1;
    if (!strcmp(runwayutil_data->output_runway_II_cmd, "32L")) sec_land_dir = 0;
    if (!strcmp(runwayutil_data->output_runway_II_cmd, "14R")) sec_land_dir = 1;
    if (pri_land_dir == 0) strcpy(runwayutil_data->input_runway_I_rep,  "32R");
    if (pri_land_dir == 1) strcpy(runwayutil_data->input_runway_I_rep,  "14L");
    if (sec_land_dir == 0) strcpy(runwayutil_data->input_runway_II_rep, "32L");
    if (sec_land_dir == 1) strcpy(runwayutil_data->input_runway_II_rep, "14R");
    if (connected_agl)
      strncpy(runwayutil_data->input_agl_server, server[nowserver], 8);

    /*****
      1) If not connected via a socket to an IRIS server that we send mode
         change messages to, try to establish this connection.
    *****/
    if (!connected_iris_mode && !iris_pending)
    {
      iris_mode_send_to = 0;
      ifamily = AF_INET;
      hostptr = gethostbyname((char *)(&iris_mode_name[0]));
      if (hostptr != NULL)
      {
        memset( &servaddr_in, 0, sizeof(servaddr_in));
        servaddr_in.sin_family = ifamily;
        paddress = (struct in_addr *)hostptr->h_addr_list[0];
        servaddr_in.sin_addr = *paddress;
	iris_mode_port_num = atoi(iris_mode_port);
        servaddr_in.sin_port = htons(iris_mode_port_num);
        pservaddr = (struct sockaddr *)&servaddr_in;
        iaddrsize = sizeof( servaddr_in );
      }
      else
      {
	sprintf(log_str, "Error getting hostname: %s\n", iris_mode_name);
	Lprintf(log_str);
	goto SECTION2; 
      }

      iris_mode_s = socket(ifamily,SOCK_STREAM,0);
      if (iris_mode_s != -1)
      {
        /* Set up so that i/o is nonblocking */
        iflag = 1;
        answer = ioctl( iris_mode_s, FIONBIO, &iflag );
      }
      else
      {
	Lprintf("Socket open failed to IRIS mode change server.\n");
	goto SECTION2;
      }

      answer = connect(iris_mode_s, pservaddr, iaddrsize);
      if (answer >= 0)
      {
        /* Set up a signal handler for the SIGIO signal */
        action.sa_handler = sigio_handler;
        sigemptyset( &action.sa_mask );
        action.sa_flags = SA_RESTART;
        answer = sigaction( SIGIO, &action, NULL );
        /* Set up so that i/o causes the SIGIO signal */
	/*        iflag = getpid();
        answer  = ioctl( iris_mode_s, SIOCSPGRP, &iflag );
	*/
	{
	  pid_t iPid = getpid();
	  answer = fcntl( iris_mode_s, F_SETOWN, iPid );
	}

#ifdef LINUX
        answer = fcntl( iris_mode_s, F_SETFL, FASYNC );
#else
        iflag = 1;
        answer = ioctl( iris_mode_s, FIOASYNC, &iflag );
#endif
        iflag = 1;
        answer = ioctl( iris_mode_s, FIONBIO, &iflag );
	connected_iris_mode = 1;
	sprintf(log_str, "Connected successfully to IRIS mode change server %s port %s.\n", 
                 iris_mode_name, iris_mode_port);
        Lprintf(log_str);
      }
      else
      {
        if (errno == 245)
        {
          sprintf(log_str, "Connection pending to IRIS mode change server %s port %s.\n",
                   iris_mode_name, iris_mode_port);
          Lprintf(log_str);
          iris_pending = 1;
        }
        else
        {
          sprintf(log_str, "Connection failed to IRIS mode change server %s with errno = %d.\n",
                  iris_mode_name, errno);
          Lprintf(log_str);
          iris_pending = 0;
          close(iris_mode_s);
          iris_mode_s = 0;
        }   
      }
    }
    else
    {
      iris_mode_send_to++;
    }

    /*****     
    2) If connected to an IRIS server for mode changes, then check to see
       if we have a mode update to send it, or check to see if a timer has
       expired after which we send anyways regardless of if a mode change
       is being signaled.
    *****/
    SECTION2:
    if (connected_iris_mode && (iris_mode_send_to >= 5))
    {
      iris_mode_send_to = 0;
      strcpy(report_mode, "MODE ACTIVE");
      answer = send(iris_mode_s, report_mode, strlen(report_mode)+1, 0);
      sprintf(log_str, "Sending %s to IRIS mode change server.\n", report_mode);
      Lprintf(log_str);
      if (answer < 0)
      {
        sprintf(log_str, "Error errno = %d in sending to mode change messages\n.", errno);
        Lprintf(log_str);
      } 
    }

    /*****
      3) See if any connections are pending on the IRIS server socket that we
         listen to for product notifications.  If so, then accept this
         connection.
    *****/
    if (!connected_iris_prod)
    {
      if (iris_ms > 0)
      {
	close (iris_ms);
	iris_ms = 0;
      }
      
      FD_ZERO(&afds);
      FD_SET(iris_ss, &afds); 
      answer = select(32, &afds, NULL, NULL, &tv);
      switch (answer)
      {
	case 0: /* timeout */
	  break;

        case -1: /* error */
          sprintf(log_str, "select() for IRIS notification server returned errno %d\n", errno);
	  Lprintf(log_str);
          break;

        default:
          if (FD_ISSET(iris_ss, &afds))
	  {
	    iris_ms = accept(iris_ss, (struct sockaddr *) &fsin, (void *)&alen);
            if (iris_ms <= 0)
	    {
	      sprintf( log_str,
		       "Error errno = %d in accept() for IRIS notification server.\n",
		       errno);
	      Lprintf(log_str);
            }
            else
	    {
              iflag = 1;
              answer = ioctl( iris_ms, FIONBIO, &iflag );
	      Lprintf("Connection established to an IRIS notification server.\n");
	      connected_iris_prod = 1;
	    }
	  }
	  break;
      } /* end switch */
    } /* endif connected_iris_prod */	  

    /*****
      4) If we do not have a connection established to an AGL server, then try
         to establish one.
    *****/
    if (!connected_agl && !agl_pending)
    {
      if (agl_s > 0) 
      {
        Lprintf ("Closing connection to current AGL server.\n");
        close (agl_s);
	agl_s = 0;
      }

      hostptr = gethostbyname((char *)(&server[nowserver][0]));
      if (hostptr == NULL)
      {
        sprintf(log_str, "Gethostbyname failed for AGL server %s with errno %d\n", server[nowserver], errno);
        Lprintf(log_str);
        nodata++;
        nowserver = (nowserver+1) % servercount;
      }
      else 
      {
        memset( &servaddr_in, 0, sizeof(servaddr_in));
        servaddr_in.sin_family = ifamily;
        paddress = (struct in_addr *)hostptr->h_addr_list[0];
        servaddr_in.sin_addr = *paddress;
	iris_mode_port_num = atoi(port[nowserver]);
        servaddr_in.sin_port = htons(iris_mode_port_num);
        pservaddr = (struct sockaddr *)&servaddr_in;
        iaddrsize = sizeof( servaddr_in );

        agl_s = socket (AF_INET, SOCK_STREAM, 0);
        if (agl_s < 0) 
        {
          sprintf(log_str, "Socket call failed for AGL server with errno %d\n", errno);
          Lprintf(log_str);
        }
        else
        {
          iflag = 1;
          answer = ioctl( agl_s, FIONBIO, &iflag );
          answer = connect(agl_s, pservaddr, iaddrsize);
          if (answer >= 0)
          {
	    connected_agl = 1;
            agl_pending = 0;
	    strncpy(runwayutil_data->input_agl_server, server[nowserver], 8);
	    sprintf(log_str, "Connected successfully to AGL server %s port %s.\n",
                     server[nowserver], port[nowserver]);
            Lprintf(log_str);
            nowserver = (nowserver+1) % servercount;
          }
          else
          {
            if (errno == 245)
            {
              sprintf(log_str, "Connection pending to AGL server %s port %s.\n",
		          server[nowserver], port[nowserver]);
              Lprintf(log_str);
              agl_pending = 1;
            }
            else
            {
              sprintf(log_str, "Connection failed to AGL server %s with errno = %d\n", server[nowserver], errno);
              Lprintf(log_str);
              agl_pending = 0;
              close(agl_s);
              agl_s = 0;
              nodata++;
              nowserver = (nowserver+1) % servercount;
            }
          }
        }
      }
    } /* endif agl */

    /*****
      5) Listen to both the AGL socket and the IRIS product notification
         socket to see if any messages are pending.  If so, then process them.
    *****/
    FD_ZERO(&afds);
    FD_ZERO(&bfds);
    if (iris_pending) FD_SET(iris_mode_s, &bfds);
    if (agl_pending)  FD_SET(agl_s, &bfds);
    if (connected_iris_prod) FD_SET(iris_ms, &afds);
    if (connected_agl)  FD_SET(agl_s, &afds);
    answer = select(32, NULL, NULL, NULL, &tv1);
    answer = select(32, &afds, &bfds, NULL, &tv);
    switch (answer)
    {
      case -1: /* error */	
        sprintf(log_str, "select() for IRIS notification or AGL returned error (%d)\n", errno);
	Lprintf(log_str);
        break;
      default: /* got something */

        if (iris_pending)
        {
          if (FD_ISSET(iris_mode_s, &bfds))
          {
            hostptr = gethostbyname((char *)(&iris_mode_name[0]));
            if (hostptr != NULL)
            {
              memset( &servaddr_in, 0, sizeof(servaddr_in));
              servaddr_in.sin_family = ifamily;
              paddress = (struct in_addr *)hostptr->h_addr_list[0];
              servaddr_in.sin_addr = *paddress;
	      iris_mode_port_num = atoi(iris_mode_port);
              servaddr_in.sin_port = htons(iris_mode_port_num);
              pservaddr = (struct sockaddr *)&servaddr_in;
              iaddrsize = sizeof( servaddr_in );
              answer = connect(iris_mode_s, pservaddr, iaddrsize);
              if ((answer >= 0) || (answer < 0 && errno == 234))
              {
                /* Set up a signal handler for the SIGIO signal */
                action.sa_handler = sigio_handler;
                sigemptyset( &action.sa_mask );
                action.sa_flags = SA_RESTART;
                answer = sigaction( SIGIO, &action, NULL );
                /* Set up so that i/o causes the SIGIO signal */
		{
		  pid_t iPid = getpid();
		  answer = fcntl( iris_mode_s, F_SETOWN, iPid );
		}
#ifdef LINUX
                answer = fcntl( iris_mode_s, F_SETFL, FASYNC );
#else
                iflag = 1;
                answer = ioctl( iris_mode_s, FIOASYNC, &iflag );
#endif
                iflag = 1;
                answer = ioctl( iris_mode_s, FIONBIO, &iflag );
	        connected_iris_mode = 1;
                iris_pending = 0;
	        sprintf(log_str, "Connected successfully to IRIS mode change server %s.\n", iris_mode_name);
                Lprintf(log_str);
              }
              else
              {
                sprintf(log_str, "Connection failed to IRIS mode change server %s with errno = %d\n", iris_mode_name, errno);
                Lprintf(log_str);
                iris_pending = 0;
                close(iris_mode_s);
                iris_mode_s = 0;
              }
            }
            else
            {    
	      sprintf(log_str, "Error getting hostname: %s\n", iris_mode_name);
  	      Lprintf(log_str);
              iris_pending = 0;
              close(iris_mode_s);
              iris_mode_s = 0;
            }
          }
          else
          {
            iris_pending++;
            if (iris_pending == 30)
            {
              Lprintf ("IRIS mode change connection not established.  Will try again fresh.\n");
              iris_pending = 0;
              close(iris_mode_s);
              iris_mode_s = 0;
            }
          }
        }

        if (agl_pending)
        {
          if (FD_ISSET(agl_s, &bfds))
          {
            hostptr = gethostbyname((char *)(&server[nowserver][0]));
            if (hostptr != NULL)
            {
              memset( &servaddr_in, 0, sizeof(servaddr_in));
              servaddr_in.sin_family = ifamily;
              paddress = (struct in_addr *)hostptr->h_addr_list[0];
              servaddr_in.sin_addr = *paddress;
	      iris_mode_port_num = atoi(&port[nowserver][0]);
              servaddr_in.sin_port = htons(iris_mode_port_num);
              pservaddr = (struct sockaddr *)&servaddr_in;
              iaddrsize = sizeof( servaddr_in );
              answer = connect(agl_s, pservaddr, iaddrsize);
              if ((answer >= 0) || (answer < 0 && errno == 234))
              {
	        connected_agl = 1;
                agl_pending = 0;
	        strncpy(runwayutil_data->input_agl_server, server[nowserver], 8);
	        sprintf(log_str, "Connected successfully to AGL server %s.\n", server[nowserver]);
                Lprintf(log_str);
                nowserver = (nowserver+1) % servercount;
              }
              else
              {
                sprintf(log_str,"Connection failed to AGL server %s with errno = %d\n", server[nowserver], errno);
                Lprintf(log_str);
                agl_pending = 0;
                close(agl_s);
                agl_s = 0;
                nodata++;
                nowserver = (nowserver+1) % servercount;
              }
            }
            else
            {    
              sprintf(log_str,"Gethostbyname failed for AGL server %s with errno %d\n", server[nowserver], errno);
  	      Lprintf(log_str);
              agl_pending = 0;
              close(agl_s);
              agl_s = 0;
              nodata++;
              nowserver = (nowserver+1) % servercount;
            }
          }
          else
          {
            agl_pending++;
            if (agl_pending == 10)
            {
              Lprintf ("AGL server connection not established.  Will try again fresh.\n");
              agl_pending = 0;
              close(agl_s);
              agl_s = 0;
              nodata++;
              nowserver = (nowserver+1) % servercount;
            }
          }
        }

	if (iris_ms > 0)
	{
          if (FD_ISSET(iris_ms, &afds))
          {
	    Lprintf("Reading from IRIS notification socket.\n");
	    offset = 0;
	    do {
              n = recv(iris_ms, &buf[offset], 1024, 0);
	      offset += n;
	    } while (n > 0);
	    buf[offset] = '\0' ;
            n = 0;
	    if (offset > 0)
	    {
	      if (strncmp(&buf[n], "FILE", 4) == 0)
	      {
		count = 0;
                do {
		  sprintf(&prod_file_name[count][0], "%s%s", iris_dir, &buf[n+5]);
                  n = n + strlen(&buf[n]) + 1;
                  count++;
                } while(n < offset);
                for (i=0;i<count;i++)
		{
		  if( (prod_file = fopen(&prod_file_name[i][0], "r+b")) != 0 ) 
		  {
		    answer = fread(&prod_hdr, 1, PRODUCT_HDR_SIZE, prod_file);
		    switch (prod_hdr.pcf.iptype) 
		    {
                      case PROD_WARN:
		      case PROD_SLINE:   
                        warn_time = time(NULL);
                        fdps_send_count = 55;
		        sprintf(log_str, "Received WARN/SLINE product %s from IRIS.\n", &prod_file_name[i][0]);
		        Lprintf(log_str);

			for (j=0; j<7; j++)
			{
			  if (pri_land_dir == 1) memcpy(fdps_msg.adb.alert_status[j].runway, "14L ", 4);
			  else memcpy(fdps_msg.adb.alert_status[j].runway, "32R ", 4);
                        }
			for (j=7; j<14; j++)
			{
			  if (sec_land_dir == 1) memcpy(fdps_msg.adb.alert_status[j].runway, "14R ", 4);
			  else memcpy(fdps_msg.adb.alert_status[j].runway, "32L ", 4);
                        }
		        memcpy(fdps_msg.adb.alert_status[0].arena, "3MF ", 4);
		        memcpy(fdps_msg.adb.alert_status[1].arena, "2MF ", 4);
		        memcpy(fdps_msg.adb.alert_status[2].arena, "1MF ", 4);
		        memcpy(fdps_msg.adb.alert_status[3].arena, "RWY ", 4);
		        memcpy(fdps_msg.adb.alert_status[4].arena, "1MD ", 4);
		        memcpy(fdps_msg.adb.alert_status[5].arena, "2MD ", 4);
		        memcpy(fdps_msg.adb.alert_status[6].arena, "3MD ", 4);
		        memcpy(fdps_msg.adb.alert_status[7].arena, "3MF ", 4);
		        memcpy(fdps_msg.adb.alert_status[8].arena, "2MF ", 4);
		        memcpy(fdps_msg.adb.alert_status[9].arena, "1MF ", 4);
		        memcpy(fdps_msg.adb.alert_status[10].arena, "RWY ", 4);
		        memcpy(fdps_msg.adb.alert_status[11].arena, "1MD ", 4);
		        memcpy(fdps_msg.adb.alert_status[12].arena, "2MD ", 4);
		        memcpy(fdps_msg.adb.alert_status[13].arena, "3MD ", 4);
			for (j=0; j<14; j++)
			{
		          memcpy(fdps_msg.adb.alert_status[j].type, "    ", 4);
		          memcpy(fdps_msg.adb.alert_status[j].level, "    ", 4);
			  warn_strength[j] = 0;
			}  

                        hour_int = prod_hdr.pcf.ing_time.isec /
			             3600;
                        fdps_msg.adb.hour[0] = 48 + (hour_int / 10);
                        fdps_msg.adb.hour[1] = 48 + (hour_int % 10);
        
                        minu_int = (prod_hdr.pcf.ing_time.isec -
                                     (3600 * hour_int)) / 60;
                        fdps_msg.adb.minute[0] = 48 + (minu_int / 10);
                        fdps_msg.adb.minute[1] = 48 + (minu_int % 10);
        
                        seco_int = prod_hdr.pcf.ing_time.isec -
                                     ((3600 * hour_int) + (60 * minu_int));
                        fdps_msg.adb.second[0] = 48 + (seco_int / 10);
                        fdps_msg.adb.second[1] = 48 + (seco_int % 10);
        
			year_int = prod_hdr.pcf.ing_time.iyear;
			if (year_int >= 2000) 
			{
			  fdps_msg.adb.year[0] = 0x30 + 2;
			  fdps_msg.adb.year[1] = 0x30 + 0;
                        }
			else
			{
			  fdps_msg.adb.year[0] = 0x30 + 1;
			  fdps_msg.adb.year[1] = 0x30 + 9;
			}
			fdps_msg.adb.year[2] = 48 + ((year_int % 100) / 10);
			fdps_msg.adb.year[3] = 48 + (year_int % 10);

			month_int = prod_hdr.pcf.ing_time.imon;
                        fdps_msg.adb.month[0] = 48 + (month_int / 10);
                        fdps_msg.adb.month[1] = 48 + (month_int % 10);

			day_int = prod_hdr.pcf.ing_time.iday;
                        fdps_msg.adb.day[0] = 48 + (day_int / 10);
                        fdps_msg.adb.day[1] = 48 + (day_int % 10);

                        /* get the data out of the warn sline product */
                        /* read in the protected area info (1024 bytes) */
  		        answer = fread(&protect_buf, 1, sizeof(struct protect_setup),
		      	          prod_file);

		        if (prod_hdr.pcf.iptype == PROD_WARN) 
		        {
  		          answer = fread(&warning_buf, 1, sizeof(struct warning_results),
		      	            prod_file);
                          while (answer > 0)
			  {
                            /* do primary runway */
                            hit_mask = 0x00000001;
                            /* for each area on the primary runway */
                            for (j=0; j<7; j++)
                            {
                              if (pri_land_dir == 0) k = 6-j;
                              else k = j;
                              if (warning_buf.iprotect_mask & hit_mask)
			      {
                                faxis = ((float)(warning_buf.iEllipseMajor+warning_buf.iEllipseMinor))/200000.0;
                                fstrength = faxis * ((float)warning_buf.iaverage_value[0])/100.0;
                                fstrength *= 3600.0 / (1000.0*KM_PER_NM);  /* Convert to knots */
			        fstrength = (fstrength + 0.5);
			        istrength = (int)fstrength;
			        if (istrength >= 100) istrength = 99;
			        if (istrength >= warn_strength[k])
			        {
			          warn_strength[k] = istrength;
			          if (istrength < 10) sprintf(tmp_str, "0%dK-", istrength);
			          else sprintf(tmp_str, "%dK-", istrength);

			          memcpy(fdps_msg.adb.alert_status[k].level, tmp_str, 4);  

			          if (istrength < 30) memcpy(fdps_msg.adb.alert_status[k].type, "WSA ", 4);
			          else memcpy(fdps_msg.adb.alert_status[k].type, "MBA ", 4);
                                }
			      }
			      hit_mask = hit_mask << 1;
			    }

                            /* do secondary runway */
                            hit_mask = 0x00000080;
                            /* for each area on the secondary runway */
                            for (j=0; j<7; j++)
                            {
                              if (sec_land_dir == 0) k = 13-j;
                              else k = j + 7;
                              if (warning_buf.iprotect_mask & hit_mask)
			      {
                                faxis = ((float)(warning_buf.iEllipseMajor+warning_buf.iEllipseMinor))/200000.0;
                                fstrength = faxis * ((float)warning_buf.iaverage_value[0])/100.0;
                                fstrength *= 3600.0 / (1000.0*KM_PER_NM);  /* Convert to knots */
			        fstrength = (fstrength + 0.5);
			        istrength = (int)fstrength;
			        if (istrength >= 100) istrength = 99;
			        if (istrength >= warn_strength[k])
			        {
			          warn_strength[k] = istrength;
			          if (istrength < 10) sprintf(tmp_str, "0%dK-", istrength);
			          else sprintf(tmp_str, "%dK-", istrength);

			          memcpy(fdps_msg.adb.alert_status[k].level, tmp_str, 4);  

			          if (istrength < 30) memcpy(fdps_msg.adb.alert_status[k].type, "WSA ", 4);
			          else memcpy(fdps_msg.adb.alert_status[k].type, "MBA ", 4);
                                }
			      }
			      hit_mask = hit_mask << 1;
			    }
  		            answer = fread(&warning_buf, 1, sizeof(struct warning_results),
		      	             prod_file);
			  }
                        }

                        else /* must be a SLINE product */
			{
  		          answer = fread(&sline_buf, 1, sizeof(struct sline_results),
		      	            prod_file);
                          while (answer > 0)
			  {
                            /* do primary runway */
                            /* for each area on the primary runway */
                            for (j=0; j<7; j++)
                            {
                              if (pri_land_dir == 0) k = 6-j;
                              else k = j;
                              if (sline_buf.iprotect_etas[k] == 0)
			      {
				/* speed is in mm/s, must convert to knots */
				fstrength = 
				    (fabs((sline_buf.iref_wind_speed * 3600.0/1852000.0) * 
				    cos((320.0 * PI/180.0) - (sline_buf.iref_wind_direction * PI/32768)))) +
				    (fabs((sline_buf.iother_wind_speed * 3600.0/1852000.0) * 
				    cos((320.0 * PI/180.0) - (sline_buf.iother_wind_direction * PI/32768))));
			        fstrength = (fstrength + 0.5);
			        istrength = (int)fstrength;
			        if (istrength >= 100) istrength = 99;
			        if (istrength >= warn_strength[k])
			        {
			          warn_strength[k] = istrength;
			          if (istrength < 10) sprintf(tmp_str, "0%dK+", istrength);
			          else sprintf(tmp_str, "%dK+", istrength);
			          memcpy(fdps_msg.adb.alert_status[k].level, tmp_str, 4);  
			          memcpy(fdps_msg.adb.alert_status[k].type, "WSA ", 4);
                                }
			      }
			    }

                            /* do secondary runway */
                            /* for each area on the secondary runway */
                            for (j=0; j<7; j++)
                            {
                              if (sec_land_dir == 0) k = 13-j;
                              else k = j + 7;
                              if (sline_buf.iprotect_etas[k] == 0)
			      {
				fstrength = 
				    (fabs((sline_buf.iref_wind_speed * 3600.0/1852000.0) * 
				    cos((320.0 * PI/180.0) - (sline_buf.iref_wind_direction * PI/32768)))) +
				    (fabs((sline_buf.iother_wind_speed * 3600.0/1852000.0) * 
				    cos((320.0 * PI/180.0) - (sline_buf.iother_wind_direction * PI/32768))));
			        fstrength = (fstrength + 0.5);
			        istrength = (int)fstrength;
			        if (istrength >= 100) istrength = 99;
			        if (istrength >= warn_strength[k])
			        {
			          warn_strength[k] = istrength;
			          if (istrength < 10) sprintf(tmp_str, "0%dK+", istrength);
			          else sprintf(tmp_str, "%dK+", istrength);
			          memcpy(fdps_msg.adb.alert_status[k].level, tmp_str, 4);  
			          memcpy(fdps_msg.adb.alert_status[k].type, "WSA ", 4);
                                }
			      }
			    }
  		            answer = fread(&sline_buf, 1, sizeof(struct sline_results),
		      	             prod_file);
			  }
                        }
		        break;

                      default:
		        sprintf(log_str, "Received a notification of another type of product: %s\n", &prod_file_name[i][0]);
		        Lprintf(log_str);
                        break;
                    } /* end switch */
		    fclose(prod_file);
		  } /* end fopen */
		  else
		  {
		    sprintf(log_str, "Unable to open the product: %s\n", &prod_file_name[i][0]);
		    Lprintf(log_str);
                  }
                } /* end for count */
              } /* end strncmp FILE */
	      else
	      {
	        sprintf(log_str, "Received unknown string from IRIS notification server: %s\n", buf);
		Lprintf(log_str);
              }
	      sprintf(del_string, "rm -rf %s*", iris_dir);
	      system(del_string); 
	    } /* end offset > 0 */
	    else if (offset == 0)
	    {
	      connected_iris_prod = 0;
	      Lprintf("Closing connection to IRIS notification server.  Recv returned 0.\n");
            }
	    else
	    {
	      sprintf(log_str, 
		 "Error errno = %d when reading IRIS notification server.  Closing connection.\n", errno);
	      Lprintf(log_str);
	      connected_iris_prod = 0;
            }
          }
        }
	if (agl_s > 0)
	{
          if(FD_ISSET(agl_s, &afds))
          {
            agl_to_counter = 0;
            n = read(agl_s, u, 100);
            if (n == 16)
            {
	      Lprintf("AGL reports: ");
	      for (t=0; t<8; t++)
	      {
		u[t] = ntohs(u[t]);
                sprintf(log_str, "%s=%d ", labels[t], u[t]);
	        Lprintf(log_str);
              }
	      Lprintf("\n");
	      if (u[0] != 10)
	      {
		Lprintf("AGL message ID is incorrect.  Connection closed.\n");
		runwayutil_data->input_agl_server[0] = '\0' ;
	        connected_agl = 0;
	      }
              else if (u[1] == 0) 
              {
		Lprintf("AGL flag indicates data INVALID.  Connection closed.\n");
		runwayutil_data->input_agl_server[0] = '\0' ;
	        connected_agl = 0;
              }
              else
              {
                nodata=0;
              }
	      if (connected_agl) 
              {
		if (!runwayutil_data->output_runway_I_cmd[0] || 
		    !strcmp(runwayutil_data->output_runway_I_cmd, "AGL"))
		{     
                  pri_land_dir = (int)u[2];
                }
		if (!runwayutil_data->output_runway_II_cmd[0] || 
		    !strcmp(runwayutil_data->output_runway_II_cmd, "AGL"))
                {
                  sec_land_dir = (int)u[5];
		} 
              }
            }
            else
            {
	      Lprintf("AGL read not correct length.  Connection closed.\n");
	      runwayutil_data->input_agl_server[0] = '\0' ;
	      connected_agl = 0;
            }
          }
          else
          {
            if (connected_agl)
            {
              agl_to_counter++;
              if (agl_to_counter == 10)
              {
                Lprintf ("AGL server timeout, closing connection.\n");
	        runwayutil_data->input_agl_server[0] = '\0' ;
                connected_agl = 0;
                agl_to_counter = 0;
              }
            }
          }
        }
        break;
    } /* end switch */

    if (fdps_send_count >= 55)
    {
      if ((time(NULL) - warn_time) < 450)
      {
        for (i=0; i<fdps_servers; i++)
        {
          if ((fdps_s = socket(PF_INET, SOCK_DGRAM, 0)) < 0)
          {
            sprintf(log_str, "Cannot get FDPS socket.  errno = %d\n", errno);
  	    Lprintf(log_str);
          }
          else
          {
            iflag = 1;
            answer = ioctl( fdps_s, FIONBIO, &iflag );

            hostptr = gethostbyname((char *)(&fdps_name[i][0]));
            if (hostptr == NULL)
            {
 	      sprintf(log_str, "Error getting hostname: %s\n", &fdps_name[i][0]);
	      Lprintf(log_str);
	      close(fdps_s);
            }
	    else
	    {
              memset( &servaddr_in, 0, sizeof(servaddr_in));
              servaddr_in.sin_family = ifamily;
              paddress = (struct in_addr *)hostptr->h_addr_list[0];
              servaddr_in.sin_addr = *paddress;
	      fdps_port_num = atoi(&fdps_port[i][0]);
              servaddr_in.sin_port = htons(fdps_port_num);
              pservaddr = (struct sockaddr *)&servaddr_in;
              iaddrsize = sizeof( servaddr_in );
              if (sendto(fdps_s, &fdps_msg, sizeof(struct hwws_msg), 0, pservaddr,
	  	 iaddrsize) < 0)
	      {
	        sprintf(log_str, "Cannot send FDPS message to %s.  errno = %d\n", &fdps_name[i][0], errno);
	        Lprintf(log_str);
              }
	      else
	      {
                sprintf(log_str, "Sent HWWS msg to FDPS server %s.\n", &fdps_name[i][0]);
                Lprintf(log_str);
	      }
	      close(fdps_s);
            }
          }
        }
        msg_counter++;
        fdps_msg.msg_counter = htons(msg_counter);
      }
      fdps_send_count = 0;
    }
    fdps_send_count++;
  } /* end while(1) */
}

static void sighup_handler(int signal_a)
{
  action.sa_handler = sighup_handler;
  sigemptyset( &action.sa_mask );
  action.sa_flags = SA_RESTART;
  sigaction( SIGHUP, &action, NULL );
}

static void sigio_handler( int signal_a )
{
  struct sigaction action;
  char data[100];
  int isize;

  isize = recv( iris_mode_s, data, 99, 0 );
  if (isize > 0)
  {
    /* We got some valid data here.  Add terminating NULL, then process */
    data[isize] = 0;
    if (0 == strcmp( data, "NOP" ))
    {
    }
    else if (0 == strcmp( data, "EXIT" ))
    {
    }
    else
    {
      sprintf(log_str, "recv read unknown message: '%s' from IRIS mode change server.\n", data );
      Lprintf(log_str);
    }
  }
  else if (isize < 0)
  {
    if (errno != EWOULDBLOCK)
    {
      sprintf(log_str, "recv error errno = %d from IRIS mode change server.\n", errno);
      Lprintf(log_str);
    }
  }
  else
  {
    /* Zero size indicates that the socket has been closed at the other end */
    Lprintf ("Link broken to IRIS mode change server - closing connection.\n");
    action.sa_handler = SIG_IGN;
    sigemptyset( &action.sa_mask );
    action.sa_flags = SA_RESTART;
    sigaction( SIGIO, &action, NULL );
    connected_iris_mode = 0;
    close(iris_mode_s);
    iris_mode_s = 0;
  }
  return;
}

void Lprintf(const char *log_str)
{
  if (!logging) return;
  fprintf(log_file, "%s", log_str);
  fflush(log_file);
  return;
}
