/**********************************************************************
 
	Copyright (C) 2003 Hirohisa MORI <joshua@nichibun.ac.jp>
 
	This program is free software; you can redistribute it 
	and/or modify it under the terms of the GLOBALBASE 
	Library General Public License (G-LGPL) as published by 

	http://www.globalbase.org/
 
	This program is distributed in the hope that it will be 
	useful, but WITHOUT ANY WARRANTY; without even the 
	implied warranty of MERCHANTABILITY or FITNESS FOR A 
	PARTICULAR PURPOSE.

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



#include	<errno.h>
#include	<stdio.h>
#include	<sys/types.h>
#include	<winsock2.h>
#include	"change_endian.h"
#include	"memory_debug.h"
#include	"task.h"
#include	"netutils.h"
#include	"blacklist.h"
#include	"resolve.h"

typedef struct gethostbyname_type {
	char *		name;
	struct hostent * h_hp;
	struct hostent * hp;
	char *		h_buf;
	int		h_size;
	int		er;
} GETHOSTBYNAME_TYPE;

typedef struct gethostbyname_cmd {
	BL_CMD			cmd;
	struct hostent *	h;
} GETHOSTBYNAME_CMD;

extern SEM netutils_lock;

int
_gethostbyname_r(GETHOSTBYNAME_TYPE * a)
{
struct hostent *
gethostbyname_r(const char *hostname, struct hostent *dest, void *buf, size_t buf_size, int *error);

	errno = 0;
	a->hp = gethostbyname_r(
			a->name,
			a->h_hp,
			a->h_buf,
			a->h_size,
			&a->er);
	if ( a->er == TRY_AGAIN ) {
	}
	return errno;
}

struct hostent *
_gethostbyname_rr(char * name)
{
int err;
GETHOSTBYNAME_TYPE a;
void set_buffer(void * buf);

	a.name = name;
	a.h_size = 100;
	a.h_hp = d_alloc(sizeof(*a.h_hp),11);
	a.h_buf = d_alloc(a.h_size,12);
	for ( ; ; ) {
		err = _gethostbyname_r(&a);
		if ( a.hp )
			break;
		if ( err != ERANGE )
			break;
		a.h_size += 100;
		a.h_buf = d_re_alloc(a.h_buf,a.h_size);
	}

	if ( a.hp ) {
		set_buffer(a.h_hp);
		set_buffer(a.h_buf);
		return a.hp;
	}
	else {
		d_f_ree(a.h_hp);
		d_f_ree(a.h_buf);
		return 0;
	}
}


int
gethostbyname_rr_proc(BLACKLIST * bl,GETHOSTBYNAME_CMD * cmd)
{
unsigned int t;
int get_xltime();

	lock_task(netutils_lock);
	sethostent_rr(0);

	t = get_xltime();

	cmd->h = _gethostbyname_rr(cmd->cmd.name);
	bl->polling_initial = 2*(get_xltime() - t);

	endhostent_rr();
	unlock_task(netutils_lock,"gethostbyname_rr_proc");

	if ( cmd->h )
		return BLS_OK;
	return BLS_ERROR;
}

int
gethostbyname_rr_retry(BLACKLIST * bl)
{
struct hostent * h;
int ret;
unsigned int t;

	t = get_xltime();
	lock_task(netutils_lock);
	sethostent_rr(0);
	h = _gethostbyname_rr(bl->name);
	if ( h )
		ret = BLS_OK;
	else	ret = BLS_ERROR;
	endhostent_rr();
	unlock_task(netutils_lock,"new_connect");
	return ret;
}

HOST_ENTRY *
intr_gethostbyname_rr(char * name)
{
GETHOSTBYNAME_CMD c;
HOST_ENTRY * machine2he_v4(struct hostent*);
int bl_do(void * cmd);
	c.cmd.name = name;
	c.cmd.name_len = strlen(name)+1;
	c.cmd.retry = gethostbyname_rr_retry;
	c.cmd.proc = gethostbyname_rr_proc;
	c.cmd.type = BLT_RESOLVE;
	c.h = 0;
	bl_do(&c);
	return machine2he_v4(c.h);
}
