/* * QEMU DNS resolver * * Copyright (c) 2016-2017 Red Hat, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see . * */ #ifndef QIO_DNS_RESOLVER_H #define QIO_DNS_RESOLVER_H #include "qapi/qapi-types-sockets.h" #include "qom/object.h" #include "io/task.h" #define TYPE_QIO_DNS_RESOLVER "qio-dns-resolver" OBJECT_DECLARE_TYPE(QIODNSResolver, QIODNSResolverClass, qio_dns_resolver, QIO_DNS_RESOLVER) /** * QIODNSResolver: * * The QIODNSResolver class provides a framework for doing * DNS resolution on SocketAddress objects, independently * of socket creation. * * * Resolving addresses synchronously * * int mylisten(SocketAddress *addr, Error **errp) { * QIODNSResolver *resolver = qio_dns_resolver_get_instance(); * SocketAddress **rawaddrs = NULL; * size_t nrawaddrs = 0; * Error *err = NULL; * QIOChannel **socks = NULL; * size_t nsocks = 0; * * if (qio_dns_resolver_lookup_sync(dns, addr, &nrawaddrs, * &rawaddrs, errp) < 0) { * return -1; * } * * for (i = 0; i < nrawaddrs; i++) { * QIOChannel *sock = qio_channel_new(); * Error *local_err = NULL; * qio_channel_listen_sync(sock, rawaddrs[i], &local_err); * if (local_err) { * error_propagate(&err, local_err); * } else { * socks = g_renew(QIOChannelSocket *, socks, nsocks + 1); * socks[nsocks++] = sock; * } * qapi_free_SocketAddress(rawaddrs[i]); * } * g_free(rawaddrs); * * if (nsocks == 0) { * error_propagate(errp, err); * } else { * error_free(err); * } * } * * * * * Resolving addresses asynchronously * * typedef struct MyListenData { * Error *err; * QIOChannelSocket **socks; * size_t nsocks; * } MyListenData; * * void mylistenresult(QIOTask *task, void *opaque) { * MyListenData *data = opaque; * QIODNSResolver *resolver = * QIO_DNS_RESOLVER(qio_task_get_source(task); * SocketAddress **rawaddrs = NULL; * size_t nrawaddrs = 0; * Error *err = NULL; * * if (qio_task_propagate_error(task, &data->err)) { * return; * } * * qio_dns_resolver_lookup_result(resolver, task, * &nrawaddrs, &rawaddrs); * * for (i = 0; i < nrawaddrs; i++) { * QIOChannel *sock = qio_channel_new(); * Error *local_err = NULL; * qio_channel_listen_sync(sock, rawaddrs[i], &local_err); * if (local_err) { * error_propagate(&err, local_err); * } else { * socks = g_renew(QIOChannelSocket *, socks, nsocks + 1); * socks[nsocks++] = sock; * } * qapi_free_SocketAddress(rawaddrs[i]); * } * g_free(rawaddrs); * * if (nsocks == 0) { * error_propagate(&data->err, err); * } else { * error_free(err); * } * } * * void mylisten(SocketAddress *addr, MyListenData *data) { * QIODNSResolver *resolver = qio_dns_resolver_get_instance(); * qio_dns_resolver_lookup_async(dns, addr, * mylistenresult, data, NULL); * } * * */ struct QIODNSResolver { Object parent; }; struct QIODNSResolverClass { ObjectClass parent; }; /** * qio_dns_resolver_get_instance: * * Get the singleton dns resolver instance. The caller * does not own a reference on the returned object. * * Returns: the single dns resolver instance */ QIODNSResolver *qio_dns_resolver_get_instance(void); /** * qio_dns_resolver_lookup_sync: * @resolver: the DNS resolver instance * @addr: the address to resolve * @naddr: pointer to hold number of resolved addresses * @addrs: pointer to hold resolved addresses * @errp: pointer to NULL initialized error object * * This will attempt to resolve the address provided * in @addr. If resolution succeeds, @addrs will be filled * with all the resolved addresses. @naddrs will specify * the number of entries allocated in @addrs. The caller * is responsible for freeing each entry in @addrs, as * well as @addrs itself. @naddrs is guaranteed to be * greater than zero on success. * * DNS resolution will be done synchronously so execution * of the caller may be blocked for an arbitrary length * of time. * * Returns: 0 if resolution was successful, -1 on error */ int qio_dns_resolver_lookup_sync(QIODNSResolver *resolver, SocketAddress *addr, size_t *naddrs, SocketAddress ***addrs, Error **errp); /** * qio_dns_resolver_lookup_async: * @resolver: the DNS resolver instance * @addr: the address to resolve * @func: the callback to invoke on lookup completion * @opaque: data blob to pass to @func * @notify: the callback to free @opaque, or NULL * * This will attempt to resolve the address provided * in @addr. The callback @func will be invoked when * resolution has either completed or failed. On * success, the @func should call the method * qio_dns_resolver_lookup_result() to obtain the * results. * * DNS resolution will be done asynchronously so execution * of the caller will not be blocked. */ void qio_dns_resolver_lookup_async(QIODNSResolver *resolver, SocketAddress *addr, QIOTaskFunc func, gpointer opaque, GDestroyNotify notify); /** * qio_dns_resolver_lookup_result: * @resolver: the DNS resolver instance * @task: the task object to get results for * @naddr: pointer to hold number of resolved addresses * @addrs: pointer to hold resolved addresses * * This method should be called from the callback passed * to qio_dns_resolver_lookup_async() in order to obtain * results. @addrs will be filled with all the resolved * addresses. @naddrs will specify the number of entries * allocated in @addrs. The caller is responsible for * freeing each entry in @addrs, as well as @addrs itself. */ void qio_dns_resolver_lookup_result(QIODNSResolver *resolver, QIOTask *task, size_t *naddrs, SocketAddress ***addrs); #endif /* QIO_DNS_RESOLVER_H */