/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* bos720 src/bos/usr/samples/tcpip/dynload/rnd_ho.c 1.2                  */
/*                                                                        */
/* Licensed Materials - Property of IBM                                   */
/*                                                                        */
/* Restricted Materials of IBM                                            */
/*                                                                        */
/* COPYRIGHT International Business Machines Corp. 1999                   */
/* All Rights Reserved                                                    */
/*                                                                        */
/* US Government Users Restricted Rights - Use, duplication or            */
/* disclosure restricted by GSA ADP Schedule Contract with IBM Corp.      */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
/*
	    NOTICE TO USERS OF THE SOURCE CODE EXAMPLES

 INTERNATIONAL BUSINESS MACHINES CORPORATION PROVIDES THE SOURCE CODE
 EXAMPLES, BOTH INDIVIDUALLY AND AS ONE OR MORE GROUPS, "AS IS" WITHOUT
 WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT
 LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 PARTICULAR PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE
 OF THE SOURCE CODE EXAMPLES, BOTH INDIVIDUALLY AND AS ONE OR MORE GROUPS,
 IS WITH YOU.  SHOULD ANY PART OF THE SOURCE CODE EXAMPLES PROVE
 DEFECTIVE, YOU (AND NOT IBM OR AN AUTHORIZED RISC System/6000* WORKSTATION
 DEALER) ASSUME THE ENTIRE COST OF ALL NECESSARY SERVICING, REPAIR OR
 CORRECTION.

  RISC System/6000 is a trademark of International Business Machines
   Corporation.
*/
/* INCLUDE for structure definitions */
#include <stdlib.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/nameser.h>
#include <sys/errno.h>
#include <resolv.h>
#include <netdb.h>
#include <fcntl.h>
#include <pthread.h>

typedef struct _ho_pvt {
	pthread_t pvt_thd;
	struct hostent	pvt_hostent;	/* hostent for return */
} ho_pvt;

void *ho_pvtinit();
void ho_close();
void ho_rewind();
void ho_minimize();
struct hostent *ho_next();
struct hostent *ho_byaddr();
struct hostent *ho_byname();
struct hostent *ho_byname2();
struct hostent *rnd_makehost();

void *
ho_pvtinit()
{
	/* Step 1: Allocate memory and clear it */
	ho_pvt *pvt = (ho_pvt *)malloc(sizeof(*pvt));
	bzero(pvt,sizeof(*pvt));

        /* Step 2: Initialize whatever needs be done per-process */
	pvt->pvt_thd = pthread_self();

	return pvt;
}

/*
 * ho_close() - inverse of ho_pvtinit();
 */
void
ho_close(void *this)
{
	if (!this) return;
	free(this);
}

void
ho_rewind(void *this)
{
	ho_pvt *pvt = NULL;
	if (!this) return;
	pvt = (ho_pvt *)this;

}

void
ho_minimize(void *this)
{
	/* Nothing to do */
}

/* ho_next is not supported in this example, since
 * we are not sequentially searching...
 */

/*
 * ho_byname() return a hostent struct, given a host name 
 */
struct hostent *
ho_byname(void *this, const char *name)
{
	struct hostent *hp;

	/* Check for IPv6 forced lookup */
    	if ((_res.options & RES_INIT) == 0 && res_init() == -1)
       	 	return (NULL);
    	if (_res.options & RES_USE_INET6) {
        	hp = ho_byname2(this, name, AF_INET6);
        	if (hp)
            		return (hp);
    	}
	/* Fall back on IPv4 if not forced or IPv6 failed */
    	return (ho_byname2(this, name, AF_INET));
}

/*
 * ho_byname2() - return a hostent struct, given a name and address family
 */
struct hostent *
ho_byname2(void *this, const char *name, int af)
{
	ho_pvt *pvt = NULL;

	/* Get private struct */
	if (!this) {
		errno = EINVAL;
		return(NULL);
	}
	pvt = (ho_pvt *)this;

	/* build up our hostent */
	return(rnd_makehost(this,name,af, NULL));
}

/*
 * ho_byaddr() - return a hostent struct, given an address
 */
struct hostent *
ho_byaddr(void *this, const void *addr, size_t len, int af)
{
	ho_pvt *pvt = NULL;

	/* Get private struct */
	if (!this) {
		errno = EINVAL;
		return(NULL);
	}
	pvt = (ho_pvt *)this;

	/* make and return hostent from data */
	return(rnd_makehost(this, NULL, af, addr));
}

/*
 * rnd_makehost() - internal function to build hostent from private data
 */
struct hostent *
rnd_makehost(void *this, char *name, int af, void *addr)
{
	ho_pvt *pvt = (ho_pvt *)this;
	unsigned long	v4_prefix=inet_addr("1.4.8.0");
	int	len;

	pvt->pvt_hostent.h_aliases = NULL;	
	pvt->pvt_hostent.h_addrtype = af;
	pvt->pvt_hostent.h_length = (af == AF_INET)?4:16;
	pvt->pvt_hostent.h_addr_list = (char **)
		malloc(sizeof &pvt->pvt_hostent.h_addr_list);

	/* gethostbyname case */
	if ( addr == NULL )  {
		len = strlen(name);
		pvt->pvt_hostent.h_name = (char *) malloc(strlen(name)+1);
		bzero(pvt->pvt_hostent.h_name, sizeof pvt->pvt_hostent.h_name);
		strcpy(pvt->pvt_hostent.h_name, name);

		if ( af == AF_INET )  {
			v4_prefix |= len;
			pvt->pvt_hostent.h_addr_list[0] = &v4_prefix;
		}
		else {
			char format[1024];
			char  buf[1024];
			bzero(format, sizeof format);
			bzero(buf, sizeof buf);
			sprintf(format, "beef:feed::%d", len);
			inet_pton(AF_INET6, format, buf);
			pvt->pvt_hostent.h_addr_list[0] = buf;
		}
	}

	/* gethostbyaddr case */
	else if ( name == NULL )  {
		char buf[50];
		char format[1024];
		int tmp;
		char  *ptr = (char *) addr;

		bzero(buf, sizeof buf);
		bzero(format, sizeof format);

		pvt->pvt_hostent.h_addr_list[0] = addr;

		if ( af == AF_INET )  {
			tmp=(int) ptr[3];
			sprintf(format, "hostname%d", tmp);
			pvt->pvt_hostent.h_name = format;
		}
		else  {
			tmp=(int) ptr[15];
			sprintf(format, "hostname%x", tmp);
			pvt->pvt_hostent.h_name = format;
		}

	}

	/* Return */
	return(&(pvt->pvt_hostent));
}

