/**********************************************************************
 * ti library's initialization routine
 *
 * $Author: brlewis $
 * $Source: /mit/techinfodev/src/libti/RCS/open.c,v $
 * $Header: /mit/techinfodev/src/libti/RCS/open.c,v 4.3 1995/04/10 20:21:57 brlewis Exp $
 *
 * Copyright 1991 by the Massachusetts Institute of Technology.
 *
 * For copying and distribution information, please see the file
 * <mit-copyright.h>.
 **********************************************************************/

#include <mit-copyright.h>

#ifndef lint
static char rcsid_ti_open_c[] = "$Header: /mit/techinfodev/src/libti/RCS/open.c,v 4.3 1995/04/10 20:21:57 brlewis Exp $";
#endif /* lint */

#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <fcntl.h>
#include <ctype.h>
#include <ti/memory.h>
#include <ti/ti.h>
#ifdef USE_KERBEROS
#include <krb_err.h>
#endif

/**********************************************************************
 * ti_open(char *hostname, char *portname, TI **tip)
 *	caller sets hostname, portname (NULL means use default)
 *
 * - initializes everything for ti library
 * - connects to server
 * - fills in TI structure
 * - returns error code
 **********************************************************************/

long
ti_open(hostname, portname, tip)
     char *hostname, *portname;
     TI **tip;
{
  long code;
  struct hostent *hp;
  extern int h_errno;
  int i, portnum;
  struct servent *sp;
#if defined(POSIX) || defined(_POSIX_SOURCE)
  sigset_t posixmask;
#endif

  /* NULL means use default */
  if (!hostname) hostname = TI_DEF_HOST;
  if (!portname) portname = TI_DEF_PORT;

  /* initialize if this is first connection */
  if (!ti_nconnections)
    {
      initialize_ti_error_table();
      initialize_tiS_error_table();
#ifdef USE_KERBEROS
      initialize_krb_error_table();
#endif
      memset(ti_connections, 0, TI_MAX_OPEN * sizeof(TI));

      /* don't get killed if the server closes the connection */
#if defined(POSIX) || defined(_POSIX_SOURCE)
      sigemptyset(&posixmask);
      sigaddset(&posixmask, SIGPIPE);
      sigprocmask(SIG_BLOCK, &posixmask, (sigset_t *)0);
#else
      sigblock(sigmask(SIGPIPE)); /* XXX what about Mac, DOS? */
#endif
    }

  /* resolve hostname */
  hp = gethostbyname(hostname);
  if (hp == NULL)
    {
      /* set error context and return error code */
      strcpy(ti_context, hostname);
      switch(h_errno)
	{
	case HOST_NOT_FOUND:
	  return(TI_ERR_HOST_NOT_FOUND);
	case TRY_AGAIN:
	  return(TI_ERR_TRY_AGAIN);
	case NO_RECOVERY:
	  return(TI_ERR_NO_RECOVERY);
	case NO_ADDRESS:
	  return(TI_ERR_NO_ADDRESS);
	default:
	  return(TI_ERR_HOST);
	}
    }

  /* resolve portname */
  if (isdigit(*portname))
    portnum = htons(atoi(portname));/***/
  else
    {
      sp = getservbyname(portname, "tcp");
      if (sp == NULL)
	{
	  strcpy(ti_context, portname);
	  return(TI_ERR_UNKNOWN_PORT);
	}
      portnum = sp->s_port;
      portname = sp->s_name;
    }

  /* find TI already connected to that host and port, if one exists */
  for(i=0; i<TI_MAX_OPEN; i++)
    {
      if (ti_connections[i].links <= 0) continue;
      if (hp->h_addrtype == ti_connections[i].sname.sin_family &&
	  portnum == ti_connections[i].sname.sin_port &&
	  !memcmp(hp->h_addr, &(ti_connections[i].sname.sin_addr),
		  hp->h_length))
	{
	  *tip = &(ti_connections[i]);
	  goto SUCCESS;
	}
    }

  /* find first free TI */
  for(i=0; i<TI_MAX_OPEN; i++)
    if (!ti_connections[i].links) break;
  if (i>= TI_MAX_OPEN)
    {
      *ti_context='\0';
      return(TI_ERR_TOOMANY);
    }
  *tip = &(ti_connections[i]);

  /* build server socket name */
  memset(&((*tip)->sname), 0, sizeof((*tip)->sname));
  (*tip)->sname.sin_family = AF_INET;
  memcpy(&(*tip)->sname.sin_addr, hp->h_addr, hp->h_length);
  (*tip)->sname.sin_port = portnum;

  /* fill in strings */
  TI_MEM((*tip)->strings = NewArray(char *, TI_STRINGS));
  memset((*tip)->strings, 0, (TI_STRINGS)*sizeof(char*));
  TI_MEM(ti_host(*tip) = newstring(hostname));
  strcpy(ti_host(*tip), hostname);
  TI_MEM(ti_port(*tip) = newstring(portname));
  strcpy(ti_port(*tip), portname);

  /* make a connection to the specified server on the socket */
  if (code = ti_connect(*tip)) return(code);
  ti_nconnections++;

 SUCCESS:
  /* increment reference count to this connection */
  (*tip)->links++;
  return(0L);
}
