/**********************************************************************
 
	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	"utils.h"
#include	"memory_debug.h"
#include	"task.h"
#include	"netutils.h"
#include	"blacklist.h"
#include	"resolve.h"


extern SEM netutils_lock;

typedef struct gethostbyaddr_type {
	char *		addr;
	int		len;
	int		type;
	struct hostent * h_hp;
	struct hostent * hp;
	char *		h_buf;
	int		h_size;
	int		er;
} GETHOSTBYADDR_TYPE;


typedef struct gethostbyaddr_cmd {
	BL_CMD			cmd;
	struct hostent *	h;
} GETHOSTBYADDR_CMD;


struct hostent *
_gethostbyaddr_r(
	char *		addr,
	int		len,
	int		type,
	struct hostent * h_hp,
	char *		h_buf,
	int		h_size,
	int *		er);

struct hostent *
_gethostbyaddr_rr(char * addr,int len,int type)
{
GETHOSTBYADDR_TYPE a;


	a.addr = addr;
	a.len = len;
	a.type = type;
	a.h_size = 100;
	a.h_hp = d_alloc(sizeof(*a.h_hp),11);
	a.h_buf = d_alloc(a.h_size,12);
	for ( ; ; ) {
		errno = 0;
		a.hp = _gethostbyaddr_r(
				a.addr,
				a.len,
				a.type,
				a.h_hp,
				a.h_buf,
				a.h_size,
				&a.er);
		if ( a.hp )
			break;
		if ( errno != ERANGE )
			break;
		a.h_size += 100;
		a.h_buf = d_re_alloc(a.h_buf,a.h_size);
	}
/*
	if ( err )
		fprintf(stderr,"gethostbyname err = %i\n",err);
*/

	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
gethostbyaddr_rr_proc(BLACKLIST * bl,GETHOSTBYADDR_CMD * cmd)
{
int type;
int * ptr;
char * addr;
int addr_len;
unsigned int t;

	lock_task(netutils_lock);
	sethostent_rr(0);

	t = get_xltime();
	
	addr_len = cmd->cmd.name_len - sizeof(type);
	ptr = (int*)cmd->cmd.name;
	type = *ptr;
	ptr ++;
	addr = (char*)ptr;
	
	
	cmd->h = _gethostbyaddr_rr(addr,addr_len,type);

	bl->polling_initial = 2*(get_xltime() - t);

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

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

int
gethostbyaddr_rr_retry(BLACKLIST * bl)
{
int type;
int * ptr;
char * addr;
int addr_len;
int ret;

	lock_task(netutils_lock);
	sethostent_rr(0);
	addr_len = bl->name_len - sizeof(type);
	ptr = (int*)bl->name;
	type = *ptr;
	ptr ++;
	addr = (char*)ptr;
	if ( _gethostbyaddr_rr(addr,addr_len,type) )
		ret = BLS_OK;
	else	ret = BLS_ERROR;
	endhostent_rr();
	unlock_task(netutils_lock,"new_connect");

	return ret;
}

HOST_ENTRY * 
intr_gethostbyaddr_rr(HOST_ADDR a)
{
char * addr;
int len;
int type;
GETHOSTBYADDR_CMD cmd;
int * type_p;
HOST_ENTRY * machine2he_v4(struct hostent*);
void er_panic(char * str);
int bl_do(void * cmd);

	if ( a.type != HAT_V4 )
		er_panic("gethostbyaddr_rr");
	a.d.v4 = htonl(a.d.v4);
	addr = (char*)&a.d;
	len = sizeof(a.d.v4);
	type = AF_INET;

	cmd.cmd.retry = gethostbyaddr_rr_retry;
	cmd.cmd.proc =  gethostbyaddr_rr_proc;
	cmd.cmd.type = BLT_RESOLVE;
	cmd.cmd.name = d_alloc(len + sizeof(type),1234);
	cmd.cmd.name_len = len + sizeof(type);
	cmd.h = 0;
	type_p = (int*)cmd.cmd.name;
	*type_p = type;
	type_p ++;
	memcpy(type_p,addr,len);

	bl_do(&cmd);

	d_f_ree(cmd.cmd.name);

	return machine2he_v4(cmd.h);
}


