1/*
2 * Copyright (c) 2003 - 2008 Apple, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24#include <stdlib.h>
25#include <string.h>
26#include <stdio.h>
27#include <mach/mach.h>
28#include <pthread.h>
29#include <netdb.h>
30#include <netdb_async.h>
31#include <netinet/in.h>
32#include <arpa/inet.h>
33#include <dns.h>
34#include <dns_util.h>
35#include <stdarg.h>
36#include <si_module.h>
37
38extern void *LI_ils_create(char *fmt, ...);
39
40/*
41 typedef void (*dns_async_callback)(int32_t status, char *buf, uint32_t len, struct sockaddr *from, int fromlen, void *context);
42*/
43
44typedef struct
45{
46	void *orig_callback;
47	void *orig_context;
48	si_mod_t *dns;
49} _dns_context_t;
50
51static void
52_dns_callback(si_item_t *item, uint32_t status, void *ctx)
53{
54	_dns_context_t *my_ctx;
55	si_dnspacket_t *res;
56	char *packet;
57	struct sockaddr *from;
58	uint32_t pl;
59	int fl;
60
61	if (ctx == NULL) return;
62
63	my_ctx = (_dns_context_t *)ctx;
64	if (my_ctx->orig_callback == NULL)
65	{
66		si_item_release(item);
67		si_module_release(my_ctx->dns);
68		free(my_ctx);
69		return;
70	}
71
72	if (status >= SI_STATUS_INTERNAL) status = NO_RECOVERY;
73
74	packet = NULL;
75	pl = 0;
76	from = NULL;
77	fl = 0;
78
79	res = NULL;
80	if (item != NULL) res = (si_dnspacket_t *)((char *)item + sizeof(si_item_t));
81
82	if ((res != NULL) && (res->dns_packet_len > 0))
83	{
84		packet = malloc(res->dns_packet_len);
85		if (packet == NULL) status = NO_RECOVERY;
86		else
87		{
88			pl = res->dns_packet_len;
89			memcpy(packet, res->dns_packet, res->dns_packet_len);
90
91			if (res->dns_server_len > 0)
92			{
93				from = malloc(res->dns_server_len);
94				if (from == NULL)
95				{
96					status = NO_RECOVERY;
97					free(packet);
98					packet = NULL;
99					pl = 0;
100				}
101				else
102				{
103					fl = res->dns_server_len;
104					memcpy(from, res->dns_server, res->dns_server_len);
105				}
106			}
107		}
108	}
109
110	si_item_release(item);
111
112	((dns_async_callback)(my_ctx->orig_callback))(status, packet, pl, from, fl, my_ctx->orig_context);
113
114	si_module_release(my_ctx->dns);
115	free(my_ctx);
116}
117
118int32_t
119dns_async_start(mach_port_t *p, const char *name, uint16_t dnsclass, uint16_t dnstype, uint32_t do_search, dns_async_callback callback, void *context)
120{
121	si_mod_t *dns;
122	int call;
123	uint32_t c, t;
124	_dns_context_t *my_ctx;
125
126	*p = MACH_PORT_NULL;
127
128	if (name == NULL) return NO_RECOVERY;
129
130	dns = si_module_with_name("mdns");
131	if (dns == NULL) return NO_RECOVERY;
132
133	my_ctx = (_dns_context_t *)calloc(1, sizeof(_dns_context_t));
134	if (my_ctx == NULL)
135	{
136		si_module_release(dns);
137		return NO_RECOVERY;
138	}
139
140	my_ctx->orig_callback = callback;
141	my_ctx->orig_context = context;
142	my_ctx->dns = dns;
143
144	call = SI_CALL_DNS_QUERY;
145	if (do_search != 0) call = SI_CALL_DNS_SEARCH;
146
147	c = dnsclass;
148	t = dnstype;
149
150	*p = si_async_call(dns, call, name, NULL, NULL, c, t, 0, 0, (void *)_dns_callback, (void *)my_ctx);
151	if (*p == MACH_PORT_NULL)
152	{
153		free(my_ctx);
154		si_module_release(dns);
155		return NO_RECOVERY;
156	}
157
158	return 0;
159}
160
161void
162dns_async_cancel(mach_port_t p)
163{
164	si_async_cancel(p);
165}
166
167int32_t
168dns_async_send(mach_port_t *p, const char *name, uint16_t dnsclass, uint16_t dnstype, uint32_t do_search)
169{
170	return dns_async_start(p, name, dnsclass, dnstype, do_search, NULL, NULL);
171}
172
173/* unsupported */
174int32_t
175dns_async_receive(mach_port_t p, char **buf, uint32_t *len, struct sockaddr **from, uint32_t *fromlen)
176{
177	return 0;
178}
179
180int32_t
181dns_async_handle_reply(void *msg)
182{
183	si_async_handle_reply(msg);
184	return 0;
185}
186