Files
interactive/application/sp-console(down)/Common/neon-0.25.4/ne_socket.c.20090827 쓰레드 디버깅 최종
T
2026-08-07 17:38:18 +09:00

2324 lines
56 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
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 1
#define __DEBUG__
#endif
#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;
}
}
/*
//
// hostent copy logic
//
size_t n = 0;
for (n = 0; hp->h_addr_list[n] != NULL; n++) ;
stHp[i]->h_length = hp->h_length;
stHp[i]->h_addrtype = n; // for test, stHp[i]->h_addrtype = hp->h_addrtype;
stHp[i]->h_name = malloc(strlen(hp->h_name) + 1);
memset(stHp[i]->h_name, 0, strlen(hp->h_name) + 1);
strcpy(stHp[i]->h_name, hp->h_name);
stHp[i]->h_addr_list = (char **)malloc( (n * sizeof (char *)) + 1);
memset(stHp[i]->h_addr_list, 0, (n * sizeof (char *)) + 1);
for (n = 0; hp->h_addr_list[n] != NULL; n++)
{
size_t h_addr_list_len = strlen(hp->h_addr_list[n]) ;
stHp[i]->h_addr_list[n] = (char *)malloc( h_addr_list_len + 1);
memset(stHp[i]->h_addr_list[n], 0, h_addr_list_len + 1);
memcpy(stHp[i]->h_addr_list[n], hp->h_addr_list[n], h_addr_list_len);
}
*/
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 ; // ij ˻
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, "==> ** ij ** 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, "==> ij1 [%s] stHp[%d][%s][%p]"
, hostname, k, stHp[k]->h_name, stHp[k] );
writing_file(msg_tries);
}
}
}
#endif
#endif
if(FirstTried == FALSE)
{
// 60 ȿ ij
if(currentTime - oldTime < dns_cache_reload_time)
{
int i;
#ifdef __DEBUG__
{
char msg_tries[256];
memset(msg_tries, 0, 256);
sprintf(msg_tries, "==> ij˻ ");
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, "==> ij 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, "==> ij DNS ȹ [%s] stHp[%d][%p]"
, hp->h_name, i, hp );
writing_file(msg_tries);
}
#endif
break;
}
}
} // end of 60 ij
// ij , 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));
// ֱ ij ʱȭ
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, "==> ij ij [%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("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, "[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, "ij thread ˻ ");
else
sprintf(msg_tries, "ij 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
////////////////////////////////////////////////////////////////////////////
// ij Ҵ
////////////////////////////////////////////////////////////////////////////
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 ̰, ij ˻ ߾
{
int i;
#ifdef __DEBUG__
{
char msg_tries[256];
memset(msg_tries, 0, 256);
sprintf(msg_tries, "[thread ˻] ij ȸ");
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, "==> ij DNS ȹ [%s] stHp[%d][%p]", hp->h_name, i, hp );
writing_file(msg_tries);
}
#endif
break;
}
}
} // end of , ij
} // end of
} // end of ij
} // 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, "[ij˻ ]");
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
} // ̰.. ̴.
}
///////////////////////////////////////////////////////////////////////
// ij
///////////////////////////////////////////////////////////////////////
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, "==> ij Ϸ [%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] ij ȵǴ±
////////////////////////////////////////////////////////////////////////////
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
#if 0
struct sockaddr_in sa = {0};
sa.sin_family = AF_INET;
sa.sin_port = port;
sa.sin_addr = *addr;
return connect(fd, (struct sockaddr *)&sa, sizeof sa);
////////////////////////////////////////////////////////////////////
// <== ۾
#else
RConnect SConnect;
DWORD dwThreadID, ConnectValue = 0;
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;
#if 0
{
char msg_tries[256];
memset(msg_tries, 0, 256);
sprintf(msg_tries, "***************************** Connect IP[%s]\n", inet_ntoa(SConnect.sa.sin_addr));
writing_file(msg_tries);
}
#endif
//connect(SConnect.fd, &SConnect.sa, sizeof SConnect.sa );
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, 5000);
WaitForSingleObject(hConnectThread, socket_connect_timeout);
GetExitCodeThread(hConnectThread, &ConnectValue);
CloseHandle(hConnectThread); // threadƮ Ҹ
return ConnectValue;
/*
*/
//////////////////////////////////////////////////////////////////////////////////
#endif
#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;
#ifdef __DEBUG__
//////////////////////////////////////////////////////////////////////////////////
// sangkeun.ha test
{
time_t start_time = 0, end_time = 0, gap;
start_time = time(NULL);
#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);
#endif
end_time = time(NULL);
gap = end_time - start_time;
if(gap > 0)
{
char msg_tries[256];
memset(msg_tries, 0, 256);
sprintf(msg_tries, "GAP ==> ne_sock_connect::socket : [%ld] sec", gap);
writing_file(msg_tries);
}
if (fd < 0) {
set_strerror(sock, ne_errno);
#ifdef __DEBUG__
{
char msg_tries[256];
memset(msg_tries, 0, 256);
sprintf(msg_tries, "ERR ==> ne_sock_connect::socket err: [%ld] sec err[%s]", gap, strerror(ne_errno));
writing_file(msg_tries);
}
#endif
return -1;
}
}
#else
#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);
#endif
if (fd < 0) {
set_strerror(sock, ne_errno);
return -1;
}
#endif
#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
#ifdef __DEBUG__
//////////////////////////////////////////////////////////////////////////////////
// sangkeun.ha test
{
time_t start_time = 0, end_time = 0, gap;
start_time = time(NULL);
if (raw_connect(fd, addr, htons(port))) {
set_strerror(sock, ne_errno);
// ne_close(fd);
end_time = time(NULL);
gap = end_time - start_time;
{
char msg_tries[256];
memset(msg_tries, 0, 256);
if(gap > 0)
{
sprintf(msg_tries, "GAP ==> ne_sock_connect::raw_connect err: [%ld] sec", gap);
writing_file(msg_tries);
}
}
ne_close(fd);
return -1;
}
end_time = time(NULL);
gap = end_time - start_time;
if(gap > 0)
{
char msg_tries[256];
memset(msg_tries, 0, 256);
sprintf(msg_tries, "GAP ==> ne_sock_connect::raw_connect : [%ld] sec", gap);
writing_file(msg_tries);
}
}
//////////////////////////////////////////////////////////////////////////////////
#else
if (raw_connect(fd, addr, htons(port))) {
set_strerror(sock, ne_errno);
ne_close(fd);
return -1;
}
#endif
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;
}