X-Git-Url: https://git.m6w6.name/?p=m6w6%2Fext-ares;a=blobdiff_plain;f=php_ares.c;h=a0c526bfe298b8bdefca286c6672ac17d4e7c864;hp=2ac6c35a3a979b6fa1af5d831ba84af2f2dc2aa0;hb=123ef365ae7831622a4ee7e8c998a7dc37d8d93a;hpb=009456e5f325f392be5db8fefe7c64210f466969 diff --git a/php_ares.c b/php_ares.c index 2ac6c35..a0c526b 100644 --- a/php_ares.c +++ b/php_ares.c @@ -18,6 +18,7 @@ #include "php.h" #include "php_ini.h" +#include "php_streams.h" #include "ext/standard/info.h" #include "php_ares.h" @@ -174,6 +175,18 @@ static const char *php_ares_T_names[] = { #define PHP_ARES_QUERY_BUFFER_LEN 2<<0xf +#ifdef HAVE_ARES_INET_PTON +# define inet_pton ares_inet_pton_wrapper +static inline int ares_inet_pton_wrapper(int af, const void *src, char *dst, socklen_t size) +{ + return dst == ares_inet_pton(af, src, dst, size); +} +#endif + +#ifdef HAVE_ARES_INET_NTOP +# define inet_ntop ares_inet_ntop +#endif + /* {{{ typedefs */ typedef struct _php_ares_options { struct ares_options strct; @@ -553,11 +566,19 @@ local php_ares_options *php_ares_options_ctor(php_ares_options *options, HashTab } if ((SUCCESS == zend_hash_find(ht, "udp_port", sizeof("udp_port"), (void *) &opt)) && is_numeric(opt, &lval)) { options->flags |= ARES_OPT_UDP_PORT; +#ifdef PHP_ARES_CARES options->strct.udp_port = (unsigned short) lval; +#else + options->strct.udp_port = htons((unsigned short) lval); +#endif } if ((SUCCESS == zend_hash_find(ht, "tcp_port", sizeof("tcp_port"), (void *) &opt)) && is_numeric(opt, &lval)) { options->flags |= ARES_OPT_TCP_PORT; +#ifdef PHP_ARES_CARES options->strct.tcp_port = (unsigned short) lval; +#else + options->strct.tcp_port = htons((unsigned short) lval); +#endif } if ((SUCCESS == zend_hash_find(ht, "servers", sizeof("servers"), (void *) &opt)) && (Z_TYPE_PP(opt) == IS_ARRAY) && (i = zend_hash_num_elements(Z_ARRVAL_PP(opt)))) { options->strct.servers = ecalloc(i, sizeof(struct in_addr)); @@ -565,7 +586,7 @@ local php_ares_options *php_ares_options_ctor(php_ares_options *options, HashTab SUCCESS == zend_hash_get_current_data(Z_ARRVAL_PP(opt), (void *) &entry); zend_hash_move_forward(Z_ARRVAL_PP(opt))) { if (Z_TYPE_PP(entry) == IS_STRING) { - inet_aton(Z_STRVAL_PP(entry), &options->strct.servers[options->strct.nservers++]); + inet_pton(AF_INET, Z_STRVAL_PP(entry), &options->strct.servers[options->strct.nservers++]); } } if (options->strct.nservers) { @@ -652,13 +673,153 @@ local PHP_ARES_EXPAND_LEN_TYPE php_ares_skip(const unsigned char *pointer, const return -1; } +local int php_ares_parse_record(const unsigned char *abuf, const int alen, const unsigned char **rptr, zval *result TSRMLS_DC) +{ + uint16_t stmp, type, class; + uint32_t ltmp, ttl; + zval *entry = NULL; + PHP_ARES_EXPAND_LEN_TYPE byte_count; + const unsigned char *pointer = *rptr; + char *name; + int rc; + + if (0 > (byte_count = php_ares_skip(pointer, abuf, alen TSRMLS_CC))) { + return FAILURE; + } + + pointer += byte_count; + + MAKE_STD_ZVAL(entry); + array_init(entry); + + GETSHORT(type, pointer); + add_assoc_string(entry, "type", estrdup(php_ares_T_names[type]), 0); + GETSHORT(class, pointer); + add_assoc_string(entry, "class", estrdup(php_ares_C_names[class]), 0); + GETLONG(ttl, pointer); + add_assoc_long(entry, "ttl", ttl); + GETSHORT(byte_count, pointer); +#if 0 + fprintf(stderr, ">> processing %s answer of length %d\n", php_ares_T_names[type], byte_count); +#endif + switch (type) { + case T_A: + name = ecalloc(1, 16); + inet_ntop(AF_INET, pointer, name, 16); + add_assoc_string(entry, "addr", name, 0); + pointer += byte_count; + break; +#ifdef T_AAAA + case T_AAAA: + name = ecalloc(1, 48); + inet_ntop(AF_INET6, pointer, name, 48); + add_assoc_string(entry, "addr", name, 0); + pointer += byte_count; + break; +#endif + + case T_NS: + case T_PTR: + case T_CNAME: + if (ARES_SUCCESS != (rc = ares_expand_name(pointer, abuf, alen, &name, &byte_count))) { + PHP_ARES_ERROR(rc); + return FAILURE; + } + pointer += byte_count; + add_assoc_string(entry, "name", name, 1); + ares_free_string(name); + break; + + case T_MX: + GETSHORT(stmp, pointer); + if (ARES_SUCCESS != (rc = ares_expand_name(pointer, abuf, alen, &name, &byte_count))) { + PHP_ARES_ERROR(rc); + return FAILURE; + } + pointer += byte_count; + add_assoc_long(entry, "weight", stmp); + add_assoc_string(entry, "name", name, 1); + ares_free_string(name); + break; + + case T_SRV: + GETSHORT(stmp, pointer); + add_assoc_long(entry, "priority", stmp); + GETSHORT(stmp, pointer); + add_assoc_long(entry, "weight", stmp); + GETSHORT(stmp, pointer); + add_assoc_long(entry, "port", stmp); + + if (ARES_SUCCESS != (rc = ares_expand_name(pointer, abuf, alen, &name, &byte_count))) { + PHP_ARES_ERROR(rc); + zval_ptr_dtor(&entry); + return FAILURE; + } + pointer += byte_count; + add_assoc_string(entry, "name", name, 1); + ares_free_string(name); + break; + + case T_SOA: + if (ARES_SUCCESS != (rc = ares_expand_name(pointer, abuf, alen, &name, &byte_count))) { + PHP_ARES_ERROR(rc); + zval_ptr_dtor(&entry); + return FAILURE; + } + pointer += byte_count; + add_assoc_string(entry, "name", name, 1); + ares_free_string(name); + + if (ARES_SUCCESS != (rc = ares_expand_name(pointer, abuf, alen, &name, &byte_count))) { + PHP_ARES_ERROR(rc); + zval_ptr_dtor(&entry); + return FAILURE; + } + pointer += byte_count; + add_assoc_string(entry, "mail", name, 1); + ares_free_string(name); + + GETLONG(ltmp, pointer); + add_assoc_long(entry, "serial", ltmp); + GETLONG(ltmp, pointer); + add_assoc_long(entry, "refresh", ltmp); + GETLONG(ltmp, pointer); + add_assoc_long(entry, "retry", ltmp); + GETLONG(ltmp, pointer); + add_assoc_long(entry, "expire", ltmp); + GETLONG(ltmp, pointer); + add_assoc_long(entry, "minimum-ttl", ltmp); + break; + + case T_TXT: + for (ltmp = 0; ltmp < byte_count; ltmp += pointer[ltmp] + 1) { + add_next_index_stringl(entry, (const char *) &pointer[ltmp + 1], pointer[ltmp], 1); + } + pointer += byte_count; + break; + + default: +#ifndef HAVE_INET_PTON + skip: +#endif + zval_ptr_dtor(&entry); + entry = NULL; + pointer += byte_count; + break; + } + + if (entry) { + add_next_index_zval(result, entry); + } + return SUCCESS; +} + local int php_ares_parse(const unsigned char *abuf, int alen, zval *result TSRMLS_DC) /* {{{ */ { HEADER *header; PHP_ARES_EXPAND_LEN_TYPE byte_count; const unsigned char *pointer; - char *name; - int rc, query_count, answer_count; + int query_count, answer_count, auth_count, other_count; convert_to_array(result); @@ -668,7 +829,7 @@ local int php_ares_parse(const unsigned char *abuf, int alen, zval *result TSRML header = (HEADER *) abuf; pointer = abuf + HFIXEDSZ; - + for (query_count = ntohs(header->qdcount); query_count--; pointer += byte_count + QFIXEDSZ) { if (0 > (byte_count = php_ares_skip(pointer, abuf, alen TSRMLS_CC))) { return FAILURE; @@ -676,125 +837,20 @@ local int php_ares_parse(const unsigned char *abuf, int alen, zval *result TSRML } for (answer_count = ntohs(header->ancount); answer_count-- && pointer < (abuf + alen); ) { - uint16_t stmp, type, class; - uint32_t ltmp, ttl; - zval **entry_ptr, *entry = NULL; - - if (0 > (byte_count = php_ares_skip(pointer, abuf, alen TSRMLS_CC))) { + if (SUCCESS != php_ares_parse_record(abuf, alen, &pointer, result TSRMLS_CC)) { return FAILURE; } + } - pointer += byte_count; - - MAKE_STD_ZVAL(entry); - array_init(entry); - - GETSHORT(type, pointer); - add_assoc_string(entry, "type", estrdup(php_ares_T_names[type]), 0); - GETSHORT(class, pointer); - add_assoc_string(entry, "class", estrdup(php_ares_C_names[class]), 0); - GETLONG(ttl, pointer); - add_assoc_long(entry, "ttl", ttl); - GETSHORT(byte_count, pointer); -#if 0 - fprintf(stderr, ">> processing %s answer of length %d\n", php_ares_T_names[type], byte_count); -#endif - switch (type) { - case T_A: - spprintf(&name, 0, "%d.%d.%d.%d", pointer[0], pointer[1], pointer[2], pointer[3]); - add_assoc_string(entry, "addr", name, 0); - pointer += byte_count; - break; - - case T_NS: - case T_PTR: - case T_CNAME: - if (ARES_SUCCESS != (rc = ares_expand_name(pointer, abuf, alen, &name, &byte_count))) { - PHP_ARES_ERROR(rc); - return FAILURE; - } - pointer += byte_count; - add_assoc_string(entry, "name", name, 1); - ares_free_string(name); - break; - - case T_MX: - GETSHORT(stmp, pointer); - if (ARES_SUCCESS != (rc = ares_expand_name(pointer, abuf, alen, &name, &byte_count))) { - PHP_ARES_ERROR(rc); - return FAILURE; - } - pointer += byte_count; - add_assoc_long(entry, "weight", stmp); - add_assoc_string(entry, "name", name, 1); - ares_free_string(name); - break; - - case T_SRV: - GETSHORT(stmp, pointer); - add_assoc_long(entry, "priority", stmp); - GETSHORT(stmp, pointer); - add_assoc_long(entry, "weight", stmp); - GETSHORT(stmp, pointer); - add_assoc_long(entry, "port", stmp); - - if (ARES_SUCCESS != (rc = ares_expand_name(pointer, abuf, alen, &name, &byte_count))) { - PHP_ARES_ERROR(rc); - zval_ptr_dtor(&entry); - return FAILURE; - } - pointer += byte_count; - add_assoc_string(entry, "name", name, 1); - ares_free_string(name); - break; - - case T_SOA: - if (ARES_SUCCESS != (rc = ares_expand_name(pointer, abuf, alen, &name, &byte_count))) { - PHP_ARES_ERROR(rc); - zval_ptr_dtor(&entry); - return FAILURE; - } - pointer += byte_count; - add_assoc_string(entry, "name", name, 1); - ares_free_string(name); - - if (ARES_SUCCESS != (rc = ares_expand_name(pointer, abuf, alen, &name, &byte_count))) { - PHP_ARES_ERROR(rc); - zval_ptr_dtor(&entry); - return FAILURE; - } - pointer += byte_count; - add_assoc_string(entry, "mail", name, 1); - ares_free_string(name); - - GETLONG(ltmp, pointer); - add_assoc_long(entry, "serial", ltmp); - GETLONG(ltmp, pointer); - add_assoc_long(entry, "refresh", ltmp); - GETLONG(ltmp, pointer); - add_assoc_long(entry, "retry", ltmp); - GETLONG(ltmp, pointer); - add_assoc_long(entry, "expire", ltmp); - GETLONG(ltmp, pointer); - add_assoc_long(entry, "minimum-ttl", ltmp); - break; - - case T_TXT: - for (ltmp = 0; ltmp < byte_count; ltmp += pointer[ltmp] + 1) { - add_next_index_stringl(entry, (const char *) &pointer[ltmp + 1], pointer[ltmp], 1); - } - pointer += byte_count; - break; - - default: - zval_ptr_dtor(&entry); - entry = NULL; - pointer += byte_count; - break; + for (auth_count = ntohs(header->nscount); auth_count-- && pointer < (abuf + alen); ) { + if (SUCCESS != php_ares_parse_record(abuf, alen, &pointer, result TSRMLS_CC)) { + return FAILURE; } + } - if (entry) { - add_next_index_zval(result, entry); + for (other_count = ntohs(header->arcount); other_count-- && pointer < (abuf + alen); ) { + if (SUCCESS != php_ares_parse_record(abuf, alen, &pointer, result TSRMLS_CC)) { + return FAILURE; } } @@ -816,7 +872,7 @@ static void php_ares_callback_func_old(void *aq, int status, unsigned char *abuf MAKE_STD_ZVAL(parsed); ZVAL_NULL(parsed); - if (SUCCESS == php_ares_parse(abuf, alen, parsed)) { + if (SUCCESS == php_ares_parse(abuf, alen, parsed TSRMLS_CC)) { q->result.std.arr = parsed; } else { zval_ptr_dtor(&parsed); @@ -1003,13 +1059,19 @@ local int php_ares_process(php_ares *ares, long max_timeout) /* {{{ */ } /* }}} */ -local int php_ares_publish_fds(fd_set *R, fd_set *W, zval *r, zval *w) /* {{{ */ +local int php_ares_publish_fds(fd_set *R, fd_set *W, zval *r, zval *w, HashTable *resource_map) /* {{{ */ { int i, nfds = 0; + zval **fd; for (i = 0; i < FD_SETSIZE; ++i) { if (FD_ISSET(i, R)) { - add_next_index_long(r, i); + if (resource_map && (SUCCESS == zend_hash_index_find(resource_map, i, (void *) &fd))) { + zval_add_ref(fd); + add_next_index_zval(r, *fd); + } else { + add_next_index_long(r, i); + } if (i > nfds) { nfds = i; } @@ -1018,7 +1080,12 @@ local int php_ares_publish_fds(fd_set *R, fd_set *W, zval *r, zval *w) /* {{{ */ for (i = 0; i < FD_SETSIZE; ++i) { if (FD_ISSET(i, W)) { - add_next_index_long(w, i); + if (resource_map && (SUCCESS == zend_hash_index_find(resource_map, i, (void *) &fd))) { + zval_add_ref(fd); + add_next_index_zval(r, *fd); + } else { + add_next_index_long(w, i); + } if (i > nfds) { nfds = i; } @@ -1029,16 +1096,33 @@ local int php_ares_publish_fds(fd_set *R, fd_set *W, zval *r, zval *w) /* {{{ */ } /* }}} */ -local int php_ares_extract_fds(zval *r, zval *w, fd_set *R, fd_set *W) /* {{{ */ +local int php_ares_extract_fds(zval *r, zval *w, fd_set *R, fd_set *W, HashTable *resource_map TSRMLS_DC) /* {{{ */ { zval **fd; int nfds = 0; + zval zmap; + INIT_ZVAL(zmap); + Z_ARRVAL(zmap) = resource_map; + Z_TYPE(zmap) = IS_ARRAY; if (r && zend_hash_num_elements(Z_ARRVAL_P(r))) { for ( zend_hash_internal_pointer_reset(Z_ARRVAL_P(r)); SUCCESS == zend_hash_get_current_data(Z_ARRVAL_P(r), (void *) &fd); zend_hash_move_forward(Z_ARRVAL_P(r))) { - if (Z_TYPE_PP(fd) == IS_LONG) { + if (Z_TYPE_PP(fd) == IS_RESOURCE) { + php_stream *s = NULL; + int id = 0; + + ZEND_FETCH_RESOURCE_NO_RETURN(s, php_stream *, fd, -1, NULL, php_file_le_stream()); + if (s && (SUCCESS == php_stream_cast(s, PHP_STREAM_AS_FD_FOR_SELECT, (void *) &id, 1))) { + zval_add_ref(fd); + add_index_zval(&zmap, id, *fd); + FD_SET(id, R); + if (id > nfds) { + nfds = id; + } + } + } else if (Z_TYPE_PP(fd) == IS_LONG) { FD_SET(Z_LVAL_PP(fd), R); if (Z_LVAL_PP(fd) > nfds) { nfds = Z_LVAL_PP(fd); @@ -1051,7 +1135,20 @@ local int php_ares_extract_fds(zval *r, zval *w, fd_set *R, fd_set *W) /* {{{ */ for ( zend_hash_internal_pointer_reset(Z_ARRVAL_P(w)); SUCCESS == zend_hash_get_current_data(Z_ARRVAL_P(w), (void *) &fd); zend_hash_move_forward(Z_ARRVAL_P(w))) { - if (Z_TYPE_PP(fd) == IS_LONG) { + if (Z_TYPE_PP(fd) == IS_RESOURCE) { + php_stream *s = NULL; + int id = 0; + + ZEND_FETCH_RESOURCE_NO_RETURN(s, php_stream *, fd, -1, NULL, php_file_le_stream()); + if (s && (SUCCESS == php_stream_cast(s, PHP_STREAM_AS_FD_FOR_SELECT, (void *) &id, 1))) { + zval_add_ref(fd); + add_index_zval(&zmap, id, *fd); + FD_SET(id, W); + if (id > nfds) { + nfds = id; + } + } + } else if (Z_TYPE_PP(fd) == IS_LONG) { FD_SET(Z_LVAL_PP(fd), W); if (Z_LVAL_PP(fd) > nfds) { nfds = Z_LVAL_PP(fd); @@ -1097,7 +1194,7 @@ static PHP_FUNCTION(ares_init) RETURN_FALSE; } - ares = emalloc(sizeof(php_ares)); + ares = ecalloc(1, sizeof(php_ares)); TSRMLS_SET_CTX(ares->tsrm_ls); zend_llist_init(&ares->queries, sizeof(php_ares_query *), (llist_dtor_func_t) php_ares_query_llist_dtor, 0); php_ares_options_ctor(&ares->options, opt_array ? Z_ARRVAL_P(opt_array) : NULL); @@ -1479,26 +1576,6 @@ static PHP_FUNCTION(ares_result) } switch (query->error) { - case 0: - switch (query->type) { - case PHP_ARES_CB_STD: - if (query->result.std.arr) { - RETVAL_ZVAL(query->result.std.arr, 1, 0); - } else { - RETVAL_STRINGL(query->result.std.buf, query->result.std.len, 1); - } - break; - case PHP_ARES_CB_HOST: - object_init(return_value); - php_ares_hostent_to_struct(&query->result.host, HASH_OF(return_value)); - break; - case PHP_ARES_CB_NINFO: - object_init(return_value); - add_property_string(return_value, "node", query->result.ninfo.node ? query->result.ninfo.node : "", 1); - add_property_string(return_value, "service", query->result.ninfo.service ? query->result.ninfo.service : "", 1); - break; - } - break; case -1: RETVAL_FALSE; break; @@ -1514,6 +1591,30 @@ static PHP_FUNCTION(ares_result) #endif } RETVAL_FALSE; + /* no break */ + case 0: + switch (query->type) { + case PHP_ARES_CB_STD: + if (query->result.std.arr) { + RETVAL_ZVAL(query->result.std.arr, 1, 0); + } else if (query->result.std.len > 0) { + RETVAL_STRINGL(query->result.std.buf, query->result.std.len, 1); + } + break; + case PHP_ARES_CB_HOST: + if (query->result.host.h_name) { + object_init(return_value); + php_ares_hostent_to_struct(&query->result.host, HASH_OF(return_value)); + } + break; + case PHP_ARES_CB_NINFO: + if (query->result.ninfo.node || query->result.ninfo.service) { + object_init(return_value); + add_property_string(return_value, "node", query->result.ninfo.node ? query->result.ninfo.node : "", 1); + add_property_string(return_value, "service", query->result.ninfo.service ? query->result.ninfo.service : "", 1); + } + break; + } break; } } @@ -1657,7 +1758,7 @@ static PHP_FUNCTION(ares_process) FD_ZERO(&R); FD_ZERO(&W); - php_ares_extract_fds(read, write, &R, &W); + php_ares_extract_fds(read, write, &R, &W, NULL TSRMLS_CC); ares_process(ares->channel, &R, &W); } /* }}} */ @@ -1671,6 +1772,7 @@ static PHP_FUNCTION(ares_select) int nfds; long timeout; struct timeval tv; + HashTable resource_map; if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "aal", &read, &write, &timeout)) { RETURN_FALSE; @@ -1687,14 +1789,17 @@ static PHP_FUNCTION(ares_select) FD_ZERO(&R); FD_ZERO(&W); - nfds = php_ares_extract_fds(read, write, &R, &W); + zend_hash_init(&resource_map, zend_hash_num_elements(Z_ARRVAL_P(read) + zend_hash_num_elements(Z_ARRVAL_P(write))), NULL, ZVAL_PTR_DTOR, 0); + nfds = php_ares_extract_fds(read, write, &R, &W, &resource_map TSRMLS_CC); if (-1 < select(nfds, &R, &W, NULL, &tv)) { zend_hash_clean(Z_ARRVAL_P(read)); zend_hash_clean(Z_ARRVAL_P(write)); - php_ares_publish_fds(&R, &W, read, write); - RETURN_TRUE; + php_ares_publish_fds(&R, &W, read, write, &resource_map); + RETVAL_TRUE; + } else { + RETVAL_FALSE; } - RETURN_FALSE; + zend_hash_destroy(&resource_map); } /* }}} */ @@ -1740,7 +1845,7 @@ static PHP_FUNCTION(ares_fds) array_init(read); array_init(write); ares_fds(ares->channel, &R, &W); - RETVAL_LONG(php_ares_publish_fds(&R, &W, read, write)); + RETVAL_LONG(php_ares_publish_fds(&R, &W, read, write, NULL)); } /* }}} */ @@ -2248,6 +2353,15 @@ zend_function_entry ares_functions[] = { PHP_FE(ares_select, ai_ares_select) PHP_FE(ares_fds, ai_ares_fds) PHP_FE(ares_timeout, NULL) +#ifdef HAVE_ARES_SET_LOCAL_DEV + PHP_FE(ares_set_local_dev, NULL) +#endif +#ifdef HAVE_ARES_SET_LOCAL_IP4 + PHP_FE(ares_set_local_ip4, NULL) +#endif +#ifdef HAVE_ARES_SET_LOCAL_IP6 + PHP_FE(ares_set_local_ip6, NULL) +#endif {NULL, NULL, NULL} }; /* }}} */