/***************************************************************
*  
*  Update these defines:
*  MY_NOME is the path to your home directory where the sshr_cron will run.
*  MY_SSH_TARGET   is the node name or IP of the machine you ware attaching
*                  to.  (Your home machine).
*  MY_IDRSA        Name of the id_rsa file in the .ssh directory when it is not
*                  in it's "live" name.
*                  The alternate name means that it only is active when we make	
*                  the connection.  The default version is probably good.
*  
***************************************************************/

#define MY_HOME       "/home/stymar"
#define MY_SSH_TARGET "styma8a"
#define MY_IDRSA      "id_rsa8a"
#define SSH_PATH      "/usr/bin/ssh"
#define NOHUP_PATH    "/usr/bin/nohup"


/*******************************************************************

 PROGRAM:  sshr_cron - SSH Roll Your Own VPN Monitor keep alive

 DESCRIPTION:
   This program is made to be called by cron from the user setting
   up the personal roll your own VPN.  It checks to see if the
   echo port forwarded through ssh is open.  If not, it kills and
   restarts the ssh service.

 INPUT ARGUMENTS: (see manual page for descriptions)
     -c<cmd>        -  The ssh command to execute
     -d             -  debug option
     -e <name>      -  Name to search for in the process table to restart server
     -f <pscmd>     -  PS command to run to find process to restart server
     -h             -  Print help message and quit
     -p <port>      -  echo server port at this end.
     -r             -  force restart even if everything is OK
     -t             -  Use the daytime service instead of the echo service

 INTERNAL ROUTINES:
   echo_test             -  Connect to the remote echo server via a forwarded port.
   wait_for_data         -  Wait for response from the echo server
   restart_ssh           -  Restart the ssh command on the local node
   kill_process          -  Kill a process after getting the PID from the ps output.
   catch                 -  Interupt handler
   system_w_timeout      -  Call the system command with a timeout
   usage                 -  Print usage prompt and exit.

*******************************************************************/

#include <stdio.h>                  /* /usr/include/stdio.h       */
#include <string.h>                 /* /usr/include/string.h      */
#include <sys/types.h>              /* /usr/include/sys/types.h   */
#include <fcntl.h>                  /* /usr/include/fcntl.h       */
#include <sys/times.h>              /* /usr/include/sys/times.h   */
#include <time.h>                   /* /usr/include/time.h        */
#include <signal.h>                 /* /usr/include/signal.h      */
#include <setjmp.h>                 /* /usr/include/setjmp.h      */
#include <errno.h>                  /* /usr/include/errno.h       */
#include <unistd.h>                 /* /usr/include/unistd.h      */
#include <stdlib.h>                 /* /usr/include/stdlib.h      */

#include <sys/socket.h>      /* /usr/include/sys/socket.h   */
#include <netinet/in.h>      /* /usr/include/netinet/in.h   */
#include <arpa/inet.h>       /* /usr/include/arpa/inet.h    */
#include <netdb.h>           /* /usr/include/netdb.h        */
#ifndef FD_ZERO
#include <sys/select.h>      /* /usr/include/sys/select.h   */
#endif
#include <malloc.h>          /* /usr/include/malloc.h       */

#ifdef solaris
#define SA1  (struct sockaddr *)
#else
#define SA1
#endif


#ifndef True
#define True 1
#endif
#ifndef False
#define False 0
#endif



/***************************************************************
*  
*  Values from command line arguments
*  
***************************************************************/

/*  -c   <cmd>             */
char   command[256]               = "mv " MY_HOME "/.ssh/" MY_IDRSA " " MY_HOME "/.ssh/id_rsa;" NOHUP_PATH " " SSH_PATH " -N -f " MY_SSH_TARGET ";mv " MY_HOME "/.ssh/id_rsa  " MY_HOME "/.ssh/" MY_IDRSA;

/*  -d   Debug option  */ 
int    debug                      = 0;

/*  -e   <string>                */
char   ps_search[256]             = " -N -f " MY_SSH_TARGET;

/*  -f   <ps command>   */
#ifdef linux
char   ps_cmd[256]                = "ps auxw";
#else
char   ps_cmd[256]                = "ps -ef -o \"user,pid,ppid,stime,tty,time,args\""; 
#endif

/*  -p   <echo server query port>  */
char   local_forwarded_port[32]= "7777";

/* -r force restart */
int    force_restart              = False;

/* -t use daytime server */
int    use_daytime                = False;

/***************************************************************
*  
*  Definition for CURRENT_TIME
*  This macro may be substituted where you need a pointer to
*  char.  such as:
*  printf("%s\n", CURRENT_TIME);
*  The current time is what the pointer points to.  You can
*  change _t1_ and _t3_ to something else if needed.
*  the _t3_ manipulations take off the \n from the string
*  returned by asctime.
*  If you copy this definition, you need an include for  <time.h>

*  
***************************************************************/

time_t       _t1_;
char         *_t3_;
#define CURRENT_TIME    ((_t3_ = asctime(localtime((_t1_ = time(NULL), &_t1_)))),(_t3_[strlen(_t3_)-1]='\0'), _t3_ )


/***************************************************************
*  
*  Local prototypes
*  
***************************************************************/

static int  echo_test(const char *echo_local_forward_port);

static int  daytime_test(const char *time_local_forward_port);

static int wait_for_data(int fd);

static void restart_ssh(const char *command, const char *ps_search, const char *ps_cmd);

static void kill_process(const char *ps_line);

void  catch();

static int  system_w_timeout(const char  *cmd);
jmp_buf         setjmp_env; /* used when alarm goes off */

static void usage(void);

static int tcp_open(const char  *host, const char *service, int reserved, char *msg);


/***************************************************************
*  
*  Main Entry Point
*  
***************************************************************/

int main (int  argc, char  *argv[])
{
char                   ch;
int                    i;
int                    rc;


/******************************************
 check the arguments to get the host name, 
 mvs process name (from offer), 
 and the Debug parm.
*****************************************/

while ((ch = getopt(argc, argv, "c:de:f:hp:rt")) != EOF)
switch (ch)
{
case 'c' :
   strncpy(command, optarg, sizeof(command));
   break;

case 'd' :
   debug++;
   break;

case 'e' :
   strncpy(ps_search, optarg, sizeof(ps_search));
   break;

case 'f' :
   strncpy(ps_cmd, optarg, sizeof(ps_cmd));
   break;

case 'h' :
   usage();
   /* usage does not return */
   break;

case 'p' :   /* echo server forwarded port  */
   strncpy(local_forwarded_port, optarg, sizeof(local_forwarded_port));
   break;

case 'r' :
   force_restart = True;
   break;

case 't' :
   use_daytime = True;
   break;

default  :
   usage();
   /* usage does not return */
   break;
} /* end of switch on ch */



/***************************************************************
*  Dump the args is -d was specified.
***************************************************************/
if (debug)
   {
      fprintf(stderr, "Running with options:\n");
      fprintf(stderr, "    -c <command>         = %s\n", command);
      fprintf(stderr, "    -e <ps_search_str>   = %s\n", ps_search);
      fprintf(stderr, "    -f <ps_cmd>          = %s\n", ps_cmd);
      fprintf(stderr, "    -p <forwarded_port>  = %s\n", local_forwarded_port);
      fprintf(stderr, "    -r                   = %s\n", (force_restart ? "True" : "False"));
      fprintf(stderr, "    -t                   = %s\n", (use_daytime ? "True" : "False"));
   }


/***************************************************************
*  One last sanity check on the args
***************************************************************/
if (optind < argc)
   {
      fprintf(stderr, "%s takes no positional arguments -> \"%s\"\n", argv[0], argv[optind]);
      usage(); /* usage does not return */
   }

/***************************************************************
*  See if we can contact the echo server.  If not, or if -r
*  was specified, do the restart.
***************************************************************/
if (!force_restart)
   {
      if (use_daytime)
         rc = daytime_test(local_forwarded_port);
      else
         rc = echo_test(local_forwarded_port);
   }
else
   rc = 1;

if (rc != 0)
   restart_ssh(command, ps_search, ps_cmd);

return(0);
}  /* end of main procedure */


/*******************************************************************

 MODULE: echo_test - Connect to the remote echo server via a forwarded port.

 DESCRIPTION:
    Use the forwarded ssh port to connect to the tcp echo server on
    the remote node.  This tests to see if the port forwarding is working.

 INPUT PARAMETERS: 
  1. echo_local_forward_port - This is the local port which is forwarded
                               to the echo server on the remote host.
 FUNCTIONS:
  1.  Set an alarm and a longjump  so we can time out the tcp open in
      case it hanges.

  2.  Open a connection to the remote echo server via the local forwarded
      port.  

  3.  Write a message out and read it badc/

 RETURNED VALUES:
   rc    -   return code
             0  -  All is well, the echo server was contacted
            -1  -  error,   Message output
 
*******************************************************************/

#define TEST_ECHO_MESSAGE "Test Echo Message"

static int  echo_test(const char *echo_local_forward_port)
{
int                    i;
int                    cli_addr_size;
int                    rc;
int                    nread;
int                    sockfd;
char                   msg_buff[1024];

rc = setjmp(setjmp_env);
if (rc == 0)
   {
      signal(SIGALRM, catch);   /* Timeout doing the socket open call */
      alarm(30); /* set alarm for 30 seconds, more than enough time */

      sockfd = tcp_open("localhost", echo_local_forward_port, 0, msg_buff);
      if (sockfd < 0)
         {
            fprintf(stderr, "Could not connect to echo server port localhost:%s (%s)\n", echo_local_forward_port, strerror(errno));
            fputs(msg_buff, stderr);
            rc = -1;
         }
      else
         if (debug)
            fprintf(stderr, "Connected to localhost : %s\n", echo_local_forward_port );
   }
else
   fprintf(stderr, "?  Timeout opening tcp socket\n");

alarm(0); /* cancel the alarm */
signal(SIGALRM, SIG_DFL);   /* Timeout doing a system call */

if (rc == 0)
   {
      nread = send(sockfd, TEST_ECHO_MESSAGE, sizeof(TEST_ECHO_MESSAGE), 0);
      if (nread < 0)
         {
            fprintf(stderr, "Send error on echo server port localhost:%s (%s)\n", echo_local_forward_port, strerror(errno));
            rc = -1;
         }
      if (rc == 0)
         {
            nread = wait_for_data(sockfd); /* returns result of a select */
            if (nread > 0)
               {
                  nread = recv(sockfd, msg_buff, sizeof(msg_buff), 0);
                  if (nread < 0)
                     {
                        fprintf(stderr, "Recv error on echo server port localhost:%s (%s)\n", echo_local_forward_port, strerror(errno));
                        rc = -1;
                     }
                  else
                     if (nread != sizeof(TEST_ECHO_MESSAGE))
                        {
                           msg_buff[nread] = '\0';
                           fprintf(stderr, "Data sent not echoed - Sent %d bytes '%s' Received %d bytes '%s'\n", sizeof(TEST_ECHO_MESSAGE), TEST_ECHO_MESSAGE, nread, msg_buff);
                           rc = -1;
                        }
                     else
                        {
                           if (debug)
                              {
                                 msg_buff[nread] = '\0';
                                 fprintf(stderr, "Echo worked - Sent '%s' Received '%s'\n", TEST_ECHO_MESSAGE, msg_buff);
                              }
                           rc = 0;
                        }
               }
            else
               if (nread < 0)
                  {
                     fprintf(stderr, "Select failure on echo server port localhost:%s (%s)\n", echo_local_forward_port, strerror(errno));
                     rc = -1;
                  }
               else
                  {
                     fprintf(stderr, "Select timed out on echo server port localhost:%s\n", echo_local_forward_port);
                     rc = -1;
                  }
         }
      close(sockfd);
   }

return(rc);

} /* end of echo_test */


/*******************************************************************

 MODULE: daytime_test - Connect to the remote http server via a forwarded port.

 DESCRIPTION:
    Use the forwarded ssh port to connect to the daytime server on
    the remote node.  This server just sends the current time back.
    This tests to see if the port forwarding is working.

 INPUT PARAMETERS: 
  1. daytime_test_local_forward_port - This is the local port which is forwarded
                               to the daytime server  (port 13) on the remote host.
 FUNCTIONS:
  1.  Set an alarm and a longjump  so we can time out the tcp open in
      case it hanges.

  2.  Open a connection to the remote http server via the local forwarded
      port.  

  3.  Write a message out and read it badc/

 RETURNED VALUES:
   rc    -   return code
             0  -  All is well, the http server was contacted
            -1  -  error,   Message output
 
*******************************************************************/


static int  daytime_test(const char *daytime_test_local_forward_port)
{
int                    i;
int                    cli_addr_size;
int                    rc;
int                    nread;
int                    sockfd;
char                   msg_buff[8192];

rc = setjmp(setjmp_env);
if (rc == 0)
   {
      signal(SIGALRM, catch);   /* Timeout doing the socket open call */
      alarm(30); /* set alarm for 30 seconds, more than enough time */

      sockfd = tcp_open("localhost", daytime_test_local_forward_port, 0, msg_buff);
      if (sockfd < 0)
         {
            fprintf(stderr, "Could not connect to daytime server port localhost:%s (%s)\n", daytime_test_local_forward_port, strerror(errno));
            fputs(msg_buff, stderr);
            rc = -1;
         }

   }
else
   fprintf(stderr, "?  Timeout opening tcp socket\n");

alarm(0); /* cancel the alarm */
signal(SIGALRM, SIG_DFL);   /* Timeout doing a system call */

if (rc == 0)
   {
      nread = wait_for_data(sockfd); /* returns result of a select */
      if (nread > 0)
         {
            nread = recv(sockfd, msg_buff, sizeof(msg_buff)-1, 0);
            if (nread < 0)
               {
                  fprintf(stderr, "Recv error on daytime server port localhost:%s\n", daytime_test_local_forward_port);
                  rc = -1;
               }
            else
               if (nread == 0)
                  {
                     fprintf(stderr, "No data read from daytime server on forwarded local port localhost:%s\n", daytime_test_local_forward_port);
                     rc = -1;
                  }
               else
                  {
                     if (debug)
                        {
                           msg_buff[nread] = '\0';
                           fprintf(stderr, "%s (%d bytes)\n", msg_buff, nread);
                        }
                     rc = 0;
                  }
         }
      else
         if (nread < 0)
            {
               fprintf(stderr, "Select failure on daytime server port localhost:%s (%s)\n", daytime_test_local_forward_port, strerror(errno));
               rc = -1;
            }
         else
            {
               fprintf(stderr, "Select timed out on daytime server port localhost:%s\n", daytime_test_local_forward_port);
               rc = -1;
            }
      close(sockfd);
   }

return(rc);

} /* end of daytime_test */


/************************************************************************

NAME:      wait_for_data -  Wait for response from the echo server

PURPOSE:    This routine is called after a sendto to wait for the
            server to respond.  The select is used to allow a
            timeout after 10 seconds.

PARAMETERS:
   1.  sockfd              -  int (INPUT)
                              This is the UDP datagram socket file descriptor.

FUNCTIONS :
   1.   Issue a select on the file descriptor with a timeout of 10 seconds.

RETURNED VALUE:
   rc   -    int
            >0  -  Datagram ready
             0  -  select timed out
            -1  -  Timeout

*************************************************************************/

#ifdef _INCLUDE_HPUX_SOURCE
#define HT (int *)
#else
#define HT (fd_set *)
#endif

static int wait_for_data(int fd)
{
fd_set                readfds;
struct timeval        time_out;
int                   nfound;

FD_ZERO(&readfds);
FD_SET(fd, &readfds);

/* wait 75 seconds for data to be ready */
time_out.tv_sec = 75;
time_out.tv_usec = 0;


nfound = select(fd+1, HT &readfds, NULL, NULL, &time_out);

return(nfound);

} /* end of wait_for_data  */



/************************************************************************

NAME:      restart_ssh -  Restart the ssh command on the local node

PURPOSE:    This routine is called to restart an ssh command.  It is called when
            the server cannot respond and also after a SIGUSR1.

PARAMETERS:
   1.  command          -  pointer to const char (INPUT)
                           This is the command used to restart the ssh

   2.  ps_search        -  pointer to const char (INPUT)
                           This is the string to search for in the ps output.

   2.  ps_cmd           -  pointer to const char (INPUT)
                           This is the ps command to popen to look for the
                           command to restart.

FUNCTIONS :
   1.   Popen the ps command.

   2.   Read through the list looking for the ssh command to stop.

   3.   If found call the routine to kill the process.

   4.   Use the system command to restart the server.

*************************************************************************/

static void restart_ssh(const char *ssh_cmd, const char *ps_search, const char *ps_cmd)
{
int                    rc;
char                   cmd_buff[1024];
char                   msg_buff[2048];
char                   subj[80];
char                  *p;
FILE                  *ps_stream;

ps_stream = popen(ps_cmd, "r");
if (ps_stream != NULL)
   {
      while(fgets(msg_buff, sizeof(msg_buff), ps_stream) != NULL)
      {
         if (strstr(msg_buff, ps_search) != NULL)
           {
              fprintf(stderr, "Killing process %s", msg_buff);
               kill_process(msg_buff);
           }
      }
      rc = pclose(ps_stream);
      if (rc < 0)
         fprintf(stderr, "pclose failure (%s)\n", strerror(errno));
   }
else
   fprintf(stderr, "Popen failed for \"%s\" (%s)\n", ps_cmd, strerror(errno));

errno = 0;
rc = system_w_timeout(ssh_cmd);

sprintf(msg_buff, "Return code from system call to restart = %d (%s)\n", rc, (errno ? strerror(errno) : "no error"));

} /* end of restart_ssh */


/************************************************************************

NAME:      kill_process -  Kill a process given its PS line.

PURPOSE:    This routine is called to kill an ssh command.
            The process table entry for the command is passed.
            The second token in the line is the PID

PARAMETERS:
   1.  ps_line          -  pointer to const char (INPUT)
                           This is the line from the ps coomand which has
                           the PID of the process to kill as the second token.

FUNCTIONS :
   1.   Parse the PS line to get the PID.

   2.   Hit it with a sigterm (15)

   3.   Hit it with a sigkill (9)

   4.   Report any errors.

*************************************************************************/

static void kill_process(const char *ps_line)
{
int                    rc;
char                   cmd_buff[1024];
char                   user[256];
int                    pid_to_kill;

if (sscanf(ps_line, "%s %d", user, &pid_to_kill) == 2)
   {
      rc  = kill(pid_to_kill, SIGTERM); /* try to kill it nicely */
      if (rc != 0)
         fprintf(stderr, "SIGTERM to process %d failed (%s)\n", pid_to_kill, strerror(errno));

      rc = kill(pid_to_kill, SIGKILL); /* blast it */
      if ((rc != 0) && (errno != ESRCH))
         fprintf(stderr, "SIGTERM to process %d failed (%s)\n", pid_to_kill, strerror(errno));
      fprintf(stderr, "sent kill to %d\n", pid_to_kill);
   }
else
   {
      fprintf(stderr, "Cannot parse process id from second token in line \"%s\"\n", ps_line);
   }


}


/*******************************************************************
*
* MODULE: catch  - interupt handler
*
* DESCRIPTION:
*     This routine will catch assorted signals and deal with them.
*     It is called asyncronously by the system.
*
*
* PARAMETERS: 
*     1.  sig    -    int (INPUT)
*                     The signal handler is passed the signal number.
*
*
* 
*******************************************************************/

void catch(int sig)
{

switch(sig)
{
case SIGHUP: /* got a hup */
   break;

case SIGALRM: /* got a SIGALRM, something timed out */
   fprintf(stderr, "Caught SIGALRM\n");
   longjmp(setjmp_env, 1);
   break;

default:
   fprintf(stderr, "Unexpected signal trapped %d\n", sig);
   break; /* makes lint happy */
}

signal(sig, catch); /* reset signal handler */

}


/*******************************************************************
*
* MODULE: system_w_timeout      -  Call the system command with a timeout

*
* DESCRIPTION:
*     This routine issues the system call to execute a program or
*     shell script.  It has a timeout to deal with the node hanging.
*
*
* PARAMETERS: 
*     1.  cmd    -    pointer to const char (INPUT)
*                     This is the command to pass to the system command.
*
* FUNCTIONS:
*     1.  Set the signal handler to trap alarm signals.  If the handler
*         catches the alarm signal, a longjmp will take place.
*
*     2.  Set an alarm clock for 10 minutes.  If it goes off, we hare
*         hung up for sure.
*
*     3.  Issue the system call.
*
*     4.  If the call completes, cancel the alarm and the signal handler.
*
*     5.  If the timeout occurs, the longjmp will return to the setjmp
*         position with a non-zero return code.  
*
* RETURNED VALUE:
*     rc   -   int
*              The return code from system, or setjmp in the event 
*              of a timeout.
*
* 
*******************************************************************/

static int  system_w_timeout(const char  *cmd)
{
int    rc = 0;
FILE  *sys_stream;
char    msg_buff[1024];

rc = setjmp(setjmp_env);
if (rc == 0)
   {
      signal(SIGALRM, catch);   /* Timeout doing a system call */
      alarm(120); /* set alarm for 2 minutes, more than enough time */

      rc = system(cmd);
      fprintf(stderr, "rc = %d, from call to system \"%s\"\n", rc, cmd);
      if (rc != 0)
         fprintf(stderr, "%s\n", strerror(errno));


   }
else
   fprintf(stderr, "?  Timeout processing system command \"%s\"\n", cmd);

alarm(0); /* cancel the alarm */
signal(SIGALRM, SIG_DFL);   /* Timeout doing a system call */

return(rc);

} /* end of system_w_timeout */



/************************************************************************

NAME:      tcp_open - open a TCP socket for a client

PURPOSE:   This routine opens a socket for a client.  The clien specifies
           who he wants to talk to.

PARAMETERS:
   1.   host      -  pointer to char (INPUT)
                     This is the host to connect to.
                     It may be the name or the dotted number address.
 
   2.   service    - pointer to char (INPUT)
                     The name of the service to connect to.  This can
                     be either a character string port number or a
                     service name.  ei,  "1069" or na_server

   3.   reserved   - int (INPUT)
                     This flag specifies that a reserved port is to be
                     used instead of a normal port.  Root only.

FUNCTIONS :

   1.   Determine whether the passed service is a service name or a port
        number.
   2.   Determine whether the passed host is a dotted TCP/IP Internet
        address or a name of the host.
   3.   Bind to either a reserved or a non-reserved port based on the 
        reseved parm
   4.   Do a connect to the host.
   5.   If the connect works and debug is on, dump the socket data.

OUTPUTS:  

   fd   -   file descriptor
            The socket file descriptor is returned.  On error, -1 is returned.

OTHER OUTPUTS:  

   stderr -  debugging and error messages are written to stderr.


*************************************************************************/

static int tcp_open(const char  *host, const char *service, int reserved, char *msg)
{
struct sockaddr_in     tcp_srv_addr;   /* servers' Internet socket addr */

int                    fd;
#if !defined(OMVS) && !defined(WIN32)
int                    resvport;
#endif
unsigned long          inaddr;
struct servent        *sp;
struct hostent        *hp;
char                   scrap[50];
int                    server_port;
int                    count;
char                   lcl_msg[256];

#ifdef WIN32
init_sock();
#endif

*msg = '\0';

/***************************************************************
*  
*  Initialize the server's Internet address structure.
*  Service can be either a string of digits representing
*  a port or a service name.  We use sscanf to tell the
*  difference.  If count is 1, everything was digits.
*  If count is 2 or 0, this is a service name.
*  
***************************************************************/

memset((char *) &tcp_srv_addr, 0, sizeof(tcp_srv_addr));
tcp_srv_addr.sin_family = AF_INET;

count = sscanf(service, "%d%s", &server_port, scrap);
if (count != 1) /* not all digits, must be a server name */
   {
#ifdef DEBUG_OUTPUT
      if (debug > 2)
         fprintf(stderr, "Assuming %s is a service name\n", service);
#endif

      if ((sp = getservbyname(service, "tcp")) == NULL)
         {
#ifdef WIN32
            sprintf(lcl_msg, "?    tcp_open:  Cannot get port information for service name %s (%s)\n", service, getWSAmsg(NULL, 0));
#else
            sprintf(lcl_msg, "?    tcp_open:  Cannot get port information for service name %s (%s)\n", service, strerror(errno));
#endif
            strcat(msg, lcl_msg);
            return(-1);
         }
      tcp_srv_addr.sin_port = sp->s_port;

#ifdef DEBUG_OUTPUT
      if (debug > 2)
         fprintf(stderr, "%s is port %d\n", service, ntohs(tcp_srv_addr.sin_port));
#endif
   }
else
   {
#ifdef DEBUG_OUTPUT
      if (debug > 2)
         fprintf(stderr, "Assuming %s is a port number\n", service);
#endif

      tcp_srv_addr.sin_port = htons((short)server_port);
   }

/***************************************************************
*  
*  Try to use the host address as a dotted-decimal number.  If
*  this fails, try to get the host value by name.
*  
***************************************************************/

if ((inaddr = inet_addr(host)) != -1)
   {
      /* it worked, it's dotted decimal */
      memcpy((char *)&tcp_srv_addr.sin_addr, (char *)&inaddr, sizeof(inaddr));

#ifdef DEBUG_OUTPUT
      if (debug > 2)
         fprintf(stderr, "%s is a dotted Internet address\n", host);
#endif
   }
else
   {
      if ((hp = gethostbyname(host)) == NULL)
         {
#ifdef WIN32
            sprintf(lcl_msg, "?    tcp_open:  Cannot convert hostname %s to an internet address(%s)\n", host, getWSAmsg(NULL, 0));
#else
            sprintf(lcl_msg, "?    tcp_open:  Cannot convert hostname %s to an internet address(%s)\n", host, strerror(errno));
#endif
            strcat(msg, lcl_msg);
            return(-1);
         }
      memcpy((char *)&tcp_srv_addr.sin_addr, hp->h_addr, hp->h_length);

#ifdef DEBUG_OUTPUT
      if (debug > 2)
         {
            fprintf(stderr, "%s is a host name\n", host);
            fprintf(stderr, "            host addr:  %s\n", inet_ntoa(*(struct in_addr *)(hp->h_addr)));
         }
#endif
   }

/***************************************************************
*  
*  Now take care of the client side.  Get a socket, either
*  regular or reserved depending upon the parm.
*  
***************************************************************/

#if !defined(OMVS) && !defined(WIN32)
if (reserved)
   {
#ifdef DEBUG_OUTPUT
      if (debug > 2)
         fprintf(stderr, "Requesting reserved port\n");
#endif

      resvport = IPPORT_RESERVED - 1;
      if ((fd = rresvport(&resvport)) < 0)
         {
            sprintf(lcl_msg, "?    tcp_open:  Cannot get a reserved TCP port for service %s on host %s (%s)\n", service, host, strerror(errno));
            strcat(msg, lcl_msg);
            return(-1);
         }
   }
else
#endif
   {
#ifdef DEBUG_OUTPUT
      if (debug > 2)
         fprintf(stderr, "Requesting default port\n");
#endif

#ifdef WIN32
      if ((fd = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
         {
            sprintf(lcl_msg, "?    tcp_open:  Cannot get a socket file descriptor for service %s on host %s (%s)\n", service, host, getWSAmsg(NULL, 0));
            strcat(msg, lcl_msg);
            return(-1);
         }
#else
      if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
         {
            sprintf(lcl_msg, "?    tcp_open:  Cannot get a socket file descriptor for service %s on host %s (%s)\n", service, host, strerror(errno));
            strcat(msg, lcl_msg);
            return(-1);
         }
#endif
   }


/***************************************************************
*  
*  Now we are ready to establish the connection
*  
***************************************************************/

if (connect(fd, (struct sockaddr *)&tcp_srv_addr, sizeof(tcp_srv_addr)) < 0)
   {
#ifdef WIN32
      sprintf(lcl_msg, "?    tcp_open:  Cannot connect to service %s on host %s (%s)\n", service, host, getWSAmsg(NULL, 0));
#else
      sprintf(lcl_msg, "?    tcp_open:  Cannot connect to service %s on host %s (%s)\n", service, host, strerror(errno));
#endif
      strcat(msg, lcl_msg);
      close(fd);
      return(-1);
   }
 
#ifdef DEBUG_OUTPUT
if (debug > 2)
   {
      fprintf(stderr, "Socket file descriptor: %d\n", fd);
      display_port(fd, DISPLAY_PORT_REMOTE, DISPLAY_PORT_VERBOSE);
      display_port(fd, DISPLAY_PORT_LOCAL, DISPLAY_PORT_VERBOSE);
   } 
#endif
return(fd);  /* all is ok */


} /* end of tcp_open */



 /***
 *
 * Usage
 *
 * Print a blurb saying how to invoke this program.
 *
 */

static void usage(void)
{
    fprintf(stderr, "usage: sshr_cron [-c<cmd>] [-d] [-e<string>] [-f<cmd>] [-l<port>] [-r]\n");
    fprintf(stderr, "       -c<cmd>        -  The ssh command to execute\n");
    fprintf(stderr, "       -d             -  debug option\n");
    fprintf(stderr, "       -h             -  print this help message\n");
    fprintf(stderr, "       -p <port>      -  echo server port at this end.\n");
    fprintf(stderr, "       -e <string>    -  Name to search for in the process table to restart server\n");
    fprintf(stderr, "       -f <pscmd>     -  PS command to run to find process to restart server\n");
    fprintf(stderr, "       -r             -  Force restart\n");
    fprintf(stderr, "       -t             -  Use the daytime service instead of the echo service\n");

    exit(1);
}