#include "php.h"
#include "php_ini.h"
+#include "php_streams.h"
#include "ext/standard/info.h"
#include "php_ares.h"
static const char *php_ares_C_names[] = {
"INVALID",
"IN",
+ "C2"
"CHAOS",
- "HS",
- "NONE",
- "ANY",
+ "HS", /* 4 */
+ "","","","","","","","","","","","","","","","","","","","", /* 20x */
+ "","","","","","","","","","","","","","","","","","","","", /* 20x */
+ "","","","","","","","","","","","","","","","","","","","", /* 20x */
+ "","","","","","","","","","","","","","","","","","","","", /* 20x */
+ "","","","","","","","","","","","","","","","","","","","", /* 20x */
+ "","","","","","","","","","","","","","","","","","","","", /* 20x */
+ "","","","","","","","","","","","","","","","","","","","", /* 20x */
+ "","","","","","","","","","","","","","","","","","","","", /* 20x */
+ "","","","","","","","","","","","","","","","","","","","", /* 20x */
+ "","","","","","","","","","","","","","","","","","","","", /* 20x */
+ "","","","","","","","","","","","","","","","","","","","", /* 20x */
+ "","","","","","","","","", /* 9x */
+ "NONE", /* 254 */
+ "ANY", /* 255 */
};
static const char *php_ares_T_names[] = {
"","","","","","","","","","","","","","","","","","","","", /* 20x */
"","","","","","","","","","","","","","","","","","","","", /* 20x */
"","","","","","","","","","","","","","","","","","","","", /* 20x */
- "","","","","","","","","","","","","","","","","","","","", /* 20x */
- "","","","","","","","","","","","","","","","","","","","", /* 20x */
"","","","","","", /* 6x */
"TKEY", /* 249 */
"TSIG",
#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;
}
/* }}} */
+local zend_bool is_numeric(zval **p, long *lval) { /* {{{ */
+ zval *tmp = *p;
+ switch (Z_TYPE_PP(p)) {
+ case IS_STRING:
+ convert_to_long_ex(&tmp);
+ /* no break */
+ case IS_LONG:
+ *lval = Z_LVAL_P(tmp);
+ if (tmp != *p) {
+ zval_ptr_dtor(&tmp);
+ }
+ return !!*lval;
+ }
+ return 0;
+} /* }}} */
+
local php_ares_options *php_ares_options_ctor(php_ares_options *options, HashTable *ht) /* {{{ */
{
int i;
+ long lval;
zval **opt, **entry;
if (!options) {
memset(options, 0, sizeof(php_ares_options));
if (ht && zend_hash_num_elements(ht)) {
- if ((SUCCESS == zend_hash_find(ht, "flags", sizeof("flags"), (void *) &opt)) && (Z_TYPE_PP(opt) == IS_LONG)) {
+ if ((SUCCESS == zend_hash_find(ht, "flags", sizeof("flags"), (void *) &opt)) && is_numeric(opt, &lval)) {
options->flags |= ARES_OPT_FLAGS;
- options->strct.flags = Z_LVAL_PP(opt);
+ options->strct.flags = lval;
}
- if ((SUCCESS == zend_hash_find(ht, "timeout", sizeof("timeout"), (void *) &opt)) && (Z_TYPE_PP(opt) == IS_LONG)) {
+#ifdef ARES_OPT_TIMEOUTMS
+ if ((SUCCESS == zend_hash_find(ht, "timeoutms", sizeof("timeoutms"), (void *) &opt)) && is_numeric(opt, &lval)) {
+ options->flags |= ARES_OPT_TIMEOUTMS;
+ options->strct.timeout = lval;
+ } else
+#endif
+ if ((SUCCESS == zend_hash_find(ht, "timeout", sizeof("timeout"), (void *) &opt)) && is_numeric(opt, &lval)) {
options->flags |= ARES_OPT_TIMEOUT;
- options->strct.timeout = Z_LVAL_PP(opt);
+ options->strct.timeout = lval;
}
- if ((SUCCESS == zend_hash_find(ht, "tries", sizeof("tries"), (void *) &opt)) && (Z_TYPE_PP(opt) == IS_LONG)) {
+ if ((SUCCESS == zend_hash_find(ht, "tries", sizeof("tries"), (void *) &opt)) && is_numeric(opt, &lval)) {
options->flags |= ARES_OPT_TRIES;
- options->strct.tries = Z_LVAL_PP(opt);
+ options->strct.tries = lval;
}
- if ((SUCCESS == zend_hash_find(ht, "ndots", sizeof("ndots"), (void *) &opt)) && (Z_TYPE_PP(opt) == IS_LONG)) {
+ if ((SUCCESS == zend_hash_find(ht, "ndots", sizeof("ndots"), (void *) &opt)) && is_numeric(opt, &lval)) {
options->flags |= ARES_OPT_NDOTS;
- options->strct.ndots = Z_LVAL_PP(opt);
+ options->strct.ndots = lval;
}
- if ((SUCCESS == zend_hash_find(ht, "udp_port", sizeof("udp_port"), (void *) &opt)) && (Z_TYPE_PP(opt) == IS_LONG)) {
+ if ((SUCCESS == zend_hash_find(ht, "udp_port", sizeof("udp_port"), (void *) &opt)) && is_numeric(opt, &lval)) {
options->flags |= ARES_OPT_UDP_PORT;
- options->strct.udp_port = htons((unsigned short) Z_LVAL_PP(opt));
+#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)) && (Z_TYPE_PP(opt) == IS_LONG)) {
+ if ((SUCCESS == zend_hash_find(ht, "tcp_port", sizeof("tcp_port"), (void *) &opt)) && is_numeric(opt, &lval)) {
options->flags |= ARES_OPT_TCP_PORT;
- options->strct.tcp_port = htons((unsigned short) Z_LVAL_PP(opt));
+#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));
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) {
options->flags |= ARES_OPT_LOOKUPS;
options->strct.lookups = estrdup(Z_STRVAL_PP(opt));
}
+#ifdef ARES_OPT_ROTATE
+ if ((SUCCESS == zend_hash_find(ht, "rotate", sizeof("rotate"), (void *) &opt)) && i_zend_is_true(*opt)) {
+ options->flags |= ARES_OPT_ROTATE;
+ }
+#endif
+#ifdef ARES_OPT_EDNSPSZ
+ if ((SUCCESS == zend_hash_find(ht, "ednspsz", sizeof("ednspsz"), (void *) &opt)) && is_numeric(opt, &lval)) {
+ options->flags |= ARES_OPT_EDNSPSZ;
+ options->strct.ednspsz = lval;
+ }
+#endif
}
return options;
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;
+ zval *entry = NULL;
if (0 > (byte_count = php_ares_skip(pointer, abuf, alen TSRMLS_CC))) {
return FAILURE;
#endif
switch (type) {
case T_A:
- spprintf(&name, 0, "%d.%d.%d.%d", pointer[0], pointer[1], pointer[2], pointer[3]);
+ 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:
break;
default:
+#ifndef HAVE_INET_PTON
+ skip:
+#endif
zval_ptr_dtor(&entry);
entry = NULL;
pointer += byte_count;
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);
php_ares *ares = NULL;
int err;
- if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a!", &opt_array)) {
+ if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a/!", &opt_array)) {
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);
}
/* }}} */
+#ifdef HAVE_ARES_SET_LOCAL_DEV
+/* {{{ proto void ares_set_local_dev(resource ares, string dev)
+ Set the local interface name to bind to. */
+static PHP_FUNCTION(ares_set_local_dev)
+{
+ zval *rsrc;
+ char *dev_str = NULL;
+ int dev_len = 0;
+ php_ares *ares;
+
+ if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs!", &rsrc, &dev_str, &dev_len)) {
+ RETURN_FALSE;
+ }
+ ZEND_FETCH_RESOURCE(ares, php_ares *, &rsrc, -1, PHP_ARES_LE_NAME, le_ares);
+
+ ares_set_local_dev(ares->channel, dev_str);
+}
+#endif
+
+#ifdef HAVE_ARES_SET_LOCAL_IP4
+/* {{{ proto void ares_set_local_ip4(resource ares, int addr)
+ Set the local IPv4 address to bind to. */
+static PHP_FUNCTION(ares_set_local_ip4)
+{
+ zval *rsrc;
+ long ip4_num;
+ php_ares *ares;
+
+ if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &rsrc, &ip4_num)) {
+ RETURN_FALSE;
+ }
+ ZEND_FETCH_RESOURCE(ares, php_ares *, &rsrc, -1, PHP_ARES_LE_NAME, le_ares);
+
+ ares_set_local_ip4(ares->channel, (unsigned int) ip4_num);
+}
+#endif
+
+#ifdef HAVE_ARES_SET_LOCAL_IP6
+/* {{{ proto void ares_set_local_ip6(resource ares, string addr128bit)
+ Set the local IPv6 address to bind to. */
+static PHP_FUNCTION(ares_set_local_ip6)
+{
+ zval *rsrc;
+ char *ip6_str;
+ int ip6_len;
+ php_ares *ares;
+
+ if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &rsrc, &ip6_str, &ip6_len)) {
+ RETURN_FALSE;
+ }
+ if (16 != ip6_len) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Binary IPv6 address string must be exactly 16 bytes long");
+ }
+ ZEND_FETCH_RESOURCE(ares, php_ares *, &rsrc, -1, PHP_ARES_LE_NAME, le_ares);
+
+ ares_set_local_ip6(ares->channel, (unsigned char *) ip6_str);
+}
+#endif
+
/* {{{ proto void ares_destroy(resource ares)
Destroy the ares handle */
static PHP_FUNCTION(ares_destroy)
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));
}
/* }}} */
REGISTER_LONG_CONSTANT("ARES_FLAG_NOSEARCH", ARES_FLAG_NOSEARCH, CONST_PERSISTENT|CONST_CS);
REGISTER_LONG_CONSTANT("ARES_FLAG_NOALIASES", ARES_FLAG_NOALIASES, CONST_PERSISTENT|CONST_CS);
REGISTER_LONG_CONSTANT("ARES_FLAG_NOCHECKRESP", ARES_FLAG_NOCHECKRESP, CONST_PERSISTENT|CONST_CS);
+#ifdef ARES_FLAG_EDNS
+ REGISTER_LONG_CONSTANT("ARES_FLAG_EDNS", ARES_FLAG_EDNS, CONST_PERSISTENT|CONST_CS);
+#endif
/*
* Address Family Constants
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}
};
/* }}} */