/* 
   Socket handling routines
   Copyright (C) 1998-2005, Joe Orton <joe@manyfish.co.uk>, 
   Copyright (C) 1999-2000 Tommi Komulainen <Tommi.Komulainen@iki.fi>
   Copyright (C) 2004 Aleix Conchillo Flaque <aleix@member.fsf.org>

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public
   License as published by the Free Software Foundation; either
   version 2 of the License, or (at your option) any later version.
   
   This library 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.  See the GNU
   Library General Public License for more details.

   You should have received a copy of the GNU Library General Public
   License along with this library; if not, write to the Free
   Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
   MA 02111-1307, USA
*/

/*
  portions were originally under GPL in Mutt, http://www.mutt.org/
  Relicensed under LGPL for neon, http://www.webdav.org/neon/
*/


#if 0
#define __DEBUG__
#endif

int socket_connect_timeout	= 3600;		// connection (sec)
int dns_query_timeout		= -1;		// gethostbyname (mili second)
int dns_cache_reload_time	= 86400 * 10;	// hostent cache (sec)

#include "config.h"

#ifdef __hpux
/* pick up hstrerror */
#define _XOPEN_SOURCE_EXTENDED 1
#endif

#include <sys/types.h>
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif


#include <sys/stat.h>
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif

#ifdef NE_USE_POLL
#include <sys/poll.h>
#elif defined(HAVE_SYS_SELECT_H)
#include <sys/select.h>
#endif

#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
#ifdef HAVE_NETINET_TCP_H
#include <netinet/tcp.h>
#endif
#ifdef HAVE_ARPA_INET_H
#include <arpa/inet.h>
#endif
#ifdef HAVE_NETDB_H
#include <netdb.h>
#endif

#ifdef WIN32
#include <winsock2.h>
#include <stddef.h>
#ifdef USE_GETADDRINFO
#include <ws2tcpip.h>
#endif
#endif

#if defined(HAVE_OPENSSL) && defined(HAVE_LIMITS_H)
#include <limits.h> /* for INT_MAX */
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#ifdef HAVE_STRINGS_H
#include <strings.h>
#endif 
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_SIGNAL_H
#include <signal.h>
#endif
#ifdef HAVE_ERRNO_H
#include <errno.h>
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif

#ifdef HAVE_SOCKS_H
#include <socks.h>
#endif

#ifdef HAVE_OPENSSL
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/pkcs12.h> /* for PKCS12_PBE_add */
#include <openssl/rand.h>
#include <openssl/opensslv.h> /* for OPENSSL_VERSION_NUMBER */
#endif

#ifdef HAVE_GNUTLS
#include <gnutls/gnutls.h>
#endif

#define NE_INET_ADDR_DEFINED
/* A slightly ugly hack: change the ne_inet_addr definition to be the
 * real address type used.  The API only exposes ne_inet_addr as a
 * pointer to an opaque object, so this should be well-defined
 * behaviour.  It avoids the hassle of a real wrapper ne_inet_addr
 * structure, or losing type-safety by using void *. */
#ifdef USE_GETADDRINFO
typedef struct addrinfo ne_inet_addr;
#else
typedef struct in_addr ne_inet_addr;
#endif

#ifdef NE_HAVE_SSL
#include "ne_privssl.h" /* MUST come after ne_inet_addr is defined */
#endif

/* To avoid doing AAAA queries unless absolutely necessary, either use
 * AI_ADDRCONFIG where available, or a run-time check for working IPv6
 * support; the latter is only known to work on Linux. */
#if defined(USE_GETADDRINFO) && !defined(USE_GAI_ADDRCONFIG) && defined(__linux__)
#define USE_CHECK_IPV6
#endif

#include "ne_i18n.h"
#include "ne_utils.h"
#include "ne_string.h"
#include "ne_socket.h"
#include "ne_alloc.h"
#include "ne_sspi.h"

#if defined(__BEOS__) && !defined(BONE_VERSION)
/* pre-BONE */
#define ne_close(s) closesocket(s)
#define ne_errno errno
#elif defined(WIN32)
#define ne_close(s) closesocket(s)
#define ne_errno WSAGetLastError()
#else /* really Unix! */
#define ne_close(s) close(s)
#define ne_errno errno
#endif

#ifdef WIN32
#define NE_ISRESET(e) ((e) == WSAECONNABORTED || (e) == WSAETIMEDOUT || \
                       (e) == WSAECONNRESET || (e) == WSAENETRESET)
#define NE_ISCLOSED(e) ((e) == WSAESHUTDOWN || (e) == WSAENOTCONN)
#define NE_ISINTR(e) (0)
#else /* Unix */
/* Also treat ECONNABORTED and ENOTCONN as "connection reset" errors;
 * both can be returned by Winsock-based sockets layers e.g. CygWin */
#ifndef ECONNABORTED
#define ECONNABORTED ECONNRESET
#endif
#ifndef ENOTCONN
#define ENOTCONN ECONNRESET
#endif
#define NE_ISRESET(e) ((e) == ECONNRESET || (e) == ECONNABORTED || (e) == ENOTCONN)
#define NE_ISCLOSED(e) ((e) == EPIPE)
#define NE_ISINTR(e) ((e) == EINTR)
#endif

/* Socket read timeout */
#define SOCKET_READ_TIMEOUT 120

/* Critical I/O functions on a socket: useful abstraction for easily
 * handling SSL I/O alongside raw socket I/O. */
struct iofns {
    /* Read up to 'len' bytes into 'buf' from socket.  Return <0 on
     * error or EOF, or >0; number of bytes read. */
    ssize_t (*sread)(ne_socket *s, char *buf, size_t len);
    /* Write up to 'len' bytes from 'buf' to socket.  Return number of
     * bytes written on success, or <0 on error. */
    ssize_t (*swrite)(ne_socket *s, const char *buf, size_t len);
    /* Wait up to 'n' seconds for socket to become readable.  Returns
     * 0 when readable, otherwise NE_SOCK_TIMEOUT or NE_SOCK_ERROR. */
    int (*readable)(ne_socket *s, int n);
};

struct ne_socket_s {
    int fd;
    char error[200];
    void *progress_ud;
    int rdtimeout; /* read timeout. */
    const struct iofns *ops;
#ifdef NE_HAVE_SSL
    ne_ssl_socket ssl;
#endif
    /* The read buffer: ->buffer stores byte which have been read; as
     * these are consumed and passed back to the caller, bufpos
     * advances through ->buffer.  ->bufavail gives the number of
     * bytes which remain to be consumed in ->buffer (from ->bufpos),
     * and is hence always <= RDBUFSIZ. */
#define RDBUFSIZ 4096
    char buffer[RDBUFSIZ];
    char *bufpos;
    size_t bufavail;
};

/* ne_sock_addr represents an Internet address. */
struct ne_sock_addr_s {
#ifdef USE_GETADDRINFO
    struct addrinfo *result, *cursor;
#else
    struct in_addr *addrs;
    size_t cursor, count;
#endif
    int errnum;
};

/* set_error: set socket error string to 'str'. */
#define set_error(s, str) ne_strnzcpy((s)->error, (str), sizeof (s)->error)

/* set_strerror: set socket error to system error string for 'errnum' */
#ifdef WIN32
/* Print system error message to given buffer. */
static void print_error(int errnum, char *buffer, size_t buflen)
{
    if (FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM
                       | FORMAT_MESSAGE_IGNORE_INSERTS,
                       NULL, (DWORD) errnum, 0, 
                       buffer, buflen, NULL) == 0)
        ne_snprintf(buffer, buflen, "Socket error %d", errnum);
}
#define set_strerror(s, e) print_error((e), (s)->error, sizeof (s)->error)
#else /* not WIN32 */
#define set_strerror(s, e) ne_strerror((e), (s)->error, sizeof (s)->error)
#endif

#if defined(HAVE_OPENSSL)
static void init_ssl(void)
{
    SSL_load_error_strings();
    SSL_library_init();
    OpenSSL_add_all_algorithms();
}
#elif defined(HAVE_GNUTLS)
static void init_ssl(void)
{
    gnutls_global_init();
}
#endif /* HAVE_OPENSSL */

#ifdef HAVE_OPENSSL
/* Seed the SSL PRNG, if necessary; returns non-zero on failure. */
static int seed_ssl_prng(void)
{
    /* Check whether the PRNG has already been seeded. */
    if (RAND_status() == 1)
	return 0;

#if defined(EGD_PATH)
    NE_DEBUG(NE_DBG_SOCKET, "Seeding PRNG from " EGD_PATH "...\n");
    if (RAND_egd(EGD_PATH) != -1)
	return 0;
#elif defined(ENABLE_EGD)
    {
	static const char *paths[] = { "/var/run/egd-pool", "/dev/egd-pool",
				       "/etc/egd-pool", "/etc/entropy" };
	size_t n;
	for (n = 0; n < sizeof(paths) / sizeof(char *); n++) {
	    NE_DEBUG(NE_DBG_SOCKET, "Seeding PRNG from %s...\n", paths[n]);
	    if (RAND_egd(paths[n]) != -1)
		return 0;
	}
    }
#endif /* EGD_PATH */

    NE_DEBUG(NE_DBG_SOCKET, "No entropy source found; could not seed PRNG.\n");
    return -1;
}
#endif /* HAVE_OPENSSL */

#ifdef USE_CHECK_IPV6
static int ipv6_disabled = 0;

/* On Linux kernels, IPv6 is typically built as a loadable module, and
 * socket(AF_INET6, ...) will fail if this module is not loaded, so
 * the slow AAAA lookups can be avoided for this common case. */
static void init_ipv6(void)
{
    int fd = socket(AF_INET6, SOCK_STREAM, 0);
    
    if (fd < 0)
        ipv6_disabled = 1;
    else
        close(fd);
}
#else
#define ipv6_disabled (0)
#endif

static int init_result = 0;

int ne_sock_init(void)
{
#ifdef WIN32
    WORD wVersionRequested;
    WSADATA wsaData;
    int err;
#endif

    if (init_result > 0) 
	return 0;
    else if (init_result < 0)
	return -1;

#ifdef WIN32    
    wVersionRequested = MAKEWORD(2, 2);
    
    err = WSAStartup(wVersionRequested, &wsaData);
    if (err != 0) {
	init_result = -1;
	return -1;
    }

#endif

#ifdef HAVE_SSPI
    if (ne_sspi_init() < 0) {
        init_result = -1;
        return init_result;
    }
#endif

#ifdef NE_HAVE_SOCKS
    SOCKSinit("neon");
#endif

#if defined(HAVE_SIGNAL) && defined(SIGPIPE)
    (void) signal(SIGPIPE, SIG_IGN);
#endif

#ifdef USE_CHECK_IPV6
    init_ipv6();
#endif

#ifdef NE_HAVE_SSL
    init_ssl();
#endif

    init_result = 1;
    return 0;
}

void ne_sock_exit(void)
{
#ifdef WIN32
    WSACleanup();
#endif
#ifdef HAVE_GNUTLS
    gnutls_global_deinit();
#endif

#ifdef HAVE_SSPI
    ne_sspi_deinit();
#endif

    init_result = 0;
}

int ne_sock_block(ne_socket *sock, int n)
{
    if (sock->bufavail)
	return 0;
    return sock->ops->readable(sock, n);
}

/* Cast address object AD to type 'sockaddr_TY' */ 
#define SACAST(ty, ad) ((struct sockaddr_##ty *)(ad))

ssize_t ne_sock_read(ne_socket *sock, char *buffer, size_t buflen)
{
    ssize_t bytes;

#if 0
    NE_DEBUG(NE_DBG_SOCKET, "buf: at %d, %d avail [%s]\n", 
	     sock->bufpos - sock->buffer, sock->bufavail, sock->bufpos);
#endif

    if (sock->bufavail > 0) {
	/* Deliver buffered data. */
	if (buflen > sock->bufavail)
	    buflen = sock->bufavail;
	memcpy(buffer, sock->bufpos, buflen);
	sock->bufpos += buflen;
	sock->bufavail -= buflen;
	return buflen;
    } else if (buflen >= sizeof sock->buffer) {
	/* No need for read buffer. */
	return sock->ops->sread(sock, buffer, buflen);
    } else {
	/* Fill read buffer. */
	bytes = sock->ops->sread(sock, sock->buffer, sizeof sock->buffer);
	if (bytes <= 0)
	    return bytes;

	if (buflen > (size_t)bytes)
	    buflen = bytes;
	memcpy(buffer, sock->buffer, buflen);
	sock->bufpos = sock->buffer + buflen;
	sock->bufavail = bytes - buflen;
	return buflen; 
    }
}

ssize_t ne_sock_peek(ne_socket *sock, char *buffer, size_t buflen)
{
    ssize_t bytes;
    
    if (sock->bufavail) {
	/* just return buffered data. */
	bytes = sock->bufavail;
    } else {
	/* fill the buffer. */
	bytes = sock->ops->sread(sock, sock->buffer, sizeof sock->buffer);
	if (bytes <= 0)
	    return bytes;

	sock->bufpos = sock->buffer;
	sock->bufavail = bytes;
    }

    if (buflen > (size_t)bytes)
	buflen = bytes;

    memcpy(buffer, sock->bufpos, buflen);

    return buflen;
}

/* Await data on raw fd in socket. */
static int readable_raw(ne_socket *sock, int secs)
{
    int ret;
#ifdef NE_USE_POLL
    struct pollfd fds;
    int timeout = secs > 0 ? secs * 1000 : -1;

    fds.fd = sock->fd;
    fds.events = POLLIN;
    fds.revents = 0;

    do {
        ret = poll(&fds, 1, timeout);
    } while (ret < 0 && NE_ISINTR(ne_errno));
#else
    int fdno = sock->fd;
    fd_set rdfds;
    struct timeval timeout, *tvp = (secs >= 0 ? &timeout : NULL);

    /* Init the fd set */
    FD_ZERO(&rdfds);
    do {
	FD_SET(fdno, &rdfds);
	if (tvp) {
	    tvp->tv_sec = secs;
	    tvp->tv_usec = 0;
	}

	ret = select(fdno + 1, &rdfds, NULL, NULL, tvp);
    } while (ret < 0 && NE_ISINTR(ne_errno));
#endif

    if (ret < 0) {
	set_strerror(sock, ne_errno);
	return NE_SOCK_ERROR;
    }
    return (ret == 0) ? NE_SOCK_TIMEOUT : 0;
}

static ssize_t read_raw(ne_socket *sock, char *buffer, size_t len)
{
    ssize_t ret;
    
    ret = readable_raw(sock, sock->rdtimeout);
    if (ret) return ret;

    do {
	ret = recv(sock->fd, buffer, len, 0);
    } while (ret == -1 && NE_ISINTR(ne_errno));

    if (ret == 0) {
	set_error(sock, _("Connection closed"));
	ret = NE_SOCK_CLOSED;
    } else if (ret < 0) {
	int errnum = ne_errno;
	ret = NE_ISRESET(errnum) ? NE_SOCK_RESET : NE_SOCK_ERROR;
	set_strerror(sock, errnum);
    }

    return ret;
}

#define MAP_ERR(e) (NE_ISCLOSED(e) ? NE_SOCK_CLOSED : \
                    (NE_ISRESET(e) ? NE_SOCK_RESET : NE_SOCK_ERROR))

static ssize_t write_raw(ne_socket *sock, const char *data, size_t length) 
{
    ssize_t ret;
    
    do {
	ret = send(sock->fd, data, length, 0);
    } while (ret == -1 && NE_ISINTR(ne_errno));

    if (ret < 0) {
	int errnum = ne_errno;
	set_strerror(sock, errnum);
	return MAP_ERR(errnum);
    }
    return ret;
}

static const struct iofns iofns_raw = { read_raw, write_raw, readable_raw };

#ifdef HAVE_OPENSSL
/* OpenSSL I/O function implementations. */
static int readable_ossl(ne_socket *sock, int secs)
{
    if (SSL_pending(sock->ssl))
	return 0;
    return readable_raw(sock, secs);
}

/* SSL error handling, according to SSL_get_error(3). */
static int error_ossl(ne_socket *sock, int sret)
{
    int errnum = SSL_get_error(sock->ssl, sret);
    unsigned long err;

    if (errnum == SSL_ERROR_ZERO_RETURN) {
	set_error(sock, _("Connection closed"));
        return NE_SOCK_CLOSED;
    }
    
    /* for all other errors, look at the OpenSSL error stack */
    err = ERR_get_error();
    if (err == 0) {
        /* Empty error stack, presume this is a system call error: */
        if (sret == 0) {
            /* EOF without close_notify, possible truncation */
            set_error(sock, _("Secure connection truncated"));
            return NE_SOCK_TRUNC;
        } else {
            /* Other socket error. */
            errnum = ne_errno;
            set_strerror(sock, errnum);
            return MAP_ERR(errnum);
        }
    }

    if (ERR_reason_error_string(err)) {
        ne_snprintf(sock->error, sizeof sock->error, 
                    _("SSL error: %s"), ERR_reason_error_string(err));
    } else {
	ne_snprintf(sock->error, sizeof sock->error, 
                    _("SSL error code %d/%d/%lu"), sret, errnum, err);
    }
    
    /* make sure the error stack is now empty. */
    ERR_clear_error();
    return NE_SOCK_ERROR;
}

/* Work around OpenSSL's use of 'int' rather than 'size_t', to prevent
 * accidentally passing a negative number, etc. */
#define CAST2INT(n) (((n) > INT_MAX) ? INT_MAX : (n))

static ssize_t read_ossl(ne_socket *sock, char *buffer, size_t len)
{
    int ret;

    ret = readable_ossl(sock, sock->rdtimeout);
    if (ret) return ret;
    
    ret = SSL_read(sock->ssl, buffer, CAST2INT(len));
    if (ret <= 0)
	ret = error_ossl(sock, ret);

    return ret;
}

static ssize_t write_ossl(ne_socket *sock, const char *data, size_t len)
{
    int ret, ilen = CAST2INT(len);
    ret = SSL_write(sock->ssl, data, ilen);
    /* ssl.h says SSL_MODE_ENABLE_PARTIAL_WRITE must be enabled to
     * have SSL_write return < length...  so, SSL_write should never
     * return < length. */
    if (ret != ilen)
	return error_ossl(sock, ret);
    return ret;
}

static const struct iofns iofns_ssl = {
    read_ossl,
    write_ossl,
    readable_ossl
};

#elif defined(HAVE_GNUTLS)

/* Return zero if an alert value can be ignored. */
static int check_alert(ne_socket *sock, ssize_t ret)
{
    const char *alert;

    if (ret == GNUTLS_E_WARNING_ALERT_RECEIVED) {
        alert = gnutls_alert_get_name(gnutls_alert_get(sock->ssl));
        NE_DEBUG(NE_DBG_SOCKET, "TLS warning alert: %s\n", alert);
        return 0;
    } else if (ret == GNUTLS_E_FATAL_ALERT_RECEIVED) {
        alert = gnutls_alert_get_name(gnutls_alert_get(sock->ssl));
        NE_DEBUG(NE_DBG_SOCKET, "TLS fatal alert: %s\n", alert);
        return -1;
    }
    return ret;
}

static int readable_gnutls(ne_socket *sock, int secs)
{
    if (gnutls_record_check_pending(sock->ssl)) {
        return 0;
    }
    return readable_raw(sock, secs);
}

static ssize_t error_gnutls(ne_socket *sock, ssize_t sret)
{
    ssize_t ret;

    switch (sret) {
    case 0:
	ret = NE_SOCK_CLOSED;
	set_error(sock, _("Connection closed"));
	break;
    case GNUTLS_E_FATAL_ALERT_RECEIVED:
	ret = NE_SOCK_RESET;
        ne_snprintf(sock->error, sizeof sock->error, _("SSL error: %s"),
                    gnutls_alert_get_name(gnutls_alert_get(sock->ssl)));
        break;
    default:
        ret = NE_SOCK_ERROR;
        ne_snprintf(sock->error, sizeof sock->error, _("SSL error: %s"),
                    gnutls_strerror(sret));
    }
    return ret;
}

#define RETRY_GNUTLS(sock, ret) ((ret < 0) \
    && (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN \
        || check_alert(sock, ret) == 0))

static ssize_t read_gnutls(ne_socket *sock, char *buffer, size_t len)
{
    ssize_t ret;

    ret = readable_gnutls(sock, sock->rdtimeout);
    if (ret) return ret;
    
    do {
        ret = gnutls_record_recv(sock->ssl, buffer, len);
    } while (RETRY_GNUTLS(sock, ret));

    if (ret <= 0)
	ret = error_gnutls(sock, ret);

    return ret;
}

static ssize_t write_gnutls(ne_socket *sock, const char *data, size_t len)
{
    ssize_t ret;

    do {
        ret = gnutls_record_send(sock->ssl, data, len);
    } while (RETRY_GNUTLS(sock, ret));

    if (ret < 0)
	return error_gnutls(sock, ret);

    return ret;
}

static const struct iofns iofns_ssl = {
    read_gnutls,
    write_gnutls,
    readable_gnutls
};

#endif

int ne_sock_fullwrite(ne_socket *sock, const char *data, size_t len)
{
    ssize_t ret;
    do {
        ret = sock->ops->swrite(sock, data, len);
//		printf("ne_sock_fullwrite return : %d\n",ret);
        if (ret > 0) {
            data += ret;
            len -= ret;
        }
    } while (ret > 0 && len > 0);

    return ret < 0 ? ret : 0;
}

ssize_t ne_sock_readline(ne_socket *sock, char *buf, size_t buflen)
{
    char *lf;
    size_t len;
    
    if ((lf = memchr(sock->bufpos, '\n', sock->bufavail)) == NULL
	&& sock->bufavail < RDBUFSIZ) {
	/* The buffered data does not contain a complete line: move it
	 * to the beginning of the buffer. */
	if (sock->bufavail)
	    memmove(sock->buffer, sock->bufpos, sock->bufavail);
	sock->bufpos = sock->buffer;
	
	/* Loop filling the buffer whilst no newline is found in the data
	 * buffered so far, and there is still buffer space available */ 
	do {
	    /* Read more data onto end of buffer. */
	    ssize_t ret = sock->ops->sread(sock, sock->buffer + sock->bufavail,
                                           RDBUFSIZ - sock->bufavail);
	    if (ret < 0) return ret;
	    sock->bufavail += ret;
	} while ((lf = memchr(sock->buffer, '\n', sock->bufavail)) == NULL
		 && sock->bufavail < RDBUFSIZ);
    }

    if (lf)
	len = lf - sock->bufpos + 1;
    else
	len = buflen; /* fall into "line too long" error... */

    if ((len + 1) > buflen) {
	set_error(sock, _("Line too long"));
	return NE_SOCK_ERROR;
    }

    memcpy(buf, sock->bufpos, len);
    buf[len] = '\0';
    /* consume the line from buffer: */
    sock->bufavail -= len;
    sock->bufpos += len;
    return len;
}

ssize_t ne_sock_fullread(ne_socket *sock, char *buffer, size_t buflen) 
{
    ssize_t len;

    while (buflen > 0) {
	len = ne_sock_read(sock, buffer, buflen);
	if (len < 0) return len;
	buflen -= len;
	buffer += len;
    }

    return 0;
}

#ifndef INADDR_NONE
#define INADDR_NONE ((in_addr_t) -1)
#endif

#if !defined(USE_GETADDRINFO) && !defined(HAVE_DECL_H_ERRNO) && !defined(WIN32)
/* Ancient versions of netdb.h don't export h_errno. */
extern int h_errno;
#endif

/* This implemementation does not attempt to support IPv6 using
 * gethostbyname2 et al.  */


#include <stdio.h>
#include <windows.h>
#include <process.h>
//#include <winsock2.h>
//#include <netdb.h>

#define CACHE_MAX_CNT	512
#define MAX_ADDR_CNT	16

//HANDLE hThread;

/*
typedef struct
{
	char hostname[256];
	struct hostent hp;
} threadParam;
*/


/*
struct  hostent {
        char    FAR * h_name;           
        char    FAR * FAR * h_aliases;  
        short   h_addrtype;             
        short   h_length;               
        char    FAR * FAR * h_addr_list;
#define h_addr  h_addr_list[0]          
};
*/
typedef struct
{
        char    h_name[256];           
        char    h_aliases[256];  
        short   h_addrtype;             
        short   h_length;               
        char    h_addr_list[256];
} threadParam;



DWORD WINAPI GetHostThreadFunction(threadParam * sThreadParam);

DWORD WINAPI GetHostThreadFunction(threadParam * sThreadParam)
{
	struct hostent *tmp_hp;
	struct in_addr in1, in2;
	char sHaddr[10][128];

	int i;
	char *p;

	memset(sHaddr, 0, sizeof(sHaddr) );

	tmp_hp = gethostbyname(sThreadParam->h_name);

	
	//printf("in_addr s[%d]\n", sizeof(struct in_addr));
	if(tmp_hp)
	{
		//memset(&(sThreadParam->hp), 0,  sizeof(struct hostent));
		//memcpy( &(sThreadParam-> hp), tmp_hp, sizeof(struct hostent));

		for (i = 0, p = tmp_hp->h_addr_list[0]; p != NULL;  p=tmp_hp->h_addr_list[++i]) 
		{
				memcpy(sHaddr[i], p, tmp_hp->h_length);
                memcpy(&in1.s_addr, p, tmp_hp->h_length);
                //printf("IP aliases1: %s\n",inet_ntoa(in1));

				memcpy(&in2.s_addr, sHaddr[i], tmp_hp->h_length);
                //printf("IP aliases2: %s\n",inet_ntoa(in2));
		}


		sThreadParam->h_length		= tmp_hp->h_length;
		sThreadParam->h_addrtype	= tmp_hp->h_addrtype;		// for test, sThreadParam->h_addrtype = hp->h_addrtype;

		memset(sThreadParam->h_addr_list, 0, sizeof(sThreadParam->h_addr_list));

		for (i = 0, p = tmp_hp->h_addr_list[0]; p != NULL;  p=tmp_hp->h_addr_list[++i])
			memcpy(sThreadParam->h_addr_list + (i * tmp_hp->h_length) , p, tmp_hp->h_length);

		

		//for (i = 0, p = sThreadParam->h_addr_list[0]; p != NULL;  p=sThreadParam->h_addr_list[++i]) 
		for (i = 0, p = sThreadParam->h_addr_list; p != NULL && *p != NULL
			;  p=sThreadParam->h_addr_list + (++i * tmp_hp->h_length)) 
		{
                memcpy(&in1.s_addr, p, sThreadParam->h_length);
                //printf("IP aliases3: %s\n",inet_ntoa(in1));
		}


		return TRUE;
		// 정보를 제대로 얻어오네?
	}
	else
	{
		return FALSE;
	}
}



ne_sock_addr *ne_addr_resolve(const char *hostname, int flags)
{
    ne_sock_addr *addr = ne_calloc(sizeof *addr);
#ifdef USE_GETADDRINFO
    struct addrinfo hints = {0};
    char *pnt;
    hints.ai_socktype = SOCK_STREAM;
    if (hostname[0] == '[' && ((pnt = strchr(hostname, ']')) != NULL)) {
	char *hn = ne_strdup(hostname + 1);
	hn[pnt - hostname - 1] = '\0';
#ifdef AI_NUMERICHOST /* added in the RFC2553 API */
	hints.ai_flags = AI_NUMERICHOST;
#endif
        hints.ai_family = AF_INET6;
	addr->errnum = getaddrinfo(hn, NULL, &hints, &addr->result);
	ne_free(hn);
    } else {
#ifdef USE_GAI_ADDRCONFIG /* added in the RFC3493 API */
        hints.ai_flags = AI_ADDRCONFIG;
        hints.ai_family = AF_UNSPEC;
        addr->errnum = getaddrinfo(hostname, NULL, &hints, &addr->result);
#else
        hints.ai_family = ipv6_disabled ? AF_INET : AF_UNSPEC;
	addr->errnum = getaddrinfo(hostname, NULL, &hints, &addr->result);
#endif
    }
#else /* Use gethostbyname() */
    in_addr_t laddr;
    struct hostent *hp = NULL, *pHp = NULL;
	static struct hostent *stHp[CACHE_MAX_CNT]	= {0,};

	static unsigned char CacheInitialized = FALSE, FirstTried = TRUE;
	unsigned char CacheVerified = FALSE, CacheFound = FALSE ;	// 캐쉬 검색 안했음
	unsigned char HostCheckFlag = FALSE;	// 이전 질의된 host명과 동일

	static char *oldHostName	= NULL;
	static char *oldIpAddress	= NULL;

	static time_t oldTime = 0;
							
	time_t currentTime;
	int errnum = -1;

	threadParam sThreadParam;

	memset(&sThreadParam, 0, sizeof(threadParam));


	
    laddr = inet_addr(hostname);
    if (laddr == INADDR_NONE) {
//hp = gethostbyname(hostname);


	DWORD dwThreadID, ThreadReturnValue = FALSE, dwErr;
	HANDLE hThread;
		
	currentTime = time(0);

	if(FirstTried == TRUE)
	{
		oldTime = currentTime ;
		currentTime += dns_cache_reload_time;
	}

	
//////////////////////////////////////////////////////////////////////////////////

	#ifdef __DEBUG__
	{
		char msg_tries[256];
		memset(msg_tries, 0, 256);
		sprintf(msg_tries, "==> 검색 요청 host [%s]",  hostname);
		writing_file(msg_tries);
	}
	#endif

	// DNS Caching 기능 사용하지 않음
	if(dns_query_timeout == -1)
	{
		hp = gethostbyname(hostname);
		
		if(hp && hp->h_name)
		{
	#ifdef __DEBUG__
			{
				char msg_tries[256];
				memset(msg_tries, 0, 256);
				sprintf(msg_tries, "==> ** 캐쉬 사용하지 않음  ** DNS 정보 획득 [%s] [%p] ThreadReturnValue[%ld]"
				, hp->h_name, hp, ThreadReturnValue );

				writing_file(msg_tries);
			}
	#endif
		}
	}
	else	// DNS Caching 기능 사용
	{
		

		if(CacheInitialized == FALSE)
		{
			int i;
		
			for(i = 0; i < CACHE_MAX_CNT; i++)
			{
				stHp[i] = malloc(sizeof(struct hostent));

				if(stHp[i] == NULL)
				{
					printf("xxxxxxxxxxxxx shHp[%d] malloc err\n", i);
					return -1;
				}

				memset(stHp[i], 0, sizeof(struct hostent));
				stHp[i]->h_name = NULL;

			}

			CacheInitialized = TRUE;

			//printf("xxxxxxxxxxxxx CacheInitialized [%d]\n", i);
		}

		if(oldHostName == NULL)
		{
			oldHostName = malloc(512);

			if(oldHostName == NULL)
			{
				printf("xxxxxxxxxxxxx oldHostName malloc err\n");
				return -1;
			}
		}

		if(oldIpAddress == NULL)
		{
			oldIpAddress = malloc(20);

			if(oldIpAddress == NULL)
			{
				printf("xxxxxxxxxxxxx oldIpAddress malloc err\n");
				return -1;
			}
		}

		if(oldHostName)
		{
			if (strncmp(oldHostName, hostname, strlen(hostname)) == 0)
				HostCheckFlag = TRUE;	// host명 일치 dns 정보 필요 없음
			else
			{
				memset(oldHostName, 0, 512);

				strncpy(oldHostName, hostname, strlen(hostname));
				HostCheckFlag = FALSE;	// 이전 host명이 없거나, 불일치 dns 정보 필요
			}
		}

#if 0
		#ifdef __DEBUG__
		{
			int k;
			for(k = 0; k < CACHE_MAX_CNT; k++)
			{
				if(stHp[k]->h_name  )
				{
						char msg_tries[256];
						memset(msg_tries, 0, 256);
						sprintf(msg_tries, "==> 캐쉬정보1 [%s] stHp[%d][%s][%p]"
							, hostname, k, stHp[k]->h_name, stHp[k] );
						writing_file(msg_tries);
				}
			}
		}
		#endif
#endif

		
		if(FirstTried == FALSE)
		{
			// 60초 동안에는 캐쉬 사용
			if(currentTime - oldTime < dns_cache_reload_time)	
			{
				int i;

				#ifdef __DEBUG__			
				{
					char msg_tries[256];
					memset(msg_tries, 0, 256);
					sprintf(msg_tries, "==> 캐쉬검색 ");
					writing_file(msg_tries);
				}
				#endif

				CacheVerified	= TRUE;					
				CacheFound		= FALSE;

				for(i = 0; i < CACHE_MAX_CNT && (stHp[i]->h_name); i++)
				{
#if 0
					#ifdef __DEBUG__			
					{
						char msg_tries[256];

						if(stHp[i]->h_name)
						{
							memset(msg_tries, 0, 256);
							sprintf(msg_tries, "==> 캐쉬 정보 stHp[%s][%d]", stHp[i]->h_name, i );
							writing_file(msg_tries);
						}
					}
					#endif
#endif

					if(stHp[i]->h_name && ( (strncmp(hostname, stHp[i]->h_name, strlen(hostname)) == 0) ) )
					{
						hp = stHp[i];

						CacheFound = TRUE;

						#ifdef __DEBUG__			
						{
							char msg_tries[256];
							memset(msg_tries, 0, 256);
							sprintf(msg_tries, "==> 캐쉬에서 DNS 정보 획득 [%s] stHp[%d][%p]"
								, hp->h_name, i, hp );
							writing_file(msg_tries);
						}
						#endif

						break;
					}
				}
			}	// end of 60초 동안은 캐쉬 사용

			// 캐쉬에 없는 내용일 경우, 쓰레드 실행 gethostbyname(60)
			if ( (currentTime - oldTime >= dns_cache_reload_time)	||	
				(CacheVerified == TRUE && CacheFound == FALSE ) )	
			{
				//memset(&sThreadParam, 0, sizeof(sThreadParam));
				memcpy(sThreadParam.h_name, hostname, strlen(hostname));

				// 주기적으로 캐쉬 초기화
				if(currentTime - oldTime >= dns_cache_reload_time)
				{
					int i;
					
					#ifdef __DEBUG__
					{
						int k;
						for(k = 0; k < CACHE_MAX_CNT; k++)
						{
							if(stHp[k]->h_name  )
							{
								char msg_tries[256];
								memset(msg_tries, 0, 256);
								sprintf(msg_tries, "==> 캐쉬 삭제전 캐쉬정보 [%s] stHp[%d][%s][%p]"
									, hostname, k, stHp[k]->h_name, stHp[k] );
								writing_file(msg_tries);
							}
						}
					}
					#endif

					for(i = 0; i < CACHE_MAX_CNT; i++)
					{
						memset(stHp[i], 0, sizeof(struct hostent));	
					}

					oldTime = currentTime;
				}

				//
				// gethostbyname(60)
				//
				hThread = (HANDLE)_beginthreadex (
					NULL, 0,
					GetHostThreadFunction,
					&sThreadParam, 0,
					(unsigned *)&dwThreadID
					);

				if (hThread == 0) 
				{
					fputs("DNS Thread creation error\n", stdout);
				}

				
				//dwErr = WAIT_OBJECT_0;	// 0
				//dwErr = WAIT_TIMEOUT;		// 258
				
#if 1
				dwErr = WaitForSingleObject(hThread, dns_query_timeout);
#else
				dwErr = WaitForSingleObject(hThread, 1);
#endif
				

	#if 1
				//정상
				if(dwErr == WAIT_OBJECT_0) // 정상
					GetExitCodeThread(hThread, &ThreadReturnValue);
				else //if(dwErr == WAIT_TIMEOUT) 
				{
					TerminateThread(hThread, -1);
				}
	#else
				//비정상
				if(dwErr == WAIT_OBJECT_0) // 정상 -> 쓰레드로 디버깅 돌리기 위해 for toto
					ThreadReturnValue = FALSE;
				else //if(dwErr == WAIT_TIMEOUT) 
					GetExitCodeThread(hThread, &ThreadReturnValue);
	#endif				

	#ifdef __DEBUG__
	{
		char msg_tries[256];
		char result_buf[64];
		char thread_return_buf[64];
		memset(msg_tries, 0, 256);
		memset(result_buf, 0, 64);
		memset(thread_return_buf, 0, 64);

		switch(dwErr)
		{
		case WAIT_OBJECT_0:
			strcpy(result_buf, "WAIT_OBJECT_0");
			break;
		case WAIT_TIMEOUT:
			strcpy(result_buf, "WAIT_TIMEOUT");
			break;
		default:
			strcpy(result_buf, "ETC");
			break;
		}

		switch(ThreadReturnValue)
		{
		case TRUE:
			strcpy(thread_return_buf, "TRUE");
			break;
		case FALSE:
			strcpy(thread_return_buf, "FALSE");
			break;
		case STILL_ACTIVE:
			strcpy(thread_return_buf, "STILL_ACTIVE");
			break;
		default:
			strcpy(thread_return_buf, "ETC");
			break;
		}
			


		sprintf(msg_tries, "[DNS Thread] 쓰레드 종료 코드 dwErr[%d][%s] ThreadReturnValue[%d][%s]"
			, dwErr, result_buf
			, ThreadReturnValue, thread_return_buf);

		writing_file(msg_tries);
	}
	#endif




				CloseHandle(hThread);	// thread오브젝트 소멸

				#ifdef __DEBUG__
				{
					char msg_tries[256];
					memset(msg_tries, 0, 256);

					if( CacheFound == FALSE)
						sprintf(msg_tries, "캐쉬에 없다   thread 검색  ");
					else
						sprintf(msg_tries, "캐쉬 reload로 thread 검색 ");

					writing_file(msg_tries);
				}
				#endif

				if(ThreadReturnValue == TRUE)	// 쓰레드 조회 성공
				{
					int i, n;
					struct in_addr in1;
					char *p;

					#ifdef __DEBUG__
					{
						char msg_tries[256];
						memset(msg_tries, 0, 256);
						sprintf(msg_tries, "[thread 검색성공]");

						writing_file(msg_tries);
					}
					#endif

////////////////////////////////////////////////////////////////////////////
// 캐쉬 할당
////////////////////////////////////////////////////////////////////////////							

					pHp = hp = malloc(sizeof (struct hostent));

					if(hp)
					{

						hp->h_name		= &sThreadParam.h_name;
						hp->h_addrtype	= sThreadParam.h_addrtype;
						hp->h_length	= sThreadParam.h_length;

						for (i = 0, p = sThreadParam.h_addr_list; p != NULL && *p != NULL
							;  p=sThreadParam.h_addr_list + (++i * sThreadParam.h_length)) 
								;

						n = i;

						hp->h_addr_list = (char **)malloc(sizeof (char *) * (i + 1));

						if(hp->h_addr_list)
						{
						
							for(i = 0; i < n + 1; i++)		// for end NULL
								hp->h_addr_list[i] = NULL;

							for (i = 0, p = sThreadParam.h_addr_list; p != NULL && *p != NULL
								;  p=sThreadParam.h_addr_list + (++i * sThreadParam.h_length)) 
								hp->h_addr_list[i] =  p; 

		#ifdef __DEBUG__
							for (i = 0, p = hp->h_addr_list[0]; i < n ;  p=hp->h_addr_list[++i]) 
							{
								memcpy(&in1.s_addr, p, hp->h_length);
								//printf("IP aliases4: %s\n",inet_ntoa(in1));
							}
		#endif
						}
		
					}

////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
					
				}		// end of  쓰레드 조회 성공
				else 
				if(ThreadReturnValue == FALSE)	// 쓰레드 조회 실패
				{
					#ifdef __DEBUG__
					{
						char msg_tries[256];
						memset(msg_tries, 0, 256);
						sprintf(msg_tries, "[thread 검색실패]");

						writing_file(msg_tries);
					}
					#endif

					if( CacheVerified == FALSE )	// thread 실패이고, 캐쉬 검색 안했었을 경우
					{
						int i;

						#ifdef __DEBUG__
						{
							char msg_tries[256];
							memset(msg_tries, 0, 256);
							sprintf(msg_tries, "[thread 검색실패] 캐쉬에서 조회");

							writing_file(msg_tries);
						}
						#endif


						CacheVerified	= TRUE;
						CacheFound		= FALSE;

						for(i = 0; i < CACHE_MAX_CNT; i++)
						{
							if(stHp[i]->h_name && (strncmp(hostname, stHp[i]->h_name, strlen(hostname)) == 0) )
							{
								CacheFound = TRUE;

								hp = stHp[i];

								#ifdef __DEBUG__			
								{
									char msg_tries[256];
									memset(msg_tries, 0, 256);
									sprintf(msg_tries, "==> 캐쉬에서 DNS 정보 획득 [%s] stHp[%d][%p]", hp->h_name, i, hp );
									writing_file(msg_tries);
								}
								#endif

								break;
							}
						}
						

					}	// end of 쓰레드 실패 후, 캐쉬 조사 실패

				}	// end of 쓰레드 실패 일 경우
			
			}	// end of 캐쉬에 없는 내용일 경우

		}	// end of 첫질의 아닌경우

		//oldTime = currentTime;
	} // end of DNS Caching 기능 사용




	// gethostbyname(INFINITE) 실패는 없다
	//if(	FirstTried == TRUE	|| 
	//	FirstTried == FALSE	&& (ThreadReturnValue == FALSE && CacheFound == FALSE) )

	if(	FirstTried == TRUE)
	{
		#ifdef __DEBUG__
		{
			char msg_tries[256];
			memset(msg_tries, 0, 256);

			sprintf(msg_tries, "==> ** gethostbyname()** 검색 시작");

			if(FirstTried == TRUE)
				strcat(msg_tries, "[최초]");

			if(ThreadReturnValue == FALSE)
				strcat(msg_tries, "[thread 실패]");

			if(CacheFound == FALSE)
				strcat(msg_tries, "[캐쉬검색 실패]");

			writing_file(msg_tries);
		}
		#endif


		hp = gethostbyname(hostname);

		#ifdef __DEBUG__
		{
			char msg_tries[256];
			memset(msg_tries, 0, 256);

			sprintf(msg_tries, "==> ** gethostbyname()** 검색 완료 hp[%p]", hp);

			writing_file(msg_tries);
		}
		#endif


		if(hp && hp->h_name)
		{
			#ifdef __DEBUG__
			{
				char msg_tries[256];
				memset(msg_tries, 0, 256);

				sprintf(msg_tries, "==> ** gethostbyname()** DNS 정보 획득 [%s] [%p] ThreadReturnValue[%ld]"
						, hp->h_name, hp, ThreadReturnValue );

				writing_file(msg_tries);
			}
			#endif

			if(FirstTried  == TRUE)
				FirstTried = FALSE;
		}
		else
		{
			//hp = NULL;

			#ifdef __DEBUG__			
			{
				char msg_tries[256];
				memset(msg_tries, 0, 256);
				sprintf(msg_tries, "==> HP is NULL!!!! 할만큼 했다");
				writing_file(msg_tries);
			}
			#endif
		}	// 이건.. 막장이다.
	}	


///////////////////////////////////////////////////////////////////////
// 캐쉬 저장
///////////////////////////////////////////////////////////////////////
	if( (dns_query_timeout != -1) && (CacheFound == FALSE) && (hp && hp->h_name && strlen(hp->h_name) > 0))
	{
		int st, i, n;
		char *p;
		struct in_addr in1;

		for(st = 0; st < CACHE_MAX_CNT; st++)
		{
			// 같은 이름이 존재하면 통과
			if( (stHp[st]->h_name && strlen(stHp[st]->h_name) > 0) && (strcmp(hostname, stHp[st]->h_name) == 0) )  
				break;

			if( stHp[st]->h_name == NULL)  // 비었으면
			{
				//
				//	hostent copy logic
				//
				stHp[st]->h_length		= hp->h_length;
				stHp[st]->h_addrtype	= hp->h_addrtype;

				stHp[st]->h_name = malloc(strlen(hp->h_name) + 1);
				memset(stHp[st]->h_name, 0, strlen(hp->h_name) + 1);
				strcpy(stHp[st]->h_name, hp->h_name);
				
				for (i = 0, p = hp->h_addr_list[0]; p != NULL;  p=hp->h_addr_list[++i])
						;

				n = i;

				//stHp[st]->h_addr_list = (char **)malloc(  (i * sizeof (char *))  + 1);		
				stHp[st]->h_addr_list = (char **)malloc(  sizeof (char *) * (i + 1) );		
				memset(stHp[st]->h_addr_list, 0, sizeof (char *) * (i + 1) );

				for(i = 0; i < n + 1; i++)		// for end NULL
					stHp[st]->h_addr_list[i] = NULL;

				for (i = 0, p = hp->h_addr_list[0]; i < n; p=hp->h_addr_list[++i])
				{
					stHp[st]->h_addr_list[i] = (char *)malloc(	hp->h_length);
					memset(stHp[st]->h_addr_list[i], 0,			hp->h_length);
					memcpy(stHp[st]->h_addr_list[i], p, hp->h_length);
				}

		for (i = 0, p = hp->h_addr_list[0]; i < n ;  p=hp->h_addr_list[++i]) 
		{
			memcpy(&in1.s_addr, p, hp->h_length);
			//printf("IP aliases5: %s\n",inet_ntoa(in1));
		}

				#ifdef __DEBUG__			
				{
					char msg_tries[256];
					memset(msg_tries, 0, 256);
					sprintf(msg_tries, "==> 캐쉬 삽입 완료 [%s] stHp[%d][%p]"
						, stHp[st]->h_name, st, stHp[st] );
					writing_file(msg_tries);
				}
				#endif

				break;
			}
		}
	}

///////////////////////////////////////////////////////////////////////



	if (hp == NULL) {
#ifdef WIN32
	    //addr->errnum = WSAGetLastError();
		addr->errnum = NO_RECOVERY;
#else
            addr->errnum = h_errno;
#endif
	} else if (hp->h_length != sizeof(struct in_addr)) {
	    /* fail gracefully if somebody set RES_USE_INET6 */
	    addr->errnum = NO_RECOVERY;

#ifdef __DEBUG__
	{
		char msg_tries[256];
		memset(msg_tries, 0, 256);

		sprintf(msg_tries, "xxxxxxxxxxxxxxxxxxxxxxhp->h_length [%d] sizeof(struct in_addr) [%d]"
			, hp->h_length, sizeof(struct in_addr));

		writing_file(msg_tries);
	}
#endif

	} else {
	    size_t n;
		
	    /* count addresses */
	    //for (n = 0; hp->h_addr_list[n] != NULL; n++)
		/* noop */;


		///////////////////////////////////////////////////////////////////////////
		///////////////////////////////////////////////////////////////////////////
		// 왠지 모르지만 n 값이 넘어간다. 그래서 편법으로 h_addrtype을 이용했다.
		///////////////////////////////////////////////////////////////////////////
		///////////////////////////////////////////////////////////////////////////
		//for (n = 0; n < hp->h_addrtype  && (hp->h_addr_list[n] != NULL); n++)
		///* noop */;

		for (n = 0; n < hp->h_addr_list[n] != NULL; n++)
		/* noop */;

#if 0
		addr->count = n;

	    addr->addrs = ne_malloc(n * sizeof *addr->addrs);

	    for (n = 0; n < addr->count; n++)
		memcpy(&addr->addrs[n], hp->h_addr_list[n], hp->h_length);
#else

		addr->count = n;
		addr->addrs = ne_malloc(n * sizeof *addr->addrs);

		if( (HostCheckFlag == TRUE) && oldIpAddress && (addr->count > 0))
		{
			int rotate_index;
			static int rotate_adding_number = 0;

			rotate_adding_number = (rotate_adding_number + 1)  % (addr->count);

			// 이전 주소와 현재 주소가 같다면 rotate 시킨다
			for (n = 0; n < addr->count; n++)
			{
				rotate_index = (n + rotate_adding_number) % (addr->count);
				memcpy(&addr->addrs[rotate_index], hp->h_addr_list[n], hp->h_length);
			}
		}
		else
		{
			for (n = 0; n < addr->count; n++)	
				memcpy(&addr->addrs[n], hp->h_addr_list[n], hp->h_length);



		}

		if(dns_query_timeout != -1)
		{
			strcpy(oldIpAddress, inet_ntoa(addr->addrs[0]) );

			#ifdef __DEBUG__
			{
				char msg_tries[256];
				memset(msg_tries, 0, 256);

				sprintf(msg_tries, " 최종 주소 : [%s]", oldIpAddress);
				writing_file(msg_tries);

			}
			#endif

		}

#endif
	}





////////////////////////////////////////////////////////////////////////////
// pHp->h_addr_list[0] 캐쉬 해제가 안되는구나
////////////////////////////////////////////////////////////////////////////							
	
	if ( (dns_query_timeout != -1) && pHp )
	{

		if(pHp->h_addr_list)
			free((char **)pHp->h_addr_list);

		if(pHp)
			free(pHp);
	}
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////





	} else {
	addr->addrs = ne_malloc(sizeof *addr->addrs);
	addr->count = 1;
	memcpy(addr->addrs, &laddr, sizeof *addr->addrs);
    }
#endif



	



	


    return addr;
}

int ne_addr_result(const ne_sock_addr *addr)
{
    return addr->errnum;
}

const ne_inet_addr *ne_addr_first(ne_sock_addr *addr)
{
#ifdef USE_GETADDRINFO
    addr->cursor = addr->result->ai_next;
    return addr->result;
#else
    addr->cursor = 0;
    return &addr->addrs[0];
#endif
}

const ne_inet_addr *ne_addr_next(ne_sock_addr *addr)
{
#ifdef USE_GETADDRINFO
    struct addrinfo *ret = addr->cursor;
    if (addr->cursor) addr->cursor = addr->cursor->ai_next;
#else
    struct in_addr *ret;
    if (++addr->cursor < addr->count)
	ret = &addr->addrs[addr->cursor];
    else
	ret = NULL;
#endif
    return ret;
}

char *ne_addr_error(const ne_sock_addr *addr, char *buf, size_t bufsiz)
{
#ifdef WIN32
    print_error(addr->errnum, buf, bufsiz);
#else
    const char *err;
#ifdef USE_GETADDRINFO
    /* override horrible generic "Name or service not known" error. */
    if (addr->errnum == EAI_NONAME)
	err = _("Host not found");
    else
	err = gai_strerror(addr->errnum);
#elif defined(HAVE_HSTRERROR)
    err = hstrerror(addr->errnum);
#else
    err = _("Host not found");
#endif
    ne_strnzcpy(buf, err, bufsiz);
#endif /* WIN32 */
    return buf;
}

char *ne_iaddr_print(const ne_inet_addr *ia, char *buf, size_t bufsiz)
{
#if defined(USE_GETADDRINFO) && defined(HAVE_INET_NTOP)
    const char *ret;
#ifdef AF_INET6
    if (ia->ai_family == AF_INET6) {
	struct sockaddr_in6 *in6 = SACAST(in6, ia->ai_addr);
	ret = inet_ntop(AF_INET6, &in6->sin6_addr, buf, bufsiz);
    } else
#endif
    if (ia->ai_family == AF_INET) {
	struct sockaddr_in *in = SACAST(in, ia->ai_addr);
	ret = inet_ntop(AF_INET, &in->sin_addr, buf, bufsiz);
    } else
	ret = NULL;
    if (ret == NULL)
	ne_strnzcpy(buf, "[IP address]", bufsiz);
#elif defined(USE_GETADDRINFO) && defined(NI_NUMERICHOST)
    /* use getnameinfo instead for Win32, which lacks inet_ntop: */
    if (getnameinfo(ia->ai_addr, ia->ai_addrlen, buf, bufsiz, NULL, 0,
                    NI_NUMERICHOST))
        ne_strnzcpy(buf, "[IP address]", bufsiz);
#else /* USE_GETADDRINFO */
    ne_strnzcpy(buf, inet_ntoa(*ia), bufsiz);
#endif
    return buf;
}

void ne_addr_destroy(ne_sock_addr *addr)
{
#ifdef USE_GETADDRINFO
    if (addr->result)
	freeaddrinfo(addr->result);
#else
    if (addr->addrs)
	ne_free(addr->addrs);
#endif
    ne_free(addr);
}






typedef struct
{
	int fd;
	struct sockaddr_in sa;	
} RConnect;


DWORD WINAPI ConnectThreadFunction(const RConnect * SConnect);

DWORD WINAPI ConnectThreadFunction(const RConnect * SConnect)
{
	DWORD ConnectValue;



	ConnectValue = connect(SConnect->fd,  (struct sockaddr *) &(SConnect->sa), sizeof SConnect->sa );
	//connect(SConnect.fd, &SConnect.sa, sizeof SConnect.sa );

	

	return ConnectValue;
}


/* Connect socket 'fd' to address 'addr' on given 'port': */
static int raw_connect(int fd, const ne_inet_addr *addr, unsigned int port)
{

#ifdef USE_GETADDRINFO
#ifdef AF_INET6
    /* fill in the _family field for AIX 4.3, which forgets to do so. */
    if (addr->ai_family == AF_INET6) {
	struct sockaddr_in6 in6;
	memcpy(&in6, addr->ai_addr, sizeof in6);
	in6.sin6_port = port;
        in6.sin6_family = AF_INET6;
	return connect(fd, (struct sockaddr *)&in6, sizeof in6);
    } else
#endif
    if (addr->ai_family == AF_INET) {
	struct sockaddr_in in;
	memcpy(&in, addr->ai_addr, sizeof in);
	in.sin_port = port;
        in.sin_family = AF_INET;
	return connect(fd, (struct sockaddr *)&in, sizeof in);
    } else {
	errno = EINVAL;
	return -1;
    }
#else

	RConnect SConnect;
	DWORD dwThreadID, ConnectValue = 0, dwErr;
	HANDLE hConnectThread;

	struct sockaddr_in sa = {0};
    sa.sin_family = AF_INET;
    sa.sin_port = port;
    sa.sin_addr = *addr;

	
	SConnect.fd = fd;
	SConnect.sa.sin_family	= sa.sin_family;
    SConnect.sa.sin_port	= sa.sin_port;
    SConnect.sa.sin_addr	= sa.sin_addr;

	hConnectThread = (HANDLE)_beginthreadex (
		NULL, 0,
		ConnectThreadFunction,
		//NULL, 0,
		&SConnect, 0,
		(unsigned *)&dwThreadID
		);

	if (hConnectThread == 0) {
		fputs("Thread creation error\n", stdout);
		return -1;
	};


	// 4초동안 타이머 작동 시작

	WaitForSingleObject(hConnectThread, socket_connect_timeout);

	GetExitCodeThread(hConnectThread, &ConnectValue);

	CloseHandle(hConnectThread);	// thread오브젝트 소멸

	return ConnectValue;

#endif
}

////////////////////////////////////////////////////////////////////





ne_socket *ne_sock_create(void)
{
    ne_socket *sock = ne_calloc(sizeof *sock);
    sock->rdtimeout = SOCKET_READ_TIMEOUT;
    sock->bufpos = sock->buffer;
    sock->ops = &iofns_raw;
    sock->fd = -1;
    return sock;
}

int ne_sock_connect(ne_socket *sock, const ne_inet_addr *addr, unsigned int port)
{
    int fd;
	LINGER linger;                         // 윈도우 기준입니다…linux라면 struct linger linger; 로 하세요

#ifdef USE_GETADDRINFO
    // use SOCK_STREAM rather than ai_socktype: some getaddrinfo
    // implementations do not set ai_socktype, e.g. RHL6.2. 
    fd = socket(addr->ai_family, SOCK_STREAM, addr->ai_protocol);
#else
    fd = socket(AF_INET, SOCK_STREAM, 0);

	
	linger.l_onoff = 1;                     // LINGER ON
	linger.l_linger = 0;                     // No WAIT
	setsockopt(fd, SOL_SOCKET, SO_LINGER, &linger, sizeof(linger));
#endif
	if (fd < 0) {
        set_strerror(sock, ne_errno);
			return -1;
    }
    
#if !defined(NE_USE_POLL) && !defined(WIN32)
    if (fd > FD_SETSIZE) {
        ne_close(fd);
        set_error(sock, _("Socket descriptor number exceeds FD_SETSIZE"));
        return NE_SOCK_ERROR;
    }
#endif

#if defined(TCP_NODELAY) && defined(HAVE_SETSOCKOPT) && defined(IPPROTO_TCP)
    { /* Disable the Nagle algorithm; better to add write buffering
       * instead of doing this. */
        int flag = 1;
        setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof flag);
    }
#endif
	if (raw_connect(fd, addr, htons(port))) {
		set_strerror(sock, ne_errno);
		shutdown(fd, SD_BOTH);
		ne_close(fd);
		return -1;
	}

    sock->fd = fd;
    return 0;
}

ne_inet_addr *ne_iaddr_make(ne_iaddr_type type, const unsigned char *raw)
{
    ne_inet_addr *ia;
#if !defined(AF_INET6) || !defined(USE_GETADDRINFO)
    /* fail if IPv6 address is given if IPv6 is not supported. */
    if (type == ne_iaddr_ipv6)
	return NULL;
#endif
    ia = ne_calloc(sizeof *ia);
#ifdef USE_GETADDRINFO
    /* ai_protocol and ai_socktype aren't used by raw_connect so
     * ignore them here. (for now) */
    if (type == ne_iaddr_ipv4) {
	struct sockaddr_in *in4 = ne_calloc(sizeof *in4);
	ia->ai_family = AF_INET;
	ia->ai_addr = (struct sockaddr *)in4;
	ia->ai_addrlen = sizeof *in4;
	in4->sin_family = AF_INET;
	memcpy(&in4->sin_addr.s_addr, raw, sizeof in4->sin_addr.s_addr);
    }
#ifdef AF_INET6
    else {
	struct sockaddr_in6 *in6 = ne_calloc(sizeof *in6);
	ia->ai_family = AF_INET6;
	ia->ai_addr = (struct sockaddr *)in6;
	ia->ai_addrlen = sizeof *in6;
	in6->sin6_family = AF_INET6;
	memcpy(&in6->sin6_addr, raw, sizeof in6->sin6_addr.s6_addr);
    }
#endif
#else /* !USE_GETADDRINFO */
    memcpy(&ia->s_addr, raw, sizeof ia->s_addr);
#endif    
    return ia;
}

ne_iaddr_type ne_iaddr_typeof(const ne_inet_addr *ia)
{
#ifdef USE_GETADDRINFO
    return ia->ai_family == AF_INET6 ? ne_iaddr_ipv6 : ne_iaddr_ipv4;
#else
    return ne_iaddr_ipv4;
#endif
}

int ne_iaddr_cmp(const ne_inet_addr *i1, const ne_inet_addr *i2)
{
#ifdef USE_GETADDRINFO
    if (i1->ai_family != i2->ai_family)
	return i2->ai_family - i1->ai_family;
    if (i1->ai_family == AF_INET) {
	struct sockaddr_in *in1 = SACAST(in, i1->ai_addr), 
	    *in2 = SACAST(in, i2->ai_addr);
	return memcmp(&in1->sin_addr.s_addr, &in2->sin_addr.s_addr, 
		      sizeof in1->sin_addr.s_addr);
    } else if (i1->ai_family == AF_INET6) {
	struct sockaddr_in6 *in1 = SACAST(in6, i1->ai_addr), 
	    *in2 = SACAST(in6, i2->ai_addr);
	return memcmp(in1->sin6_addr.s6_addr, in2->sin6_addr.s6_addr,
		      sizeof in1->sin6_addr.s6_addr);
    } else
	return -1;
#else
    return memcmp(&i1->s_addr, &i2->s_addr, sizeof i1->s_addr);
#endif
}

void ne_iaddr_free(ne_inet_addr *addr)
{
#ifdef USE_GETADDRINFO
    ne_free(addr->ai_addr);
#endif
    ne_free(addr);
}

int ne_sock_accept(ne_socket *sock, int listener) 
{
    int fd = accept(listener, NULL, NULL);

    if (fd < 0)
        return -1;

    sock->fd = fd;
    return 0;
}

int ne_sock_fd(const ne_socket *sock)
{
    return sock->fd;
}

void ne_sock_read_timeout(ne_socket *sock, int timeout)
{
    sock->rdtimeout = timeout;
}

#ifdef NE_HAVE_SSL

int ne_sock_accept_ssl(ne_socket *sock, ne_ssl_context *ctx)
{
    int ret;
    ne_ssl_socket ssl;

#if defined(HAVE_OPENSSL)
    ssl = SSL_new(ctx->ctx);
    
    SSL_set_fd(ssl, sock->fd);

    sock->ssl = ssl;
    ret = SSL_accept(ssl);
    if (ret != 1) {
        return error_ossl(sock, ret);
    }
#elif defined(HAVE_GNUTLS)
    gnutls_init(&ssl, GNUTLS_SERVER);
    gnutls_credentials_set(ssl, GNUTLS_CRD_CERTIFICATE, ctx->cred);
    gnutls_set_default_priority(ssl);

    sock->ssl = ssl;
    gnutls_transport_set_ptr(sock->ssl, (gnutls_transport_ptr) sock->fd);
    ret = gnutls_handshake(ssl);
    if (ret < 0) {
        return error_gnutls(sock, ret);
    }
#endif
    sock->ops = &iofns_ssl;
    return 0;
}

int ne_sock_connect_ssl(ne_socket *sock, ne_ssl_context *ctx, void *userdata)
{
    int ret;

#if defined(HAVE_OPENSSL)
    SSL *ssl;

    if (seed_ssl_prng()) {
	set_error(sock, _("SSL disabled due to lack of entropy"));
	return NE_SOCK_ERROR;
    }

    /* If runtime library version differs from compile-time version
     * number in major/minor/fix level, abort soon. */
    if ((SSLeay() ^ OPENSSL_VERSION_NUMBER) & 0xFFFFF000) {
        set_error(sock, _("SSL disabled due to library version mismatch"));
        return NE_SOCK_ERROR;
    }

    sock->ssl = ssl = SSL_new(ctx->ctx);
    if (!ssl) {
	set_error(sock, _("Could not create SSL structure"));
	return NE_SOCK_ERROR;
    }
    
    SSL_set_app_data(ssl, userdata);
    SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
    SSL_set_fd(ssl, sock->fd);
    sock->ops = &iofns_ssl;
    
    if (ctx->sess)
	SSL_set_session(ssl, ctx->sess);

    ret = SSL_connect(ssl);
    if (ret != 1) {
	error_ossl(sock, ret);
	SSL_free(ssl);
	sock->ssl = NULL;
	return NE_SOCK_ERROR;
    }
#elif defined(HAVE_GNUTLS)
    /* DH and RSA params are set in ne_ssl_context_create */
    gnutls_init(&sock->ssl, GNUTLS_CLIENT);
    gnutls_set_default_priority(sock->ssl);
    gnutls_session_set_ptr(sock->ssl, userdata);
    gnutls_credentials_set(sock->ssl, GNUTLS_CRD_CERTIFICATE, ctx->cred);

    gnutls_transport_set_ptr(sock->ssl, (gnutls_transport_ptr) sock->fd);
    sock->ops = &iofns_ssl;

    ret = gnutls_handshake(sock->ssl);
    if (ret < 0) {
	error_gnutls(sock, ret);
        return NE_SOCK_ERROR;
    }
#endif
    return 0;
}

ne_ssl_socket ne__sock_sslsock(ne_socket *sock)
{
    return sock->ssl;
}

#endif

const char *ne_sock_error(const ne_socket *sock)
{
    return sock->error;
}

/* Closes given ne_socket */
int ne_sock_close(ne_socket *sock)
{
    int ret;

#if defined(HAVE_OPENSSL)
    if (sock->ssl) {
	SSL_shutdown(sock->ssl);
	SSL_free(sock->ssl);
    }
#elif defined(HAVE_GNUTLS)
    if (sock->ssl) {
        do {
            ret = gnutls_bye(sock->ssl, GNUTLS_SHUT_RDWR);
        } while (ret < 0
                 && (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN));
    }
#endif

    if (sock->fd < 0)
        ret = 0;
    else
        ret = ne_close(sock->fd);
    ne_free(sock);
    return ret;
}
