+local PHP_ARES_EXPAND_LEN_TYPE php_ares_skip(const unsigned char *pointer, const unsigned char *abuf, int alen TSRMLS_DC)
+{
+ char *name;
+ int rc;
+ PHP_ARES_EXPAND_LEN_TYPE byte_count;
+
+ /* NOTE: byte_count is not neccessarily the length of the string,
+ i.e. if there were back references */
+ if (ARES_SUCCESS == (rc = ares_expand_name(pointer, abuf, alen, &name, &byte_count))) {
+ /*fprintf(stderr, "-- skipping %s\n", name);*/
+ ares_free_string(name);
+ return byte_count;
+ }
+ PHP_ARES_ERROR(rc);
+ return -1;
+}
+
+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;
+
+ convert_to_array(result);
+
+ if (!alen || !abuf || !*abuf) {
+ return SUCCESS;
+ }
+
+ 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))) {
+ 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;
+ }
+
+ if (entry) {
+ add_next_index_zval(result, entry);
+ }
+ }
+
+ return SUCCESS;
+}
+/* }}} */
+