#if !defined(lint) && !defined(__INSIGHT__)
static char sos__rcsid[] = "make_conn.c,v 1.1.1.1 1995/06/16 21:10:49 seth Exp";
static char sos__copyright[] = "Copyright (c) 1994, 1995 SOS Corporation";
static char sos__contact[] = "SOS Corporation <sos-info@soscorp.com> +1 800 SOS UNIX";
#endif /* not lint */

/*
 * ++Copyright Released Product++
 *
 * Copyright (c) 1994, 1995 Sources of Supply Corporation ("SOS").
 * All rights reserved.
 *
 * The SOS Released Product License Agreement specifies the terms and
 * conditions for redistribution.  You may find the License Agreement
 * in the file LICENSE.
 *
 * SOS Corporation
 * 461 5th Ave.; 16th floor
 * New York, NY 10017
 *
 * +1 800 SOS UNIX
 * <sos-info@soscorp.com>
 *
 * --Copyright Released Product--
 */

/*
 * External entry points for core Brimstone functions
 */

#include "sos.h"
#include "interface.h"

static void sos_Connection_timeout();
static struct sigaction old_action;	/* Caches the old sigvec.  */
static struct sigaction timeout = SIGACTIONDEFINE( (void *)sos_Connection_timeout, 0, _INTERRUPT_SYSCALLS_ );

static int TIMEDOUT = 0;



/*
 * Trivial timeout handler so I can catch SIGALRM without aborting
 * If connect really timesout, the system call will return interupted
 */
static void
sos_Connection_timeout()
{
  TIMEDOUT = 1;

  /*
   * Reset your old action vector to whatever it was
   */
  sigaction(SIGALRM, (struct sigaction *)&old_action,
	    (struct sigaction *)NULL);
  return;
}



/*
 * Brimstone make_conn
 *
 * In addition to libsos make_conn, it performs ACL checks
 *
 * Print state information on verbose if (verbose)
 */
int
bs_make_conn(char *hoststring, int numport, int timeout_val, int socopts, char *username, struct sos_conninfo *sourceinfo, FILE *verbose)
{
  struct hostent *hostp;	/* Library return value */
  struct sockaddr_in svc_addr;	/* Name of the service on host */
  int sock = -1;		/* Connection_socket */
  int one = 1;
  char **haddrs;
  int oldtime;
  int ret;

  /*
   * We need to sneak our timeout values
   * without disturbing everything else
   */
  oldtime = alarm(timeout_val);	/* Timeout alarm */
  sigaction(SIGALRM, (struct sigaction *)&timeout,
	    (struct sigaction *)&old_action);

  /*
   * Set the association structure.
   */
  memset((caddr_t) & svc_addr, 0, sizeof(svc_addr));
  svc_addr.sin_family = AF_INET;

  /*
   * Translate port string -> port number
   */
  svc_addr.sin_port = htons(numport);

  /*
   * Get the hostent containing all addresses
   *
   * (Note: if hoststring is an dotted quad
   * it will NOT be looked up in DNS)
   */
  if ( (hostp=sos_getmcbyfoo(hoststring)) == NULL )
    {
      sock = -2;
      goto exit;
    }

  /* Try to connect to all A records */
  for (haddrs = hostp->h_addr_list; *haddrs; haddrs++)
    {
      memcpy((caddr_t)&svc_addr.sin_addr, *haddrs, hostp->h_length);
      TIMEDOUT = 0;

      if (verbose)
	{
	  fprintf(verbose, "Trying... %s port %d.",
		  inet_ntoa(svc_addr.sin_addr), numport);
	  fflush(verbose);
	}

      /* Permission checking */
      ret = BS_CheckACL_Num(username, sourceinfo->addr,sourceinfo->port,svc_addr.sin_addr,numport);
      if (ret != AUTH_SUCCEED)
	{
	  if (ret == AUTH_FAIL)
	    {
	      soslog(SOSLOG_NOTICE, SOSLOG_TYPE_EVENT, 0,
		     "checkacl: DENY: user %s denied permission srcaddr: %s, srcport: %d, dstaddr: %s [%s], dstport: %d: %s\n",
		     username,
		     sourceinfo->printhost, sourceinfo->port,
		     hoststring, inet_ntoa(svc_addr.sin_addr), numport,
		     bs_auth_extended);
	    }
	  else
	    {
	      soslog(SOSLOG_ERR, SOSLOG_TYPE_CONDITION, 1,
		     "checkacl: Error checking ACL: %s", bs_auth_extended);
	    }
	  if (verbose)
	    {
	      fprintf(verbose, "  Permission denied\r\n");
	      fflush(verbose);
	    }
	  continue;
	}
      if (TIMEDOUT) { if (verbose) fprintf(verbose, "  Timed out.\r\n"); continue; }

      /* Creat a new socket */
      alarm(timeout_val);
      if ((sock = socket(svc_addr.sin_family, SOCK_STREAM, 0)) < 0)
	{
	  if (TIMEDOUT) { continue; }
	  goto exit;
	}
      if (TIMEDOUT) { if (verbose) fprintf(verbose, "  Timed out.\r\n"); close(sock); sock = -1; continue; }

      /* Set the options on this socket */
      alarm(timeout_val);
      if (socopts)
	if (setsockopt(sock, SOL_SOCKET, socopts, (char *)&one, sizeof(one)) < 0)
	  {
	    if (TIMEDOUT) { if (verbose) fprintf(verbose, "  Timed out.\r\n"); close(sock); sock = -1; continue; }
	    close(sock);
	    sock = -1;
	    goto exit;
	  }

      /* Try to connect to this new address */
      alarm(timeout_val);
      if ((connect(sock, (struct sockaddr *)&svc_addr, sizeof(svc_addr))) < 0)
	{
	  if (TIMEDOUT)
	    {
	      if (verbose) fprintf(verbose,"  Connection timed out.\r\n");
	    }
	  else
	    {
	      if (verbose) fprintf(verbose,"  Connection refused.\r\n");
	    }
	    
	  close(sock);
	  sock = -1;
	  continue;
	}

      /* WE WON!!! */
      if (verbose)
	{
	  fprintf(verbose, "  Accepted.\r\n");
	  fflush(verbose);
	}
      break;
    }

 exit:
  sigaction(SIGALRM, (struct sigaction *)&old_action,
	    (struct sigaction *)NULL);
  alarm(oldtime);		/* Cancel alarm request */

  return (sock);
}

	
