1 | /* |
2 | * QEMU DNS resolver |
3 | * |
4 | * Copyright (c) 2016-2017 Red Hat, Inc. |
5 | * |
6 | * This library is free software; you can redistribute it and/or |
7 | * modify it under the terms of the GNU Lesser General Public |
8 | * License as published by the Free Software Foundation; either |
9 | * version 2 of the License, or (at your option) any later version. |
10 | * |
11 | * This library is distributed in the hope that it will be useful, |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
14 | * Lesser General Public License for more details. |
15 | * |
16 | * You should have received a copy of the GNU Lesser General Public |
17 | * License along with this library; if not, see <http://www.gnu.org/licenses/>. |
18 | * |
19 | */ |
20 | |
21 | #ifndef QIO_DNS_RESOLVER_H |
22 | #define QIO_DNS_RESOLVER_H |
23 | |
24 | #include "qapi/qapi-types-sockets.h" |
25 | #include "qom/object.h" |
26 | #include "io/task.h" |
27 | |
28 | #define TYPE_QIO_DNS_RESOLVER "qio-dns-resolver" |
29 | #define QIO_DNS_RESOLVER(obj) \ |
30 | OBJECT_CHECK(QIODNSResolver, (obj), TYPE_QIO_DNS_RESOLVER) |
31 | #define QIO_DNS_RESOLVER_CLASS(klass) \ |
32 | OBJECT_CLASS_CHECK(QIODNSResolverClass, klass, TYPE_QIO_DNS_RESOLVER) |
33 | #define QIO_DNS_RESOLVER_GET_CLASS(obj) \ |
34 | OBJECT_GET_CLASS(QIODNSResolverClass, obj, TYPE_QIO_DNS_RESOLVER) |
35 | |
36 | typedef struct QIODNSResolver QIODNSResolver; |
37 | typedef struct QIODNSResolverClass QIODNSResolverClass; |
38 | |
39 | /** |
40 | * QIODNSResolver: |
41 | * |
42 | * The QIODNSResolver class provides a framework for doing |
43 | * DNS resolution on SocketAddress objects, independently |
44 | * of socket creation. |
45 | * |
46 | * <example> |
47 | * <title>Resolving addresses synchronously</title> |
48 | * <programlisting> |
49 | * int mylisten(SocketAddress *addr, Error **errp) { |
50 | * QIODNSResolver *resolver = qio_dns_resolver_get_instance(); |
51 | * SocketAddress **rawaddrs = NULL; |
52 | * size_t nrawaddrs = 0; |
53 | * Error *err = NULL; |
54 | * QIOChannel **socks = NULL; |
55 | * size_t nsocks = 0; |
56 | * |
57 | * if (qio_dns_resolver_lookup_sync(dns, addr, &nrawaddrs, |
58 | * &rawaddrs, errp) < 0) { |
59 | * return -1; |
60 | * } |
61 | * |
62 | * for (i = 0; i < nrawaddrs; i++) { |
63 | * QIOChannel *sock = qio_channel_new(); |
64 | * Error *local_err = NULL; |
65 | * qio_channel_listen_sync(sock, rawaddrs[i], &local_err); |
66 | * if (local_err) { |
67 | * error_propagate(&err, local_err); |
68 | * } else { |
69 | * socks = g_renew(QIOChannelSocket *, socks, nsocks + 1); |
70 | * socks[nsocks++] = sock; |
71 | * } |
72 | * qapi_free_SocketAddress(rawaddrs[i]); |
73 | * } |
74 | * g_free(rawaddrs); |
75 | * |
76 | * if (nsocks == 0) { |
77 | * error_propagate(errp, err); |
78 | * } else { |
79 | * error_free(err); |
80 | * } |
81 | * } |
82 | * </programlisting> |
83 | * </example> |
84 | * |
85 | * <example> |
86 | * <title>Resolving addresses asynchronously</title> |
87 | * <programlisting> |
88 | * typedef struct MyListenData { |
89 | * Error *err; |
90 | * QIOChannelSocket **socks; |
91 | * size_t nsocks; |
92 | * } MyListenData; |
93 | * |
94 | * void mylistenresult(QIOTask *task, void *opaque) { |
95 | * MyListenData *data = opaque; |
96 | * QIODNSResolver *resolver = |
97 | * QIO_DNS_RESOLVER(qio_task_get_source(task); |
98 | * SocketAddress **rawaddrs = NULL; |
99 | * size_t nrawaddrs = 0; |
100 | * Error *err = NULL; |
101 | * |
102 | * if (qio_task_propagate_error(task, &data->err)) { |
103 | * return; |
104 | * } |
105 | * |
106 | * qio_dns_resolver_lookup_result(resolver, task, |
107 | * &nrawaddrs, &rawaddrs); |
108 | * |
109 | * for (i = 0; i < nrawaddrs; i++) { |
110 | * QIOChannel *sock = qio_channel_new(); |
111 | * Error *local_err = NULL; |
112 | * qio_channel_listen_sync(sock, rawaddrs[i], &local_err); |
113 | * if (local_err) { |
114 | * error_propagate(&err, local_err); |
115 | * } else { |
116 | * socks = g_renew(QIOChannelSocket *, socks, nsocks + 1); |
117 | * socks[nsocks++] = sock; |
118 | * } |
119 | * qapi_free_SocketAddress(rawaddrs[i]); |
120 | * } |
121 | * g_free(rawaddrs); |
122 | * |
123 | * if (nsocks == 0) { |
124 | * error_propagate(&data->err, err); |
125 | * } else { |
126 | * error_free(err); |
127 | * } |
128 | * } |
129 | * |
130 | * void mylisten(SocketAddress *addr, MyListenData *data) { |
131 | * QIODNSResolver *resolver = qio_dns_resolver_get_instance(); |
132 | * qio_dns_resolver_lookup_async(dns, addr, |
133 | * mylistenresult, data, NULL); |
134 | * } |
135 | * </programlisting> |
136 | * </example> |
137 | */ |
138 | struct QIODNSResolver { |
139 | Object parent; |
140 | }; |
141 | |
142 | struct QIODNSResolverClass { |
143 | ObjectClass parent; |
144 | }; |
145 | |
146 | |
147 | /** |
148 | * qio_dns_resolver_get_instance: |
149 | * |
150 | * Get the singleton dns resolver instance. The caller |
151 | * does not own a reference on the returned object. |
152 | * |
153 | * Returns: the single dns resolver instance |
154 | */ |
155 | QIODNSResolver *qio_dns_resolver_get_instance(void); |
156 | |
157 | /** |
158 | * qio_dns_resolver_lookup_sync: |
159 | * @resolver: the DNS resolver instance |
160 | * @addr: the address to resolve |
161 | * @naddr: pointer to hold number of resolved addresses |
162 | * @addrs: pointer to hold resolved addresses |
163 | * @errp: pointer to NULL initialized error object |
164 | * |
165 | * This will attempt to resolve the address provided |
166 | * in @addr. If resolution succeeds, @addrs will be filled |
167 | * with all the resolved addresses. @naddrs will specify |
168 | * the number of entries allocated in @addrs. The caller |
169 | * is responsible for freeing each entry in @addrs, as |
170 | * well as @addrs itself. @naddrs is guaranteed to be |
171 | * greater than zero on success. |
172 | * |
173 | * DNS resolution will be done synchronously so execution |
174 | * of the caller may be blocked for an arbitrary length |
175 | * of time. |
176 | * |
177 | * Returns: 0 if resolution was successful, -1 on error |
178 | */ |
179 | int qio_dns_resolver_lookup_sync(QIODNSResolver *resolver, |
180 | SocketAddress *addr, |
181 | size_t *naddrs, |
182 | SocketAddress ***addrs, |
183 | Error **errp); |
184 | |
185 | /** |
186 | * qio_dns_resolver_lookup_async: |
187 | * @resolver: the DNS resolver instance |
188 | * @addr: the address to resolve |
189 | * @func: the callback to invoke on lookup completion |
190 | * @opaque: data blob to pass to @func |
191 | * @notify: the callback to free @opaque, or NULL |
192 | * |
193 | * This will attempt to resolve the address provided |
194 | * in @addr. The callback @func will be invoked when |
195 | * resolution has either completed or failed. On |
196 | * success, the @func should call the method |
197 | * qio_dns_resolver_lookup_result() to obtain the |
198 | * results. |
199 | * |
200 | * DNS resolution will be done asynchronously so execution |
201 | * of the caller will not be blocked. |
202 | */ |
203 | void qio_dns_resolver_lookup_async(QIODNSResolver *resolver, |
204 | SocketAddress *addr, |
205 | QIOTaskFunc func, |
206 | gpointer opaque, |
207 | GDestroyNotify notify); |
208 | |
209 | /** |
210 | * qio_dns_resolver_lookup_result: |
211 | * @resolver: the DNS resolver instance |
212 | * @task: the task object to get results for |
213 | * @naddr: pointer to hold number of resolved addresses |
214 | * @addrs: pointer to hold resolved addresses |
215 | * |
216 | * This method should be called from the callback passed |
217 | * to qio_dns_resolver_lookup_async() in order to obtain |
218 | * results. @addrs will be filled with all the resolved |
219 | * addresses. @naddrs will specify the number of entries |
220 | * allocated in @addrs. The caller is responsible for |
221 | * freeing each entry in @addrs, as well as @addrs itself. |
222 | */ |
223 | void qio_dns_resolver_lookup_result(QIODNSResolver *resolver, |
224 | QIOTask *task, |
225 | size_t *naddrs, |
226 | SocketAddress ***addrs); |
227 | |
228 | #endif /* QIO_DNS_RESOLVER_H */ |
229 | |