2017-11-18 17:09:20 +01:00
|
|
|
/* SPDX-License-Identifier: LGPL-2.1+ */
|
2014-01-06 13:41:59 +01:00
|
|
|
|
|
|
|
#include <errno.h>
|
2015-10-24 22:58:24 +02:00
|
|
|
#include <poll.h>
|
|
|
|
#include <pthread.h>
|
2014-01-06 13:41:59 +01:00
|
|
|
#include <resolv.h>
|
2015-10-24 22:58:24 +02:00
|
|
|
#include <signal.h>
|
2014-01-06 13:41:59 +01:00
|
|
|
#include <stdint.h>
|
2015-10-24 22:58:24 +02:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
2014-01-06 13:41:59 +01:00
|
|
|
#include <sys/prctl.h>
|
2015-10-24 22:58:24 +02:00
|
|
|
#include <unistd.h>
|
|
|
|
|
|
|
|
#include "sd-resolve.h"
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2015-10-27 03:01:06 +01:00
|
|
|
#include "alloc-util.h"
|
2017-11-27 14:54:55 +01:00
|
|
|
#include "dns-domain.h"
|
2015-10-25 13:14:12 +01:00
|
|
|
#include "fd-util.h"
|
2015-10-25 14:08:25 +01:00
|
|
|
#include "io-util.h"
|
2014-01-27 20:12:14 +01:00
|
|
|
#include "list.h"
|
2014-04-29 15:44:31 +02:00
|
|
|
#include "missing.h"
|
2015-10-24 22:58:24 +02:00
|
|
|
#include "socket-util.h"
|
|
|
|
#include "util.h"
|
2018-01-11 00:39:12 +01:00
|
|
|
#include "process-util.h"
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2014-04-29 15:44:31 +02:00
|
|
|
#define WORKERS_MIN 1U
|
|
|
|
#define WORKERS_MAX 16U
|
|
|
|
#define QUERIES_MAX 256U
|
|
|
|
#define BUFSIZE 10240U
|
2014-01-06 13:41:59 +01:00
|
|
|
|
|
|
|
typedef enum {
|
|
|
|
REQUEST_ADDRINFO,
|
|
|
|
RESPONSE_ADDRINFO,
|
|
|
|
REQUEST_NAMEINFO,
|
|
|
|
RESPONSE_NAMEINFO,
|
|
|
|
REQUEST_TERMINATE,
|
|
|
|
RESPONSE_DIED
|
2014-01-15 18:21:30 +01:00
|
|
|
} QueryType;
|
2014-01-06 13:41:59 +01:00
|
|
|
|
|
|
|
enum {
|
2014-01-27 20:12:14 +01:00
|
|
|
REQUEST_RECV_FD,
|
|
|
|
REQUEST_SEND_FD,
|
|
|
|
RESPONSE_RECV_FD,
|
|
|
|
RESPONSE_SEND_FD,
|
|
|
|
_FD_MAX
|
2014-01-06 13:41:59 +01:00
|
|
|
};
|
|
|
|
|
2014-01-14 18:18:43 +01:00
|
|
|
struct sd_resolve {
|
2014-04-29 15:44:31 +02:00
|
|
|
unsigned n_ref;
|
|
|
|
|
2014-01-27 20:12:14 +01:00
|
|
|
bool dead:1;
|
|
|
|
pid_t original_pid;
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2014-01-27 20:12:14 +01:00
|
|
|
int fds[_FD_MAX];
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2014-01-27 20:12:14 +01:00
|
|
|
pthread_t workers[WORKERS_MAX];
|
|
|
|
unsigned n_valid_workers;
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2014-08-12 19:29:27 +02:00
|
|
|
unsigned current_id;
|
2014-05-15 16:34:38 +02:00
|
|
|
sd_resolve_query* query_array[QUERIES_MAX];
|
2014-08-12 19:29:38 +02:00
|
|
|
unsigned n_queries, n_done, n_outstanding;
|
2014-04-29 15:44:31 +02:00
|
|
|
|
|
|
|
sd_event_source *event_source;
|
|
|
|
sd_event *event;
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2014-04-29 15:44:31 +02:00
|
|
|
sd_resolve_query *current;
|
|
|
|
|
|
|
|
sd_resolve **default_resolve_ptr;
|
|
|
|
pid_t tid;
|
2014-05-15 16:34:38 +02:00
|
|
|
|
|
|
|
LIST_HEAD(sd_resolve_query, queries);
|
2014-01-06 13:41:59 +01:00
|
|
|
};
|
|
|
|
|
2014-01-14 18:18:43 +01:00
|
|
|
struct sd_resolve_query {
|
2014-04-29 15:44:31 +02:00
|
|
|
unsigned n_ref;
|
|
|
|
|
2014-01-15 18:21:29 +01:00
|
|
|
sd_resolve *resolve;
|
2014-04-29 15:44:31 +02:00
|
|
|
|
|
|
|
QueryType type:4;
|
2014-01-27 20:12:14 +01:00
|
|
|
bool done:1;
|
2014-05-15 16:34:38 +02:00
|
|
|
bool floating:1;
|
2014-01-06 13:41:59 +01:00
|
|
|
unsigned id;
|
2014-01-27 20:12:14 +01:00
|
|
|
|
2014-01-06 13:41:59 +01:00
|
|
|
int ret;
|
|
|
|
int _errno;
|
|
|
|
int _h_errno;
|
|
|
|
struct addrinfo *addrinfo;
|
|
|
|
char *serv, *host;
|
2014-01-27 20:12:14 +01:00
|
|
|
|
2014-04-29 15:44:31 +02:00
|
|
|
union {
|
|
|
|
sd_resolve_getaddrinfo_handler_t getaddrinfo_handler;
|
|
|
|
sd_resolve_getnameinfo_handler_t getnameinfo_handler;
|
|
|
|
};
|
2014-01-27 20:12:14 +01:00
|
|
|
|
2014-04-29 15:44:31 +02:00
|
|
|
void *userdata;
|
2018-11-03 16:56:58 +01:00
|
|
|
sd_resolve_destroy_t destroy_callback;
|
2014-05-15 16:34:38 +02:00
|
|
|
|
|
|
|
LIST_FIELDS(sd_resolve_query, queries);
|
2014-01-06 13:41:59 +01:00
|
|
|
};
|
|
|
|
|
2014-01-15 18:21:30 +01:00
|
|
|
typedef struct RHeader {
|
|
|
|
QueryType type;
|
2014-01-06 13:41:59 +01:00
|
|
|
unsigned id;
|
|
|
|
size_t length;
|
2014-01-15 18:21:30 +01:00
|
|
|
} RHeader;
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2014-01-15 18:21:30 +01:00
|
|
|
typedef struct AddrInfoRequest {
|
|
|
|
struct RHeader header;
|
2014-01-27 20:12:14 +01:00
|
|
|
bool hints_valid;
|
2014-01-06 13:41:59 +01:00
|
|
|
int ai_flags;
|
|
|
|
int ai_family;
|
|
|
|
int ai_socktype;
|
|
|
|
int ai_protocol;
|
|
|
|
size_t node_len, service_len;
|
2014-01-15 18:21:30 +01:00
|
|
|
} AddrInfoRequest;
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2014-01-15 18:21:30 +01:00
|
|
|
typedef struct AddrInfoResponse {
|
|
|
|
struct RHeader header;
|
2014-01-06 13:41:59 +01:00
|
|
|
int ret;
|
|
|
|
int _errno;
|
|
|
|
int _h_errno;
|
|
|
|
/* followed by addrinfo_serialization[] */
|
2014-01-15 18:21:30 +01:00
|
|
|
} AddrInfoResponse;
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2014-01-15 18:21:30 +01:00
|
|
|
typedef struct AddrInfoSerialization {
|
2014-01-06 13:41:59 +01:00
|
|
|
int ai_flags;
|
|
|
|
int ai_family;
|
|
|
|
int ai_socktype;
|
|
|
|
int ai_protocol;
|
|
|
|
size_t ai_addrlen;
|
|
|
|
size_t canonname_len;
|
|
|
|
/* Followed by ai_addr amd ai_canonname with variable lengths */
|
2014-01-15 18:21:30 +01:00
|
|
|
} AddrInfoSerialization;
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2014-01-15 18:21:30 +01:00
|
|
|
typedef struct NameInfoRequest {
|
|
|
|
struct RHeader header;
|
2014-01-06 13:41:59 +01:00
|
|
|
int flags;
|
|
|
|
socklen_t sockaddr_len;
|
2014-01-27 20:12:14 +01:00
|
|
|
bool gethost:1, getserv:1;
|
2014-01-15 18:21:30 +01:00
|
|
|
} NameInfoRequest;
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2014-01-15 18:21:30 +01:00
|
|
|
typedef struct NameInfoResponse {
|
|
|
|
struct RHeader header;
|
2014-01-06 13:41:59 +01:00
|
|
|
size_t hostlen, servlen;
|
|
|
|
int ret;
|
|
|
|
int _errno;
|
|
|
|
int _h_errno;
|
2014-01-15 18:21:30 +01:00
|
|
|
} NameInfoResponse;
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2014-01-15 18:21:30 +01:00
|
|
|
typedef union Packet {
|
|
|
|
RHeader rheader;
|
|
|
|
AddrInfoRequest addrinfo_request;
|
|
|
|
AddrInfoResponse addrinfo_response;
|
|
|
|
NameInfoRequest nameinfo_request;
|
|
|
|
NameInfoResponse nameinfo_response;
|
|
|
|
} Packet;
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2014-04-29 15:44:31 +02:00
|
|
|
static int getaddrinfo_done(sd_resolve_query* q);
|
|
|
|
static int getnameinfo_done(sd_resolve_query *q);
|
|
|
|
|
2014-05-15 16:34:38 +02:00
|
|
|
static void resolve_query_disconnect(sd_resolve_query *q);
|
|
|
|
|
2014-04-29 15:44:31 +02:00
|
|
|
#define RESOLVE_DONT_DESTROY(resolve) \
|
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
|
|
|
_cleanup_(sd_resolve_unrefp) _unused_ sd_resolve *_dont_destroy_##resolve = sd_resolve_ref(resolve)
|
2014-04-29 15:44:31 +02:00
|
|
|
|
2018-05-18 20:35:01 +02:00
|
|
|
static void query_assign_errno(sd_resolve_query *q, int ret, int error, int h_error) {
|
|
|
|
assert(q);
|
|
|
|
|
|
|
|
q->ret = ret;
|
|
|
|
q->_errno = abs(error);
|
|
|
|
q->_h_errno = h_error;
|
|
|
|
}
|
2014-01-27 20:12:14 +01:00
|
|
|
|
2018-05-14 09:50:58 +02:00
|
|
|
static int send_died(int out_fd) {
|
2014-04-29 15:44:31 +02:00
|
|
|
RHeader rh = {
|
|
|
|
.type = RESPONSE_DIED,
|
|
|
|
.length = sizeof(RHeader),
|
|
|
|
};
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2014-04-29 15:44:31 +02:00
|
|
|
assert(out_fd >= 0);
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2014-01-27 20:12:14 +01:00
|
|
|
if (send(out_fd, &rh, rh.length, MSG_NOSIGNAL) < 0)
|
|
|
|
return -errno;
|
|
|
|
|
|
|
|
return 0;
|
2014-01-06 13:41:59 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void *serialize_addrinfo(void *p, const struct addrinfo *ai, size_t *length, size_t maxlength) {
|
2014-01-15 18:21:30 +01:00
|
|
|
AddrInfoSerialization s;
|
2014-01-06 13:41:59 +01:00
|
|
|
size_t cnl, l;
|
2014-01-27 20:12:14 +01:00
|
|
|
|
2014-01-06 13:41:59 +01:00
|
|
|
assert(p);
|
|
|
|
assert(ai);
|
|
|
|
assert(length);
|
|
|
|
assert(*length <= maxlength);
|
|
|
|
|
2014-01-27 20:12:14 +01:00
|
|
|
cnl = ai->ai_canonname ? strlen(ai->ai_canonname)+1 : 0;
|
2014-01-15 18:21:30 +01:00
|
|
|
l = sizeof(AddrInfoSerialization) + ai->ai_addrlen + cnl;
|
2014-01-06 13:41:59 +01:00
|
|
|
|
|
|
|
if (*length + l > maxlength)
|
|
|
|
return NULL;
|
|
|
|
|
2018-07-29 09:01:37 +02:00
|
|
|
s = (AddrInfoSerialization) {
|
|
|
|
.ai_flags = ai->ai_flags,
|
|
|
|
.ai_family = ai->ai_family,
|
|
|
|
.ai_socktype = ai->ai_socktype,
|
|
|
|
.ai_protocol = ai->ai_protocol,
|
|
|
|
.ai_addrlen = ai->ai_addrlen,
|
|
|
|
.canonname_len = cnl,
|
|
|
|
};
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2014-01-15 18:21:30 +01:00
|
|
|
memcpy((uint8_t*) p, &s, sizeof(AddrInfoSerialization));
|
|
|
|
memcpy((uint8_t*) p + sizeof(AddrInfoSerialization), ai->ai_addr, ai->ai_addrlen);
|
2016-02-02 03:57:41 +01:00
|
|
|
memcpy_safe((char*) p + sizeof(AddrInfoSerialization) + ai->ai_addrlen,
|
|
|
|
ai->ai_canonname, cnl);
|
2014-01-06 13:41:59 +01:00
|
|
|
|
|
|
|
*length += l;
|
|
|
|
return (uint8_t*) p + l;
|
|
|
|
}
|
|
|
|
|
2014-01-27 20:12:14 +01:00
|
|
|
static int send_addrinfo_reply(
|
|
|
|
int out_fd,
|
|
|
|
unsigned id,
|
|
|
|
int ret,
|
|
|
|
struct addrinfo *ai,
|
|
|
|
int _errno,
|
|
|
|
int _h_errno) {
|
|
|
|
|
2018-07-29 09:04:56 +02:00
|
|
|
AddrInfoResponse resp = {};
|
2014-01-27 20:12:14 +01:00
|
|
|
union {
|
|
|
|
AddrInfoSerialization ais;
|
|
|
|
uint8_t space[BUFSIZE];
|
|
|
|
} buffer;
|
2018-05-14 15:53:00 +02:00
|
|
|
struct iovec iov[2];
|
|
|
|
struct msghdr mh;
|
2014-01-27 20:12:14 +01:00
|
|
|
|
2014-01-06 13:41:59 +01:00
|
|
|
assert(out_fd >= 0);
|
|
|
|
|
2018-07-29 09:04:56 +02:00
|
|
|
resp = (AddrInfoResponse) {
|
|
|
|
.header.type = RESPONSE_ADDRINFO,
|
|
|
|
.header.id = id,
|
|
|
|
.header.length = sizeof(AddrInfoResponse),
|
|
|
|
.ret = ret,
|
|
|
|
._errno = _errno,
|
|
|
|
._h_errno = _h_errno,
|
|
|
|
};
|
|
|
|
|
2014-01-06 13:41:59 +01:00
|
|
|
if (ret == 0 && ai) {
|
2014-01-27 20:12:14 +01:00
|
|
|
void *p = &buffer;
|
2014-01-06 13:41:59 +01:00
|
|
|
struct addrinfo *k;
|
|
|
|
|
|
|
|
for (k = ai; k; k = k->ai_next) {
|
2014-01-27 20:12:14 +01:00
|
|
|
p = serialize_addrinfo(p, k, &resp.header.length, (uint8_t*) &buffer + BUFSIZE - (uint8_t*) p);
|
2014-01-12 19:42:33 +01:00
|
|
|
if (!p) {
|
2014-01-27 20:12:14 +01:00
|
|
|
freeaddrinfo(ai);
|
|
|
|
return -ENOBUFS;
|
2014-01-06 13:41:59 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ai)
|
|
|
|
freeaddrinfo(ai);
|
|
|
|
|
2018-11-27 10:34:32 +01:00
|
|
|
iov[0] = IOVEC_MAKE(&resp, sizeof(AddrInfoResponse));
|
|
|
|
iov[1] = IOVEC_MAKE(&buffer, resp.header.length - sizeof(AddrInfoResponse));
|
2014-01-27 20:12:14 +01:00
|
|
|
|
2018-11-27 10:34:32 +01:00
|
|
|
mh = (struct msghdr) {
|
|
|
|
.msg_iov = iov,
|
|
|
|
.msg_iovlen = ELEMENTSOF(iov)
|
|
|
|
};
|
2014-01-27 20:12:14 +01:00
|
|
|
|
|
|
|
if (sendmsg(out_fd, &mh, MSG_NOSIGNAL) < 0)
|
|
|
|
return -errno;
|
|
|
|
|
|
|
|
return 0;
|
2014-01-06 13:41:59 +01:00
|
|
|
}
|
|
|
|
|
2014-01-27 20:12:14 +01:00
|
|
|
static int send_nameinfo_reply(
|
|
|
|
int out_fd,
|
|
|
|
unsigned id,
|
|
|
|
int ret,
|
|
|
|
const char *host,
|
|
|
|
const char *serv,
|
|
|
|
int _errno,
|
|
|
|
int _h_errno) {
|
|
|
|
|
2018-07-29 09:04:56 +02:00
|
|
|
NameInfoResponse resp = {};
|
2014-01-27 20:12:14 +01:00
|
|
|
struct iovec iov[3];
|
2018-05-14 15:53:00 +02:00
|
|
|
struct msghdr mh;
|
2014-01-06 13:41:59 +01:00
|
|
|
size_t hl, sl;
|
|
|
|
|
|
|
|
assert(out_fd >= 0);
|
|
|
|
|
|
|
|
sl = serv ? strlen(serv)+1 : 0;
|
|
|
|
hl = host ? strlen(host)+1 : 0;
|
|
|
|
|
2018-07-29 09:01:37 +02:00
|
|
|
resp = (NameInfoResponse) {
|
|
|
|
.header.type = RESPONSE_NAMEINFO,
|
|
|
|
.header.id = id,
|
|
|
|
.header.length = sizeof(NameInfoResponse) + hl + sl,
|
|
|
|
.hostlen = hl,
|
|
|
|
.servlen = sl,
|
|
|
|
.ret = ret,
|
|
|
|
._errno = _errno,
|
|
|
|
._h_errno = _h_errno,
|
|
|
|
};
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2018-11-27 10:34:32 +01:00
|
|
|
iov[0] = IOVEC_MAKE(&resp, sizeof(NameInfoResponse));
|
|
|
|
iov[1] = IOVEC_MAKE((void*) host, hl);
|
|
|
|
iov[2] = IOVEC_MAKE((void*) serv, sl);
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2018-11-27 10:34:32 +01:00
|
|
|
mh = (struct msghdr) {
|
|
|
|
.msg_iov = iov,
|
|
|
|
.msg_iovlen = ELEMENTSOF(iov)
|
|
|
|
};
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2014-01-27 20:12:14 +01:00
|
|
|
if (sendmsg(out_fd, &mh, MSG_NOSIGNAL) < 0)
|
|
|
|
return -errno;
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2014-01-27 20:12:14 +01:00
|
|
|
return 0;
|
2014-01-06 13:41:59 +01:00
|
|
|
}
|
|
|
|
|
2014-01-15 18:21:30 +01:00
|
|
|
static int handle_request(int out_fd, const Packet *packet, size_t length) {
|
|
|
|
const RHeader *req;
|
2014-01-27 20:12:14 +01:00
|
|
|
|
2014-01-06 13:41:59 +01:00
|
|
|
assert(out_fd >= 0);
|
2014-01-27 20:12:14 +01:00
|
|
|
assert(packet);
|
2014-01-06 13:41:59 +01:00
|
|
|
|
|
|
|
req = &packet->rheader;
|
2014-01-27 20:12:14 +01:00
|
|
|
|
2018-05-14 11:08:59 +02:00
|
|
|
assert_return(length >= sizeof(RHeader), -EIO);
|
|
|
|
assert_return(length == req->length, -EIO);
|
2014-01-06 13:41:59 +01:00
|
|
|
|
|
|
|
switch (req->type) {
|
2014-01-27 20:12:14 +01:00
|
|
|
|
2014-01-06 13:41:59 +01:00
|
|
|
case REQUEST_ADDRINFO: {
|
2014-01-15 18:21:30 +01:00
|
|
|
const AddrInfoRequest *ai_req = &packet->addrinfo_request;
|
2018-05-14 15:53:00 +02:00
|
|
|
struct addrinfo hints, *result = NULL;
|
2014-01-06 13:41:59 +01:00
|
|
|
const char *node, *service;
|
|
|
|
int ret;
|
|
|
|
|
2018-05-14 11:08:59 +02:00
|
|
|
assert_return(length >= sizeof(AddrInfoRequest), -EBADMSG);
|
|
|
|
assert_return(length == sizeof(AddrInfoRequest) + ai_req->node_len + ai_req->service_len, -EBADMSG);
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2018-05-14 15:53:00 +02:00
|
|
|
hints = (struct addrinfo) {
|
|
|
|
.ai_flags = ai_req->ai_flags,
|
|
|
|
.ai_family = ai_req->ai_family,
|
|
|
|
.ai_socktype = ai_req->ai_socktype,
|
|
|
|
.ai_protocol = ai_req->ai_protocol,
|
|
|
|
};
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2014-01-15 18:21:30 +01:00
|
|
|
node = ai_req->node_len ? (const char*) ai_req + sizeof(AddrInfoRequest) : NULL;
|
|
|
|
service = ai_req->service_len ? (const char*) ai_req + sizeof(AddrInfoRequest) + ai_req->node_len : NULL;
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2018-05-14 15:52:17 +02:00
|
|
|
ret = getaddrinfo(node, service,
|
|
|
|
ai_req->hints_valid ? &hints : NULL,
|
|
|
|
&result);
|
2014-01-06 13:41:59 +01:00
|
|
|
|
|
|
|
/* send_addrinfo_reply() frees result */
|
|
|
|
return send_addrinfo_reply(out_fd, req->id, ret, result, errno, h_errno);
|
|
|
|
}
|
|
|
|
|
|
|
|
case REQUEST_NAMEINFO: {
|
2014-01-15 18:21:30 +01:00
|
|
|
const NameInfoRequest *ni_req = &packet->nameinfo_request;
|
2014-01-06 13:41:59 +01:00
|
|
|
char hostbuf[NI_MAXHOST], servbuf[NI_MAXSERV];
|
2014-01-27 20:12:14 +01:00
|
|
|
union sockaddr_union sa;
|
|
|
|
int ret;
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2018-05-14 11:08:59 +02:00
|
|
|
assert_return(length >= sizeof(NameInfoRequest), -EBADMSG);
|
|
|
|
assert_return(length == sizeof(NameInfoRequest) + ni_req->sockaddr_len, -EBADMSG);
|
|
|
|
assert_return(ni_req->sockaddr_len <= sizeof(sa), -EBADMSG);
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2014-01-15 18:21:30 +01:00
|
|
|
memcpy(&sa, (const uint8_t *) ni_req + sizeof(NameInfoRequest), ni_req->sockaddr_len);
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2014-01-27 20:12:14 +01:00
|
|
|
ret = getnameinfo(&sa.sa, ni_req->sockaddr_len,
|
2018-05-14 15:52:17 +02:00
|
|
|
ni_req->gethost ? hostbuf : NULL, ni_req->gethost ? sizeof(hostbuf) : 0,
|
|
|
|
ni_req->getserv ? servbuf : NULL, ni_req->getserv ? sizeof(servbuf) : 0,
|
|
|
|
ni_req->flags);
|
2014-01-06 13:41:59 +01:00
|
|
|
|
|
|
|
return send_nameinfo_reply(out_fd, req->id, ret,
|
2018-05-14 15:52:17 +02:00
|
|
|
ret == 0 && ni_req->gethost ? hostbuf : NULL,
|
|
|
|
ret == 0 && ni_req->getserv ? servbuf : NULL,
|
|
|
|
errno, h_errno);
|
2014-01-06 13:41:59 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
case REQUEST_TERMINATE:
|
|
|
|
/* Quit */
|
2014-01-27 20:12:14 +01:00
|
|
|
return -ECONNRESET;
|
2014-01-06 13:41:59 +01:00
|
|
|
|
|
|
|
default:
|
2014-01-27 20:12:14 +01:00
|
|
|
assert_not_reached("Unknown request");
|
2014-01-06 13:41:59 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void* thread_worker(void *p) {
|
2014-01-15 18:21:29 +01:00
|
|
|
sd_resolve *resolve = p;
|
2014-01-27 20:12:14 +01:00
|
|
|
|
|
|
|
/* Assign a pretty name to this thread */
|
2017-12-22 13:31:55 +01:00
|
|
|
(void) pthread_setname_np(pthread_self(), "sd-resolve");
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2014-01-14 18:18:43 +01:00
|
|
|
while (!resolve->dead) {
|
2014-01-27 20:12:14 +01:00
|
|
|
union {
|
|
|
|
Packet packet;
|
|
|
|
uint8_t space[BUFSIZE];
|
|
|
|
} buf;
|
2014-01-06 13:41:59 +01:00
|
|
|
ssize_t length;
|
|
|
|
|
2018-05-14 15:52:17 +02:00
|
|
|
length = recv(resolve->fds[REQUEST_RECV_FD], &buf, sizeof buf, 0);
|
2014-01-27 20:12:14 +01:00
|
|
|
if (length < 0) {
|
|
|
|
if (errno == EINTR)
|
2014-01-06 13:41:59 +01:00
|
|
|
continue;
|
2014-01-27 20:12:14 +01:00
|
|
|
|
2014-01-06 13:41:59 +01:00
|
|
|
break;
|
|
|
|
}
|
2014-01-27 20:12:14 +01:00
|
|
|
if (length == 0)
|
|
|
|
break;
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2014-01-27 20:12:14 +01:00
|
|
|
if (handle_request(resolve->fds[RESPONSE_SEND_FD], &buf.packet, (size_t) length) < 0)
|
2014-01-06 13:41:59 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2014-01-14 18:18:43 +01:00
|
|
|
send_died(resolve->fds[RESPONSE_SEND_FD]);
|
2014-01-06 13:41:59 +01:00
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2014-01-27 20:12:14 +01:00
|
|
|
static int start_threads(sd_resolve *resolve, unsigned extra) {
|
2017-12-29 21:21:54 +01:00
|
|
|
sigset_t ss, saved_ss;
|
2014-01-27 20:12:14 +01:00
|
|
|
unsigned n;
|
2017-12-29 21:21:54 +01:00
|
|
|
int r, k;
|
|
|
|
|
|
|
|
if (sigfillset(&ss) < 0)
|
|
|
|
return -errno;
|
|
|
|
|
|
|
|
/* No signals in forked off threads please. We set the mask before forking, so that the threads never exist
|
|
|
|
* with a different mask than a fully blocked one */
|
|
|
|
r = pthread_sigmask(SIG_BLOCK, &ss, &saved_ss);
|
|
|
|
if (r > 0)
|
|
|
|
return -r;
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2014-08-12 19:29:38 +02:00
|
|
|
n = resolve->n_outstanding + extra;
|
2014-04-29 15:44:31 +02:00
|
|
|
n = CLAMP(n, WORKERS_MIN, WORKERS_MAX);
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2014-01-27 20:12:14 +01:00
|
|
|
while (resolve->n_valid_workers < n) {
|
|
|
|
r = pthread_create(&resolve->workers[resolve->n_valid_workers], NULL, thread_worker, resolve);
|
2017-12-29 21:21:54 +01:00
|
|
|
if (r > 0) {
|
|
|
|
r = -r;
|
|
|
|
goto finish;
|
|
|
|
}
|
2014-01-27 20:12:14 +01:00
|
|
|
|
2016-02-23 05:32:04 +01:00
|
|
|
resolve->n_valid_workers++;
|
2014-01-06 13:41:59 +01:00
|
|
|
}
|
|
|
|
|
2017-12-29 21:21:54 +01:00
|
|
|
r = 0;
|
|
|
|
|
|
|
|
finish:
|
|
|
|
k = pthread_sigmask(SIG_SETMASK, &saved_ss, NULL);
|
|
|
|
if (k > 0 && r >= 0)
|
|
|
|
r = -k;
|
|
|
|
|
|
|
|
return r;
|
2014-01-27 20:12:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static bool resolve_pid_changed(sd_resolve *r) {
|
|
|
|
assert(r);
|
|
|
|
|
|
|
|
/* We don't support people creating a resolver and keeping it
|
|
|
|
* around after fork(). Let's complain. */
|
|
|
|
|
2017-07-20 16:19:18 +02:00
|
|
|
return r->original_pid != getpid_cached();
|
2014-01-27 20:12:14 +01:00
|
|
|
}
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2014-01-27 20:12:14 +01:00
|
|
|
_public_ int sd_resolve_new(sd_resolve **ret) {
|
2018-05-14 15:53:00 +02:00
|
|
|
_cleanup_(sd_resolve_unrefp) sd_resolve *resolve = NULL;
|
|
|
|
int i;
|
2014-01-27 20:12:14 +01:00
|
|
|
|
|
|
|
assert_return(ret, -EINVAL);
|
|
|
|
|
|
|
|
resolve = new0(sd_resolve, 1);
|
|
|
|
if (!resolve)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2014-04-29 15:44:31 +02:00
|
|
|
resolve->n_ref = 1;
|
2017-07-20 16:19:18 +02:00
|
|
|
resolve->original_pid = getpid_cached();
|
2014-04-29 15:44:31 +02:00
|
|
|
|
2014-01-27 20:12:14 +01:00
|
|
|
for (i = 0; i < _FD_MAX; i++)
|
2014-01-14 18:18:43 +01:00
|
|
|
resolve->fds[i] = -1;
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2018-05-14 15:53:00 +02:00
|
|
|
if (socketpair(PF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0, resolve->fds + REQUEST_RECV_FD) < 0)
|
|
|
|
return -errno;
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2018-05-14 15:53:00 +02:00
|
|
|
if (socketpair(PF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0, resolve->fds + RESPONSE_RECV_FD) < 0)
|
|
|
|
return -errno;
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2018-02-09 17:53:28 +01:00
|
|
|
for (i = 0; i < _FD_MAX; i++)
|
|
|
|
resolve->fds[i] = fd_move_above_stdio(resolve->fds[i]);
|
|
|
|
|
|
|
|
(void) fd_inc_sndbuf(resolve->fds[REQUEST_SEND_FD], QUERIES_MAX * BUFSIZE);
|
|
|
|
(void) fd_inc_rcvbuf(resolve->fds[REQUEST_RECV_FD], QUERIES_MAX * BUFSIZE);
|
|
|
|
(void) fd_inc_sndbuf(resolve->fds[RESPONSE_SEND_FD], QUERIES_MAX * BUFSIZE);
|
|
|
|
(void) fd_inc_rcvbuf(resolve->fds[RESPONSE_RECV_FD], QUERIES_MAX * BUFSIZE);
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2018-02-09 17:53:28 +01:00
|
|
|
(void) fd_nonblock(resolve->fds[RESPONSE_RECV_FD], true);
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2018-05-14 15:53:00 +02:00
|
|
|
*ret = TAKE_PTR(resolve);
|
2014-01-27 20:12:14 +01:00
|
|
|
return 0;
|
2014-01-06 13:41:59 +01:00
|
|
|
}
|
|
|
|
|
2014-04-29 15:44:31 +02:00
|
|
|
_public_ int sd_resolve_default(sd_resolve **ret) {
|
|
|
|
static thread_local sd_resolve *default_resolve = NULL;
|
|
|
|
sd_resolve *e = NULL;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
if (!ret)
|
|
|
|
return !!default_resolve;
|
|
|
|
|
|
|
|
if (default_resolve) {
|
|
|
|
*ret = sd_resolve_ref(default_resolve);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_resolve_new(&e);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
e->default_resolve_ptr = &default_resolve;
|
|
|
|
e->tid = gettid();
|
|
|
|
default_resolve = e;
|
|
|
|
|
|
|
|
*ret = e;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
_public_ int sd_resolve_get_tid(sd_resolve *resolve, pid_t *tid) {
|
|
|
|
assert_return(resolve, -EINVAL);
|
|
|
|
assert_return(tid, -EINVAL);
|
|
|
|
assert_return(!resolve_pid_changed(resolve), -ECHILD);
|
|
|
|
|
|
|
|
if (resolve->tid != 0) {
|
|
|
|
*tid = resolve->tid;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (resolve->event)
|
|
|
|
return sd_event_get_tid(resolve->event, tid);
|
|
|
|
|
|
|
|
return -ENXIO;
|
|
|
|
}
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2018-08-27 07:01:46 +02:00
|
|
|
static sd_resolve *resolve_free(sd_resolve *resolve) {
|
2014-04-29 15:44:31 +02:00
|
|
|
PROTECT_ERRNO;
|
2014-05-15 16:34:38 +02:00
|
|
|
sd_resolve_query *q;
|
2014-01-27 20:12:14 +01:00
|
|
|
unsigned i;
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2014-04-29 15:44:31 +02:00
|
|
|
assert(resolve);
|
|
|
|
|
2014-05-15 16:34:38 +02:00
|
|
|
while ((q = resolve->queries)) {
|
|
|
|
assert(q->floating);
|
|
|
|
resolve_query_disconnect(q);
|
|
|
|
sd_resolve_query_unref(q);
|
|
|
|
}
|
|
|
|
|
2014-04-29 15:44:31 +02:00
|
|
|
if (resolve->default_resolve_ptr)
|
|
|
|
*(resolve->default_resolve_ptr) = NULL;
|
2014-01-27 20:12:14 +01:00
|
|
|
|
|
|
|
resolve->dead = true;
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2014-04-29 15:44:31 +02:00
|
|
|
sd_resolve_detach_event(resolve);
|
|
|
|
|
2014-01-14 18:18:43 +01:00
|
|
|
if (resolve->fds[REQUEST_SEND_FD] >= 0) {
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2014-01-27 20:12:14 +01:00
|
|
|
RHeader req = {
|
|
|
|
.type = REQUEST_TERMINATE,
|
2018-05-14 15:52:17 +02:00
|
|
|
.length = sizeof req,
|
2014-01-27 20:12:14 +01:00
|
|
|
};
|
2014-01-06 13:41:59 +01:00
|
|
|
|
|
|
|
/* Send one termination packet for each worker */
|
2014-01-27 20:12:14 +01:00
|
|
|
for (i = 0; i < resolve->n_valid_workers; i++)
|
2015-03-15 22:17:24 +01:00
|
|
|
(void) send(resolve->fds[REQUEST_SEND_FD], &req, req.length, MSG_NOSIGNAL);
|
2014-01-06 13:41:59 +01:00
|
|
|
}
|
|
|
|
|
2016-04-09 03:08:42 +02:00
|
|
|
/* Now terminate them and wait until they are gone.
|
|
|
|
If we get an error than most likely the thread already exited. */
|
2015-11-05 13:44:15 +01:00
|
|
|
for (i = 0; i < resolve->n_valid_workers; i++)
|
2016-04-09 03:08:42 +02:00
|
|
|
(void) pthread_join(resolve->workers[i], NULL);
|
2014-01-06 13:41:59 +01:00
|
|
|
|
|
|
|
/* Close all communication channels */
|
2016-07-02 17:17:26 +02:00
|
|
|
close_many(resolve->fds, _FD_MAX);
|
2014-04-29 15:44:31 +02:00
|
|
|
|
2018-08-27 07:01:46 +02:00
|
|
|
return mfree(resolve);
|
2014-04-29 15:44:31 +02:00
|
|
|
}
|
|
|
|
|
2018-08-27 07:01:46 +02:00
|
|
|
DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_resolve, sd_resolve, resolve_free);
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2014-01-27 20:12:14 +01:00
|
|
|
_public_ int sd_resolve_get_fd(sd_resolve *resolve) {
|
|
|
|
assert_return(resolve, -EINVAL);
|
|
|
|
assert_return(!resolve_pid_changed(resolve), -ECHILD);
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2014-01-14 18:18:43 +01:00
|
|
|
return resolve->fds[RESPONSE_RECV_FD];
|
2014-01-06 13:41:59 +01:00
|
|
|
}
|
|
|
|
|
2014-01-27 20:12:14 +01:00
|
|
|
_public_ int sd_resolve_get_events(sd_resolve *resolve) {
|
|
|
|
assert_return(resolve, -EINVAL);
|
|
|
|
assert_return(!resolve_pid_changed(resolve), -ECHILD);
|
|
|
|
|
|
|
|
return resolve->n_queries > resolve->n_done ? POLLIN : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
_public_ int sd_resolve_get_timeout(sd_resolve *resolve, uint64_t *usec) {
|
|
|
|
assert_return(resolve, -EINVAL);
|
|
|
|
assert_return(usec, -EINVAL);
|
|
|
|
assert_return(!resolve_pid_changed(resolve), -ECHILD);
|
|
|
|
|
|
|
|
*usec = (uint64_t) -1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-01-15 18:21:29 +01:00
|
|
|
static sd_resolve_query *lookup_query(sd_resolve *resolve, unsigned id) {
|
|
|
|
sd_resolve_query *q;
|
2014-01-27 20:12:14 +01:00
|
|
|
|
2014-01-14 18:18:43 +01:00
|
|
|
assert(resolve);
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2014-05-15 16:34:38 +02:00
|
|
|
q = resolve->query_array[id % QUERIES_MAX];
|
2014-01-12 19:42:33 +01:00
|
|
|
if (q)
|
2014-01-06 13:41:59 +01:00
|
|
|
if (q->id == id)
|
|
|
|
return q;
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2014-04-29 15:44:31 +02:00
|
|
|
static int complete_query(sd_resolve *resolve, sd_resolve_query *q) {
|
|
|
|
int r;
|
|
|
|
|
2014-01-06 13:41:59 +01:00
|
|
|
assert(q);
|
|
|
|
assert(!q->done);
|
2014-04-29 15:44:31 +02:00
|
|
|
assert(q->resolve == resolve);
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2014-01-27 20:12:14 +01:00
|
|
|
q->done = true;
|
2016-02-23 05:32:04 +01:00
|
|
|
resolve->n_done++;
|
2014-04-29 15:44:31 +02:00
|
|
|
|
2014-05-05 23:49:19 +02:00
|
|
|
resolve->current = sd_resolve_query_ref(q);
|
2014-04-29 15:44:31 +02:00
|
|
|
|
|
|
|
switch (q->type) {
|
|
|
|
|
|
|
|
case REQUEST_ADDRINFO:
|
|
|
|
r = getaddrinfo_done(q);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case REQUEST_NAMEINFO:
|
|
|
|
r = getnameinfo_done(q);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
assert_not_reached("Cannot complete unknown query type");
|
|
|
|
}
|
|
|
|
|
2014-08-12 19:28:32 +02:00
|
|
|
resolve->current = NULL;
|
2014-04-29 15:44:31 +02:00
|
|
|
|
2014-05-15 16:34:38 +02:00
|
|
|
if (q->floating) {
|
|
|
|
resolve_query_disconnect(q);
|
2014-05-15 17:31:14 +02:00
|
|
|
sd_resolve_query_unref(q);
|
2014-05-15 16:34:38 +02:00
|
|
|
}
|
|
|
|
|
2014-08-12 19:28:32 +02:00
|
|
|
sd_resolve_query_unref(q);
|
|
|
|
|
2014-04-29 15:44:31 +02:00
|
|
|
return r;
|
2014-01-06 13:41:59 +01:00
|
|
|
}
|
|
|
|
|
2014-01-27 20:12:14 +01:00
|
|
|
static int unserialize_addrinfo(const void **p, size_t *length, struct addrinfo **ret_ai) {
|
2014-01-15 18:21:30 +01:00
|
|
|
AddrInfoSerialization s;
|
2014-01-06 13:41:59 +01:00
|
|
|
struct addrinfo *ai;
|
2018-07-29 09:01:37 +02:00
|
|
|
size_t l;
|
2014-01-27 20:12:14 +01:00
|
|
|
|
2014-01-06 13:41:59 +01:00
|
|
|
assert(p);
|
2014-01-27 20:12:14 +01:00
|
|
|
assert(*p);
|
2014-01-06 13:41:59 +01:00
|
|
|
assert(ret_ai);
|
|
|
|
assert(length);
|
|
|
|
|
2014-01-15 18:21:30 +01:00
|
|
|
if (*length < sizeof(AddrInfoSerialization))
|
2014-01-27 20:12:14 +01:00
|
|
|
return -EBADMSG;
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2014-01-27 20:12:14 +01:00
|
|
|
memcpy(&s, *p, sizeof(s));
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2014-01-15 18:21:30 +01:00
|
|
|
l = sizeof(AddrInfoSerialization) + s.ai_addrlen + s.canonname_len;
|
2014-01-06 13:41:59 +01:00
|
|
|
if (*length < l)
|
2014-01-27 20:12:14 +01:00
|
|
|
return -EBADMSG;
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2018-07-29 09:01:37 +02:00
|
|
|
ai = new(struct addrinfo, 1);
|
2014-01-12 19:42:33 +01:00
|
|
|
if (!ai)
|
2014-01-27 20:12:14 +01:00
|
|
|
return -ENOMEM;
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2018-07-29 09:01:37 +02:00
|
|
|
*ai = (struct addrinfo) {
|
|
|
|
.ai_flags = s.ai_flags,
|
|
|
|
.ai_family = s.ai_family,
|
|
|
|
.ai_socktype = s.ai_socktype,
|
|
|
|
.ai_protocol = s.ai_protocol,
|
|
|
|
.ai_addrlen = s.ai_addrlen,
|
|
|
|
};
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2014-01-27 20:12:14 +01:00
|
|
|
if (s.ai_addrlen > 0) {
|
|
|
|
ai->ai_addr = memdup((const uint8_t*) *p + sizeof(AddrInfoSerialization), s.ai_addrlen);
|
|
|
|
if (!ai->ai_addr) {
|
|
|
|
free(ai);
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
}
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2014-01-27 20:12:14 +01:00
|
|
|
if (s.canonname_len > 0) {
|
|
|
|
ai->ai_canonname = memdup((const uint8_t*) *p + sizeof(AddrInfoSerialization) + s.ai_addrlen, s.canonname_len);
|
|
|
|
if (!ai->ai_canonname) {
|
|
|
|
free(ai->ai_addr);
|
|
|
|
free(ai);
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
}
|
2014-01-06 13:41:59 +01:00
|
|
|
|
|
|
|
*length -= l;
|
|
|
|
*ret_ai = ai;
|
2014-01-27 20:12:14 +01:00
|
|
|
*p = ((const uint8_t*) *p) + l;
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2014-01-27 20:12:14 +01:00
|
|
|
return 0;
|
2014-01-06 13:41:59 +01:00
|
|
|
}
|
|
|
|
|
2014-01-15 18:21:30 +01:00
|
|
|
static int handle_response(sd_resolve *resolve, const Packet *packet, size_t length) {
|
|
|
|
const RHeader *resp;
|
2014-01-15 18:21:29 +01:00
|
|
|
sd_resolve_query *q;
|
2014-01-27 20:12:14 +01:00
|
|
|
int r;
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2014-01-14 18:18:43 +01:00
|
|
|
assert(resolve);
|
2018-05-14 11:08:59 +02:00
|
|
|
assert(packet);
|
2014-01-06 13:41:59 +01:00
|
|
|
|
|
|
|
resp = &packet->rheader;
|
2018-05-14 11:08:59 +02:00
|
|
|
assert_return(length >= sizeof(RHeader), -EIO);
|
|
|
|
assert_return(length == resp->length, -EIO);
|
2014-01-06 13:41:59 +01:00
|
|
|
|
|
|
|
if (resp->type == RESPONSE_DIED) {
|
2014-01-27 20:12:14 +01:00
|
|
|
resolve->dead = true;
|
2014-01-06 13:41:59 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-08-12 19:29:38 +02:00
|
|
|
assert(resolve->n_outstanding > 0);
|
|
|
|
resolve->n_outstanding--;
|
|
|
|
|
2014-01-14 18:18:43 +01:00
|
|
|
q = lookup_query(resolve, resp->id);
|
2014-01-12 19:42:33 +01:00
|
|
|
if (!q)
|
2014-01-06 13:41:59 +01:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
switch (resp->type) {
|
2014-01-27 20:12:14 +01:00
|
|
|
|
2014-01-06 13:41:59 +01:00
|
|
|
case RESPONSE_ADDRINFO: {
|
2014-01-15 18:21:30 +01:00
|
|
|
const AddrInfoResponse *ai_resp = &packet->addrinfo_response;
|
2014-01-06 13:41:59 +01:00
|
|
|
const void *p;
|
|
|
|
size_t l;
|
|
|
|
struct addrinfo *prev = NULL;
|
|
|
|
|
2018-05-14 11:08:59 +02:00
|
|
|
assert_return(length >= sizeof(AddrInfoResponse), -EBADMSG);
|
|
|
|
assert_return(q->type == REQUEST_ADDRINFO, -EBADMSG);
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2018-05-18 20:35:01 +02:00
|
|
|
query_assign_errno(q, ai_resp->ret, ai_resp->_errno, ai_resp->_h_errno);
|
2014-01-27 20:12:14 +01:00
|
|
|
|
2014-01-15 18:21:30 +01:00
|
|
|
l = length - sizeof(AddrInfoResponse);
|
|
|
|
p = (const uint8_t*) resp + sizeof(AddrInfoResponse);
|
2014-01-06 13:41:59 +01:00
|
|
|
|
|
|
|
while (l > 0 && p) {
|
|
|
|
struct addrinfo *ai = NULL;
|
|
|
|
|
2014-01-27 20:12:14 +01:00
|
|
|
r = unserialize_addrinfo(&p, &l, &ai);
|
|
|
|
if (r < 0) {
|
2018-05-18 20:35:01 +02:00
|
|
|
query_assign_errno(q, EAI_SYSTEM, r, 0);
|
2014-01-27 20:12:14 +01:00
|
|
|
freeaddrinfo(q->addrinfo);
|
|
|
|
q->addrinfo = NULL;
|
2014-01-06 13:41:59 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (prev)
|
|
|
|
prev->ai_next = ai;
|
|
|
|
else
|
|
|
|
q->addrinfo = ai;
|
|
|
|
|
|
|
|
prev = ai;
|
|
|
|
}
|
|
|
|
|
2014-04-29 15:44:31 +02:00
|
|
|
return complete_query(resolve, q);
|
2014-01-06 13:41:59 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
case RESPONSE_NAMEINFO: {
|
2014-01-15 18:21:30 +01:00
|
|
|
const NameInfoResponse *ni_resp = &packet->nameinfo_response;
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2018-05-14 11:08:59 +02:00
|
|
|
assert_return(length >= sizeof(NameInfoResponse), -EBADMSG);
|
|
|
|
assert_return(q->type == REQUEST_NAMEINFO, -EBADMSG);
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2017-11-27 14:54:55 +01:00
|
|
|
if (ni_resp->hostlen > DNS_HOSTNAME_MAX ||
|
|
|
|
ni_resp->servlen > DNS_HOSTNAME_MAX ||
|
2018-05-14 16:59:20 +02:00
|
|
|
sizeof(NameInfoResponse) + ni_resp->hostlen + ni_resp->servlen > length)
|
2018-05-18 20:35:01 +02:00
|
|
|
query_assign_errno(q, EAI_SYSTEM, EIO, 0);
|
2018-05-14 09:50:58 +02:00
|
|
|
else {
|
2018-05-18 20:35:01 +02:00
|
|
|
query_assign_errno(q, ni_resp->ret, ni_resp->_errno, ni_resp->_h_errno);
|
2017-11-27 14:54:55 +01:00
|
|
|
|
|
|
|
if (ni_resp->hostlen > 0) {
|
|
|
|
q->host = strndup((const char*) ni_resp + sizeof(NameInfoResponse),
|
|
|
|
ni_resp->hostlen-1);
|
2018-05-14 09:50:58 +02:00
|
|
|
if (!q->host)
|
2018-05-18 20:35:01 +02:00
|
|
|
query_assign_errno(q, EAI_MEMORY, ENOMEM, 0);
|
2014-01-27 20:12:14 +01:00
|
|
|
}
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2017-11-27 14:54:55 +01:00
|
|
|
if (ni_resp->servlen > 0) {
|
|
|
|
q->serv = strndup((const char*) ni_resp + sizeof(NameInfoResponse) + ni_resp->hostlen,
|
|
|
|
ni_resp->servlen-1);
|
2018-05-14 09:50:58 +02:00
|
|
|
if (!q->serv)
|
2018-05-18 20:35:01 +02:00
|
|
|
query_assign_errno(q, EAI_MEMORY, ENOMEM, 0);
|
2014-01-27 20:12:14 +01:00
|
|
|
}
|
|
|
|
}
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2014-04-29 15:44:31 +02:00
|
|
|
return complete_query(resolve, q);
|
2014-01-06 13:41:59 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
2014-04-29 15:44:31 +02:00
|
|
|
return 0;
|
2014-01-06 13:41:59 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-01-27 20:12:14 +01:00
|
|
|
_public_ int sd_resolve_process(sd_resolve *resolve) {
|
2014-04-29 15:44:31 +02:00
|
|
|
RESOLVE_DONT_DESTROY(resolve);
|
|
|
|
|
|
|
|
union {
|
|
|
|
Packet packet;
|
|
|
|
uint8_t space[BUFSIZE];
|
|
|
|
} buf;
|
|
|
|
ssize_t l;
|
|
|
|
int r;
|
2014-01-27 20:12:14 +01:00
|
|
|
|
|
|
|
assert_return(resolve, -EINVAL);
|
|
|
|
assert_return(!resolve_pid_changed(resolve), -ECHILD);
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2014-04-29 15:44:31 +02:00
|
|
|
/* We don't allow recursively invoking sd_resolve_process(). */
|
|
|
|
assert_return(!resolve->current, -EBUSY);
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2018-05-14 15:52:17 +02:00
|
|
|
l = recv(resolve->fds[RESPONSE_RECV_FD], &buf, sizeof buf, 0);
|
2014-04-29 15:44:31 +02:00
|
|
|
if (l < 0) {
|
|
|
|
if (errno == EAGAIN)
|
|
|
|
return 0;
|
2014-01-27 20:12:14 +01:00
|
|
|
|
2014-04-29 15:44:31 +02:00
|
|
|
return -errno;
|
|
|
|
}
|
|
|
|
if (l == 0)
|
|
|
|
return -ECONNREFUSED;
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2014-04-29 15:44:31 +02:00
|
|
|
r = handle_response(resolve, &buf.packet, (size_t) l);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2014-04-29 15:44:31 +02:00
|
|
|
return 1;
|
2014-01-27 20:12:14 +01:00
|
|
|
}
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2014-01-27 20:12:14 +01:00
|
|
|
_public_ int sd_resolve_wait(sd_resolve *resolve, uint64_t timeout_usec) {
|
|
|
|
int r;
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2014-01-27 20:12:14 +01:00
|
|
|
assert_return(resolve, -EINVAL);
|
|
|
|
assert_return(!resolve_pid_changed(resolve), -ECHILD);
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2014-04-29 15:44:31 +02:00
|
|
|
if (resolve->n_done >= resolve->n_queries)
|
2014-01-27 20:12:14 +01:00
|
|
|
return 0;
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2014-01-27 20:12:14 +01:00
|
|
|
do {
|
|
|
|
r = fd_wait_for_event(resolve->fds[RESPONSE_RECV_FD], POLLIN, timeout_usec);
|
|
|
|
} while (r == -EINTR);
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2014-01-27 20:12:14 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2017-11-27 16:28:53 +01:00
|
|
|
if (r == 0)
|
|
|
|
return -ETIMEDOUT;
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2014-01-27 20:12:14 +01:00
|
|
|
return sd_resolve_process(resolve);
|
2014-01-06 13:41:59 +01:00
|
|
|
}
|
|
|
|
|
2014-05-15 16:34:38 +02:00
|
|
|
static int alloc_query(sd_resolve *resolve, bool floating, sd_resolve_query **_q) {
|
2014-01-15 18:21:29 +01:00
|
|
|
sd_resolve_query *q;
|
2014-01-27 20:12:14 +01:00
|
|
|
int r;
|
|
|
|
|
2014-01-14 18:18:43 +01:00
|
|
|
assert(resolve);
|
2014-01-27 20:12:14 +01:00
|
|
|
assert(_q);
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2014-01-27 20:12:14 +01:00
|
|
|
if (resolve->n_queries >= QUERIES_MAX)
|
|
|
|
return -ENOBUFS;
|
|
|
|
|
|
|
|
r = start_threads(resolve, 1);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2014-08-12 19:29:27 +02:00
|
|
|
while (resolve->query_array[resolve->current_id % QUERIES_MAX])
|
2014-01-14 18:18:43 +01:00
|
|
|
resolve->current_id++;
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2014-08-12 19:29:27 +02:00
|
|
|
q = resolve->query_array[resolve->current_id % QUERIES_MAX] = new0(sd_resolve_query, 1);
|
2014-01-27 20:12:14 +01:00
|
|
|
if (!q)
|
|
|
|
return -ENOMEM;
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2014-04-29 15:44:31 +02:00
|
|
|
q->n_ref = 1;
|
2014-05-15 16:34:38 +02:00
|
|
|
q->resolve = resolve;
|
|
|
|
q->floating = floating;
|
2014-08-12 19:29:27 +02:00
|
|
|
q->id = resolve->current_id++;
|
2014-01-27 20:12:14 +01:00
|
|
|
|
2014-05-15 16:34:38 +02:00
|
|
|
if (!floating)
|
|
|
|
sd_resolve_ref(resolve);
|
|
|
|
|
|
|
|
LIST_PREPEND(queries, resolve->queries, q);
|
2014-04-29 15:44:31 +02:00
|
|
|
resolve->n_queries++;
|
|
|
|
|
2014-01-27 20:12:14 +01:00
|
|
|
*_q = q;
|
|
|
|
return 0;
|
2014-01-06 13:41:59 +01:00
|
|
|
}
|
|
|
|
|
2014-01-27 20:12:14 +01:00
|
|
|
_public_ int sd_resolve_getaddrinfo(
|
|
|
|
sd_resolve *resolve,
|
2014-02-19 23:54:58 +01:00
|
|
|
sd_resolve_query **_q,
|
2014-04-29 15:44:31 +02:00
|
|
|
const char *node, const char *service,
|
|
|
|
const struct addrinfo *hints,
|
|
|
|
sd_resolve_getaddrinfo_handler_t callback, void *userdata) {
|
2014-01-27 20:12:14 +01:00
|
|
|
|
2018-05-14 15:53:00 +02:00
|
|
|
_cleanup_(sd_resolve_query_unrefp) sd_resolve_query *q = NULL;
|
2018-07-29 09:04:56 +02:00
|
|
|
AddrInfoRequest req = {};
|
2014-01-27 20:12:14 +01:00
|
|
|
struct iovec iov[3];
|
2018-05-14 15:53:00 +02:00
|
|
|
struct msghdr mh = {};
|
2014-01-27 20:12:14 +01:00
|
|
|
int r;
|
2018-05-14 15:53:00 +02:00
|
|
|
size_t node_len, service_len;
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2014-01-27 20:12:14 +01:00
|
|
|
assert_return(resolve, -EINVAL);
|
2014-04-29 15:44:31 +02:00
|
|
|
assert_return(node || service, -EINVAL);
|
|
|
|
assert_return(callback, -EINVAL);
|
2014-01-27 20:12:14 +01:00
|
|
|
assert_return(!resolve_pid_changed(resolve), -ECHILD);
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2014-05-15 16:34:38 +02:00
|
|
|
r = alloc_query(resolve, !_q, &q);
|
2014-01-27 20:12:14 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2014-04-29 15:44:31 +02:00
|
|
|
q->type = REQUEST_ADDRINFO;
|
|
|
|
q->getaddrinfo_handler = callback;
|
|
|
|
q->userdata = userdata;
|
|
|
|
|
2018-05-14 15:53:00 +02:00
|
|
|
node_len = node ? strlen(node) + 1 : 0;
|
|
|
|
service_len = service ? strlen(service) + 1 : 0;
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2018-05-14 15:53:00 +02:00
|
|
|
req = (AddrInfoRequest) {
|
|
|
|
.node_len = node_len,
|
|
|
|
.service_len = service_len,
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2018-05-14 15:53:00 +02:00
|
|
|
.header.id = q->id,
|
|
|
|
.header.type = REQUEST_ADDRINFO,
|
|
|
|
.header.length = sizeof(AddrInfoRequest) + node_len + service_len,
|
|
|
|
|
|
|
|
.hints_valid = hints,
|
|
|
|
.ai_flags = hints ? hints->ai_flags : 0,
|
|
|
|
.ai_family = hints ? hints->ai_family : 0,
|
|
|
|
.ai_socktype = hints ? hints->ai_socktype : 0,
|
|
|
|
.ai_protocol = hints ? hints->ai_protocol : 0,
|
|
|
|
};
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2018-11-27 10:34:32 +01:00
|
|
|
iov[mh.msg_iovlen++] = IOVEC_MAKE(&req, sizeof(AddrInfoRequest));
|
2014-01-06 13:41:59 +01:00
|
|
|
if (node)
|
2018-11-27 10:34:32 +01:00
|
|
|
iov[mh.msg_iovlen++] = IOVEC_MAKE((void*) node, req.node_len);
|
2014-01-06 13:41:59 +01:00
|
|
|
if (service)
|
2018-11-27 10:34:32 +01:00
|
|
|
iov[mh.msg_iovlen++] = IOVEC_MAKE((void*) service, req.service_len);
|
2014-01-27 20:12:14 +01:00
|
|
|
mh.msg_iov = iov;
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2018-05-14 15:53:00 +02:00
|
|
|
if (sendmsg(resolve->fds[REQUEST_SEND_FD], &mh, MSG_NOSIGNAL) < 0)
|
2014-01-27 20:12:14 +01:00
|
|
|
return -errno;
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2014-08-12 19:29:38 +02:00
|
|
|
resolve->n_outstanding++;
|
|
|
|
|
2014-05-15 16:34:38 +02:00
|
|
|
if (_q)
|
|
|
|
*_q = q;
|
2018-05-14 15:53:00 +02:00
|
|
|
TAKE_PTR(q);
|
2014-05-15 16:34:38 +02:00
|
|
|
|
2014-01-27 20:12:14 +01:00
|
|
|
return 0;
|
2014-01-06 13:41:59 +01:00
|
|
|
}
|
|
|
|
|
2014-04-29 15:44:31 +02:00
|
|
|
static int getaddrinfo_done(sd_resolve_query* q) {
|
|
|
|
assert(q);
|
|
|
|
assert(q->done);
|
|
|
|
assert(q->getaddrinfo_handler);
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2014-04-29 15:44:31 +02:00
|
|
|
errno = q->_errno;
|
|
|
|
h_errno = q->_h_errno;
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2014-04-29 15:44:31 +02:00
|
|
|
return q->getaddrinfo_handler(q, q->ret, q->addrinfo, q->userdata);
|
2014-01-06 13:41:59 +01:00
|
|
|
}
|
|
|
|
|
2014-01-27 20:12:14 +01:00
|
|
|
_public_ int sd_resolve_getnameinfo(
|
|
|
|
sd_resolve *resolve,
|
2014-02-19 23:54:58 +01:00
|
|
|
sd_resolve_query**_q,
|
2014-01-27 20:12:14 +01:00
|
|
|
const struct sockaddr *sa, socklen_t salen,
|
|
|
|
int flags,
|
2014-04-29 15:44:31 +02:00
|
|
|
uint64_t get,
|
|
|
|
sd_resolve_getnameinfo_handler_t callback,
|
|
|
|
void *userdata) {
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2018-05-14 15:53:00 +02:00
|
|
|
_cleanup_(sd_resolve_query_unrefp) sd_resolve_query *q = NULL;
|
2018-07-29 09:04:56 +02:00
|
|
|
NameInfoRequest req = {};
|
2014-01-27 20:12:14 +01:00
|
|
|
struct iovec iov[2];
|
2018-05-14 15:53:00 +02:00
|
|
|
struct msghdr mh;
|
2014-01-27 20:12:14 +01:00
|
|
|
int r;
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2014-01-27 20:12:14 +01:00
|
|
|
assert_return(resolve, -EINVAL);
|
|
|
|
assert_return(sa, -EINVAL);
|
|
|
|
assert_return(salen >= sizeof(struct sockaddr), -EINVAL);
|
|
|
|
assert_return(salen <= sizeof(union sockaddr_union), -EINVAL);
|
2014-04-29 15:44:31 +02:00
|
|
|
assert_return((get & ~SD_RESOLVE_GET_BOTH) == 0, -EINVAL);
|
|
|
|
assert_return(callback, -EINVAL);
|
2014-01-27 20:12:14 +01:00
|
|
|
assert_return(!resolve_pid_changed(resolve), -ECHILD);
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2014-05-15 16:34:38 +02:00
|
|
|
r = alloc_query(resolve, !_q, &q);
|
2014-01-27 20:12:14 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2014-04-29 15:44:31 +02:00
|
|
|
q->type = REQUEST_NAMEINFO;
|
|
|
|
q->getnameinfo_handler = callback;
|
|
|
|
q->userdata = userdata;
|
|
|
|
|
2018-05-14 15:53:00 +02:00
|
|
|
req = (NameInfoRequest) {
|
|
|
|
.header.id = q->id,
|
|
|
|
.header.type = REQUEST_NAMEINFO,
|
|
|
|
.header.length = sizeof(NameInfoRequest) + salen,
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2018-05-14 15:53:00 +02:00
|
|
|
.flags = flags,
|
|
|
|
.sockaddr_len = salen,
|
|
|
|
.gethost = !!(get & SD_RESOLVE_GET_HOST),
|
|
|
|
.getserv = !!(get & SD_RESOLVE_GET_SERVICE),
|
|
|
|
};
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2018-11-27 10:34:32 +01:00
|
|
|
iov[0] = IOVEC_MAKE(&req, sizeof(NameInfoRequest));
|
|
|
|
iov[1] = IOVEC_MAKE((void*) sa, salen);
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2018-11-27 10:34:32 +01:00
|
|
|
mh = (struct msghdr) {
|
|
|
|
.msg_iov = iov,
|
|
|
|
.msg_iovlen = ELEMENTSOF(iov)
|
|
|
|
};
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2018-05-14 15:53:00 +02:00
|
|
|
if (sendmsg(resolve->fds[REQUEST_SEND_FD], &mh, MSG_NOSIGNAL) < 0)
|
2014-01-27 20:12:14 +01:00
|
|
|
return -errno;
|
2014-08-12 19:29:38 +02:00
|
|
|
|
2014-05-15 16:34:38 +02:00
|
|
|
if (_q)
|
|
|
|
*_q = q;
|
|
|
|
|
2018-05-14 15:53:00 +02:00
|
|
|
resolve->n_outstanding++;
|
|
|
|
TAKE_PTR(q);
|
|
|
|
|
2014-01-27 20:12:14 +01:00
|
|
|
return 0;
|
2014-01-06 13:41:59 +01:00
|
|
|
}
|
|
|
|
|
2014-04-29 15:44:31 +02:00
|
|
|
static int getnameinfo_done(sd_resolve_query *q) {
|
2014-01-27 20:12:14 +01:00
|
|
|
|
2014-04-29 15:44:31 +02:00
|
|
|
assert(q);
|
|
|
|
assert(q->done);
|
|
|
|
assert(q->getnameinfo_handler);
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2014-04-29 15:44:31 +02:00
|
|
|
errno = q->_errno;
|
2018-05-14 09:50:58 +02:00
|
|
|
h_errno = q->_h_errno;
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2014-04-29 15:44:31 +02:00
|
|
|
return q->getnameinfo_handler(q, q->ret, q->host, q->serv, q->userdata);
|
2014-01-06 13:41:59 +01:00
|
|
|
}
|
|
|
|
|
2014-04-29 15:44:31 +02:00
|
|
|
static void resolve_freeaddrinfo(struct addrinfo *ai) {
|
|
|
|
while (ai) {
|
|
|
|
struct addrinfo *next = ai->ai_next;
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2014-04-29 15:44:31 +02:00
|
|
|
free(ai->ai_addr);
|
|
|
|
free(ai->ai_canonname);
|
|
|
|
free(ai);
|
|
|
|
ai = next;
|
|
|
|
}
|
|
|
|
}
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2014-05-15 16:34:38 +02:00
|
|
|
static void resolve_query_disconnect(sd_resolve_query *q) {
|
|
|
|
sd_resolve *resolve;
|
2014-04-29 15:44:31 +02:00
|
|
|
unsigned i;
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2014-04-29 15:44:31 +02:00
|
|
|
assert(q);
|
2014-05-15 16:34:38 +02:00
|
|
|
|
|
|
|
if (!q->resolve)
|
|
|
|
return;
|
|
|
|
|
|
|
|
resolve = q->resolve;
|
|
|
|
assert(resolve->n_queries > 0);
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2014-01-27 20:12:14 +01:00
|
|
|
if (q->done) {
|
2014-05-15 16:34:38 +02:00
|
|
|
assert(resolve->n_done > 0);
|
|
|
|
resolve->n_done--;
|
2014-01-06 13:41:59 +01:00
|
|
|
}
|
|
|
|
|
2014-01-27 20:12:14 +01:00
|
|
|
i = q->id % QUERIES_MAX;
|
2014-05-15 16:34:38 +02:00
|
|
|
assert(resolve->query_array[i] == q);
|
|
|
|
resolve->query_array[i] = NULL;
|
|
|
|
LIST_REMOVE(queries, resolve->queries, q);
|
|
|
|
resolve->n_queries--;
|
|
|
|
|
|
|
|
q->resolve = NULL;
|
|
|
|
if (!q->floating)
|
|
|
|
sd_resolve_unref(resolve);
|
|
|
|
}
|
|
|
|
|
2018-08-27 07:01:46 +02:00
|
|
|
static sd_resolve_query *resolve_query_free(sd_resolve_query *q) {
|
2014-05-15 16:34:38 +02:00
|
|
|
assert(q);
|
|
|
|
|
|
|
|
resolve_query_disconnect(q);
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2018-11-03 16:56:58 +01:00
|
|
|
if (q->destroy_callback)
|
|
|
|
q->destroy_callback(q->userdata);
|
|
|
|
|
2014-04-29 15:44:31 +02:00
|
|
|
resolve_freeaddrinfo(q->addrinfo);
|
2014-01-06 13:41:59 +01:00
|
|
|
free(q->host);
|
|
|
|
free(q->serv);
|
|
|
|
|
2018-08-27 07:01:46 +02:00
|
|
|
return mfree(q);
|
2014-01-06 13:41:59 +01:00
|
|
|
}
|
|
|
|
|
2018-08-27 07:01:46 +02:00
|
|
|
DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_resolve_query, sd_resolve_query, resolve_query_free);
|
|
|
|
|
2014-04-29 15:44:31 +02:00
|
|
|
_public_ int sd_resolve_query_is_done(sd_resolve_query *q) {
|
2014-01-27 20:12:14 +01:00
|
|
|
assert_return(q, -EINVAL);
|
|
|
|
assert_return(!resolve_pid_changed(q->resolve), -ECHILD);
|
2014-01-06 13:41:59 +01:00
|
|
|
|
|
|
|
return q->done;
|
|
|
|
}
|
|
|
|
|
2014-04-29 15:44:31 +02:00
|
|
|
_public_ void* sd_resolve_query_set_userdata(sd_resolve_query *q, void *userdata) {
|
2014-01-27 20:12:14 +01:00
|
|
|
void *ret;
|
2014-01-06 13:41:59 +01:00
|
|
|
|
2014-01-27 20:12:14 +01:00
|
|
|
assert_return(q, NULL);
|
|
|
|
assert_return(!resolve_pid_changed(q->resolve), NULL);
|
|
|
|
|
|
|
|
ret = q->userdata;
|
2014-01-06 13:41:59 +01:00
|
|
|
q->userdata = userdata;
|
2014-01-27 20:12:14 +01:00
|
|
|
|
|
|
|
return ret;
|
2014-01-06 13:41:59 +01:00
|
|
|
}
|
|
|
|
|
2014-04-29 15:44:31 +02:00
|
|
|
_public_ void* sd_resolve_query_get_userdata(sd_resolve_query *q) {
|
2014-01-27 20:12:14 +01:00
|
|
|
assert_return(q, NULL);
|
|
|
|
assert_return(!resolve_pid_changed(q->resolve), NULL);
|
2014-01-06 13:41:59 +01:00
|
|
|
|
|
|
|
return q->userdata;
|
|
|
|
}
|
2014-04-29 15:44:31 +02:00
|
|
|
|
|
|
|
_public_ sd_resolve *sd_resolve_query_get_resolve(sd_resolve_query *q) {
|
|
|
|
assert_return(q, NULL);
|
|
|
|
assert_return(!resolve_pid_changed(q->resolve), NULL);
|
|
|
|
|
|
|
|
return q->resolve;
|
|
|
|
}
|
|
|
|
|
2018-11-03 16:56:58 +01:00
|
|
|
_public_ int sd_resolve_query_get_destroy_callback(sd_resolve_query *q, sd_resolve_destroy_t *destroy_callback) {
|
|
|
|
assert_return(q, -EINVAL);
|
|
|
|
|
|
|
|
if (destroy_callback)
|
|
|
|
*destroy_callback = q->destroy_callback;
|
|
|
|
|
|
|
|
return !!q->destroy_callback;
|
|
|
|
}
|
|
|
|
|
|
|
|
_public_ int sd_resolve_query_set_destroy_callback(sd_resolve_query *q, sd_resolve_destroy_t destroy_callback) {
|
|
|
|
assert_return(q, -EINVAL);
|
|
|
|
|
|
|
|
q->destroy_callback = destroy_callback;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-11-03 17:05:16 +01:00
|
|
|
_public_ int sd_resolve_query_get_floating(sd_resolve_query *q) {
|
|
|
|
assert_return(q, -EINVAL);
|
|
|
|
|
|
|
|
return q->floating;
|
|
|
|
}
|
|
|
|
|
|
|
|
_public_ int sd_resolve_query_set_floating(sd_resolve_query *q, int b) {
|
|
|
|
assert_return(q, -EINVAL);
|
|
|
|
|
|
|
|
if (q->floating == !!b)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (!q->resolve) /* Already disconnected */
|
|
|
|
return -ESTALE;
|
|
|
|
|
|
|
|
q->floating = b;
|
|
|
|
|
|
|
|
if (b) {
|
|
|
|
sd_resolve_query_ref(q);
|
|
|
|
sd_resolve_unref(q->resolve);
|
|
|
|
} else {
|
|
|
|
sd_resolve_ref(q->resolve);
|
|
|
|
sd_resolve_query_unref(q);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2014-04-29 15:44:31 +02:00
|
|
|
static int io_callback(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
|
|
|
|
sd_resolve *resolve = userdata;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(resolve);
|
|
|
|
|
|
|
|
r = sd_resolve_process(resolve);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2016-02-16 19:33:36 +01:00
|
|
|
_public_ int sd_resolve_attach_event(sd_resolve *resolve, sd_event *event, int64_t priority) {
|
2014-04-29 15:44:31 +02:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert_return(resolve, -EINVAL);
|
|
|
|
assert_return(!resolve->event, -EBUSY);
|
|
|
|
|
|
|
|
assert(!resolve->event_source);
|
|
|
|
|
|
|
|
if (event)
|
|
|
|
resolve->event = sd_event_ref(event);
|
|
|
|
else {
|
|
|
|
r = sd_event_default(&resolve->event);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_event_add_io(resolve->event, &resolve->event_source, resolve->fds[RESPONSE_RECV_FD], POLLIN, io_callback, resolve);
|
|
|
|
if (r < 0)
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
r = sd_event_source_set_priority(resolve->event_source, priority);
|
|
|
|
if (r < 0)
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
fail:
|
|
|
|
sd_resolve_detach_event(resolve);
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
_public_ int sd_resolve_detach_event(sd_resolve *resolve) {
|
|
|
|
assert_return(resolve, -EINVAL);
|
|
|
|
|
|
|
|
if (!resolve->event)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (resolve->event_source) {
|
|
|
|
sd_event_source_set_enabled(resolve->event_source, SD_EVENT_OFF);
|
|
|
|
resolve->event_source = sd_event_source_unref(resolve->event_source);
|
|
|
|
}
|
|
|
|
|
|
|
|
resolve->event = sd_event_unref(resolve->event);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
_public_ sd_event *sd_resolve_get_event(sd_resolve *resolve) {
|
|
|
|
assert_return(resolve, NULL);
|
|
|
|
|
|
|
|
return resolve->event;
|
|
|
|
}
|