/* Socket handling routines Copyright (C) 1998-2005, Joe Orton , Copyright (C) 1999-2000 Tommi Komulainen Copyright (C) 2004 Aleix Conchillo Flaque 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 #ifdef HAVE_SYS_TIME_H #include #endif #include #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef NE_USE_POLL #include #elif defined(HAVE_SYS_SELECT_H) #include #endif #ifdef HAVE_NETINET_IN_H #include #endif #ifdef HAVE_NETINET_TCP_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif #ifdef HAVE_NETDB_H #include #endif #ifdef WIN32 #include #include #ifdef USE_GETADDRINFO #include #endif #endif #if defined(HAVE_OPENSSL) && defined(HAVE_LIMITS_H) #include /* for INT_MAX */ #endif #ifdef HAVE_STRING_H #include #endif #ifdef HAVE_STRINGS_H #include #endif #ifdef HAVE_UNISTD_H #include #endif #ifdef HAVE_SIGNAL_H #include #endif #ifdef HAVE_ERRNO_H #include #endif #ifdef HAVE_STDLIB_H #include #endif #ifdef HAVE_SOCKS_H #include #endif #ifdef HAVE_OPENSSL #include #include #include /* for PKCS12_PBE_add */ #include #include /* for OPENSSL_VERSION_NUMBER */ #endif #ifdef HAVE_GNUTLS #include #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 #include #include //#include //#include #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, "==> ij½¬Á¤º¸1 [%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; }