Exemplo n.º 1
0
static int
gethostbyname_resolve (struct GNUNET_SERVER_TransmitContext *tc,
                       const char *hostname)
{
  struct hostent *hp;

  hp = GETHOSTBYNAME (hostname);
  if (NULL == hp)
  {
    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
                _("Could not find IP of host `%s': %s\n"),
                hostname,
                hstrerror (h_errno));
    return GNUNET_SYSERR;
  }
  if (hp->h_addrtype != AF_INET)
  {
    GNUNET_break (0);
    return GNUNET_SYSERR;
  }
  GNUNET_assert (hp->h_length == sizeof (struct in_addr));
  GNUNET_SERVER_transmit_context_append_data (tc,
					      hp->h_addr_list[0],
					      hp->h_length,
                                              GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE);
  return GNUNET_OK;
}
Exemplo n.º 2
0
cmi_status_t cmj_resolve_nod_tnd(cmi_descriptor *nod, cmi_descriptor *tnd, struct sockaddr_in *inp)
{
	cmi_status_t status = SS_NORMAL;
	char hn[MAX_HOST_NAME_LEN];
	struct hostent *hp;
	int loop_limit = MAX_GETHOST_TRIES;

	/* tnd may contain host:port */
	status = cmj_getsockaddr(tnd, inp);
	if (CMI_ERROR(status))
		return status;

	if (inp->sin_addr.s_addr == INADDR_ANY)
	{
		/* use nod as a host name if tnd was just a port */
		assert(CMI_DESC_LENGTH(nod) < (SIZEOF(hn)-1));
		memcpy(hn, CMI_DESC_POINTER(nod), CMI_DESC_LENGTH(nod));
		hn[CMI_DESC_LENGTH(nod)] = '\0';

		/* test to see if nod is a dotted quad text string */
		inp->sin_addr.s_addr = INET_ADDR(hn);
		if (inp->sin_addr.s_addr == (in_addr_t)-1)
		{
			/* assume hn is a host and query netdb */
			for (; 0 < loop_limit && (NULL == (hp = GETHOSTBYNAME(hn))) && TRY_AGAIN == h_errno; loop_limit--)
				;
			endhostent();
			if (!hp)
				return CMI_NETFAIL;
			inp->sin_addr = *(struct in_addr *)hp->h_addr;
		}
	}
	return status;
}
Exemplo n.º 3
0
//------------------------------------------------------------------------------
//
// ConnectUDP() -
//
//------------------------------------------------------------------------------
bool CActiveSocket::ConnectUDP(const char *pAddr, uint16 nPort)
{
    bool           bRetVal = false;
    struct in_addr stIpAddress;

    //------------------------------------------------------------------
    // Pre-connection setup that must be preformed
    //------------------------------------------------------------------
    memset(&m_stServerSockaddr, 0, sizeof(m_stServerSockaddr));
    m_stServerSockaddr.sin_family = AF_INET;

    if ((m_pHE = GETHOSTBYNAME(pAddr)) == NULL)
    {
#ifdef WIN32
        TranslateSocketError();
#else
        if (h_errno == HOST_NOT_FOUND)
        {
            SetSocketError(SocketInvalidAddress);
        }
#endif
        return bRetVal;
    }

    memcpy(&stIpAddress, m_pHE->h_addr_list[0], m_pHE->h_length);
    m_stServerSockaddr.sin_addr.s_addr = stIpAddress.s_addr;

    if ((int32)m_stServerSockaddr.sin_addr.s_addr == CSimpleSocket::SocketError)
    {
        TranslateSocketError();
        return bRetVal;
    }

    m_stServerSockaddr.sin_port = htons(nPort);

    //------------------------------------------------------------------
    // Connect to address "xxx.xxx.xxx.xxx"    (IPv4) address only.
    //
    //------------------------------------------------------------------
    m_timer.Initialize();
    m_timer.SetStartTime();

    if (connect(m_socket, (struct sockaddr*)&m_stServerSockaddr, sizeof(m_stServerSockaddr)) != CSimpleSocket::SocketError)
    {
        bRetVal = true;
    }

    TranslateSocketError();

    m_timer.SetEndTime();

    return bRetVal;
}
Exemplo n.º 4
0
//------------------------------------------------------------------------------
//
// ConnectRAW() -
//
//------------------------------------------------------------------------------
bool TDSocket::ConnectRAW(const char *pAddr, i16 nPort)
{
	bool           bRetVal = false;
	struct in_addr stIpAddress;
	//------------------------------------------------------------------
	// Pre-connection setup that must be preformed					 
	//------------------------------------------------------------------
	memset(&m_stServerSockaddr, 0, sizeof(m_stServerSockaddr));
	m_stServerSockaddr.sin_family = AF_INET;

	hostent * pHE = NULL;
	if ((pHE = GETHOSTBYNAME(pAddr)) == NULL)
	{
#ifdef WIN32
		TranslateSocketError();
#else
		if (h_errno == HOST_NOT_FOUND)
		{
			SetSocketError(SocketInvalidAddress);
		}
#endif
		return bRetVal;
	}

	memcpy(&stIpAddress, pHE->h_addr_list[0], pHE->h_length);
	m_stServerSockaddr.sin_addr.s_addr = stIpAddress.s_addr;

	if ((i32)m_stServerSockaddr.sin_addr.s_addr == TDSocket::SocketError)
	{
		TranslateSocketError();
		return bRetVal;
	}

	m_stServerSockaddr.sin_port = htons(nPort);

	//------------------------------------------------------------------
	// Connect to address "xxx.xxx.xxx.xxx"	(IPv4) address only.  
	// 
	//------------------------------------------------------------------

	if (connect(m_socket, (struct sockaddr*)&m_stServerSockaddr, sizeof(m_stServerSockaddr)) != TDSocket::SocketError)
	{
		bRetVal = true;
	}

	TranslateSocketError();


	return bRetVal;
}
Exemplo n.º 5
0
char *iotcp_name2ip(char *name)
{
  struct   hostent 	host, *host_ptr;
  struct   in_addr 	inaddr;
  char     		local_name[80];
  char     		ip[16];

  SPRINTF(local_name, "%s", name);

  if (NULL == (host_ptr = GETHOSTBYNAME(local_name)))
      return NULL;

  host = *host_ptr;

  inaddr = *((struct in_addr *)host.h_addr_list[0]);

  return INET_NTOA(inaddr);
}
Exemplo n.º 6
0
char * 
krb_get_phost(
    char *alias
    )
{
    struct hostent *h;
    char *p;
    /* We keep our own buffer instead of using h->h_name in case someone
       decides to call one of the resolver routines. */
    /* XXX - The buffer is not currently thread-safe */
    /* We cannot simply use __declspec(thread) if our DLL might be
       dynamically loaded with LoadLibrary.  Rather, we must use the
       TLS API.  We wil deal with this later.  Sigh. */
    static char phost[1024]; /* DNS limit is about 975 */

    // INVARIANT: h || return alias at the end of the if-else block below
    h = 0;
    /* Let's add some code to see if someone is passing around an IP address */
    /* note that a DNS name cannot start with a digit */
    if(isdigit(alias[0]))
    {
        unsigned long host_addr;
        host_addr = inet_addr(alias);
        if(host_addr != INADDR_NONE)
            h = GETHOSTBYADDR((char *)&host_addr, sizeof(host_addr), PF_INET);
    } else {
        /* OK, now this will handle the normal case of the application */
        /* passing the machine name rather than the IP address as a string */
        h = GETHOSTBYNAME(alias);
    }
    if (!h)
        return alias;
    if ((strlen(h->h_name) + 1) > sizeof(phost))
        return alias;
    strcpy(phost, h->h_name);
    p = strchr(phost, '.');
    if (p)
        *p = 0;
    p = phost;
    do {
        if (isupper(*p)) *p = tolower(*p);
    } while (*p++);
    return (phost);
}
Exemplo n.º 7
0
/*
 * kadm_init_link
 *      receives    : name, inst, realm
 *
 * initializes client parm, the Kadm_Client structure which holds the
 * data about the connection between the server and client, the services
 * used, the locations and other fun things
 */
long /* DAMMIT! USE LONGS! */
kadm_init_link(
    char n[],
    char i[],
    char r[]
    )
{
    struct servent FAR *sep;           /* service we will talk to */
    struct hostent FAR *hop;           /* host we will talk to */
    char adm_hostname[MAXHOSTNAMELEN];

    (void) strcpy(clientParm.sname, n);
    (void) strcpy(clientParm.sinst, i);
    (void) strcpy(clientParm.krbrlm, r);
    clientParm.admin_fd = -1;
    clientParm.nSocketState = STATE_NONE;

    /* set up the admin_addr - fetch name of admin host */
    if (krb_get_admhst(adm_hostname, clientParm.krbrlm, 1) != KSUCCESS)
        return KADM_NO_HOST;
    bzero((char *) &clientParm.admin_addr,
          sizeof(clientParm.admin_addr));
    if ((hop = GETHOSTBYNAME(adm_hostname)) == NULL)
        return KADM_UNK_HOST;  /* couldnt find the admin servers address */

    bcopy(hop->h_addr, &clientParm.admin_addr.sin_addr, hop->h_length);
    clientParm.admin_addr.sin_family = hop->h_addrtype;

    if (sep = getservbyname(KADM_SNAME, "tcp"))
        clientParm.admin_addr.sin_port = sep->s_port;
    else if (KADM_DEFAULT_PORT) /* set to 0 to turn this off */
        clientParm.admin_addr.sin_port = htons(KADM_DEFAULT_PORT);
    else
        return KADM_NO_SERV;   /* couldnt find the admin service */

    return KADM_SUCCESS;
}                                      /* procedure kadm_init_link */
Exemplo n.º 8
0
//------------------------------------------------------------------------------
//
// ConnectTCP() -
//
//------------------------------------------------------------------------------
bool TDSocket::ConnectTCP(const char *pAddr, i16 nPort)
{
	bool           bRetVal = false;
	struct in_addr stIpAddress;

	//------------------------------------------------------------------
	// Preconnection setup that must be preformed					 
	//------------------------------------------------------------------
	memset(&m_stServerSockaddr, 0, sizeof(m_stServerSockaddr));
	m_stServerSockaddr.sin_family = AF_INET;

	hostent * pHE = NULL;
	if ((pHE = GETHOSTBYNAME(pAddr)) == NULL)
	{
#ifdef WIN32
		TranslateSocketError();
#else
		if (h_errno == HOST_NOT_FOUND)
		{
			SetSocketError(SocketInvalidAddress);
		}
#endif
		return bRetVal;
	}

	memcpy(&stIpAddress, pHE->h_addr_list[0], pHE->h_length);
	m_stServerSockaddr.sin_addr.s_addr = stIpAddress.s_addr;

	if ((i32)m_stServerSockaddr.sin_addr.s_addr == TDSocket::SocketError)
	{
		TranslateSocketError();
		return bRetVal;
	}

	m_stServerSockaddr.sin_port = htons(nPort);

	//------------------------------------------------------------------
	// Connect to address "xxx.xxx.xxx.xxx"	(IPv4) address only.  
	// 
	//------------------------------------------------------------------

	if (connect(m_socket, (struct sockaddr*)&m_stServerSockaddr, sizeof(m_stServerSockaddr)) ==
		TDSocket::SocketError)
	{
		//--------------------------------------------------------------
		// Get error value this might be a non-blocking socket so we 
		// must first check.
		//--------------------------------------------------------------
		TranslateSocketError();

		//--------------------------------------------------------------
		// If the socket is non-blocking and the current socket error
		// is SocketEinprogress or SocketEwouldblock then poll connection 
		// with select for designated timeout period.
		// Linux returns EINPROGRESS and Windows returns WSAEWOULDBLOCK.
		//--------------------------------------------------------------
		if ((IsNonblocking()) &&
			((GetSocketError() == TDSocket::SocketEwouldblock) ||
			(GetSocketError() == TDSocket::SocketEinprogress)))
		{
			bRetVal = Select(GetConnectTimeoutSec(), GetConnectTimeoutUSec());
		}
	}
	else
	{
		TranslateSocketError();
		bRetVal = true;
	}


	return bRetVal;
}
Exemplo n.º 9
0
int gtmsource_get_opt(void)
{
	boolean_t	secondary, dotted_notation;
	int		tries, index = 0;
	unsigned short	secondary_len;
	char		secondary_sys[MAX_SECONDARY_LEN], *c;
	struct hostent	*sec_hostentry;

	boolean_t	log, log_interval_specified;
	unsigned short	log_file_len;

	boolean_t	buffsize_status;

	boolean_t	filter;
	unsigned short	filter_cmd_len;

	int		timeout_status;

	unsigned short	statslog_val_len;
	char		statslog_val[4]; /* "ON" or "OFF" */

	unsigned short	update_val_len;
	char		update_val[SIZEOF("DISABLE")]; /* "ENABLE" or "DISABLE" */

	unsigned short	connect_parms_str_len;
	char		*connect_parms_str, tmp_connect_parms_str[GTMSOURCE_CONN_PARMS_LEN + 1];
	char		*connect_parm_token_str, *connect_parm;
	int		connect_parms_index;
	boolean_t	connect_parms_badval;

	memset((char *)&gtmsource_options, 0, SIZEOF(gtmsource_options));

	gtmsource_options.start = (cli_present("START") == CLI_PRESENT);
	gtmsource_options.shut_down = (cli_present("SHUTDOWN") == CLI_PRESENT);
	gtmsource_options.activate = (cli_present("ACTIVATE") == CLI_PRESENT);
	gtmsource_options.deactivate = (cli_present("DEACTIVATE") == CLI_PRESENT);
	gtmsource_options.checkhealth = (cli_present("CHECKHEALTH") == CLI_PRESENT);
	gtmsource_options.statslog = (cli_present("STATSLOG") == CLI_PRESENT);
	gtmsource_options.showbacklog = (cli_present("SHOWBACKLOG") == CLI_PRESENT);
	gtmsource_options.changelog = (cli_present("CHANGELOG") == CLI_PRESENT);
	gtmsource_options.stopsourcefilter = (cli_present("STOPSOURCEFILTER") == CLI_PRESENT);
	gtmsource_options.update = (cli_present("UPDATE") == CLI_PRESENT);

	if (gtmsource_options.start || gtmsource_options.activate)
	{
		if (secondary = (CLI_PRESENT == cli_present("SECONDARY")))
		{
			secondary_len = MAX_SECONDARY_LEN;
			if (!cli_get_str("SECONDARY", secondary_sys, &secondary_len))
			{
				util_out_print("Error parsing SECONDARY qualifier", TRUE);
				return(-1);
			}
			/* Parse secondary_sys into secondary_host
			 * and secondary_port */
			c = secondary_sys;
			dotted_notation = TRUE;
			while(*c && *c != ':')
			{
				if ('.' != *c && !ISDIGIT(*c))
					dotted_notation = FALSE;
				gtmsource_options.secondary_host[index++] = *c++;
			}
			gtmsource_options.secondary_host[index] = '\0';
			if (':' != *c)
			{
				util_out_print("Secondary port number should be specified", TRUE);
				return(-1);
			}
			errno = 0;
			if (((0 == (gtmsource_options.secondary_port = ATOI(++c))) && (0 != errno))
				|| (0 >= gtmsource_options.secondary_port))
			{
				util_out_print("Error parsing secondary port number !AD", TRUE, LEN_AND_STR(c));
				return(-1);
			}
			/* Validate the specified secondary host name */
			if (dotted_notation)
			{
				if ((in_addr_t)-1 ==
					(gtmsource_options.sec_inet_addr = INET_ADDR(gtmsource_options.secondary_host)))
				{
					util_out_print("Invalid IP address !AD", TRUE,
						LEN_AND_STR(gtmsource_options.secondary_host));
					return(-1);
				}
			} else
			{
				for (tries = 0;
		     	     	     tries < MAX_GETHOST_TRIES &&
		     	     	     !(sec_hostentry = GETHOSTBYNAME(gtmsource_options.secondary_host)) &&
		     	     	     h_errno == TRY_AGAIN;
		     	     	     tries++);
				if (NULL == sec_hostentry)
				{
					util_out_print("Could not find IP address for !AD", TRUE,
						LEN_AND_STR(gtmsource_options.secondary_host));
					return(-1);
				}
				gtmsource_options.sec_inet_addr = ((struct in_addr *)sec_hostentry->h_addr_list[0])->s_addr;
			}
		}
		if (CLI_PRESENT == cli_present("CONNECTPARAMS"))
		{
			connect_parms_str_len = GTMSOURCE_CONN_PARMS_LEN + 1;
			if (!cli_get_str("CONNECTPARAMS", tmp_connect_parms_str, &connect_parms_str_len))
			{
				util_out_print("Error parsing CONNECTPARAMS qualifier", TRUE);
				return(-1);
			}
#ifdef VMS
			/* strip the quotes around the string. (DCL doesn't do it) */
			assert('"' == tmp_connect_parms_str[0]);
			assert('"' == tmp_connect_parms_str[connect_parms_str_len - 1]);
			connect_parms_str = &tmp_connect_parms_str[1];
			tmp_connect_parms_str[connect_parms_str_len - 1] = '\0';
#else
			connect_parms_str = &tmp_connect_parms_str[0];
#endif
			for (connect_parms_index =
					GTMSOURCE_CONN_HARD_TRIES_COUNT,
			     connect_parms_badval = FALSE,
			     connect_parm_token_str = connect_parms_str;
			     !connect_parms_badval &&
			     connect_parms_index < GTMSOURCE_CONN_PARMS_COUNT &&
			     (connect_parm = strtok(connect_parm_token_str,
						    GTMSOURCE_CONN_PARMS_DELIM))
			     		   != NULL;
			     connect_parms_index++,
			     connect_parm_token_str = NULL)

			{
				errno = 0;
				if ((0 == (gtmsource_options.connect_parms[connect_parms_index] = ATOI(connect_parm))
						&& 0 != errno) || 0 >= gtmsource_options.connect_parms[connect_parms_index])
					connect_parms_badval = TRUE;
			}
			if (connect_parms_badval)
			{
				util_out_print("Error parsing or invalid value parameter in CONNECTPARAMS", TRUE);
				return(-1);
			}
			if (GTMSOURCE_CONN_PARMS_COUNT != connect_parms_index)
			{
				util_out_print(
					"All CONNECTPARAMS - HARD TRIES, HARD TRIES PERIOD, "
					"SOFT TRIES PERIOD, "
					"ALERT TIME, HEARTBEAT INTERVAL, "
					"MAX HEARBEAT WAIT should be specified", TRUE);
				return(-1);
			}
		} else
		{
			gtmsource_options.connect_parms[GTMSOURCE_CONN_HARD_TRIES_COUNT] = REPL_CONN_HARD_TRIES_COUNT;
			gtmsource_options.connect_parms[GTMSOURCE_CONN_HARD_TRIES_PERIOD] = REPL_CONN_HARD_TRIES_PERIOD;
			gtmsource_options.connect_parms[GTMSOURCE_CONN_SOFT_TRIES_PERIOD] = REPL_CONN_SOFT_TRIES_PERIOD;
			gtmsource_options.connect_parms[GTMSOURCE_CONN_ALERT_PERIOD] = REPL_CONN_ALERT_ALERT_PERIOD;
			gtmsource_options.connect_parms[GTMSOURCE_CONN_HEARTBEAT_PERIOD] = REPL_CONN_HEARTBEAT_PERIOD;
			gtmsource_options.connect_parms[GTMSOURCE_CONN_HEARTBEAT_MAX_WAIT] = REPL_CONN_HEARTBEAT_MAX_WAIT;
		}
		if (gtmsource_options.connect_parms[GTMSOURCE_CONN_ALERT_PERIOD]<
				gtmsource_options.connect_parms[GTMSOURCE_CONN_SOFT_TRIES_PERIOD])
			gtmsource_options.connect_parms[GTMSOURCE_CONN_ALERT_PERIOD] =
				gtmsource_options.connect_parms[GTMSOURCE_CONN_SOFT_TRIES_PERIOD];
		if (gtmsource_options.connect_parms[GTMSOURCE_CONN_HEARTBEAT_MAX_WAIT] <
				gtmsource_options.connect_parms[GTMSOURCE_CONN_HEARTBEAT_PERIOD])
			gtmsource_options.connect_parms[GTMSOURCE_CONN_HEARTBEAT_MAX_WAIT] =
				gtmsource_options.connect_parms[GTMSOURCE_CONN_HEARTBEAT_PERIOD];
	}

	if (gtmsource_options.start || gtmsource_options.statslog || gtmsource_options.changelog || gtmsource_options.activate ||
	    gtmsource_options.deactivate)
	{
		log = (cli_present("LOG") == CLI_PRESENT);
		log_interval_specified = (CLI_PRESENT == cli_present("LOG_INTERVAL"));
		if (log)
		{
			log_file_len = MAX_FN_LEN + 1;
			if (!cli_get_str("LOG", gtmsource_options.log_file, &log_file_len))
			{
				util_out_print("Error parsing LOG qualifier", TRUE);
				return(-1);
			}
		} else
			gtmsource_options.log_file[0] = '\0';
		gtmsource_options.src_log_interval = 0;
		if (log_interval_specified)
		{
			if (!cli_get_num("LOG_INTERVAL", (int4 *)&gtmsource_options.src_log_interval))
			{
				util_out_print("Error parsing LOG_INTERVAL qualifier", TRUE);
				return (-1);
			}
		}
		if (gtmsource_options.start && 0 == gtmsource_options.src_log_interval)
			gtmsource_options.src_log_interval = LOGTRNUM_INTERVAL;
		/* For changelog/activate/deactivate, interval == 0 implies don't change log interval already established */
		/* We ignore interval specification for statslog, Vinaya 2005/02/07 */
	}

	if (gtmsource_options.start)
	{
		assert(secondary || CLI_PRESENT == cli_present("PASSIVE"));
		gtmsource_options.mode = ((secondary) ? GTMSOURCE_MODE_ACTIVE : GTMSOURCE_MODE_PASSIVE);
		if (buffsize_status = (CLI_PRESENT == cli_present("BUFFSIZE")))
		{
			if (!cli_get_int("BUFFSIZE", &gtmsource_options.buffsize))
			{
				util_out_print("Error parsing BUFFSIZE qualifier", TRUE);
				return(-1);
			}
			if (MIN_JNLPOOL_SIZE > gtmsource_options.buffsize)
				gtmsource_options.buffsize = MIN_JNLPOOL_SIZE;
		} else
			gtmsource_options.buffsize = DEFAULT_JNLPOOL_SIZE;
		/* Round up buffsize to the nearest (~JNL_WRT_END_MASK + 1) multiple */
		gtmsource_options.buffsize = ((gtmsource_options.buffsize + ~JNL_WRT_END_MASK) & JNL_WRT_END_MASK);
		if (filter = (CLI_PRESENT == cli_present("FILTER")))
		{
			filter_cmd_len = MAX_FILTER_CMD_LEN;
	    		if (!cli_get_str("FILTER", gtmsource_options.filter_cmd, &filter_cmd_len))
			{
				util_out_print("Error parsing FILTER qualifier", TRUE);
				return(-1);
			}
		} else
			gtmsource_options.filter_cmd[0] = '\0';
	}

	if (gtmsource_options.shut_down)
	{
		if ((timeout_status = cli_present("TIMEOUT")) == CLI_PRESENT)
		{
			if (!cli_get_int("TIMEOUT", &gtmsource_options.shutdown_time))
			{
				util_out_print("Error parsing TIMEOUT qualifier", TRUE);
				return(-1);
			}
			if (DEFAULT_SHUTDOWN_TIMEOUT < gtmsource_options.shutdown_time || 0 > gtmsource_options.shutdown_time)
			{
				gtmsource_options.shutdown_time = DEFAULT_SHUTDOWN_TIMEOUT;
				util_out_print("shutdown TIMEOUT changed to !UL", TRUE, gtmsource_options.shutdown_time);
			}
		} else if (CLI_NEGATED == timeout_status)
			gtmsource_options.shutdown_time = -1;
		else /* TIMEOUT not specified */
			gtmsource_options.shutdown_time = DEFAULT_SHUTDOWN_TIMEOUT;
	}

	if (gtmsource_options.statslog)
	{
		statslog_val_len = 4; /* max(strlen("ON"), strlen("OFF")) + 1 */
		if (!cli_get_str("STATSLOG", statslog_val, &statslog_val_len))
		{
			util_out_print("Error parsing STATSLOG qualifier", TRUE);
			return(-1);
		}
		UNIX_ONLY(cli_strupper(statslog_val);)
		if (0 == strcmp(statslog_val, "ON"))
Exemplo n.º 10
0
/*
 * send_to_kdc() sends a message to the Kerberos authentication
 * server(s) in the given realm and returns the reply message.
 * The "pkt" argument points to the message to be sent to Kerberos;
 * the "rpkt" argument will be filled in with Kerberos' reply.
 * The "realm" argument indicates the realm of the Kerberos server(s)
 * to transact with.  If the realm is null, the local realm is used.
 *
 * If more than one Kerberos server is known for a given realm,
 * different servers will be queried until one of them replies.
 * Several attempts (retries) are made for each server before
 * giving up entirely.
 *
 * If an answer was received from a Kerberos host, KSUCCESS is
 * returned.  The following errors can be returned:
 *
 * SKDC_CANT    - can't get local realm
 *              - can't find "kerberos" in /etc/services database
 *              - can't open socket
 *              - can't bind socket
 *              - all ports in use
 *              - couldn't find any Kerberos host
 *
 * SKDC_RETRY   - couldn't get an answer from any Kerberos server,
 *                after several retries
 */
int
send_to_kdc(
    KTEXT pkt,
    KTEXT rpkt,
    char *realm
    )
{
    int i;
    SOCKET f = INVALID_SOCKET;
    int no_host; /* was a kerberos host found? */
    int retry;
    int n_hosts;
    int retval;
    struct sockaddr_in to;
    struct hostent *host, *hostlist, *fphost, *temp_hostlist;
    int *portlist, *temp_portlist;
    char *cp;
    char krbhst[MAX_HSTNM];
    char lrealm[REALM_SZ];

    hostlist = 0;
    portlist = 0;

    /*
     * If "realm" is non-null, use that, otherwise get the
     * local realm.
     */                      

    if (realm && realm[0]) {
	strncpy(lrealm, realm, REALM_SZ);
        lrealm[REALM_SZ] = 0;
    }
    else
	if (krb_get_lrealm(lrealm, 1)) {
	    if (krb_debug)
		kdebug("%s: can't get local realm\n", prog);
	    return(SKDC_CANT);
	}
    if (krb_debug)
	kdebug("lrealm is %s\n", lrealm);

    if (krb_udp_port_conf == 0) {
	register struct servent FAR *sp;
        if (sp = getservbyname("kerberos", "udp")) {
            krb_udp_port_conf = sp->s_port;
        } else if (KRB_PORT) {
            if (krb_debug)
                kdebug("%s: Can't get kerberos/udp service -- "
                       "using default port\n", prog);
            krb_udp_port_conf = htons(KRB_PORT);
        } else {
            if (krb_debug)
                kdebug("%s: Can't get kerberos/udp service at all\n", prog);
            return(SKDC_CANT);
        }
        if (krb_debug)
            kdebug("krb_udp_port_conf is %d\n", ntohs(krb_udp_port_conf));
    }

    /* from now on, exit through rtn label for cleanup */

    memset((char *)&to, 0, S_AD_SZ);
    hostlist = (struct hostent *) malloc(sizeof(struct hostent));
    if (!hostlist) {
        retval = SKDC_CANT;
        goto rtn;
    }
    memset(hostlist, 0, sizeof(struct hostent));

    f = socket(AF_INET, SOCK_DGRAM, 0);
    if (f == INVALID_SOCKET) {
        if (krb_debug)
            kdebug("%s: Can't open socket (error %d)\n", prog, 
                   WSAGetLastError());
        retval = SKDC_CANT;
        goto rtn;
    }

    /* make the socket non-blocking */
    {
        u_long onOff = TRUE;
        if (ioctlsocket(f, FIONBIO, (u_long FAR*)&onOff))
        {
            if (krb_debug)
                kdebug("%s: Can't make socket non-blocking (error %d)\n", 
                       prog, WSAGetLastError());
            retval = SKDC_CANT;
            goto rtn;
        }
    }

    /*
    ** FTP Software's WINSOCK implmentation insists that
    ** a socket be bound before it can receive datagrams.
    ** This is outside specs.  Since it shouldn't hurt any
    ** other implementations we'll go ahead and do it for
    ** now.
    */
    {
	struct sockaddr_in from;
	memset ((char *)&from, 0, S_AD_SZ);
	from.sin_family = AF_INET;
	from.sin_addr.s_addr = INADDR_ANY;
	if ( bind(f, (struct sockaddr *)&from, S_AD_SZ) == SOCKET_ERROR ) {
	    if (krb_debug)
                kdebug("%s : Can't bind\n", prog);
	    retval = SKDC_CANT;
	    goto rtn;
	}
    }
    /* End of kludge for FTP Software WinSock stack.  */

    no_host = 1;
    /* get an initial allocation */
    n_hosts = 0;
    for (i = 1; krb_get_krbhst(krbhst, lrealm, i) == KSUCCESS; ++i) {
#ifdef USE_DNS
        int krb_udp_port = krb_udp_port_dns?krb_udp_port_dns:krb_udp_port_conf;
        if (krb_debug) {
            kdebug("krb_udp_port is %d\n", ntohs(krb_udp_port));
        }
#else /* !USE_DNS */
        int krb_udp_port = krb_udp_port_conf;
#endif /* !USE_DNS */
        if (krb_debug) {
            kdebug("Getting host entry for %s...", krbhst);
        }
        fphost = /* host = */ GETHOSTBYNAME(krbhst);
        if (krb_debug) {
            kdebug("%s.\n",
                   fphost ? "Got it" : "Didn't get it");
        }
        if (!fphost){
            continue;
        }    
        no_host = 0;    /* found at least one */
        n_hosts++;
        /* preserve host network address to check later
         * (would be better to preserve *all* addresses,
         * take care of that later)
         */
        temp_portlist = portlist;
        portlist = (int *) realloc(portlist, n_hosts*sizeof(int));
        if (!portlist) {
            portlist = temp_portlist;
            retval = SKDC_CANT;
            goto rtn;
        }
        portlist[n_hosts-1] = krb_udp_port;

        temp_hostlist = hostlist;
        hostlist = (struct hostent *)
            realloc((char *)hostlist,
                    (unsigned)
                    sizeof(struct hostent)*(n_hosts+1));
        if (!hostlist){
            hostlist = temp_hostlist;
            retval = SKDC_CANT;
            goto rtn;
        }
        hostlist[n_hosts-1] = *fphost;
        memset(&hostlist[n_hosts], 0, sizeof(struct hostent));
        host = &hostlist[n_hosts-1];
        cp = (char*)malloc((unsigned)host->h_length);
        if (!cp) {
            retval = SKDC_CANT;
            goto rtn;
        }
        memcpy(cp, host->h_addr, host->h_length);
        host->h_addr_list = (char **)malloc(sizeof(char *));
        if (!host->h_addr_list) {
            retval = SKDC_CANT;
            goto rtn;
        }
        host->h_addr = cp;
        to.sin_family = host->h_addrtype;
        memcpy((char *)&to.sin_addr, host->h_addr, 
	       host->h_length);
        to.sin_port = krb_udp_port;
        if (send_recv(pkt, rpkt, f, &to, hostlist)) {
            retval = KSUCCESS;
            goto rtn;
        }
        if (krb_debug) {
            kdebug("Timeout, error, or wrong descriptor\n");
        }
    }
    if (no_host) {
        if (krb_debug)
            kdebug("%s: can't find any Kerberos host.\n", prog);
        retval = SKDC_CANT;
        goto rtn;
    }
    /* retry each host in sequence */
    for (retry = 0; retry < CLIENT_KRB_RETRY; ++retry) {
        i = 0;
        for (host = hostlist; host->h_name != 0; host++) {
            to.sin_family = host->h_addrtype;
            to.sin_port = portlist[i++];
            memcpy((char *)&to.sin_addr, host->h_addr, 
		   host->h_length);
            if (send_recv(pkt, rpkt, f, &to, hostlist)) {
                retval = KSUCCESS;
                goto rtn;
            }
        }
    }
    retval = SKDC_RETRY;

 rtn:
    if (f != INVALID_SOCKET)
        if (closesocket(f) == SOCKET_ERROR)
            if (krb_debug)
                kdebug("%s: Could not close socket (error %d)\n",
                       prog, WSAGetLastError());
    if (hostlist) {
        register struct hostent *hp;
        for (hp = hostlist; hp->h_name; hp++)
            if (hp->h_addr_list) {
                if (hp->h_addr)
                    free(hp->h_addr);
                free(hp->h_addr_list);
            }
        free(hostlist);
    }
    if (portlist)
        free(portlist);
    return(retval);
}