recognize numeric option strings
[m6w6/ext-ares] / php_ares.c
1 /*
2 +--------------------------------------------------------------------+
3 | PECL :: ares |
4 +--------------------------------------------------------------------+
5 | Redistribution and use in source and binary forms, with or without |
6 | modification, are permitted provided that the conditions mentioned |
7 | in the accompanying LICENSE file are met. |
8 +--------------------------------------------------------------------+
9 | Copyright (c) 2006, Michael Wallner <mike@php.net> |
10 +--------------------------------------------------------------------+
11 */
12
13 /* $Id$ */
14
15 #ifdef HAVE_CONFIG_H
16 #include "config.h"
17 #endif
18
19 #include "php.h"
20 #include "php_ini.h"
21 #include "ext/standard/info.h"
22 #include "php_ares.h"
23
24 #include <ares.h>
25 #ifdef HAVE_ARES_VERSION
26 # include <ares_version.h>
27 #endif
28 #ifdef HAVE_NETDB_H
29 # include <netdb.h>
30 #endif
31 #ifdef HAVE_UNISTD_H
32 # include <unistd.h>
33 #endif
34 #ifdef HAVE_ARPA_INET_H
35 # include <arpa/inet.h>
36 #endif
37 #ifdef HAVE_ARPA_NAMESER_H
38 # include <arpa/nameser.h>
39 #endif
40 #ifdef HAVE_ARPA_NAMESER_COMPAT_H
41 # include <arpa/nameser_compat.h>
42 #endif
43
44 #define local static inline
45
46 #ifndef ZEND_ENGINE_2
47 # define PHP_ARES_IS_CALLABLE(a,b,c) 1
48 # ifndef ZTS
49 # undef TSRMLS_SET_CTX
50 # define TSRMLS_SET_CTX
51 # undef TSRMLS_FETCH_FROM_CTX
52 # define TSRMLS_FETCH_FROM_CTX
53 # endif
54 #endif
55 #if (PHP_MAJOR_VERSION > 5) || ((PHP_MAJOR_VERSION == 5) && (PHP_MINOR_VERSION >= 3))
56 # define ADDREF(z) Z_ADDREF_P(z)
57 # define PHP_ARES_IS_CALLABLE(a,b,c) zend_is_callable((a), (b), (c) TSRMLS_CC)
58 #else
59 # define ADDREF(z) ZVAL_ADDREF(z)
60 # define PHP_ARES_IS_CALLABLE(a,b,c) zend_is_callable((a), (b), (c))
61 #endif
62
63 #define PHP_ARES_LE_NAME "AsyncResolver"
64 #define PHP_ARES_QUERY_LE_NAME "AsyncResolverQuery"
65 static int le_ares;
66 static int le_ares_query;
67
68 static const char *php_ares_C_names[] = {
69 "INVALID",
70 "IN",
71 "C2"
72 "CHAOS",
73 "HS", /* 4 */
74 "","","","","","","","","","","","","","","","","","","","", /* 20x */
75 "","","","","","","","","","","","","","","","","","","","", /* 20x */
76 "","","","","","","","","","","","","","","","","","","","", /* 20x */
77 "","","","","","","","","","","","","","","","","","","","", /* 20x */
78 "","","","","","","","","","","","","","","","","","","","", /* 20x */
79 "","","","","","","","","","","","","","","","","","","","", /* 20x */
80 "","","","","","","","","","","","","","","","","","","","", /* 20x */
81 "","","","","","","","","","","","","","","","","","","","", /* 20x */
82 "","","","","","","","","","","","","","","","","","","","", /* 20x */
83 "","","","","","","","","","","","","","","","","","","","", /* 20x */
84 "","","","","","","","","","","","","","","","","","","","", /* 20x */
85 "","","","","","","","","", /* 9x */
86 "NONE", /* 254 */
87 "ANY", /* 255 */
88 };
89
90 static const char *php_ares_T_names[] = {
91 "INVALID",
92 "A",
93 "NS",
94 "MD",
95 "MF",
96 "CNAME",
97 "SOA",
98 "MB",
99 "MG",
100 "MR",
101 "NULL",
102 "WKS",
103 "PTR",
104 "HINFO",
105 "MINFO",
106 "MX",
107 "TXT",
108 "RP",
109 "AFSDB",
110 "X25",
111 "ISDN",
112 "RT",
113 "NSAP",
114 "NSAP_PTR",
115 "SIG",
116 "KEY",
117 "PX",
118 "GPOS",
119 "AAAA",
120 "LOC",
121 "NXT",
122 "EID",
123 "NIMLOC",
124 "SRV",
125 "ATMA",
126 "NAPTR",
127 "KX",
128 "CERT",
129 "A6",
130 "DNAME",
131 "SINK",
132 "OPT",
133 "APL", /* 42 */
134 "","","","","","","","","","","","","","","","","","","","", /* 20x */
135 "","","","","","","","","","","","","","","","","","","","", /* 20x */
136 "","","","","","","","","","","","","","","","","","","","", /* 20x */
137 "","","","","","","","","","","","","","","","","","","","", /* 20x */
138 "","","","","","","","","","","","","","","","","","","","", /* 20x */
139 "","","","","","","","","","","","","","","","","","","","", /* 20x */
140 "","","","","","","","","","","","","","","","","","","","", /* 20x */
141 "","","","","","","","","","","","","","","","","","","","", /* 20x */
142 "","","","","","","","","","","","","","","","","","","","", /* 20x */
143 "","","","","","","","","","","","","","","","","","","","", /* 20x */
144 "","","","","","", /* 6x */
145 "TKEY", /* 249 */
146 "TSIG",
147 "IXFR",
148 "AXFR",
149 "MAILB",
150 "MAILA",
151 "ANY", /* 255 */
152 "ZXFR", /* 256 */
153 };
154
155 #ifdef HAVE_OLD_ARES_STRERROR
156 # define PHP_ARES_ERROR(err) { \
157 char *__tmp = NULL; \
158 php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", ares_strerror(err, &__tmp)); \
159 if (__tmp) ares_free_errmem(__tmp); \
160 }
161 #else
162 # define PHP_ARES_ERROR(err) \
163 php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", ares_strerror(err))
164 #endif
165
166 #define RETURN_ARES_ERROR(err) \
167 PHP_ARES_ERROR(err); \
168 RETURN_FALSE
169 #define PHP_ARES_CB_ERROR(param) \
170 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Expected the " param " argument to be a valid callback")
171 #define RETURN_ARES_CB_ERROR(param) \
172 PHP_ARES_CB_ERROR(param); \
173 RETURN_FALSE
174
175 #define PHP_ARES_QUERY_BUFFER_LEN 2<<0xf
176
177 /* {{{ typedefs */
178 typedef struct _php_ares_options {
179 struct ares_options strct;
180 int flags;
181 } php_ares_options;
182
183 typedef struct _php_ares {
184 ares_channel channel;
185 php_ares_options options;
186 zend_llist queries;
187 void ***tsrm_ls;
188 unsigned in_callback:1;
189 unsigned reserved:31;
190 } php_ares;
191
192 typedef enum _php_ares_query_type {
193 PHP_ARES_CB_STD,
194 PHP_ARES_CB_HOST,
195 PHP_ARES_CB_NINFO,
196 } php_ares_query_type;
197
198 typedef enum _php_ares_query_packet_type {
199 PHP_ARES_PCKT_SEARCH,
200 PHP_ARES_PCKT_QUERY,
201 PHP_ARES_PCKT_SEND,
202 PHP_ARES_PCKT_HNAME,
203 PHP_ARES_PCKT_HADDR,
204 PHP_ARES_PCKT_NINFO,
205 } php_ares_query_packet_type;
206
207 typedef union _php_ares_query_packet_data {
208 struct {
209 char *name;
210 int name_len;
211 long type;
212 long dnsclass;
213 } search;
214 struct {
215 char *name;
216 int name_len;
217 long type;
218 long dnsclass;
219 } query;
220 struct {
221 char *buf;
222 int len;
223 } send;
224 struct {
225 char *name;
226 int name_len;
227 long family;
228 } hname;
229 struct {
230 char *addr;
231 int addr_len;
232 long family;
233 } haddr;
234 struct {
235 char *addr;
236 int addr_len;
237 long port;
238 long family;
239 long flags;
240 } ninfo;
241 } php_ares_query_packet_data;
242
243 typedef struct _php_ares_query_packet {
244 php_ares_query_packet_type type;
245 php_ares_query_packet_data data;
246 } php_ares_query_packet;
247
248 typedef union _php_ares_query_result {
249 struct {
250 zval *arr;
251 char *buf;
252 int len;
253 } std;
254 struct hostent host;
255 struct {
256 char *service;
257 char *node;
258 } ninfo;
259 } php_ares_query_result;
260
261 typedef struct _php_ares_query {
262 int id;
263 int error;
264 php_ares *ares;
265 zval *callback;
266 php_ares_query_type type;
267 php_ares_query_packet packet;
268 php_ares_query_result result;
269 } php_ares_query;
270 /* }}} */
271
272 local struct hostent *php_ares_hostent_ctor(struct hostent *host) /* {{{ */
273 {
274 if (!host) {
275 host = emalloc(sizeof(struct hostent));
276 }
277 memset(host, 0, sizeof(struct hostent));
278
279 return host;
280 }
281 /* }}} */
282
283 local void php_ares_hostent_copy(struct hostent *from, struct hostent *to) /* {{{ */
284 {
285 int i, c;
286 char **ptr;
287
288 memcpy(to, from, sizeof(struct hostent));
289 to->h_name = estrdup(from->h_name);
290 for (c = 0, ptr = from->h_aliases; *ptr; ++ptr, ++c);
291 to->h_aliases = ecalloc((c+1), sizeof(char *));
292 for (i = 0; i < c; ++i) {
293 to->h_aliases[i] = estrdup(from->h_aliases[i]);
294 }
295 for (c = 0, ptr = from->h_addr_list; *ptr; ++ptr, ++c);
296 to->h_addr_list = ecalloc((c+1), sizeof(char *));
297 for (i = 0; i < c; ++i) {
298 to->h_addr_list[i] = emalloc(from->h_length);
299 memcpy(to->h_addr_list[i], from->h_addr_list[i], from->h_length);
300 }
301 }
302 /* }}} */
303
304 local void php_ares_hostent_to_struct(struct hostent *hostent, HashTable *ht) /* {{{ */
305 {
306 zval array, *tmp;
307 char **ptr;
308
309 INIT_PZVAL(&array);
310 Z_TYPE(array) = IS_ARRAY;
311 Z_ARRVAL(array) = ht;
312
313 if (hostent) {
314 add_assoc_string(&array, "name", hostent->h_name, 1);
315
316 MAKE_STD_ZVAL(tmp);
317 array_init(tmp);
318 if (hostent->h_aliases) {
319 for (ptr = hostent->h_aliases; *ptr; ++ptr) {
320 add_next_index_string(tmp, *ptr, 1);
321 }
322 }
323 add_assoc_zval(&array, "aliases", tmp);
324 add_assoc_long(&array, "addrtype", hostent->h_addrtype);
325
326 MAKE_STD_ZVAL(tmp);
327 array_init(tmp);
328 if (hostent->h_addr_list) {
329 for (ptr = hostent->h_addr_list; *ptr; ++ptr) {
330 char name[64] = {0};
331
332 if (inet_ntop(hostent->h_addrtype, *ptr, name, sizeof(name)-1)) {
333 add_next_index_string(tmp, name, 1);
334 }
335 }
336 }
337 add_assoc_zval(&array, "addrlist", tmp);
338 }
339 }
340 /* }}} */
341
342 local void php_ares_hostent_dtor(struct hostent *host) /* {{{ */
343 {
344 char **ptr;
345
346 STR_FREE(host->h_name);
347 if (host->h_aliases) {
348 for (ptr = host->h_aliases; *ptr; ++ptr) {
349 efree(*ptr);
350 }
351 efree(host->h_aliases);
352 }
353 if (host->h_addr_list) {
354 for (ptr = host->h_addr_list; *ptr; ++ptr) {
355 efree(*ptr);
356 }
357 efree(host->h_addr_list);
358 }
359 memset(host, 0, sizeof(struct hostent));
360 }
361 /* }}} */
362
363 local void php_ares_hostent_free(struct hostent **host) /* {{{ */
364 {
365 php_ares_hostent_dtor(*host);
366 efree(*host);
367 *host = NULL;
368 }
369 /* }}} */
370
371 local php_ares_query *php_ares_query_ctor(php_ares_query *query, php_ares_query_type type, php_ares *ares, zval *callback) /* {{{ */
372 {
373 if (!query) {
374 query = emalloc(sizeof(php_ares_query));
375 }
376 memset(query, 0, sizeof(php_ares_query));
377
378 query->ares = ares;
379 query->type = type;
380 query->error = -1;
381
382 if (callback) {
383 ADDREF(callback);
384 query->callback = callback;
385 }
386
387 return query;
388 }
389 /* }}} */
390
391 local void php_ares_query_rsrc(php_ares_query *query, zval *return_value) /* {{{ */
392 {
393 TSRMLS_FETCH_FROM_CTX(query->ares->tsrm_ls);
394
395 ZEND_REGISTER_RESOURCE(return_value, query, le_ares_query);
396 query->id = Z_LVAL_P(return_value);
397 zend_list_addref(query->id);
398 zend_llist_add_element(&query->ares->queries, &query);
399 }
400 /* }}} */
401
402 local void php_ares_query_pckt(php_ares_query *query, php_ares_query_packet_type type, ...)
403 {
404 va_list argv;
405 char *buf;
406 int len;
407
408 va_start(argv, type);
409
410 switch (query->packet.type = type) {
411 case PHP_ARES_PCKT_SEARCH:
412 buf = va_arg(argv, char *);
413 len = va_arg(argv, int);
414 query->packet.data.search.name = estrndup(buf, len);
415 query->packet.data.search.name_len = len;
416 query->packet.data.search.type = va_arg(argv, long);
417 query->packet.data.search.dnsclass = va_arg(argv, long);
418 break;
419
420 case PHP_ARES_PCKT_QUERY:
421 buf = va_arg(argv, char *);
422 len = va_arg(argv, int);
423 query->packet.data.query.name = estrndup(buf, len);
424 query->packet.data.query.name_len = len;
425 query->packet.data.query.type = va_arg(argv, long);
426 query->packet.data.query.dnsclass = va_arg(argv, long);
427 break;
428
429 case PHP_ARES_PCKT_SEND:
430 buf = va_arg(argv, char *);
431 len = va_arg(argv, int);
432 query->packet.data.send.buf = estrndup(buf, len);
433 query->packet.data.send.len = len;
434 break;
435
436 case PHP_ARES_PCKT_HNAME:
437 buf = va_arg(argv, char *);
438 len = va_arg(argv, int);
439 query->packet.data.hname.name = estrndup(buf, len);
440 query->packet.data.hname.name_len = len;
441 query->packet.data.hname.family = va_arg(argv, long);
442 break;
443
444 case PHP_ARES_PCKT_HADDR:
445 buf = va_arg(argv, char *);
446 len = va_arg(argv, int);
447 query->packet.data.haddr.addr = estrndup(buf, len);
448 query->packet.data.haddr.addr_len = len;
449 query->packet.data.haddr.family = va_arg(argv, long);
450 break;
451
452 case PHP_ARES_PCKT_NINFO:
453 query->packet.data.ninfo.flags = va_arg(argv, long);
454 buf = va_arg(argv, char *);
455 len = va_arg(argv, int);
456 query->packet.data.ninfo.addr = estrndup(buf, len);
457 query->packet.data.ninfo.addr_len = len;
458 query->packet.data.ninfo.family = va_arg(argv, long);
459 query->packet.data.ninfo.port = va_arg(argv, long);
460 break;
461 }
462
463 va_end(argv);
464 }
465
466 local void php_ares_query_dtor(php_ares_query *query) /* {{{ */
467 {
468 struct php_ares_query_packet_buf {char *buf;} *packet;
469
470 packet = (struct php_ares_query_packet_buf *) &query->packet.data;
471 if (packet->buf) {
472 efree(packet->buf);
473 }
474 switch (query->type) {
475 case PHP_ARES_CB_STD:
476 if (query->result.std.arr) {
477 zval_ptr_dtor(&query->result.std.arr);
478 }
479 STR_FREE(query->result.std.buf);
480 break;
481 case PHP_ARES_CB_HOST:
482 php_ares_hostent_dtor(&query->result.host);
483 break;
484 case PHP_ARES_CB_NINFO:
485 STR_FREE(query->result.ninfo.service);
486 STR_FREE(query->result.ninfo.node);
487 break;
488 }
489 if (query->callback) {
490 zval_ptr_dtor(&query->callback);
491 }
492 memset(query, 0, sizeof(php_ares_query));
493 }
494 /* }}} */
495
496 local void php_ares_query_free(php_ares_query **query) /* {{{ */
497 {
498 php_ares_query_dtor(*query);
499 efree(*query);
500 *query = NULL;
501 }
502 /* }}} */
503
504 local zend_bool is_numeric(zval **p, long *lval) { /* {{{ */
505 zval *tmp = *p;
506 switch (Z_TYPE_PP(p)) {
507 case IS_STRING:
508 convert_to_long_ex(&tmp);
509 /* no break */
510 case IS_LONG:
511 *lval = Z_LVAL_P(tmp);
512 if (tmp != *p) {
513 zval_ptr_dtor(&tmp);
514 }
515 return !!*lval;
516 }
517 return 0;
518 } /* }}} */
519
520 local php_ares_options *php_ares_options_ctor(php_ares_options *options, HashTable *ht) /* {{{ */
521 {
522 int i;
523 long lval;
524 zval **opt, **entry;
525
526 if (!options) {
527 options = emalloc(sizeof(php_ares_options));
528 }
529 memset(options, 0, sizeof(php_ares_options));
530
531 if (ht && zend_hash_num_elements(ht)) {
532 if ((SUCCESS == zend_hash_find(ht, "flags", sizeof("flags"), (void *) &opt)) && is_numeric(opt, &lval)) {
533 options->flags |= ARES_OPT_FLAGS;
534 options->strct.flags = lval;
535 }
536 #ifdef ARES_OPT_TIMEOUTMS
537 if ((SUCCESS == zend_hash_find(ht, "timeoutms", sizeof("timeoutms"), (void *) &opt)) && is_numeric(opt, &lval)) {
538 options->flags |= ARES_OPT_TIMEOUTMS;
539 options->strct.timeout = lval;
540 } else
541 #endif
542 if ((SUCCESS == zend_hash_find(ht, "timeout", sizeof("timeout"), (void *) &opt)) && is_numeric(opt, &lval)) {
543 options->flags |= ARES_OPT_TIMEOUT;
544 options->strct.timeout = lval;
545 }
546 if ((SUCCESS == zend_hash_find(ht, "tries", sizeof("tries"), (void *) &opt)) && is_numeric(opt, &lval)) {
547 options->flags |= ARES_OPT_TRIES;
548 options->strct.tries = lval;
549 }
550 if ((SUCCESS == zend_hash_find(ht, "ndots", sizeof("ndots"), (void *) &opt)) && is_numeric(opt, &lval)) {
551 options->flags |= ARES_OPT_NDOTS;
552 options->strct.ndots = lval;
553 }
554 if ((SUCCESS == zend_hash_find(ht, "udp_port", sizeof("udp_port"), (void *) &opt)) && is_numeric(opt, &lval)) {
555 options->flags |= ARES_OPT_UDP_PORT;
556 options->strct.udp_port = htons((unsigned short) lval);
557 }
558 if ((SUCCESS == zend_hash_find(ht, "tcp_port", sizeof("tcp_port"), (void *) &opt)) && is_numeric(opt, &lval)) {
559 options->flags |= ARES_OPT_TCP_PORT;
560 options->strct.tcp_port = htons((unsigned short) lval);
561 }
562 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)))) {
563 options->strct.servers = ecalloc(i, sizeof(struct in_addr));
564 for ( zend_hash_internal_pointer_reset(Z_ARRVAL_PP(opt));
565 SUCCESS == zend_hash_get_current_data(Z_ARRVAL_PP(opt), (void *) &entry);
566 zend_hash_move_forward(Z_ARRVAL_PP(opt))) {
567 if (Z_TYPE_PP(entry) == IS_STRING) {
568 inet_aton(Z_STRVAL_PP(entry), &options->strct.servers[options->strct.nservers++]);
569 }
570 }
571 if (options->strct.nservers) {
572 options->flags |= ARES_OPT_SERVERS;
573 }
574 }
575 if ((SUCCESS == zend_hash_find(ht, "domains", sizeof("domains"), (void *) &opt)) && (Z_TYPE_PP(opt) == IS_ARRAY) && (i = zend_hash_num_elements(Z_ARRVAL_PP(opt)))) {
576 options->strct.domains = ecalloc(i, sizeof(char *));
577 for ( zend_hash_internal_pointer_reset(Z_ARRVAL_PP(opt));
578 SUCCESS == zend_hash_get_current_data(Z_ARRVAL_PP(opt), (void *) &entry);
579 zend_hash_move_forward(Z_ARRVAL_PP(opt))) {
580 if (Z_TYPE_PP(entry) == IS_STRING) {
581 options->strct.domains[options->strct.ndomains++] = estrdup(Z_STRVAL_PP(entry));
582 }
583 }
584 if (options->strct.ndomains) {
585 options->flags |= ARES_OPT_DOMAINS;
586 }
587 }
588 if ((SUCCESS == zend_hash_find(ht, "lookups", sizeof("lookups"), (void *) &opt)) && (Z_TYPE_PP(opt) == IS_STRING)) {
589 options->flags |= ARES_OPT_LOOKUPS;
590 options->strct.lookups = estrdup(Z_STRVAL_PP(opt));
591 }
592 }
593
594 return options;
595 }
596 /* }}} */
597
598 local void php_ares_options_dtor(php_ares_options *options) /* {{{ */
599 {
600 int i;
601
602 if (options->strct.servers) {
603 efree(options->strct.servers);
604 }
605
606 if (options->strct.domains) {
607 for (i = 0; i < options->strct.ndomains; ++i) {
608 efree(options->strct.domains[i]);
609 }
610 efree(options->strct.domains);
611 }
612
613 STR_FREE(options->strct.lookups);
614
615 memset(options, 0, sizeof(php_ares_options));
616 }
617 /* }}} */
618
619 local void php_ares_options_free(php_ares_options **options) /* {{{ */
620 {
621 php_ares_options_dtor(*options);
622 efree(*options);
623 *options = NULL;
624 }
625 /* }}} */
626
627 local PHP_ARES_EXPAND_LEN_TYPE php_ares_skip(const unsigned char *pointer, const unsigned char *abuf, int alen TSRMLS_DC)
628 {
629 char *name;
630 int rc;
631 PHP_ARES_EXPAND_LEN_TYPE byte_count;
632
633 /* NOTE: byte_count is not neccessarily the length of the string,
634 i.e. if there were back references */
635 if (ARES_SUCCESS == (rc = ares_expand_name(pointer, abuf, alen, &name, &byte_count))) {
636 /*fprintf(stderr, "-- skipping %s\n", name);*/
637 ares_free_string(name);
638 return byte_count;
639 }
640 PHP_ARES_ERROR(rc);
641 return -1;
642 }
643
644 local int php_ares_parse(const unsigned char *abuf, int alen, zval *result TSRMLS_DC) /* {{{ */
645 {
646 HEADER *header;
647 PHP_ARES_EXPAND_LEN_TYPE byte_count;
648 const unsigned char *pointer;
649 char *name;
650 int rc, query_count, answer_count;
651
652 convert_to_array(result);
653
654 if (!alen || !abuf || !*abuf) {
655 return SUCCESS;
656 }
657
658 header = (HEADER *) abuf;
659 pointer = abuf + HFIXEDSZ;
660
661 for (query_count = ntohs(header->qdcount); query_count--; pointer += byte_count + QFIXEDSZ) {
662 if (0 > (byte_count = php_ares_skip(pointer, abuf, alen TSRMLS_CC))) {
663 return FAILURE;
664 }
665 }
666
667 for (answer_count = ntohs(header->ancount); answer_count-- && pointer < (abuf + alen); ) {
668 uint16_t stmp, type, class;
669 uint32_t ltmp, ttl;
670 zval **entry_ptr, *entry = NULL;
671
672 if (0 > (byte_count = php_ares_skip(pointer, abuf, alen TSRMLS_CC))) {
673 return FAILURE;
674 }
675
676 pointer += byte_count;
677
678 MAKE_STD_ZVAL(entry);
679 array_init(entry);
680
681 GETSHORT(type, pointer);
682 add_assoc_string(entry, "type", estrdup(php_ares_T_names[type]), 0);
683 GETSHORT(class, pointer);
684 add_assoc_string(entry, "class", estrdup(php_ares_C_names[class]), 0);
685 GETLONG(ttl, pointer);
686 add_assoc_long(entry, "ttl", ttl);
687 GETSHORT(byte_count, pointer);
688 #if 0
689 fprintf(stderr, ">> processing %s answer of length %d\n", php_ares_T_names[type], byte_count);
690 #endif
691 switch (type) {
692 case T_A:
693 spprintf(&name, 0, "%d.%d.%d.%d", pointer[0], pointer[1], pointer[2], pointer[3]);
694 add_assoc_string(entry, "addr", name, 0);
695 pointer += byte_count;
696 break;
697
698 case T_NS:
699 case T_PTR:
700 case T_CNAME:
701 if (ARES_SUCCESS != (rc = ares_expand_name(pointer, abuf, alen, &name, &byte_count))) {
702 PHP_ARES_ERROR(rc);
703 return FAILURE;
704 }
705 pointer += byte_count;
706 add_assoc_string(entry, "name", name, 1);
707 ares_free_string(name);
708 break;
709
710 case T_MX:
711 GETSHORT(stmp, pointer);
712 if (ARES_SUCCESS != (rc = ares_expand_name(pointer, abuf, alen, &name, &byte_count))) {
713 PHP_ARES_ERROR(rc);
714 return FAILURE;
715 }
716 pointer += byte_count;
717 add_assoc_long(entry, "weight", stmp);
718 add_assoc_string(entry, "name", name, 1);
719 ares_free_string(name);
720 break;
721
722 case T_SRV:
723 GETSHORT(stmp, pointer);
724 add_assoc_long(entry, "priority", stmp);
725 GETSHORT(stmp, pointer);
726 add_assoc_long(entry, "weight", stmp);
727 GETSHORT(stmp, pointer);
728 add_assoc_long(entry, "port", stmp);
729
730 if (ARES_SUCCESS != (rc = ares_expand_name(pointer, abuf, alen, &name, &byte_count))) {
731 PHP_ARES_ERROR(rc);
732 zval_ptr_dtor(&entry);
733 return FAILURE;
734 }
735 pointer += byte_count;
736 add_assoc_string(entry, "name", name, 1);
737 ares_free_string(name);
738 break;
739
740 case T_SOA:
741 if (ARES_SUCCESS != (rc = ares_expand_name(pointer, abuf, alen, &name, &byte_count))) {
742 PHP_ARES_ERROR(rc);
743 zval_ptr_dtor(&entry);
744 return FAILURE;
745 }
746 pointer += byte_count;
747 add_assoc_string(entry, "name", name, 1);
748 ares_free_string(name);
749
750 if (ARES_SUCCESS != (rc = ares_expand_name(pointer, abuf, alen, &name, &byte_count))) {
751 PHP_ARES_ERROR(rc);
752 zval_ptr_dtor(&entry);
753 return FAILURE;
754 }
755 pointer += byte_count;
756 add_assoc_string(entry, "mail", name, 1);
757 ares_free_string(name);
758
759 GETLONG(ltmp, pointer);
760 add_assoc_long(entry, "serial", ltmp);
761 GETLONG(ltmp, pointer);
762 add_assoc_long(entry, "refresh", ltmp);
763 GETLONG(ltmp, pointer);
764 add_assoc_long(entry, "retry", ltmp);
765 GETLONG(ltmp, pointer);
766 add_assoc_long(entry, "expire", ltmp);
767 GETLONG(ltmp, pointer);
768 add_assoc_long(entry, "minimum-ttl", ltmp);
769 break;
770
771 case T_TXT:
772 for (ltmp = 0; ltmp < byte_count; ltmp += pointer[ltmp] + 1) {
773 add_next_index_stringl(entry, (const char *) &pointer[ltmp + 1], pointer[ltmp], 1);
774 }
775 pointer += byte_count;
776 break;
777
778 default:
779 zval_ptr_dtor(&entry);
780 entry = NULL;
781 pointer += byte_count;
782 break;
783 }
784
785 if (entry) {
786 add_next_index_zval(result, entry);
787 }
788 }
789
790 return SUCCESS;
791 }
792 /* }}} */
793
794 /* {{{ callbacks */
795 static void php_ares_callback_func_old(void *aq, int status, unsigned char *abuf, int alen)
796 {
797 php_ares_query *q = (php_ares_query *) aq;
798 zval *params[4], *retval, *parsed = NULL;
799 TSRMLS_FETCH_FROM_CTX(q->ares->tsrm_ls);
800
801 q->error = status;
802 if (abuf) {
803 q->result.std.buf = estrndup((char *) abuf, alen);
804 q->result.std.len = alen;
805
806 MAKE_STD_ZVAL(parsed);
807 ZVAL_NULL(parsed);
808 if (SUCCESS == php_ares_parse(abuf, alen, parsed)) {
809 q->result.std.arr = parsed;
810 } else {
811 zval_ptr_dtor(&parsed);
812 parsed = NULL;
813 }
814 }
815
816 if (q->callback) {
817 MAKE_STD_ZVAL(retval);
818 MAKE_STD_ZVAL(params[0]);
819 MAKE_STD_ZVAL(params[1]);
820 MAKE_STD_ZVAL(params[2]);
821 ZVAL_NULL(retval);
822 zend_list_addref(q->id);
823 Z_LVAL_P(params[0]) = q->id;
824 Z_TYPE_P(params[0]) = IS_RESOURCE;
825 ZVAL_LONG(params[1], status);
826 ZVAL_STRINGL(params[2], (char *) abuf, alen, 1);
827
828 if (parsed) {
829 ADDREF(parsed);
830 params[3] = parsed;
831 }
832
833 q->ares->in_callback = 1;
834 call_user_function(EG(function_table), NULL, q->callback, retval, parsed ? 4 : 3, params TSRMLS_CC);
835 q->ares->in_callback = 0;
836
837 zval_ptr_dtor(&retval);
838 zval_ptr_dtor(&params[0]);
839 zval_ptr_dtor(&params[1]);
840 zval_ptr_dtor(&params[2]);
841
842 if (parsed) {
843 zval_ptr_dtor(&params[3]);
844 }
845 }
846 }
847
848 static void php_ares_host_callback_func_old(void *aq, int status, struct hostent *hostent)
849 {
850 php_ares_query *q = (php_ares_query *) aq;
851 zval *params[3], *retval;
852 TSRMLS_FETCH_FROM_CTX(q->ares->tsrm_ls);
853
854 q->error = status;
855 if (hostent) {
856 php_ares_hostent_copy(hostent, &q->result.host);
857 }
858
859 if (q->callback) {
860 MAKE_STD_ZVAL(retval);
861 MAKE_STD_ZVAL(params[0]);
862 MAKE_STD_ZVAL(params[1]);
863 MAKE_STD_ZVAL(params[2]);
864 ZVAL_NULL(retval);
865 zend_list_addref(q->id);
866 Z_LVAL_P(params[0]) = q->id;
867 Z_TYPE_P(params[0]) = IS_RESOURCE;
868 ZVAL_LONG(params[1], status);
869 object_init(params[2]);
870 php_ares_hostent_to_struct(hostent, HASH_OF(params[2]));
871
872 q->ares->in_callback = 1;
873 call_user_function(EG(function_table), NULL, q->callback, retval, 3, params TSRMLS_CC);
874 q->ares->in_callback = 0;
875
876 zval_ptr_dtor(&retval);
877 zval_ptr_dtor(&params[0]);
878 zval_ptr_dtor(&params[1]);
879 zval_ptr_dtor(&params[2]);
880 }
881 }
882
883 #ifdef HAVE_ARES_GETNAMEINFO
884 static void php_ares_nameinfo_callback_func_old(void *aq, int status, char *node, char *service)
885 {
886 php_ares_query *q = (php_ares_query *) aq;
887 zval *params[4], *retval;
888 TSRMLS_FETCH_FROM_CTX(q->ares->tsrm_ls);
889
890 q->error = status;
891 if (node) {
892 q->result.ninfo.node = estrdup(node);
893 }
894 if (service) {
895 q->result.ninfo.service = estrdup(service);
896 }
897
898 if (q->callback) {
899 MAKE_STD_ZVAL(retval);
900 MAKE_STD_ZVAL(params[0]);
901 MAKE_STD_ZVAL(params[1]);
902 MAKE_STD_ZVAL(params[2]);
903 MAKE_STD_ZVAL(params[3]);
904 ZVAL_NULL(retval);
905 zend_list_addref(q->id);
906 Z_LVAL_P(params[0]) = q->id;
907 Z_TYPE_P(params[0]) = IS_RESOURCE;
908 ZVAL_LONG(params[1], status);
909 if (node) {
910 ZVAL_STRING(params[2], node, 1);
911 } else {
912 ZVAL_NULL(params[2]);
913 }
914 if (service) {
915 ZVAL_STRING(params[3], service, 1);
916 } else {
917 ZVAL_NULL(params[3]);
918 }
919
920 q->ares->in_callback = 1;
921 call_user_function(EG(function_table), NULL, q->callback, retval, 4, params TSRMLS_CC);
922 q->ares->in_callback = 0;
923
924 zval_ptr_dtor(&retval);
925 zval_ptr_dtor(&params[0]);
926 zval_ptr_dtor(&params[1]);
927 zval_ptr_dtor(&params[2]);
928 zval_ptr_dtor(&params[3]);
929 }
930 }
931 #endif
932
933 #if PHP_ARES_NEW_CALLBACK_API
934 # define php_ares_callback_func php_ares_callback_func_new
935 static void php_ares_callback_func_new(void *aq, int status, int timeouts, unsigned char *abuf, int alen)
936 {
937 php_ares_callback_func_old(aq, status, abuf, alen);
938 }
939
940 # define php_ares_host_callback_func php_ares_host_callback_func_new
941 static void php_ares_host_callback_func_new(void *aq, int status, int timeouts, struct hostent *hostent)
942 {
943 php_ares_host_callback_func_old(aq, status, hostent);
944 }
945
946 # ifdef HAVE_ARES_GETNAMEINFO
947 # define php_ares_nameinfo_callback_func php_ares_nameinfo_callback_func_new
948 static void php_ares_nameinfo_callback_func_new(void *aq, int status, int timeouts, char *node, char *service)
949 {
950 php_ares_nameinfo_callback_func_old(aq, status, node, service);
951 }
952 # endif
953
954 #else
955 # define php_ares_callback_func php_ares_callback_func_old
956 # define php_ares_host_callback_func php_ares_host_callback_func_old
957 # ifdef HAVE_ARES_GETNAMEINFO
958 # define php_ares_nameinfo_callback_func php_ares_nameinfo_callback_func_old
959 # endif
960 #endif
961 /* }}} */
962
963 local struct timeval *php_ares_timeout(php_ares *ares, long max_timeout, struct timeval *tv_buf) /* {{{ */
964 {
965 struct timeval maxtv;
966
967 if (max_timeout > -1) {
968 maxtv.tv_sec = max_timeout / 1000;
969 maxtv.tv_usec = max_timeout % (max_timeout * 1000);
970 }
971
972 return ares_timeout(ares->channel, max_timeout > -1 ? &maxtv : NULL, tv_buf);
973 }
974 /* }}} */
975
976 local int php_ares_process(php_ares *ares, long max_timeout) /* {{{ */
977 {
978 int nfds;
979 fd_set R, W;
980 struct timeval tv;
981
982 FD_ZERO(&R);
983 FD_ZERO(&W);
984
985 if ((nfds = ares_fds(ares->channel, &R, &W))) {
986 if (0 < select(nfds, &R, &W, NULL, php_ares_timeout(ares, max_timeout, &tv))) {
987 ares_process(ares->channel, &R, &W);
988 }
989 }
990
991 return nfds;
992 }
993 /* }}} */
994
995 local int php_ares_publish_fds(fd_set *R, fd_set *W, zval *r, zval *w) /* {{{ */
996 {
997 int i, nfds = 0;
998
999 for (i = 0; i < FD_SETSIZE; ++i) {
1000 if (FD_ISSET(i, R)) {
1001 add_next_index_long(r, i);
1002 if (i > nfds) {
1003 nfds = i;
1004 }
1005 }
1006 }
1007
1008 for (i = 0; i < FD_SETSIZE; ++i) {
1009 if (FD_ISSET(i, W)) {
1010 add_next_index_long(w, i);
1011 if (i > nfds) {
1012 nfds = i;
1013 }
1014 }
1015 }
1016
1017 return nfds ? nfds + 1 : 0;
1018 }
1019 /* }}} */
1020
1021 local int php_ares_extract_fds(zval *r, zval *w, fd_set *R, fd_set *W) /* {{{ */
1022 {
1023 zval **fd;
1024 int nfds = 0;
1025
1026 if (r && zend_hash_num_elements(Z_ARRVAL_P(r))) {
1027 for ( zend_hash_internal_pointer_reset(Z_ARRVAL_P(r));
1028 SUCCESS == zend_hash_get_current_data(Z_ARRVAL_P(r), (void *) &fd);
1029 zend_hash_move_forward(Z_ARRVAL_P(r))) {
1030 if (Z_TYPE_PP(fd) == IS_LONG) {
1031 FD_SET(Z_LVAL_PP(fd), R);
1032 if (Z_LVAL_PP(fd) > nfds) {
1033 nfds = Z_LVAL_PP(fd);
1034 }
1035 }
1036 }
1037 }
1038
1039 if (w && zend_hash_num_elements(Z_ARRVAL_P(w))) {
1040 for ( zend_hash_internal_pointer_reset(Z_ARRVAL_P(w));
1041 SUCCESS == zend_hash_get_current_data(Z_ARRVAL_P(w), (void *) &fd);
1042 zend_hash_move_forward(Z_ARRVAL_P(w))) {
1043 if (Z_TYPE_PP(fd) == IS_LONG) {
1044 FD_SET(Z_LVAL_PP(fd), W);
1045 if (Z_LVAL_PP(fd) > nfds) {
1046 nfds = Z_LVAL_PP(fd);
1047 }
1048 }
1049 }
1050 }
1051
1052 return nfds ? nfds + 1 : 0;
1053 }
1054 /* }}} */
1055
1056 static void php_ares_query_llist_dtor(void *entry)
1057 {
1058 php_ares_query *q = *(php_ares_query **) entry;
1059 TSRMLS_FETCH_FROM_CTX(q->ares->tsrm_ls);
1060 zend_list_delete(q->id);
1061 }
1062
1063 #ifdef HAVE_ARES_VERSION
1064 /* {{{ proto string ares_version()
1065 Get libares version */
1066 static PHP_FUNCTION(ares_version)
1067 {
1068 if (ZEND_NUM_ARGS()) {
1069 WRONG_PARAM_COUNT;
1070 }
1071
1072 RETURN_STRING(estrdup(ares_version(NULL)), 0);
1073 }
1074 /* }}} */
1075 #endif
1076
1077 /* {{{ proto resource ares_init([array options])
1078 Create an ares resource */
1079 static PHP_FUNCTION(ares_init)
1080 {
1081 zval *opt_array = NULL;
1082 php_ares *ares = NULL;
1083 int err;
1084
1085 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a!", &opt_array)) {
1086 RETURN_FALSE;
1087 }
1088
1089 ares = emalloc(sizeof(php_ares));
1090 TSRMLS_SET_CTX(ares->tsrm_ls);
1091 zend_llist_init(&ares->queries, sizeof(php_ares_query *), (llist_dtor_func_t) php_ares_query_llist_dtor, 0);
1092 php_ares_options_ctor(&ares->options, opt_array ? Z_ARRVAL_P(opt_array) : NULL);
1093
1094 if (ARES_SUCCESS != (err = ares_init_options(&ares->channel, &ares->options.strct, ares->options.flags))) {
1095 php_ares_options_dtor(&ares->options);
1096 zend_llist_destroy(&ares->queries);
1097 efree(ares);
1098 RETURN_ARES_ERROR(err);
1099 }
1100
1101 ZEND_REGISTER_RESOURCE(return_value, ares, le_ares);
1102 }
1103 /* }}} */
1104
1105 /* {{{ proto void ares_destroy(resource ares)
1106 Destroy the ares handle */
1107 static PHP_FUNCTION(ares_destroy)
1108 {
1109 zval *rsrc;
1110 php_ares *ares;
1111
1112 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &rsrc)) {
1113 ZEND_FETCH_RESOURCE(ares, php_ares *, &rsrc, -1, PHP_ARES_LE_NAME, le_ares);
1114 if (ares->in_callback) {
1115 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot destroy ares handle while in callback");
1116 } else {
1117 zend_list_delete(Z_LVAL_P(rsrc));
1118 }
1119 }
1120 }
1121 /* }}} */
1122
1123 /* {{{ proto string ares_strerror(int status)
1124 Get description of status code */
1125 static PHP_FUNCTION(ares_strerror)
1126 {
1127 long err;
1128 #ifdef HAVE_OLD_ARES_STRERROR
1129 char *__tmp = NULL;
1130 const char *__err;
1131 #endif
1132
1133 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &err)) {
1134 RETURN_FALSE;
1135 }
1136
1137 #ifdef HAVE_OLD_ARES_STRERROR
1138 __err = ares_strerror(err, &__tmp);
1139 RETVAL_STRING(estrdup(__err), 0);
1140 if (__tmp) {
1141 ares_free_errmem(__tmp);
1142 }
1143 #else
1144 RETURN_STRING(estrdup(ares_strerror(err)), 0);
1145 #endif
1146 }
1147 /* }}} */
1148
1149 /* {{{ proto string ares_mkquery(string name, int dnsclass, int type, int id, int rd)
1150 Compose a custom query */
1151 static PHP_FUNCTION(ares_mkquery)
1152 {
1153 char *name_str, *query_str;
1154 int name_len, query_len, err;
1155 long dnsclass, type, id, rd;
1156
1157 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sllll", &name_str, &name_len, &dnsclass, &type, &id, &rd)) {
1158 RETURN_FALSE;
1159 }
1160
1161 if (ARES_SUCCESS != (err = ares_mkquery(name_str, dnsclass, type, id, rd, (unsigned char **) &query_str, &query_len))) {
1162 RETURN_ARES_ERROR(err);
1163 }
1164 RETVAL_STRINGL(query_str, query_len, 1);
1165 ares_free_string(query_str);
1166 }
1167 /* }}} */
1168
1169 /* {{{ proto resource ares_search(resource ares, mixed callback, string name[, int type = ARES_T_A[, int dnsclass = ARES_C_IN]])
1170 Issue a domain search for name */
1171 static PHP_FUNCTION(ares_search)
1172 {
1173 zval *rsrc, *cb = NULL;
1174 php_ares *ares;
1175 php_ares_query *query;
1176 char *name;
1177 int name_len;
1178 long dnsclass = C_IN, type = T_A;
1179
1180 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rz!s|ll", &rsrc, &cb, &name, &name_len, &type, &dnsclass)) {
1181 RETURN_FALSE;
1182 }
1183 ZEND_FETCH_RESOURCE(ares, php_ares *, &rsrc, -1, PHP_ARES_LE_NAME, le_ares);
1184
1185 if (cb && !PHP_ARES_IS_CALLABLE(cb, 0, NULL)) {
1186 RETURN_ARES_CB_ERROR("second");
1187 }
1188
1189 query = php_ares_query_ctor(NULL, PHP_ARES_CB_STD, ares, cb);
1190 php_ares_query_rsrc(query, return_value);
1191 php_ares_query_pckt(query, PHP_ARES_PCKT_SEARCH, name, name_len, type, dnsclass);
1192 ares_search(ares->channel, name, dnsclass, type, php_ares_callback_func, query);
1193 }
1194 /* }}} */
1195
1196 /* {{{ proto resource ares_query(resource ares, mixed callback, string name[, int type = ARES_T_A[, int dnsclass = ARES_C_IN]])
1197 Issue a single DNS query */
1198 static PHP_FUNCTION(ares_query)
1199 {
1200 zval *rsrc, *cb = NULL;
1201 php_ares *ares;
1202 php_ares_query *query;
1203 char *name;
1204 int name_len;
1205 long dnsclass = C_IN, type = T_A;
1206
1207 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rz!s|ll", &rsrc, &cb, &name, &name_len, &type, &dnsclass)) {
1208 RETURN_FALSE;
1209 }
1210 ZEND_FETCH_RESOURCE(ares, php_ares *, &rsrc, -1, PHP_ARES_LE_NAME, le_ares);
1211
1212 if (cb && !PHP_ARES_IS_CALLABLE(cb, 0, NULL)) {
1213 RETURN_ARES_CB_ERROR("second");
1214 }
1215
1216 query = php_ares_query_ctor(NULL, PHP_ARES_CB_STD, ares, cb);
1217 php_ares_query_rsrc(query, return_value);
1218 php_ares_query_pckt(query, PHP_ARES_PCKT_QUERY, name, name_len, type, dnsclass);
1219 ares_query(ares->channel, name, dnsclass, type, php_ares_callback_func, query);
1220 }
1221 /* }}} */
1222
1223 /* {{{ proto resource ares_send(resource ares, mixed callback, string buf)
1224 Send custom query */
1225 static PHP_FUNCTION(ares_send)
1226 {
1227 zval *rsrc, *cb = NULL;
1228 php_ares *ares;
1229 php_ares_query *query;
1230 char *buf;
1231 int len;
1232
1233 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rz!s", &rsrc, &cb, &buf, &len)) {
1234 RETURN_FALSE;
1235 }
1236 ZEND_FETCH_RESOURCE(ares, php_ares *, &rsrc, -1, PHP_ARES_LE_NAME, le_ares);
1237
1238 if (cb && !PHP_ARES_IS_CALLABLE(cb, 0, NULL)) {
1239 RETURN_ARES_CB_ERROR("second");
1240 }
1241
1242 query = php_ares_query_ctor(NULL, PHP_ARES_CB_STD, ares, cb);
1243 php_ares_query_rsrc(query, return_value);
1244 php_ares_query_pckt(query, PHP_ARES_PCKT_SEND, buf, len);
1245 ares_send(ares->channel, (const unsigned char *) buf, len, php_ares_callback_func, query);
1246 }
1247 /* }}} */
1248
1249 /* {{{ proto resource ares_gethostbyname(resource ares, mixed callback, string name[, int family = AF_INET])
1250 Get host by name */
1251 static PHP_FUNCTION(ares_gethostbyname)
1252 {
1253 zval *rsrc, *cb = NULL;
1254 php_ares *ares;
1255 php_ares_query *query;
1256 char *name;
1257 int name_len;
1258 long family = AF_INET;
1259
1260 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rz!s|l", &rsrc, &cb, &name, &name_len, &family)) {
1261 RETURN_FALSE;
1262 }
1263 ZEND_FETCH_RESOURCE(ares, php_ares *, &rsrc, -1, PHP_ARES_LE_NAME, le_ares);
1264
1265 if (cb && !PHP_ARES_IS_CALLABLE(cb, 0, NULL)) {
1266 RETURN_ARES_CB_ERROR("second");
1267 }
1268
1269 query = php_ares_query_ctor(NULL, PHP_ARES_CB_HOST, ares, cb);
1270 php_ares_query_rsrc(query, return_value);
1271 php_ares_query_pckt(query, PHP_ARES_PCKT_HNAME, name, name_len, family);
1272 ares_gethostbyname(ares->channel, name, family, php_ares_host_callback_func, query);
1273 }
1274 /* }}} */
1275
1276 /* {{{ proto resource ares_gethostbyaddr(resuorce ares, mixed callback, string address[, int family = ARES_AF_INET])
1277 Get host by address */
1278 static PHP_FUNCTION(ares_gethostbyaddr)
1279 {
1280 zval *rsrc, *cb = NULL;
1281 php_ares *ares;
1282 php_ares_query *query;
1283 char *addr;
1284 int addr_len;
1285 long family = AF_INET;
1286 void *sa;
1287 int sa_len;
1288
1289 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rz!s|l", &rsrc, &cb, &addr, &addr_len, &family)) {
1290 RETURN_FALSE;
1291 }
1292 ZEND_FETCH_RESOURCE(ares, php_ares *, &rsrc, -1, PHP_ARES_LE_NAME, le_ares);
1293
1294 if (cb && !PHP_ARES_IS_CALLABLE(cb, 0, NULL)) {
1295 PHP_ARES_CB_ERROR("second");
1296 RETURN_FALSE;
1297 }
1298
1299 switch (family) {
1300 case AF_INET:
1301 sa = emalloc(sa_len = sizeof(struct in_addr));
1302 break;
1303 case AF_INET6:
1304 sa = emalloc(sa_len = sizeof(struct in6_addr));
1305 break;
1306 default:
1307 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Parameter family is neither ARES_AF_INET nor ARES_AF_INET6");
1308 RETURN_FALSE;
1309 break;
1310 }
1311
1312 if (1 > inet_pton(family, addr, sa)) {
1313 php_error_docref(NULL TSRMLS_CC, E_WARNING, "inet_pton('%s') failed", addr);
1314 RETVAL_FALSE;
1315 } else {
1316 query = php_ares_query_ctor(NULL, PHP_ARES_CB_HOST, ares, cb);
1317 php_ares_query_rsrc(query, return_value);
1318 php_ares_query_pckt(query, PHP_ARES_PCKT_HADDR, addr, addr_len, family);
1319 ares_gethostbyaddr(ares->channel, sa, sa_len, family, php_ares_host_callback_func, query);
1320 }
1321 efree(sa);
1322 }
1323 /* }}} */
1324
1325 #ifdef HAVE_ARES_GETNAMEINFO
1326 /* {{{ proto resource ares_getnameinfo(resource ares, mixed callback, int flags, string addr[, int family = ARES_AF_INET[, int port = 0]])
1327 Get name info */
1328 static PHP_FUNCTION(ares_getnameinfo)
1329 {
1330 zval *rsrc, *cb = NULL;
1331 php_ares *ares;
1332 php_ares_query *query;
1333 char *addr;
1334 int addr_len;
1335 long flags, port = 0, family = AF_INET;
1336 struct sockaddr *sa;
1337 struct sockaddr_in *in;
1338 struct sockaddr_in6 *in6;
1339 int sa_len;
1340
1341 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rz!ls|ll", &rsrc, &cb, &flags, &addr, &addr_len, &family, &port)) {
1342 RETURN_FALSE;
1343 }
1344 ZEND_FETCH_RESOURCE(ares, php_ares *, &rsrc, -1, PHP_ARES_LE_NAME, le_ares);
1345
1346 if (cb && !PHP_ARES_IS_CALLABLE(cb, 0, NULL)) {
1347 PHP_ARES_CB_ERROR("second");
1348 RETURN_FALSE;
1349 }
1350
1351 RETVAL_TRUE;
1352 switch (family) {
1353 case AF_INET:
1354 in = ecalloc(1, sa_len = sizeof(struct sockaddr_in));
1355 in->sin_family = AF_INET;
1356 in->sin_port = htons((unsigned short) port);
1357 if (1 > inet_pton(in->sin_family, addr, &in->sin_addr)) {
1358 php_error_docref(NULL TSRMLS_CC, E_WARNING, "inet_pton('%s') failed", addr);
1359 RETVAL_FALSE;
1360 }
1361 sa = (struct sockaddr *) in;
1362 break;
1363 case AF_INET6:
1364 in6 = ecalloc(1, sa_len = sizeof(struct sockaddr_in6));
1365 in6->sin6_family = AF_INET6;
1366 in6->sin6_port = htons((unsigned short) port);
1367 if (1 > inet_pton(in6->sin6_family, addr, &in6->sin6_addr)) {
1368 php_error_docref(NULL TSRMLS_CC, E_WARNING, "inet_pton('%s') failed", addr);
1369 RETVAL_FALSE;
1370 }
1371 sa = (struct sockaddr *) in6;
1372 break;
1373 default:
1374 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Parameter family is neither AF_INET nor AF_INET6");
1375 RETURN_FALSE;
1376 break;
1377 }
1378
1379 if (Z_BVAL_P(return_value)) {
1380 query = php_ares_query_ctor(NULL, PHP_ARES_CB_NINFO, ares, cb);
1381 php_ares_query_rsrc(query, return_value);
1382 php_ares_query_pckt(query, PHP_ARES_PCKT_NINFO, flags, addr, addr_len, family, port);
1383 ares_getnameinfo(ares->channel, sa, sa_len, flags, php_ares_nameinfo_callback_func, query);
1384 }
1385 efree(sa);
1386 }
1387 /* }}} */
1388 #endif
1389
1390 /* {{{ proto mixed ares_result(resource query, int &errno, string &error)
1391 Check a query for its result */
1392 static PHP_FUNCTION(ares_result)
1393 {
1394 zval *rsrc, *zerrno = NULL, *zerror = NULL;
1395 php_ares_query *query;
1396
1397 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|zz", &rsrc, &zerrno, &zerror)) {
1398 RETURN_FALSE;
1399 }
1400 ZEND_FETCH_RESOURCE(query, php_ares_query *, &rsrc, -1, PHP_ARES_QUERY_LE_NAME, le_ares_query);
1401
1402 if (zerrno) {
1403 zval_dtor(zerrno);
1404 ZVAL_LONG(zerrno, query->error);
1405 }
1406 if (zerror) {
1407 zval_dtor(zerror);
1408 ZVAL_NULL(zerror);
1409 }
1410
1411 switch (query->error) {
1412 case 0:
1413 switch (query->type) {
1414 case PHP_ARES_CB_STD:
1415 if (query->result.std.arr) {
1416 RETVAL_ZVAL(query->result.std.arr, 1, 0);
1417 } else {
1418 RETVAL_STRINGL(query->result.std.buf, query->result.std.len, 1);
1419 }
1420 break;
1421 case PHP_ARES_CB_HOST:
1422 object_init(return_value);
1423 php_ares_hostent_to_struct(&query->result.host, HASH_OF(return_value));
1424 break;
1425 case PHP_ARES_CB_NINFO:
1426 object_init(return_value);
1427 add_property_string(return_value, "node", query->result.ninfo.node ? query->result.ninfo.node : "", 1);
1428 add_property_string(return_value, "service", query->result.ninfo.service ? query->result.ninfo.service : "", 1);
1429 break;
1430 }
1431 break;
1432 case -1:
1433 RETVAL_FALSE;
1434 break;
1435 default:
1436 if (zerror) {
1437 #ifdef HAVE_OLD_ARES_STRERROR
1438 char *__tmp = NULL;
1439 const char *__err = ares_strerror(query->error, &__tmp);
1440 ZVAL_STRING(zerror, estrdup(__err), 0);
1441 if (__tmp) ares_free_errmem(__tmp);
1442 #else
1443 ZVAL_STRING(zerror, estrdup(ares_strerror(query->error)), 0);
1444 #endif
1445 }
1446 RETVAL_FALSE;
1447 break;
1448 }
1449 }
1450 /* }}} */
1451
1452 /* {{{ proto object ares_packet(resource query)
1453 Check a query for its question packet */
1454 static PHP_FUNCTION(ares_packet)
1455 {
1456 zval *rsrc, *prop;
1457 php_ares_query *query;
1458
1459 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &rsrc)) {
1460 RETURN_FALSE;
1461 }
1462 ZEND_FETCH_RESOURCE(query, php_ares_query *, &rsrc, -1, PHP_ARES_QUERY_LE_NAME, le_ares_query);
1463
1464 object_init(return_value);
1465 add_property_long(return_value, "type", query->packet.type);
1466 add_property_null(return_value, "search");
1467 add_property_null(return_value, "query");
1468 add_property_null(return_value, "send");
1469 add_property_null(return_value, "gethostbyname");
1470 add_property_null(return_value, "gethostbyaddr");
1471 add_property_null(return_value, "getnameinfo");
1472 MAKE_STD_ZVAL(prop);
1473
1474 switch (query->packet.type) {
1475 case PHP_ARES_PCKT_SEARCH:
1476 object_init(prop);
1477 add_property_stringl(prop, "name", query->packet.data.search.name, query->packet.data.search.name_len, 1);
1478 add_property_long(prop, "type", query->packet.data.search.type);
1479 add_property_long(prop, "dnsclass", query->packet.data.search.dnsclass);
1480 add_property_zval(return_value, "search", prop);
1481 break;
1482
1483 case PHP_ARES_PCKT_QUERY:
1484 object_init(prop);
1485 add_property_stringl(prop, "name", query->packet.data.query.name, query->packet.data.query.name_len, 1);
1486 add_property_long(prop, "type", query->packet.data.query.type);
1487 add_property_long(prop, "dnsclass", query->packet.data.query.dnsclass);
1488 add_property_zval(return_value, "query", prop);
1489 break;
1490
1491 case PHP_ARES_PCKT_SEND:
1492 ZVAL_STRINGL(prop, query->packet.data.send.buf, query->packet.data.send.len, 1);
1493 add_property_zval(return_value, "send", prop);
1494 break;
1495
1496 case PHP_ARES_PCKT_HNAME:
1497 object_init(prop);
1498 add_property_stringl(prop, "name", query->packet.data.hname.name, query->packet.data.hname.name_len, 1);
1499 add_property_long(prop, "family", query->packet.data.hname.family);
1500 add_property_zval(return_value, "gethostbyname", prop);
1501 break;
1502
1503 case PHP_ARES_PCKT_HADDR:
1504 object_init(prop);
1505 add_property_stringl(prop, "addr", query->packet.data.haddr.addr, query->packet.data.haddr.addr_len, 1);
1506 add_property_long(prop, "family", query->packet.data.haddr.family);
1507 add_property_zval(return_value, "gethostbyaddr", prop);
1508 break;
1509
1510 case PHP_ARES_PCKT_NINFO:
1511 object_init(prop);
1512 add_property_long(prop, "flags", query->packet.data.ninfo.flags);
1513 add_property_stringl(prop, "addr", query->packet.data.ninfo.addr, query->packet.data.ninfo.addr_len, 1);
1514 add_property_long(prop, "family", query->packet.data.ninfo.family);
1515 add_property_long(prop, "port", query->packet.data.ninfo.port);
1516 add_property_zval(return_value, "getnameinfo", prop);
1517 break;
1518 }
1519
1520 zval_ptr_dtor(&prop);
1521 }
1522 /* }}} */
1523
1524 #ifdef HAVE_ARES_CANCEL
1525 /* {{{ proto void ares_cancel(resource ares)
1526 Cancel pending queries */
1527 static PHP_FUNCTION(ares_cancel)
1528 {
1529 zval *rsrc;
1530 php_ares *ares;
1531
1532 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &rsrc)) {
1533 ZEND_FETCH_RESOURCE(ares, php_ares *, &rsrc, -1, PHP_ARES_LE_NAME, le_ares);
1534 ares_cancel(ares->channel);
1535 }
1536 }
1537 /* }}} */
1538 #endif
1539
1540 /* {{{ proto void ares_process_all(resource ares[, int max_timeout_ms])
1541 Process all pending queries */
1542 static PHP_FUNCTION(ares_process_all)
1543 {
1544 zval *rsrc;
1545 php_ares *ares;
1546 long max_timeout = -1;
1547
1548 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|l", &rsrc, &max_timeout)) {
1549 RETURN_FALSE;
1550 }
1551 ZEND_FETCH_RESOURCE(ares, php_ares *, &rsrc, -1, PHP_ARES_LE_NAME, le_ares);
1552
1553 while (php_ares_process(ares, max_timeout));
1554 }
1555 /* }}} */
1556
1557 /* {{{ proto bool ares_process_once(resource ares[, int max_timout_ms])
1558 Process once and return whether it should be called again */
1559 static PHP_FUNCTION(ares_process_once)
1560 {
1561 zval *rsrc;
1562 php_ares *ares;
1563 long max_timeout = -1;
1564
1565 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|l", &rsrc, &max_timeout)) {
1566 RETURN_FALSE;
1567 }
1568 ZEND_FETCH_RESOURCE(ares, php_ares *, &rsrc, -1, PHP_ARES_LE_NAME, le_ares);
1569
1570 RETVAL_BOOL(php_ares_process(ares, max_timeout));
1571 }
1572 /* }}} */
1573
1574 /* {{{ proto void ares_process(resource ares, array read, array write)
1575 Process call */
1576 static PHP_FUNCTION(ares_process)
1577 {
1578 zval *rsrc, *read = NULL, *write = NULL;
1579 fd_set R, W;
1580 php_ares *ares;
1581
1582 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|a!a!", &rsrc, &read, &write)) {
1583 RETURN_FALSE;
1584 }
1585 ZEND_FETCH_RESOURCE(ares, php_ares *, &rsrc, -1, PHP_ARES_LE_NAME, le_ares);
1586
1587 FD_ZERO(&R);
1588 FD_ZERO(&W);
1589
1590 php_ares_extract_fds(read, write, &R, &W);
1591 ares_process(ares->channel, &R, &W);
1592 }
1593 /* }}} */
1594
1595 /* proto bool ares_select(array &read, array &write, int timeout_ms)
1596 Select call */
1597 static PHP_FUNCTION(ares_select)
1598 {
1599 zval *read = NULL, *write = NULL;
1600 fd_set R, W;
1601 int nfds;
1602 long timeout;
1603 struct timeval tv;
1604
1605 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "aal", &read, &write, &timeout)) {
1606 RETURN_FALSE;
1607 }
1608
1609 if (timeout) {
1610 tv.tv_sec = timeout / 1000;
1611 tv.tv_usec = timeout % (timeout * 1000);
1612 } else {
1613 tv.tv_sec = 1;
1614 tv.tv_usec = 0;
1615 }
1616
1617 FD_ZERO(&R);
1618 FD_ZERO(&W);
1619
1620 nfds = php_ares_extract_fds(read, write, &R, &W);
1621 if (-1 < select(nfds, &R, &W, NULL, &tv)) {
1622 zend_hash_clean(Z_ARRVAL_P(read));
1623 zend_hash_clean(Z_ARRVAL_P(write));
1624 php_ares_publish_fds(&R, &W, read, write);
1625 RETURN_TRUE;
1626 }
1627 RETURN_FALSE;
1628 }
1629 /* }}} */
1630
1631 /* proto int ares_timeout(resource ares[, int max_timout_ms])
1632 Get suggested select timeout in ms */
1633 static PHP_FUNCTION(ares_timeout)
1634 {
1635 zval *rsrc;
1636 long max_timeout = -1;
1637 struct timeval tv, *tvptr;
1638 php_ares *ares;
1639
1640 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|l", &rsrc, &max_timeout)) {
1641 RETURN_FALSE;
1642 }
1643 ZEND_FETCH_RESOURCE(ares, php_ares *, &rsrc, -1, PHP_ARES_LE_NAME, le_ares);
1644
1645 if ((tvptr = php_ares_timeout(ares, max_timeout, &tv))) {
1646 RETURN_LONG(tvptr->tv_sec * 1000 + tvptr->tv_usec / 1000);
1647 }
1648 RETURN_LONG(0);
1649 }
1650 /* }}} */
1651
1652 /* {{{ proto int ares_fds(resource ares, array &read, array &write)
1653 Get file descriptors */
1654 static PHP_FUNCTION(ares_fds)
1655 {
1656 zval *rsrc, *read, *write;
1657 fd_set R, W;
1658 php_ares *ares;
1659
1660 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rzz", &rsrc, &read, &write)) {
1661 RETURN_FALSE;
1662 }
1663 ZEND_FETCH_RESOURCE(ares, php_ares *, &rsrc, -1, PHP_ARES_LE_NAME, le_ares);
1664
1665 FD_ZERO(&R);
1666 FD_ZERO(&W);
1667
1668 zval_dtor(read);
1669 zval_dtor(write);
1670 array_init(read);
1671 array_init(write);
1672 ares_fds(ares->channel, &R, &W);
1673 RETVAL_LONG(php_ares_publish_fds(&R, &W, read, write));
1674 }
1675 /* }}} */
1676
1677 static ZEND_RSRC_DTOR_FUNC(php_ares_le_dtor)
1678 {
1679 php_ares *ares = (php_ares *) rsrc->ptr;
1680
1681 ares_destroy(ares->channel);
1682 zend_llist_destroy(&ares->queries);
1683 php_ares_options_dtor(&ares->options);
1684 efree(ares);
1685 }
1686
1687 static ZEND_RSRC_DTOR_FUNC(php_ares_query_le_dtor)
1688 {
1689 php_ares_query *query = (php_ares_query *) rsrc->ptr;
1690
1691 php_ares_query_dtor(query);
1692 efree(query);
1693 }
1694
1695 /* {{{ PHP_MINIT_FUNCTION */
1696 static PHP_MINIT_FUNCTION(ares)
1697 {
1698 #ifdef HAVE_ARES_LIBRARY_INIT
1699 if (ARES_SUCCESS != ares_library_init(ARES_LIB_INIT_ALL)) {
1700 return FAILURE;
1701 }
1702 #endif
1703 #ifdef HAVE_ARES_VERSION
1704 {
1705 int ares_version_num;
1706 ares_version(&ares_version_num);
1707
1708 REGISTER_LONG_CONSTANT("ARES_VERSION", ares_version_num, CONST_PERSISTENT|CONST_CS);
1709 }
1710 #endif
1711
1712 REGISTER_LONG_CONSTANT("ARES_SUCCESS", ARES_SUCCESS, CONST_PERSISTENT|CONST_CS);
1713 REGISTER_LONG_CONSTANT("ARES_ENODATA", ARES_ENODATA, CONST_PERSISTENT|CONST_CS);
1714 REGISTER_LONG_CONSTANT("ARES_EFORMERR", ARES_EFORMERR, CONST_PERSISTENT|CONST_CS);
1715 REGISTER_LONG_CONSTANT("ARES_ESERVFAIL", ARES_ESERVFAIL, CONST_PERSISTENT|CONST_CS);
1716 REGISTER_LONG_CONSTANT("ARES_ENOTFOUND", ARES_ENOTFOUND, CONST_PERSISTENT|CONST_CS);
1717 REGISTER_LONG_CONSTANT("ARES_ENOTIMP", ARES_ENOTIMP, CONST_PERSISTENT|CONST_CS);
1718 REGISTER_LONG_CONSTANT("ARES_EREFUSED", ARES_EREFUSED, CONST_PERSISTENT|CONST_CS);
1719 REGISTER_LONG_CONSTANT("ARES_EBADQUERY", ARES_EBADQUERY, CONST_PERSISTENT|CONST_CS);
1720 REGISTER_LONG_CONSTANT("ARES_EBADNAME", ARES_EBADNAME, CONST_PERSISTENT|CONST_CS);
1721 REGISTER_LONG_CONSTANT("ARES_EBADFAMILY", ARES_EBADFAMILY, CONST_PERSISTENT|CONST_CS);
1722 REGISTER_LONG_CONSTANT("ARES_EBADRESP", ARES_EBADRESP, CONST_PERSISTENT|CONST_CS);
1723 REGISTER_LONG_CONSTANT("ARES_ECONNREFUSED", ARES_ECONNREFUSED, CONST_PERSISTENT|CONST_CS);
1724 REGISTER_LONG_CONSTANT("ARES_ETIMEOUT", ARES_ETIMEOUT, CONST_PERSISTENT|CONST_CS);
1725 REGISTER_LONG_CONSTANT("ARES_EOF", ARES_EOF, CONST_PERSISTENT|CONST_CS);
1726 REGISTER_LONG_CONSTANT("ARES_EFILE", ARES_EFILE, CONST_PERSISTENT|CONST_CS);
1727 REGISTER_LONG_CONSTANT("ARES_ENOMEM", ARES_ENOMEM, CONST_PERSISTENT|CONST_CS);
1728 REGISTER_LONG_CONSTANT("ARES_EDESTRUCTION", ARES_EDESTRUCTION, CONST_PERSISTENT|CONST_CS);
1729 #ifdef ARES_EBADSTR
1730 REGISTER_LONG_CONSTANT("ARES_EBADSTR", ARES_EBADSTR, CONST_PERSISTENT|CONST_CS);
1731 #endif
1732 #ifdef ARES_EBADFLAGS
1733 REGISTER_LONG_CONSTANT("ARES_EBADFLAGS", ARES_EBADFLAGS, CONST_PERSISTENT|CONST_CS);
1734 #endif
1735 #ifdef ARES_ENONAME
1736 REGISTER_LONG_CONSTANT("ARES_ENONAME", ARES_ENONAME, CONST_PERSISTENT|CONST_CS);
1737 #endif
1738 #ifdef ARES_EBADHINTS
1739 REGISTER_LONG_CONSTANT("ARES_EBADHINTS", ARES_EBADHINTS, CONST_PERSISTENT|CONST_CS);
1740 #endif
1741 #ifdef ARES_ENOTINITIALIZED
1742 REGISTER_LONG_CONSTANT("ARES_ENOTINITIALIZED", ARES_ENOTINITIALIZED, CONST_PERSISTENT|CONST_CS);
1743 #endif
1744 #ifdef ARES_ELOADIPHLPAPI
1745 REGISTER_LONG_CONSTANT("ARES_ELOADIPHLPAPI", ARES_ELOADIPHLPAPI, CONST_PERSISTENT|CONST_CS);
1746 #endif
1747 #ifdef ARES_EADDRGETNETWORKPARAMS
1748 REGISTER_LONG_CONSTANT("ARES_EADDRGETNETWORKPARAMS", ARES_EADDRGETNETWORKPARAMS, CONST_PERSISTENT|CONST_CS);
1749 #endif
1750 #ifdef ARES_ECANCELLED
1751 REGISTER_LONG_CONSTANT("ARES_ECANCELLED", ARES_ECANCELLED, CONST_PERSISTENT|CONST_CS);
1752 #endif
1753
1754 REGISTER_LONG_CONSTANT("ARES_FLAG_USEVC", ARES_FLAG_USEVC, CONST_PERSISTENT|CONST_CS);
1755 REGISTER_LONG_CONSTANT("ARES_FLAG_PRIMARY", ARES_FLAG_PRIMARY, CONST_PERSISTENT|CONST_CS);
1756 REGISTER_LONG_CONSTANT("ARES_FLAG_IGNTC", ARES_FLAG_IGNTC, CONST_PERSISTENT|CONST_CS);
1757 REGISTER_LONG_CONSTANT("ARES_FLAG_NORECURSE", ARES_FLAG_NORECURSE, CONST_PERSISTENT|CONST_CS);
1758 REGISTER_LONG_CONSTANT("ARES_FLAG_STAYOPEN", ARES_FLAG_STAYOPEN, CONST_PERSISTENT|CONST_CS);
1759 REGISTER_LONG_CONSTANT("ARES_FLAG_NOSEARCH", ARES_FLAG_NOSEARCH, CONST_PERSISTENT|CONST_CS);
1760 REGISTER_LONG_CONSTANT("ARES_FLAG_NOALIASES", ARES_FLAG_NOALIASES, CONST_PERSISTENT|CONST_CS);
1761 REGISTER_LONG_CONSTANT("ARES_FLAG_NOCHECKRESP", ARES_FLAG_NOCHECKRESP, CONST_PERSISTENT|CONST_CS);
1762
1763 /*
1764 * Address Family Constants
1765 */
1766 REGISTER_LONG_CONSTANT("ARES_AF_INET", AF_INET, CONST_PERSISTENT|CONST_CS);
1767 REGISTER_LONG_CONSTANT("ARES_AF_INET6", AF_INET6, CONST_PERSISTENT|CONST_CS);
1768
1769 /*
1770 * Name Info constants
1771 */
1772 #ifdef ARES_NI_NOFQDN
1773 REGISTER_LONG_CONSTANT("ARES_NI_NOFQDN", ARES_NI_NOFQDN, CONST_PERSISTENT|CONST_CS);
1774 #endif
1775 #ifdef ARES_NI_NUMERICHOST
1776 REGISTER_LONG_CONSTANT("ARES_NI_NUMERICHOST", ARES_NI_NUMERICHOST, CONST_PERSISTENT|CONST_CS);
1777 #endif
1778 #ifdef ARES_NI_NAMEREQD
1779 REGISTER_LONG_CONSTANT("ARES_NI_NAMEREQD", ARES_NI_NAMEREQD, CONST_PERSISTENT|CONST_CS);
1780 #endif
1781 #ifdef ARES_NI_NUMERICSERV
1782 REGISTER_LONG_CONSTANT("ARES_NI_NUMERICSERV", ARES_NI_NUMERICSERV, CONST_PERSISTENT|CONST_CS);
1783 #endif
1784 #ifdef ARES_NI_DGRAM
1785 REGISTER_LONG_CONSTANT("ARES_NI_DGRAM", ARES_NI_DGRAM, CONST_PERSISTENT|CONST_CS);
1786 #endif
1787 #ifdef ARES_NI_TCP
1788 REGISTER_LONG_CONSTANT("ARES_NI_TCP", ARES_NI_TCP, CONST_PERSISTENT|CONST_CS);
1789 #endif
1790 #ifdef ARES_NI_UDP
1791 REGISTER_LONG_CONSTANT("ARES_NI_UDP", ARES_NI_UDP, CONST_PERSISTENT|CONST_CS);
1792 #endif
1793 #ifdef ARES_NI_SCTP
1794 REGISTER_LONG_CONSTANT("ARES_NI_SCTP", ARES_NI_SCTP, CONST_PERSISTENT|CONST_CS);
1795 #endif
1796 #ifdef ARES_NI_DCCP
1797 REGISTER_LONG_CONSTANT("ARES_NI_DCCP", ARES_NI_DCCP, CONST_PERSISTENT|CONST_CS);
1798 #endif
1799 #ifdef ARES_NI_NUMERICSCOPE
1800 REGISTER_LONG_CONSTANT("ARES_NI_NUMERICSCOPE", ARES_NI_NUMERICSCOPE, CONST_PERSISTENT|CONST_CS);
1801 #endif
1802 #ifdef ARES_NI_LOOKUPHOST
1803 REGISTER_LONG_CONSTANT("ARES_NI_LOOKUPHOST", ARES_NI_LOOKUPHOST, CONST_PERSISTENT|CONST_CS);
1804 #endif
1805 #ifdef ARES_NI_LOOKUPSERVICE
1806 REGISTER_LONG_CONSTANT("ARES_NI_LOOKUPSERVICE", ARES_NI_LOOKUPSERVICE, CONST_PERSISTENT|CONST_CS);
1807 #endif
1808 #ifdef ARES_NI_IDN
1809 REGISTER_LONG_CONSTANT("ARES_NI_IDN", ARES_NI_IDN, CONST_PERSISTENT|CONST_CS);
1810 #endif
1811 #ifdef ARES_NI_IDN_ALLOW_UNASSIGNED
1812 REGISTER_LONG_CONSTANT("ARES_NI_IDN_ALLOW_UNASSIGNED", ARES_NI_IDN_ALLOW_UNASSIGNED, CONST_PERSISTENT|CONST_CS);
1813 #endif
1814 #ifdef ARES_NI_IDN_USE_STD
1815 REGISTER_LONG_CONSTANT("ARES_NI_IDN_USE_STD", ARES_NI_IDN_USE_STD, CONST_PERSISTENT|CONST_CS);
1816 #endif
1817
1818 /*
1819 * Address Info constants
1820 */
1821 #ifdef ARES_AI_CANONNAME
1822 REGISTER_LONG_CONSTANT("ARES_AI_CANONNAME", ARES_AI_CANONNAME, CONST_PERSISTENT|CONST_CS);
1823 #endif
1824 #ifdef ARES_AI_NUMERICHOST
1825 REGISTER_LONG_CONSTANT("ARES_AI_NUMERICHOST", ARES_AI_NUMERICHOST, CONST_PERSISTENT|CONST_CS);
1826 #endif
1827 #ifdef ARES_AI_PASSIVE
1828 REGISTER_LONG_CONSTANT("ARES_AI_PASSIVE", ARES_AI_PASSIVE, CONST_PERSISTENT|CONST_CS);
1829 #endif
1830 #ifdef ARES_AI_NUMERICSERV
1831 REGISTER_LONG_CONSTANT("ARES_AI_NUMERICSERV", ARES_AI_NUMERICSERV, CONST_PERSISTENT|CONST_CS);
1832 #endif
1833 #ifdef ARES_AI_V
1834 REGISTER_LONG_CONSTANT("ARES_AI_V", ARES_AI_V, CONST_PERSISTENT|CONST_CS);
1835 #endif
1836 #ifdef ARES_AI_ALL
1837 REGISTER_LONG_CONSTANT("ARES_AI_ALL", ARES_AI_ALL, CONST_PERSISTENT|CONST_CS);
1838 #endif
1839 #ifdef ARES_AI_ADDRCONFIG
1840 REGISTER_LONG_CONSTANT("ARES_AI_ADDRCONFIG", ARES_AI_ADDRCONFIG, CONST_PERSISTENT|CONST_CS);
1841 #endif
1842 #ifdef ARES_AI_IDN
1843 REGISTER_LONG_CONSTANT("ARES_AI_IDN", ARES_AI_IDN, CONST_PERSISTENT|CONST_CS);
1844 #endif
1845 #ifdef ARES_AI_IDN_ALLOW_UNASSIGNED
1846 REGISTER_LONG_CONSTANT("ARES_AI_IDN_ALLOW_UNASSIGNED", ARES_AI_IDN_ALLOW_UNASSIGNED, CONST_PERSISTENT|CONST_CS);
1847 #endif
1848 #ifdef ARES_AI_IDN_USE_STD
1849 REGISTER_LONG_CONSTANT("ARES_AI_IDN_USE_STD", ARES_AI_IDN_USE_STD, CONST_PERSISTENT|CONST_CS);
1850 #endif
1851 #ifdef ARES_AI_CANONIDN
1852 REGISTER_LONG_CONSTANT("ARES_AI_CANONIDN", ARES_AI_CANONIDN, CONST_PERSISTENT|CONST_CS);
1853 #endif
1854 #ifdef ARES_AI_MASK
1855 REGISTER_LONG_CONSTANT("ARES_AI_MASK", ARES_AI_MASK, CONST_PERSISTENT|CONST_CS);
1856 #endif
1857 #ifdef ARES_GETSOCK_MAXNUM
1858 REGISTER_LONG_CONSTANT("ARES_GETSOCK_MAXNUM", ARES_GETSOCK_MAXNUM, CONST_PERSISTENT|CONST_CS);
1859 #endif
1860
1861 /*
1862 * ns_t (type) constants (arpa/nameser.h)
1863 */
1864 #ifdef T_A
1865 /* (1) Host address. */
1866 REGISTER_LONG_CONSTANT("ARES_T_A", T_A, CONST_CS|CONST_PERSISTENT);
1867 #endif
1868 #ifdef T_NS
1869 /* (2) Authoritative server. */
1870 REGISTER_LONG_CONSTANT("ARES_T_NS", T_NS, CONST_CS|CONST_PERSISTENT);
1871 #endif
1872 #ifdef T_MD
1873 /* (3) Mail destination. */
1874 REGISTER_LONG_CONSTANT("ARES_T_MD", T_MD, CONST_CS|CONST_PERSISTENT);
1875 #endif
1876 #ifdef T_MF
1877 /* (4) Mail forwarder. */
1878 REGISTER_LONG_CONSTANT("ARES_T_MF", T_MF, CONST_CS|CONST_PERSISTENT);
1879 #endif
1880 #ifdef T_CNAME
1881 /* (5) Canonical name. */
1882 REGISTER_LONG_CONSTANT("ARES_T_CNAME", T_CNAME, CONST_CS|CONST_PERSISTENT);
1883 #endif
1884 #ifdef T_SOA
1885 /* (6) Start of authority zone. */
1886 REGISTER_LONG_CONSTANT("ARES_T_SOA", T_SOA, CONST_CS|CONST_PERSISTENT);
1887 #endif
1888 #ifdef T_MB
1889 /* (7) Mailbox domain name. */
1890 REGISTER_LONG_CONSTANT("ARES_T_MB", T_MB, CONST_CS|CONST_PERSISTENT);
1891 #endif
1892 #ifdef T_MG
1893 /* (8) Mail group member. */
1894 REGISTER_LONG_CONSTANT("ARES_T_MG", T_MG, CONST_CS|CONST_PERSISTENT);
1895 #endif
1896 #ifdef T_MR
1897 /* (9) Mail rename name. */
1898 REGISTER_LONG_CONSTANT("ARES_T_MR", T_MR, CONST_CS|CONST_PERSISTENT);
1899 #endif
1900 #ifdef T_NULL
1901 /* (10) Null resource record. */
1902 REGISTER_LONG_CONSTANT("ARES_T_NULL", T_NULL, CONST_CS|CONST_PERSISTENT);
1903 #endif
1904 #ifdef T_WKS
1905 /* (11) Well known service. */
1906 REGISTER_LONG_CONSTANT("ARES_T_WKS", T_WKS, CONST_CS|CONST_PERSISTENT);
1907 #endif
1908 #ifdef T_PTR
1909 /* (12) Domain name pointer. */
1910 REGISTER_LONG_CONSTANT("ARES_T_PTR", T_PTR, CONST_CS|CONST_PERSISTENT);
1911 #endif
1912 #ifdef T_HINFO
1913 /* (13) Host information. */
1914 REGISTER_LONG_CONSTANT("ARES_T_HINFO", T_HINFO, CONST_CS|CONST_PERSISTENT);
1915 #endif
1916 #ifdef T_MINFO
1917 /* (14) Mailbox information. */
1918 REGISTER_LONG_CONSTANT("ARES_T_MINFO", T_MINFO, CONST_CS|CONST_PERSISTENT);
1919 #endif
1920 #ifdef T_MX
1921 /* (15) Mail routing information. */
1922 REGISTER_LONG_CONSTANT("ARES_T_MX", T_MX, CONST_CS|CONST_PERSISTENT);
1923 #endif
1924 #ifdef T_TXT
1925 /* (16) Text strings. */
1926 REGISTER_LONG_CONSTANT("ARES_T_TXT", T_TXT, CONST_CS|CONST_PERSISTENT);
1927 #endif
1928 #ifdef T_RP
1929 /* (17) Responsible person. */
1930 REGISTER_LONG_CONSTANT("ARES_T_RP", T_RP, CONST_CS|CONST_PERSISTENT);
1931 #endif
1932 #ifdef T_AFSDB
1933 /* (18) AFS cell database. */
1934 REGISTER_LONG_CONSTANT("ARES_T_AFSDB", T_AFSDB, CONST_CS|CONST_PERSISTENT);
1935 #endif
1936 #ifdef T_X25
1937 /* (19) X_25 calling address. */
1938 REGISTER_LONG_CONSTANT("ARES_T_X25", T_X25, CONST_CS|CONST_PERSISTENT);
1939 #endif
1940 #ifdef T_ISDN
1941 /* (20) ISDN calling address. */
1942 REGISTER_LONG_CONSTANT("ARES_T_ISDN", T_ISDN, CONST_CS|CONST_PERSISTENT);
1943 #endif
1944 #ifdef T_RT
1945 /* (21) Router. */
1946 REGISTER_LONG_CONSTANT("ARES_T_RT", T_RT, CONST_CS|CONST_PERSISTENT);
1947 #endif
1948 #ifdef T_NSAP
1949 /* (22) NSAP address. */
1950 REGISTER_LONG_CONSTANT("ARES_T_NSAP", T_NSAP, CONST_CS|CONST_PERSISTENT);
1951 #endif
1952 #ifdef T_NSAP_PTR
1953 /* (23) Reverse NSAP lookup (deprecated). */
1954 REGISTER_LONG_CONSTANT("ARES_T_NSAP_PTR", T_NSAP_PTR, CONST_CS|CONST_PERSISTENT);
1955 #endif
1956 #ifdef T_SIG
1957 /* (24) Security signature. */
1958 REGISTER_LONG_CONSTANT("ARES_T_SIG", T_SIG, CONST_CS|CONST_PERSISTENT);
1959 #endif
1960 #ifdef T_KEY
1961 /* (25) Security key. */
1962 REGISTER_LONG_CONSTANT("ARES_T_KEY", T_KEY, CONST_CS|CONST_PERSISTENT);
1963 #endif
1964 #ifdef T_PX
1965 /* (26) X.400 mail mapping. */
1966 REGISTER_LONG_CONSTANT("ARES_T_PX", T_PX, CONST_CS|CONST_PERSISTENT);
1967 #endif
1968 #ifdef T_GPOS
1969 /* (27) Geographical position (withdrawn). */
1970 REGISTER_LONG_CONSTANT("ARES_T_GPOS", T_GPOS, CONST_CS|CONST_PERSISTENT);
1971 #endif
1972 #ifdef T_AAAA
1973 /* (28) Ip6 Address. */
1974 REGISTER_LONG_CONSTANT("ARES_T_AAAA", T_AAAA, CONST_CS|CONST_PERSISTENT);
1975 #endif
1976 #ifdef T_LOC
1977 /* (29) Location Information. */
1978 REGISTER_LONG_CONSTANT("ARES_T_LOC", T_LOC, CONST_CS|CONST_PERSISTENT);
1979 #endif
1980 #ifdef T_NXT
1981 /* (30) Next domain (security). */
1982 REGISTER_LONG_CONSTANT("ARES_T_NXT", T_NXT, CONST_CS|CONST_PERSISTENT);
1983 #endif
1984 #ifdef T_EID
1985 /* (31) Endpoint identifier. */
1986 REGISTER_LONG_CONSTANT("ARES_T_EID", T_EID, CONST_CS|CONST_PERSISTENT);
1987 #endif
1988 #ifdef T_NIMLOC
1989 /* (32) Nimrod Locator. */
1990 REGISTER_LONG_CONSTANT("ARES_T_NIMLOC", T_NIMLOC, CONST_CS|CONST_PERSISTENT);
1991 #endif
1992 #ifdef T_SRV
1993 /* (33) Server Selection. */
1994 REGISTER_LONG_CONSTANT("ARES_T_SRV", T_SRV, CONST_CS|CONST_PERSISTENT);
1995 #endif
1996 #ifdef T_ATMA
1997 /* (34) ATM Address */
1998 REGISTER_LONG_CONSTANT("ARES_T_ATMA", T_ATMA, CONST_CS|CONST_PERSISTENT);
1999 #endif
2000 #ifdef T_NAPTR
2001 /* (35) Naming Authority Pointer */
2002 REGISTER_LONG_CONSTANT("ARES_T_NAPTR", T_NAPTR, CONST_CS|CONST_PERSISTENT);
2003 #endif
2004 #ifdef T_KX
2005 /* (36) Key Exchange */
2006 REGISTER_LONG_CONSTANT("ARES_T_KX", T_KX, CONST_CS|CONST_PERSISTENT);
2007 #endif
2008 #ifdef T_CERT
2009 /* (37) Certification record */
2010 REGISTER_LONG_CONSTANT("ARES_T_CERT", T_CERT, CONST_CS|CONST_PERSISTENT);
2011 #endif
2012 #ifdef T_A6
2013 /* (38) IPv6 address (deprecates AAAA) */
2014 REGISTER_LONG_CONSTANT("ARES_T_A6", T_A6, CONST_CS|CONST_PERSISTENT);
2015 #endif
2016 #ifdef T_DNAME
2017 /* (39) Non-terminal DNAME (for IPv6) */
2018 REGISTER_LONG_CONSTANT("ARES_T_DNAME", T_DNAME, CONST_CS|CONST_PERSISTENT);
2019 #endif
2020 #ifdef T_SINK
2021 /* (40) Kitchen sink (experimentatl) */
2022 REGISTER_LONG_CONSTANT("ARES_T_SINK", T_SINK, CONST_CS|CONST_PERSISTENT);
2023 #endif
2024 #ifdef T_OPT
2025 /* (41) EDNS0 option (meta-RR) */
2026 REGISTER_LONG_CONSTANT("ARES_T_OPT", T_OPT, CONST_CS|CONST_PERSISTENT);
2027 #endif
2028 #ifdef T_TSIG
2029 /* (250) Transaction signature. */
2030 REGISTER_LONG_CONSTANT("ARES_T_TSIG", T_TSIG, CONST_CS|CONST_PERSISTENT);
2031 #endif
2032 #ifdef T_IXFR
2033 /* (251) Incremental zone transfer. */
2034 REGISTER_LONG_CONSTANT("ARES_T_IXFR", T_IXFR, CONST_CS|CONST_PERSISTENT);
2035 #endif
2036 #ifdef T_AXFR
2037 /* (252) Transfer zone of authority. */
2038 REGISTER_LONG_CONSTANT("ARES_T_AXFR", T_AXFR, CONST_CS|CONST_PERSISTENT);
2039 #endif
2040 #ifdef T_MAILB
2041 /* (253) Transfer mailbox records. */
2042 REGISTER_LONG_CONSTANT("ARES_T_MAILB", T_MAILB, CONST_CS|CONST_PERSISTENT);
2043 #endif
2044 #ifdef T_MAILA
2045 /* (254) Transfer mail agent records. */
2046 REGISTER_LONG_CONSTANT("ARES_T_MAILA", T_MAILA, CONST_CS|CONST_PERSISTENT);
2047 #endif
2048 #ifdef T_ANY
2049 /* (255) Wildcard match. */
2050 REGISTER_LONG_CONSTANT("ARES_T_ANY", T_ANY, CONST_CS|CONST_PERSISTENT);
2051 #endif
2052
2053 /*
2054 * ns_c (dnsclass) constants (arpa/nameser.h)
2055 */
2056
2057 #ifdef C_IN
2058 /* (1) Internet. */
2059 REGISTER_LONG_CONSTANT("ARES_C_IN", C_IN, CONST_CS|CONST_PERSISTENT);
2060 #endif
2061 #ifdef C_2
2062 /* (2) unallocated/unsupported. */
2063 REGISTER_LONG_CONSTANT("ARES_C_2", C_2, CONST_CS|CONST_PERSISTENT);
2064 #endif
2065 #ifdef C_CHAOS
2066 /* (3) MIT Chaos-net. */
2067 REGISTER_LONG_CONSTANT("ARES_C_CHAOS", C_CHAOS, CONST_CS|CONST_PERSISTENT);
2068 #endif
2069 #ifdef C_HS
2070 /* (4) MIT Hesiod. */
2071 REGISTER_LONG_CONSTANT("ARES_C_HS", C_HS, CONST_CS|CONST_PERSISTENT);
2072 #endif
2073 #ifdef C_NONE
2074 /* (254) for prereq. sections in update requests */
2075 REGISTER_LONG_CONSTANT("ARES_C_NONE", C_NONE, CONST_CS|CONST_PERSISTENT);
2076 #endif
2077 #ifdef C_ANY
2078 /* (255) Wildcard match. */
2079 REGISTER_LONG_CONSTANT("ARES_C_ANY", C_ANY, CONST_CS|CONST_PERSISTENT);
2080 #endif
2081
2082 le_ares = zend_register_list_destructors_ex(php_ares_le_dtor, NULL, PHP_ARES_LE_NAME, module_number);
2083 le_ares_query = zend_register_list_destructors_ex(php_ares_query_le_dtor, NULL, PHP_ARES_QUERY_LE_NAME, module_number);
2084
2085 return SUCCESS;
2086 }
2087 /* }}} */
2088
2089 /* {{{ PHP_MSHUTDOWN_FUNCTION */
2090 static PHP_MSHUTDOWN_FUNCTION(ares)
2091 {
2092 #ifdef HAVE_ARES_LIBRARY_CLEANUP
2093 ares_library_cleanup();
2094 #endif
2095 return SUCCESS;
2096 }
2097 /* }}} */
2098
2099 /* {{{ PHP_MINFO_FUNCTION */
2100 static PHP_MINFO_FUNCTION(ares)
2101 {
2102 php_info_print_table_start();
2103 php_info_print_table_header(2, "AsyncResolver support", "enabled");
2104 php_info_print_table_row(2, "Version", PHP_ARES_VERSION);
2105 php_info_print_table_end();
2106
2107 php_info_print_table_start();
2108 php_info_print_table_header(3, "Used Library", "compiled", "linked");
2109 php_info_print_table_row(3,
2110 PHP_ARES_LIBNAME,
2111 #ifdef ARES_VERSION_STR
2112 ARES_VERSION_STR,
2113 #else
2114 "unkown",
2115 #endif
2116 #ifdef HAVE_ARES_VERSION
2117 ares_version(NULL)
2118 #else
2119 "unkown"
2120 #endif
2121 );
2122 php_info_print_table_end();
2123 }
2124 /* }}} */
2125
2126 #ifdef ZEND_ENGINE_2
2127 ZEND_BEGIN_ARG_INFO(ai_ares_select, 0)
2128 ZEND_ARG_PASS_INFO(1)
2129 ZEND_ARG_PASS_INFO(1)
2130 ZEND_ARG_PASS_INFO(0)
2131 ZEND_END_ARG_INFO();
2132
2133 ZEND_BEGIN_ARG_INFO(ai_ares_result, 0)
2134 ZEND_ARG_PASS_INFO(0)
2135 ZEND_ARG_PASS_INFO(1)
2136 ZEND_ARG_PASS_INFO(1)
2137 ZEND_END_ARG_INFO();
2138
2139 ZEND_BEGIN_ARG_INFO(ai_ares_fds, 0)
2140 ZEND_ARG_PASS_INFO(0)
2141 ZEND_ARG_PASS_INFO(1)
2142 ZEND_ARG_PASS_INFO(1)
2143 ZEND_END_ARG_INFO();
2144 #else
2145 static unsigned char ai_ares_select[] = {3, BYREF_FORCE, BYREF_FORCE, BYREF_NONE};
2146 static unsigned char ai_ares_result[] = {4, BYREF_NONE, BYREF_FORCE, BYREF_FORCE};
2147 static unsigned char ai_ares_fds[] = {4, BYREF_NONE, BYREF_FORCE, BYREF_FORCE};
2148 #endif
2149
2150 /* {{{ ares_functions[] */
2151 zend_function_entry ares_functions[] = {
2152 #ifdef HAVE_ARES_VERSION
2153 PHP_FE(ares_version, NULL)
2154 #endif
2155 PHP_FE(ares_init, NULL)
2156 PHP_FE(ares_destroy, NULL)
2157 PHP_FE(ares_strerror, NULL)
2158 #ifdef HAVE_ARES_CANCEL
2159 PHP_FE(ares_cancel, NULL)
2160 #endif
2161 PHP_FE(ares_search, NULL)
2162 PHP_FE(ares_query, NULL)
2163 PHP_FE(ares_send, NULL)
2164 PHP_FE(ares_mkquery, NULL)
2165 PHP_FE(ares_gethostbyname, NULL)
2166 PHP_FE(ares_gethostbyaddr, NULL)
2167 #ifdef HAVE_ARES_GETNAMEINFO
2168 PHP_FE(ares_getnameinfo, NULL)
2169 #endif
2170 PHP_FE(ares_result, ai_ares_result)
2171 PHP_FE(ares_packet, NULL)
2172 PHP_FE(ares_process_all, NULL)
2173 PHP_FE(ares_process_once, NULL)
2174 PHP_FE(ares_process, NULL)
2175 PHP_FE(ares_select, ai_ares_select)
2176 PHP_FE(ares_fds, ai_ares_fds)
2177 PHP_FE(ares_timeout, NULL)
2178 {NULL, NULL, NULL}
2179 };
2180 /* }}} */
2181
2182 /* {{{ ares_module_entry */
2183 zend_module_entry ares_module_entry = {
2184 STANDARD_MODULE_HEADER,
2185 "ares",
2186 ares_functions,
2187 PHP_MINIT(ares),
2188 PHP_MSHUTDOWN(ares),
2189 NULL,
2190 NULL,
2191 PHP_MINFO(ares),
2192 PHP_ARES_VERSION,
2193 STANDARD_MODULE_PROPERTIES
2194 };
2195 /* }}} */
2196
2197 #ifdef COMPILE_DL_ARES
2198 ZEND_GET_MODULE(ares)
2199 #endif
2200
2201 /*
2202 * Local variables:
2203 * tab-width: 4
2204 * c-basic-offset: 4
2205 * End:
2206 * vim600: noet sw=4 ts=4 fdm=marker
2207 * vim<600: noet sw=4 ts=4
2208 */