#include "php.h"
#include "php_ini.h"
+#include "php_streams.h"
#include "ext/standard/info.h"
#include "php_ares.h"
#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;
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) {
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);
+ }
+ *rptr = pointer;
+ 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);
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;
}
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;
}
}
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);
}
/* }}} */
-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;
}
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;
}
}
/* }}} */
-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);
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);
}
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;
#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;
}
}
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);
}
/* }}} */
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;
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);
}
/* }}} */
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));
}
/* }}} */