LCOV - code coverage report
Current view: top level - libsystemd/sd-resolve - sd-resolve.c (source / functions) Hit Total Coverage
Test: systemd test coverage Lines: 510 663 76.9 %
Date: 2015-07-29 18:47:03 Functions: 35 46 76.1 %

          Line data    Source code
       1             : /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
       2             : 
       3             : /***
       4             :   This file is part of systemd.
       5             : 
       6             :   Copyright 2005-2008 Lennart Poettering
       7             : 
       8             :   systemd is free software; you can redistribute it and/or modify it
       9             :   under the terms of the GNU Lesser General Public License as published by
      10             :   the Free Software Foundation; either version 2.1 of the License, or
      11             :   (at your option) any later version.
      12             : 
      13             :   systemd is distributed in the hope that it will be useful, but
      14             :   WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
      16             :   Lesser General Public License for more details.
      17             : 
      18             :   You should have received a copy of the GNU Lesser General Public License
      19             :   along with systemd; If not, see <http://www.gnu.org/licenses/>.
      20             : ***/
      21             : 
      22             : #include <signal.h>
      23             : #include <unistd.h>
      24             : #include <stdio.h>
      25             : #include <string.h>
      26             : #include <stdlib.h>
      27             : #include <errno.h>
      28             : #include <resolv.h>
      29             : #include <stdint.h>
      30             : #include <pthread.h>
      31             : #include <sys/prctl.h>
      32             : #include <poll.h>
      33             : 
      34             : #include "util.h"
      35             : #include "list.h"
      36             : #include "socket-util.h"
      37             : #include "missing.h"
      38             : #include "resolve-util.h"
      39             : #include "sd-resolve.h"
      40             : 
      41             : #define WORKERS_MIN 1U
      42             : #define WORKERS_MAX 16U
      43             : #define QUERIES_MAX 256U
      44             : #define BUFSIZE 10240U
      45             : 
      46             : typedef enum {
      47             :         REQUEST_ADDRINFO,
      48             :         RESPONSE_ADDRINFO,
      49             :         REQUEST_NAMEINFO,
      50             :         RESPONSE_NAMEINFO,
      51             :         REQUEST_RES_QUERY,
      52             :         REQUEST_RES_SEARCH,
      53             :         RESPONSE_RES,
      54             :         REQUEST_TERMINATE,
      55             :         RESPONSE_DIED
      56             : } QueryType;
      57             : 
      58             : enum {
      59             :         REQUEST_RECV_FD,
      60             :         REQUEST_SEND_FD,
      61             :         RESPONSE_RECV_FD,
      62             :         RESPONSE_SEND_FD,
      63             :         _FD_MAX
      64             : };
      65             : 
      66             : struct sd_resolve {
      67             :         unsigned n_ref;
      68             : 
      69             :         bool dead:1;
      70             :         pid_t original_pid;
      71             : 
      72             :         int fds[_FD_MAX];
      73             : 
      74             :         pthread_t workers[WORKERS_MAX];
      75             :         unsigned n_valid_workers;
      76             : 
      77             :         unsigned current_id;
      78             :         sd_resolve_query* query_array[QUERIES_MAX];
      79             :         unsigned n_queries, n_done, n_outstanding;
      80             : 
      81             :         sd_event_source *event_source;
      82             :         sd_event *event;
      83             : 
      84             :         sd_resolve_query *current;
      85             : 
      86             :         sd_resolve **default_resolve_ptr;
      87             :         pid_t tid;
      88             : 
      89             :         LIST_HEAD(sd_resolve_query, queries);
      90             : };
      91             : 
      92             : struct sd_resolve_query {
      93             :         unsigned n_ref;
      94             : 
      95             :         sd_resolve *resolve;
      96             : 
      97             :         QueryType type:4;
      98             :         bool done:1;
      99             :         bool floating:1;
     100             :         unsigned id;
     101             : 
     102             :         int ret;
     103             :         int _errno;
     104             :         int _h_errno;
     105             :         struct addrinfo *addrinfo;
     106             :         char *serv, *host;
     107             :         unsigned char *answer;
     108             : 
     109             :         union {
     110             :                 sd_resolve_getaddrinfo_handler_t getaddrinfo_handler;
     111             :                 sd_resolve_getnameinfo_handler_t getnameinfo_handler;
     112             :                 sd_resolve_res_handler_t res_handler;
     113             :         };
     114             : 
     115             :         void *userdata;
     116             : 
     117             :         LIST_FIELDS(sd_resolve_query, queries);
     118             : };
     119             : 
     120             : typedef struct RHeader {
     121             :         QueryType type;
     122             :         unsigned id;
     123             :         size_t length;
     124             : } RHeader;
     125             : 
     126             : typedef struct AddrInfoRequest {
     127             :         struct RHeader header;
     128             :         bool hints_valid;
     129             :         int ai_flags;
     130             :         int ai_family;
     131             :         int ai_socktype;
     132             :         int ai_protocol;
     133             :         size_t node_len, service_len;
     134             : } AddrInfoRequest;
     135             : 
     136             : typedef struct AddrInfoResponse {
     137             :         struct RHeader header;
     138             :         int ret;
     139             :         int _errno;
     140             :         int _h_errno;
     141             :         /* followed by addrinfo_serialization[] */
     142             : } AddrInfoResponse;
     143             : 
     144             : typedef struct AddrInfoSerialization {
     145             :         int ai_flags;
     146             :         int ai_family;
     147             :         int ai_socktype;
     148             :         int ai_protocol;
     149             :         size_t ai_addrlen;
     150             :         size_t canonname_len;
     151             :         /* Followed by ai_addr amd ai_canonname with variable lengths */
     152             : } AddrInfoSerialization;
     153             : 
     154             : typedef struct NameInfoRequest {
     155             :         struct RHeader header;
     156             :         int flags;
     157             :         socklen_t sockaddr_len;
     158             :         bool gethost:1, getserv:1;
     159             : } NameInfoRequest;
     160             : 
     161             : typedef struct NameInfoResponse {
     162             :         struct RHeader header;
     163             :         size_t hostlen, servlen;
     164             :         int ret;
     165             :         int _errno;
     166             :         int _h_errno;
     167             : } NameInfoResponse;
     168             : 
     169             : typedef struct ResRequest {
     170             :         struct RHeader header;
     171             :         int class;
     172             :         int type;
     173             :         size_t dname_len;
     174             : } ResRequest;
     175             : 
     176             : typedef struct ResResponse {
     177             :         struct RHeader header;
     178             :         int ret;
     179             :         int _errno;
     180             :         int _h_errno;
     181             : } ResResponse;
     182             : 
     183             : typedef union Packet {
     184             :         RHeader rheader;
     185             :         AddrInfoRequest addrinfo_request;
     186             :         AddrInfoResponse addrinfo_response;
     187             :         NameInfoRequest nameinfo_request;
     188             :         NameInfoResponse nameinfo_response;
     189             :         ResRequest res_request;
     190             :         ResResponse res_response;
     191             : } Packet;
     192             : 
     193             : static int getaddrinfo_done(sd_resolve_query* q);
     194             : static int getnameinfo_done(sd_resolve_query *q);
     195             : static int res_query_done(sd_resolve_query* q);
     196             : 
     197             : static void resolve_query_disconnect(sd_resolve_query *q);
     198             : 
     199             : #define RESOLVE_DONT_DESTROY(resolve) \
     200             :         _cleanup_resolve_unref_ _unused_ sd_resolve *_dont_destroy_##resolve = sd_resolve_ref(resolve)
     201             : 
     202           4 : static int send_died(int out_fd) {
     203             : 
     204           4 :         RHeader rh = {
     205             :                 .type = RESPONSE_DIED,
     206             :                 .length = sizeof(RHeader),
     207             :         };
     208             : 
     209           4 :         assert(out_fd >= 0);
     210             : 
     211           4 :         if (send(out_fd, &rh, rh.length, MSG_NOSIGNAL) < 0)
     212           0 :                 return -errno;
     213             : 
     214           4 :         return 0;
     215             : }
     216             : 
     217           6 : static void *serialize_addrinfo(void *p, const struct addrinfo *ai, size_t *length, size_t maxlength) {
     218             :         AddrInfoSerialization s;
     219             :         size_t cnl, l;
     220             : 
     221           6 :         assert(p);
     222           6 :         assert(ai);
     223           6 :         assert(length);
     224           6 :         assert(*length <= maxlength);
     225             : 
     226           6 :         cnl = ai->ai_canonname ? strlen(ai->ai_canonname)+1 : 0;
     227           6 :         l = sizeof(AddrInfoSerialization) + ai->ai_addrlen + cnl;
     228             : 
     229           6 :         if (*length + l > maxlength)
     230           0 :                 return NULL;
     231             : 
     232           6 :         s.ai_flags = ai->ai_flags;
     233           6 :         s.ai_family = ai->ai_family;
     234           6 :         s.ai_socktype = ai->ai_socktype;
     235           6 :         s.ai_protocol = ai->ai_protocol;
     236           6 :         s.ai_addrlen = ai->ai_addrlen;
     237           6 :         s.canonname_len = cnl;
     238             : 
     239           6 :         memcpy((uint8_t*) p, &s, sizeof(AddrInfoSerialization));
     240           6 :         memcpy((uint8_t*) p + sizeof(AddrInfoSerialization), ai->ai_addr, ai->ai_addrlen);
     241             : 
     242           6 :         if (ai->ai_canonname)
     243           1 :                 memcpy((char*) p + sizeof(AddrInfoSerialization) + ai->ai_addrlen, ai->ai_canonname, cnl);
     244             : 
     245           6 :         *length += l;
     246           6 :         return (uint8_t*) p + l;
     247             : }
     248             : 
     249           2 : static int send_addrinfo_reply(
     250             :                 int out_fd,
     251             :                 unsigned id,
     252             :                 int ret,
     253             :                 struct addrinfo *ai,
     254             :                 int _errno,
     255             :                 int _h_errno) {
     256             : 
     257           2 :         AddrInfoResponse resp = {
     258             :                 .header.type = RESPONSE_ADDRINFO,
     259             :                 .header.id = id,
     260             :                 .header.length = sizeof(AddrInfoResponse),
     261             :                 .ret = ret,
     262             :                 ._errno = _errno,
     263             :                 ._h_errno = _h_errno,
     264             :         };
     265             : 
     266           2 :         struct msghdr mh = {};
     267             :         struct iovec iov[2];
     268             :         union {
     269             :                 AddrInfoSerialization ais;
     270             :                 uint8_t space[BUFSIZE];
     271             :         } buffer;
     272             : 
     273           2 :         assert(out_fd >= 0);
     274             : 
     275           2 :         if (ret == 0 && ai) {
     276           2 :                 void *p = &buffer;
     277             :                 struct addrinfo *k;
     278             : 
     279           8 :                 for (k = ai; k; k = k->ai_next) {
     280           6 :                         p = serialize_addrinfo(p, k, &resp.header.length, (uint8_t*) &buffer + BUFSIZE - (uint8_t*) p);
     281           6 :                         if (!p) {
     282           0 :                                 freeaddrinfo(ai);
     283           0 :                                 return -ENOBUFS;
     284             :                         }
     285             :                 }
     286             :         }
     287             : 
     288           2 :         if (ai)
     289           2 :                 freeaddrinfo(ai);
     290             : 
     291           2 :         iov[0] = (struct iovec) { .iov_base = &resp, .iov_len = sizeof(AddrInfoResponse) };
     292           2 :         iov[1] = (struct iovec) { .iov_base = &buffer, .iov_len = resp.header.length - sizeof(AddrInfoResponse) };
     293             : 
     294           2 :         mh.msg_iov = iov;
     295           2 :         mh.msg_iovlen = ELEMENTSOF(iov);
     296             : 
     297           2 :         if (sendmsg(out_fd, &mh, MSG_NOSIGNAL) < 0)
     298           0 :                 return -errno;
     299             : 
     300           2 :         return 0;
     301             : }
     302             : 
     303           1 : static int send_nameinfo_reply(
     304             :                 int out_fd,
     305             :                 unsigned id,
     306             :                 int ret,
     307             :                 const char *host,
     308             :                 const char *serv,
     309             :                 int _errno,
     310             :                 int _h_errno) {
     311             : 
     312           1 :         NameInfoResponse resp = {
     313             :                 .header.type = RESPONSE_NAMEINFO,
     314             :                 .header.id = id,
     315             :                 .ret = ret,
     316             :                 ._errno = _errno,
     317             :                 ._h_errno = _h_errno,
     318             :         };
     319             : 
     320           1 :         struct msghdr mh = {};
     321             :         struct iovec iov[3];
     322             :         size_t hl, sl;
     323             : 
     324           1 :         assert(out_fd >= 0);
     325             : 
     326           1 :         sl = serv ? strlen(serv)+1 : 0;
     327           1 :         hl = host ? strlen(host)+1 : 0;
     328             : 
     329           1 :         resp.header.length = sizeof(NameInfoResponse) + hl + sl;
     330           1 :         resp.hostlen = hl;
     331           1 :         resp.servlen = sl;
     332             : 
     333           1 :         iov[0] = (struct iovec) { .iov_base = &resp, .iov_len = sizeof(NameInfoResponse) };
     334           1 :         iov[1] = (struct iovec) { .iov_base = (void*) host, .iov_len = hl };
     335           1 :         iov[2] = (struct iovec) { .iov_base = (void*) serv, .iov_len = sl };
     336             : 
     337           1 :         mh.msg_iov = iov;
     338           1 :         mh.msg_iovlen = ELEMENTSOF(iov);
     339             : 
     340           1 :         if (sendmsg(out_fd, &mh, MSG_NOSIGNAL) < 0)
     341           0 :                 return -errno;
     342             : 
     343           1 :         return 0;
     344             : }
     345             : 
     346           1 : static int send_res_reply(int out_fd, unsigned id, const unsigned char *answer, int ret, int _errno, int _h_errno) {
     347             : 
     348           1 :         ResResponse resp = {
     349             :                 .header.type = RESPONSE_RES,
     350             :                 .header.id = id,
     351             :                 .ret = ret,
     352             :                 ._errno = _errno,
     353             :                 ._h_errno = _h_errno,
     354             :         };
     355             : 
     356           1 :         struct msghdr mh = {};
     357             :         struct iovec iov[2];
     358             :         size_t l;
     359             : 
     360           1 :         assert(out_fd >= 0);
     361             : 
     362           1 :         l = ret > 0 ? (size_t) ret : 0;
     363             : 
     364           1 :         resp.header.length = sizeof(ResResponse) + l;
     365             : 
     366           1 :         iov[0] = (struct iovec) { .iov_base = &resp, .iov_len = sizeof(ResResponse) };
     367           1 :         iov[1] = (struct iovec) { .iov_base = (void*) answer, .iov_len = l };
     368             : 
     369           1 :         mh.msg_iov = iov;
     370           1 :         mh.msg_iovlen = ELEMENTSOF(iov);
     371             : 
     372           1 :         if (sendmsg(out_fd, &mh, MSG_NOSIGNAL) < 0)
     373           0 :                 return -errno;
     374             : 
     375           1 :         return 0;
     376             : }
     377             : 
     378           4 : static int handle_request(int out_fd, const Packet *packet, size_t length) {
     379             :         const RHeader *req;
     380             : 
     381           4 :         assert(out_fd >= 0);
     382           4 :         assert(packet);
     383             : 
     384           4 :         req = &packet->rheader;
     385             : 
     386           4 :         assert(length >= sizeof(RHeader));
     387           4 :         assert(length == req->length);
     388             : 
     389           4 :         switch (req->type) {
     390             : 
     391             :         case REQUEST_ADDRINFO: {
     392           2 :                const AddrInfoRequest *ai_req = &packet->addrinfo_request;
     393           2 :                struct addrinfo hints = {}, *result = NULL;
     394             :                const char *node, *service;
     395             :                int ret;
     396             : 
     397           2 :                assert(length >= sizeof(AddrInfoRequest));
     398           2 :                assert(length == sizeof(AddrInfoRequest) + ai_req->node_len + ai_req->service_len);
     399             : 
     400           2 :                hints.ai_flags = ai_req->ai_flags;
     401           2 :                hints.ai_family = ai_req->ai_family;
     402           2 :                hints.ai_socktype = ai_req->ai_socktype;
     403           2 :                hints.ai_protocol = ai_req->ai_protocol;
     404             : 
     405           2 :                node = ai_req->node_len ? (const char*) ai_req + sizeof(AddrInfoRequest) : NULL;
     406           2 :                service = ai_req->service_len ? (const char*) ai_req + sizeof(AddrInfoRequest) + ai_req->node_len : NULL;
     407             : 
     408           2 :                ret = getaddrinfo(
     409             :                                node, service,
     410           2 :                                ai_req->hints_valid ? &hints : NULL,
     411             :                                &result);
     412             : 
     413             :                /* send_addrinfo_reply() frees result */
     414           2 :                return send_addrinfo_reply(out_fd, req->id, ret, result, errno, h_errno);
     415             :         }
     416             : 
     417             :         case REQUEST_NAMEINFO: {
     418           1 :                const NameInfoRequest *ni_req = &packet->nameinfo_request;
     419             :                char hostbuf[NI_MAXHOST], servbuf[NI_MAXSERV];
     420             :                union sockaddr_union sa;
     421             :                int ret;
     422             : 
     423           1 :                assert(length >= sizeof(NameInfoRequest));
     424           1 :                assert(length == sizeof(NameInfoRequest) + ni_req->sockaddr_len);
     425           1 :                assert(sizeof(sa) >= ni_req->sockaddr_len);
     426             : 
     427           1 :                memcpy(&sa, (const uint8_t *) ni_req + sizeof(NameInfoRequest), ni_req->sockaddr_len);
     428             : 
     429           5 :                ret = getnameinfo(&sa.sa, ni_req->sockaddr_len,
     430           2 :                                ni_req->gethost ? hostbuf : NULL, ni_req->gethost ? sizeof(hostbuf) : 0,
     431           2 :                                ni_req->getserv ? servbuf : NULL, ni_req->getserv ? sizeof(servbuf) : 0,
     432             :                                ni_req->flags);
     433             : 
     434           4 :                return send_nameinfo_reply(out_fd, req->id, ret,
     435           1 :                                ret == 0 && ni_req->gethost ? hostbuf : NULL,
     436           1 :                                ret == 0 && ni_req->getserv ? servbuf : NULL,
     437           2 :                                errno, h_errno);
     438             :         }
     439             : 
     440             :         case REQUEST_RES_QUERY:
     441             :         case REQUEST_RES_SEARCH: {
     442           1 :                  const ResRequest *res_req = &packet->res_request;
     443             :                  union {
     444             :                          HEADER header;
     445             :                          uint8_t space[BUFSIZE];
     446             :                  } answer;
     447             :                  const char *dname;
     448             :                  int ret;
     449             : 
     450           1 :                  assert(length >= sizeof(ResRequest));
     451           1 :                  assert(length == sizeof(ResRequest) + res_req->dname_len);
     452             : 
     453           1 :                  dname = (const char *) res_req + sizeof(ResRequest);
     454             : 
     455           1 :                  if (req->type == REQUEST_RES_QUERY)
     456           1 :                          ret = res_query(dname, res_req->class, res_req->type, (unsigned char *) &answer, BUFSIZE);
     457             :                  else
     458           0 :                          ret = res_search(dname, res_req->class, res_req->type, (unsigned char *) &answer, BUFSIZE);
     459             : 
     460           1 :                  return send_res_reply(out_fd, req->id, (unsigned char *) &answer, ret, errno, h_errno);
     461             :         }
     462             : 
     463             :         case REQUEST_TERMINATE:
     464             :                  /* Quit */
     465           0 :                  return -ECONNRESET;
     466             : 
     467             :         default:
     468           0 :                 assert_not_reached("Unknown request");
     469             :         }
     470             : 
     471             :         return 0;
     472             : }
     473             : 
     474           4 : static void* thread_worker(void *p) {
     475           4 :         sd_resolve *resolve = p;
     476             :         sigset_t fullset;
     477             : 
     478             :         /* No signals in this thread please */
     479           4 :         assert_se(sigfillset(&fullset) == 0);
     480           3 :         assert_se(pthread_sigmask(SIG_BLOCK, &fullset, NULL) == 0);
     481             : 
     482             :         /* Assign a pretty name to this thread */
     483           4 :         prctl(PR_SET_NAME, (unsigned long) "sd-resolve");
     484             : 
     485           4 :         while (!resolve->dead) {
     486             :                 union {
     487             :                         Packet packet;
     488             :                         uint8_t space[BUFSIZE];
     489             :                 } buf;
     490             :                 ssize_t length;
     491             : 
     492           7 :                 length = recv(resolve->fds[REQUEST_RECV_FD], &buf, sizeof(buf), 0);
     493           7 :                 if (length < 0) {
     494           0 :                         if (errno == EINTR)
     495           0 :                                 continue;
     496             : 
     497           3 :                         break;
     498             :                 }
     499           7 :                 if (length == 0)
     500           0 :                         break;
     501             : 
     502           7 :                 if (resolve->dead)
     503           3 :                         break;
     504             : 
     505           4 :                 if (handle_request(resolve->fds[RESPONSE_SEND_FD], &buf.packet, (size_t) length) < 0)
     506           0 :                         break;
     507             :         }
     508             : 
     509           4 :         send_died(resolve->fds[RESPONSE_SEND_FD]);
     510             : 
     511           4 :         return NULL;
     512             : }
     513             : 
     514           4 : static int start_threads(sd_resolve *resolve, unsigned extra) {
     515             :         unsigned n;
     516             :         int r;
     517             : 
     518           4 :         n = resolve->n_outstanding + extra;
     519           4 :         n = CLAMP(n, WORKERS_MIN, WORKERS_MAX);
     520             : 
     521          12 :         while (resolve->n_valid_workers < n) {
     522             : 
     523           4 :                 r = pthread_create(&resolve->workers[resolve->n_valid_workers], NULL, thread_worker, resolve);
     524           4 :                 if (r != 0)
     525           0 :                         return -r;
     526             : 
     527           4 :                 resolve->n_valid_workers ++;
     528             :         }
     529             : 
     530           4 :         return 0;
     531             : }
     532             : 
     533          16 : static bool resolve_pid_changed(sd_resolve *r) {
     534          16 :         assert(r);
     535             : 
     536             :         /* We don't support people creating a resolver and keeping it
     537             :          * around after fork(). Let's complain. */
     538             : 
     539          16 :         return r->original_pid != getpid();
     540             : }
     541             : 
     542           1 : _public_ int sd_resolve_new(sd_resolve **ret) {
     543           1 :         sd_resolve *resolve = NULL;
     544             :         int i, r;
     545             : 
     546           1 :         assert_return(ret, -EINVAL);
     547             : 
     548           1 :         resolve = new0(sd_resolve, 1);
     549           1 :         if (!resolve)
     550           0 :                 return -ENOMEM;
     551             : 
     552           1 :         resolve->n_ref = 1;
     553           1 :         resolve->original_pid = getpid();
     554             : 
     555           5 :         for (i = 0; i < _FD_MAX; i++)
     556           4 :                 resolve->fds[i] = -1;
     557             : 
     558           1 :         r = socketpair(PF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0, resolve->fds + REQUEST_RECV_FD);
     559           1 :         if (r < 0) {
     560           0 :                 r = -errno;
     561           0 :                 goto fail;
     562             :         }
     563             : 
     564           1 :         r = socketpair(PF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0, resolve->fds + RESPONSE_RECV_FD);
     565           1 :         if (r < 0) {
     566           0 :                 r = -errno;
     567           0 :                 goto fail;
     568             :         }
     569             : 
     570           1 :         fd_inc_sndbuf(resolve->fds[REQUEST_SEND_FD], QUERIES_MAX * BUFSIZE);
     571           1 :         fd_inc_rcvbuf(resolve->fds[REQUEST_RECV_FD], QUERIES_MAX * BUFSIZE);
     572           1 :         fd_inc_sndbuf(resolve->fds[RESPONSE_SEND_FD], QUERIES_MAX * BUFSIZE);
     573           1 :         fd_inc_rcvbuf(resolve->fds[RESPONSE_RECV_FD], QUERIES_MAX * BUFSIZE);
     574             : 
     575           1 :         fd_nonblock(resolve->fds[RESPONSE_RECV_FD], true);
     576             : 
     577           1 :         *ret = resolve;
     578           1 :         return 0;
     579             : 
     580             : fail:
     581           0 :         sd_resolve_unref(resolve);
     582           0 :         return r;
     583             : }
     584             : 
     585           1 : _public_ int sd_resolve_default(sd_resolve **ret) {
     586             : 
     587             :         static thread_local sd_resolve *default_resolve = NULL;
     588           1 :         sd_resolve *e = NULL;
     589             :         int r;
     590             : 
     591           1 :         if (!ret)
     592           0 :                 return !!default_resolve;
     593             : 
     594           1 :         if (default_resolve) {
     595           0 :                 *ret = sd_resolve_ref(default_resolve);
     596           0 :                 return 0;
     597             :         }
     598             : 
     599           1 :         r = sd_resolve_new(&e);
     600           1 :         if (r < 0)
     601           0 :                 return r;
     602             : 
     603           1 :         e->default_resolve_ptr = &default_resolve;
     604           1 :         e->tid = gettid();
     605           1 :         default_resolve = e;
     606             : 
     607           1 :         *ret = e;
     608           1 :         return 1;
     609             : }
     610             : 
     611           0 : _public_ int sd_resolve_get_tid(sd_resolve *resolve, pid_t *tid) {
     612           0 :         assert_return(resolve, -EINVAL);
     613           0 :         assert_return(tid, -EINVAL);
     614           0 :         assert_return(!resolve_pid_changed(resolve), -ECHILD);
     615             : 
     616           0 :         if (resolve->tid != 0) {
     617           0 :                 *tid = resolve->tid;
     618           0 :                 return 0;
     619             :         }
     620             : 
     621           0 :         if (resolve->event)
     622           0 :                 return sd_event_get_tid(resolve->event, tid);
     623             : 
     624           0 :         return -ENXIO;
     625             : }
     626             : 
     627           1 : static void resolve_free(sd_resolve *resolve) {
     628           2 :         PROTECT_ERRNO;
     629             :         sd_resolve_query *q;
     630             :         unsigned i;
     631             : 
     632           1 :         assert(resolve);
     633             : 
     634           3 :         while ((q = resolve->queries)) {
     635           1 :                 assert(q->floating);
     636           1 :                 resolve_query_disconnect(q);
     637           1 :                 sd_resolve_query_unref(q);
     638             :         }
     639             : 
     640           1 :         if (resolve->default_resolve_ptr)
     641           1 :                 *(resolve->default_resolve_ptr) = NULL;
     642             : 
     643           1 :         resolve->dead = true;
     644             : 
     645           1 :         sd_resolve_detach_event(resolve);
     646             : 
     647           1 :         if (resolve->fds[REQUEST_SEND_FD] >= 0) {
     648             : 
     649           1 :                 RHeader req = {
     650             :                         .type = REQUEST_TERMINATE,
     651             :                         .length = sizeof(req)
     652             :                 };
     653             : 
     654             :                 /* Send one termination packet for each worker */
     655           5 :                 for (i = 0; i < resolve->n_valid_workers; i++)
     656           4 :                         (void) send(resolve->fds[REQUEST_SEND_FD], &req, req.length, MSG_NOSIGNAL);
     657             :         }
     658             : 
     659             :         /* Now terminate them and wait until they are gone. */
     660           5 :         for (i = 0; i < resolve->n_valid_workers; i++) {
     661             :                 for (;;) {
     662           4 :                         if (pthread_join(resolve->workers[i], NULL) != EINTR)
     663           4 :                                 break;
     664           0 :                 }
     665             :         }
     666             : 
     667             :         /* Close all communication channels */
     668           5 :         for (i = 0; i < _FD_MAX; i++)
     669           4 :                 safe_close(resolve->fds[i]);
     670             : 
     671           1 :         free(resolve);
     672           1 : }
     673             : 
     674           6 : _public_ sd_resolve* sd_resolve_ref(sd_resolve *resolve) {
     675           6 :         assert_return(resolve, NULL);
     676             : 
     677           6 :         assert(resolve->n_ref >= 1);
     678           6 :         resolve->n_ref++;
     679             : 
     680           6 :         return resolve;
     681             : }
     682             : 
     683           7 : _public_ sd_resolve* sd_resolve_unref(sd_resolve *resolve) {
     684             : 
     685           7 :         if (!resolve)
     686           0 :                 return NULL;
     687             : 
     688           7 :         assert(resolve->n_ref >= 1);
     689           7 :         resolve->n_ref--;
     690             : 
     691           7 :         if (resolve->n_ref <= 0)
     692           1 :                 resolve_free(resolve);
     693             : 
     694           7 :         return NULL;
     695             : }
     696             : 
     697           0 : _public_ int sd_resolve_get_fd(sd_resolve *resolve) {
     698           0 :         assert_return(resolve, -EINVAL);
     699           0 :         assert_return(!resolve_pid_changed(resolve), -ECHILD);
     700             : 
     701           0 :         return resolve->fds[RESPONSE_RECV_FD];
     702             : }
     703             : 
     704           0 : _public_ int sd_resolve_get_events(sd_resolve *resolve) {
     705           0 :         assert_return(resolve, -EINVAL);
     706           0 :         assert_return(!resolve_pid_changed(resolve), -ECHILD);
     707             : 
     708           0 :         return resolve->n_queries > resolve->n_done ? POLLIN : 0;
     709             : }
     710             : 
     711           0 : _public_ int sd_resolve_get_timeout(sd_resolve *resolve, uint64_t *usec) {
     712           0 :         assert_return(resolve, -EINVAL);
     713           0 :         assert_return(usec, -EINVAL);
     714           0 :         assert_return(!resolve_pid_changed(resolve), -ECHILD);
     715             : 
     716           0 :         *usec = (uint64_t) -1;
     717           0 :         return 0;
     718             : }
     719             : 
     720           3 : static sd_resolve_query *lookup_query(sd_resolve *resolve, unsigned id) {
     721             :         sd_resolve_query *q;
     722             : 
     723           3 :         assert(resolve);
     724             : 
     725           3 :         q = resolve->query_array[id % QUERIES_MAX];
     726           3 :         if (q)
     727           3 :                 if (q->id == id)
     728           3 :                         return q;
     729             : 
     730           0 :         return NULL;
     731             : }
     732             : 
     733           3 : static int complete_query(sd_resolve *resolve, sd_resolve_query *q) {
     734             :         int r;
     735             : 
     736           3 :         assert(q);
     737           3 :         assert(!q->done);
     738           3 :         assert(q->resolve == resolve);
     739             : 
     740           3 :         q->done = true;
     741           3 :         resolve->n_done ++;
     742             : 
     743           3 :         resolve->current = sd_resolve_query_ref(q);
     744             : 
     745           3 :         switch (q->type) {
     746             : 
     747             :         case REQUEST_ADDRINFO:
     748           1 :                 r = getaddrinfo_done(q);
     749           1 :                 break;
     750             : 
     751             :         case REQUEST_NAMEINFO:
     752           1 :                 r = getnameinfo_done(q);
     753           1 :                 break;
     754             : 
     755             :         case REQUEST_RES_QUERY:
     756             :         case REQUEST_RES_SEARCH:
     757           1 :                 r = res_query_done(q);
     758           1 :                 break;
     759             : 
     760             :         default:
     761           0 :                 assert_not_reached("Cannot complete unknown query type");
     762             :         }
     763             : 
     764           3 :         resolve->current = NULL;
     765             : 
     766           3 :         if (q->floating) {
     767           0 :                 resolve_query_disconnect(q);
     768           0 :                 sd_resolve_query_unref(q);
     769             :         }
     770             : 
     771           3 :         sd_resolve_query_unref(q);
     772             : 
     773           3 :         return r;
     774             : }
     775             : 
     776           2 : static int unserialize_addrinfo(const void **p, size_t *length, struct addrinfo **ret_ai) {
     777             :         AddrInfoSerialization s;
     778             :         size_t l;
     779             :         struct addrinfo *ai;
     780             : 
     781           2 :         assert(p);
     782           2 :         assert(*p);
     783           2 :         assert(ret_ai);
     784           2 :         assert(length);
     785             : 
     786           2 :         if (*length < sizeof(AddrInfoSerialization))
     787           0 :                 return -EBADMSG;
     788             : 
     789           2 :         memcpy(&s, *p, sizeof(s));
     790             : 
     791           2 :         l = sizeof(AddrInfoSerialization) + s.ai_addrlen + s.canonname_len;
     792           2 :         if (*length < l)
     793           0 :                 return -EBADMSG;
     794             : 
     795           2 :         ai = new0(struct addrinfo, 1);
     796           2 :         if (!ai)
     797           0 :                 return -ENOMEM;
     798             : 
     799           2 :         ai->ai_flags = s.ai_flags;
     800           2 :         ai->ai_family = s.ai_family;
     801           2 :         ai->ai_socktype = s.ai_socktype;
     802           2 :         ai->ai_protocol = s.ai_protocol;
     803           2 :         ai->ai_addrlen = s.ai_addrlen;
     804             : 
     805           2 :         if (s.ai_addrlen > 0) {
     806           2 :                 ai->ai_addr = memdup((const uint8_t*) *p + sizeof(AddrInfoSerialization), s.ai_addrlen);
     807           2 :                 if (!ai->ai_addr) {
     808           0 :                         free(ai);
     809           0 :                         return -ENOMEM;
     810             :                 }
     811             :         }
     812             : 
     813           2 :         if (s.canonname_len > 0) {
     814           1 :                 ai->ai_canonname = memdup((const uint8_t*) *p + sizeof(AddrInfoSerialization) + s.ai_addrlen, s.canonname_len);
     815           1 :                 if (!ai->ai_canonname) {
     816           0 :                         free(ai->ai_addr);
     817           0 :                         free(ai);
     818           0 :                         return -ENOMEM;
     819             :                 }
     820             :         }
     821             : 
     822           2 :         *length -= l;
     823           2 :         *ret_ai = ai;
     824           2 :         *p = ((const uint8_t*) *p) + l;
     825             : 
     826           2 :         return 0;
     827             : }
     828             : 
     829           3 : static int handle_response(sd_resolve *resolve, const Packet *packet, size_t length) {
     830             :         const RHeader *resp;
     831             :         sd_resolve_query *q;
     832             :         int r;
     833             : 
     834           3 :         assert(resolve);
     835             : 
     836           3 :         resp = &packet->rheader;
     837           3 :         assert(resp);
     838           3 :         assert(length >= sizeof(RHeader));
     839           3 :         assert(length == resp->length);
     840             : 
     841           3 :         if (resp->type == RESPONSE_DIED) {
     842           0 :                 resolve->dead = true;
     843           0 :                 return 0;
     844             :         }
     845             : 
     846           3 :         assert(resolve->n_outstanding > 0);
     847           3 :         resolve->n_outstanding--;
     848             : 
     849           3 :         q = lookup_query(resolve, resp->id);
     850           3 :         if (!q)
     851           0 :                 return 0;
     852             : 
     853           3 :         switch (resp->type) {
     854             : 
     855             :         case RESPONSE_ADDRINFO: {
     856           1 :                 const AddrInfoResponse *ai_resp = &packet->addrinfo_response;
     857             :                 const void *p;
     858             :                 size_t l;
     859           1 :                 struct addrinfo *prev = NULL;
     860             : 
     861           1 :                 assert(length >= sizeof(AddrInfoResponse));
     862           1 :                 assert(q->type == REQUEST_ADDRINFO);
     863             : 
     864           1 :                 q->ret = ai_resp->ret;
     865           1 :                 q->_errno = ai_resp->_errno;
     866           1 :                 q->_h_errno = ai_resp->_h_errno;
     867             : 
     868           1 :                 l = length - sizeof(AddrInfoResponse);
     869           1 :                 p = (const uint8_t*) resp + sizeof(AddrInfoResponse);
     870             : 
     871           4 :                 while (l > 0 && p) {
     872           2 :                         struct addrinfo *ai = NULL;
     873             : 
     874           2 :                         r = unserialize_addrinfo(&p, &l, &ai);
     875           2 :                         if (r < 0) {
     876           0 :                                 q->ret = EAI_SYSTEM;
     877           0 :                                 q->_errno = -r;
     878           0 :                                 q->_h_errno = 0;
     879           0 :                                 freeaddrinfo(q->addrinfo);
     880           0 :                                 q->addrinfo = NULL;
     881           0 :                                 break;
     882             :                         }
     883             : 
     884           2 :                         if (prev)
     885           1 :                                 prev->ai_next = ai;
     886             :                         else
     887           1 :                                 q->addrinfo = ai;
     888             : 
     889           2 :                         prev = ai;
     890             :                 }
     891             : 
     892           1 :                 return complete_query(resolve, q);
     893             :         }
     894             : 
     895             :         case RESPONSE_NAMEINFO: {
     896           1 :                 const NameInfoResponse *ni_resp = &packet->nameinfo_response;
     897             : 
     898           1 :                 assert(length >= sizeof(NameInfoResponse));
     899           1 :                 assert(q->type == REQUEST_NAMEINFO);
     900             : 
     901           1 :                 q->ret = ni_resp->ret;
     902           1 :                 q->_errno = ni_resp->_errno;
     903           1 :                 q->_h_errno = ni_resp->_h_errno;
     904             : 
     905           1 :                 if (ni_resp->hostlen > 0) {
     906           1 :                         q->host = strndup((const char*) ni_resp + sizeof(NameInfoResponse), ni_resp->hostlen-1);
     907           1 :                         if (!q->host) {
     908           0 :                                 q->ret = EAI_MEMORY;
     909           0 :                                 q->_errno = ENOMEM;
     910           0 :                                 q->_h_errno = 0;
     911             :                         }
     912             :                 }
     913             : 
     914           1 :                 if (ni_resp->servlen > 0) {
     915           1 :                         q->serv = strndup((const char*) ni_resp + sizeof(NameInfoResponse) + ni_resp->hostlen, ni_resp->servlen-1);
     916           1 :                         if (!q->serv) {
     917           0 :                                 q->ret = EAI_MEMORY;
     918           0 :                                 q->_errno = ENOMEM;
     919           0 :                                 q->_h_errno = 0;
     920             :                         }
     921             :                 }
     922             : 
     923           1 :                 return complete_query(resolve, q);
     924             :         }
     925             : 
     926             :         case RESPONSE_RES: {
     927           1 :                 const ResResponse *res_resp = &packet->res_response;
     928             : 
     929           1 :                 assert(length >= sizeof(ResResponse));
     930           1 :                 assert(q->type == REQUEST_RES_QUERY || q->type == REQUEST_RES_SEARCH);
     931             : 
     932           1 :                 q->ret = res_resp->ret;
     933           1 :                 q->_errno = res_resp->_errno;
     934           1 :                 q->_h_errno = res_resp->_h_errno;
     935             : 
     936           1 :                 if (res_resp->ret >= 0)  {
     937           1 :                         q->answer = memdup((const char *)resp + sizeof(ResResponse), res_resp->ret);
     938           1 :                         if (!q->answer) {
     939           0 :                                 q->ret = -1;
     940           0 :                                 q->_errno = ENOMEM;
     941           0 :                                 q->_h_errno = 0;
     942             :                         }
     943             :                 }
     944             : 
     945           1 :                 return complete_query(resolve, q);
     946             :         }
     947             : 
     948             :         default:
     949           0 :                 return 0;
     950             :         }
     951             : }
     952             : 
     953           3 : _public_ int sd_resolve_process(sd_resolve *resolve) {
     954           6 :         RESOLVE_DONT_DESTROY(resolve);
     955             : 
     956             :         union {
     957             :                 Packet packet;
     958             :                 uint8_t space[BUFSIZE];
     959             :         } buf;
     960             :         ssize_t l;
     961             :         int r;
     962             : 
     963           3 :         assert_return(resolve, -EINVAL);
     964           3 :         assert_return(!resolve_pid_changed(resolve), -ECHILD);
     965             : 
     966             :         /* We don't allow recursively invoking sd_resolve_process(). */
     967           3 :         assert_return(!resolve->current, -EBUSY);
     968             : 
     969           3 :         l = recv(resolve->fds[RESPONSE_RECV_FD], &buf, sizeof(buf), 0);
     970           3 :         if (l < 0) {
     971           0 :                 if (errno == EAGAIN)
     972           0 :                         return 0;
     973             : 
     974           0 :                 return -errno;
     975             :         }
     976           3 :         if (l == 0)
     977           0 :                 return -ECONNREFUSED;
     978             : 
     979           3 :         r = handle_response(resolve, &buf.packet, (size_t) l);
     980           3 :         if (r < 0)
     981           0 :                 return r;
     982             : 
     983           3 :         return 1;
     984             : }
     985             : 
     986           3 : _public_ int sd_resolve_wait(sd_resolve *resolve, uint64_t timeout_usec) {
     987             :         int r;
     988             : 
     989           3 :         assert_return(resolve, -EINVAL);
     990           3 :         assert_return(!resolve_pid_changed(resolve), -ECHILD);
     991             : 
     992           3 :         if (resolve->n_done >= resolve->n_queries)
     993           0 :                 return 0;
     994             : 
     995             :         do {
     996           3 :                 r = fd_wait_for_event(resolve->fds[RESPONSE_RECV_FD], POLLIN, timeout_usec);
     997           3 :         } while (r == -EINTR);
     998             : 
     999           3 :         if (r < 0)
    1000           0 :                 return r;
    1001             : 
    1002           3 :         return sd_resolve_process(resolve);
    1003             : }
    1004             : 
    1005           4 : static int alloc_query(sd_resolve *resolve, bool floating, sd_resolve_query **_q) {
    1006             :         sd_resolve_query *q;
    1007             :         int r;
    1008             : 
    1009           4 :         assert(resolve);
    1010           4 :         assert(_q);
    1011             : 
    1012           4 :         if (resolve->n_queries >= QUERIES_MAX)
    1013           0 :                 return -ENOBUFS;
    1014             : 
    1015           4 :         r = start_threads(resolve, 1);
    1016           4 :         if (r < 0)
    1017           0 :                 return r;
    1018             : 
    1019           8 :         while (resolve->query_array[resolve->current_id % QUERIES_MAX])
    1020           0 :                 resolve->current_id++;
    1021             : 
    1022           4 :         q = resolve->query_array[resolve->current_id % QUERIES_MAX] = new0(sd_resolve_query, 1);
    1023           4 :         if (!q)
    1024           0 :                 return -ENOMEM;
    1025             : 
    1026           4 :         q->n_ref = 1;
    1027           4 :         q->resolve = resolve;
    1028           4 :         q->floating = floating;
    1029           4 :         q->id = resolve->current_id++;
    1030             : 
    1031           4 :         if (!floating)
    1032           3 :                 sd_resolve_ref(resolve);
    1033             : 
    1034           4 :         LIST_PREPEND(queries, resolve->queries, q);
    1035           4 :         resolve->n_queries++;
    1036             : 
    1037           4 :         *_q = q;
    1038           4 :         return 0;
    1039             : }
    1040             : 
    1041           2 : _public_ int sd_resolve_getaddrinfo(
    1042             :                 sd_resolve *resolve,
    1043             :                 sd_resolve_query **_q,
    1044             :                 const char *node, const char *service,
    1045             :                 const struct addrinfo *hints,
    1046             :                 sd_resolve_getaddrinfo_handler_t callback, void *userdata) {
    1047             : 
    1048           2 :         AddrInfoRequest req = {};
    1049           2 :         struct msghdr mh = {};
    1050             :         struct iovec iov[3];
    1051             :         sd_resolve_query *q;
    1052             :         int r;
    1053             : 
    1054           2 :         assert_return(resolve, -EINVAL);
    1055           2 :         assert_return(node || service, -EINVAL);
    1056           2 :         assert_return(callback, -EINVAL);
    1057           2 :         assert_return(!resolve_pid_changed(resolve), -ECHILD);
    1058             : 
    1059           2 :         r = alloc_query(resolve, !_q, &q);
    1060           2 :         if (r < 0)
    1061           0 :                 return r;
    1062             : 
    1063           2 :         q->type = REQUEST_ADDRINFO;
    1064           2 :         q->getaddrinfo_handler = callback;
    1065           2 :         q->userdata = userdata;
    1066             : 
    1067           2 :         req.node_len = node ? strlen(node)+1 : 0;
    1068           2 :         req.service_len = service ? strlen(service)+1 : 0;
    1069             : 
    1070           2 :         req.header.id = q->id;
    1071           2 :         req.header.type = REQUEST_ADDRINFO;
    1072           2 :         req.header.length = sizeof(AddrInfoRequest) + req.node_len + req.service_len;
    1073             : 
    1074           2 :         if (hints) {
    1075           1 :                 req.hints_valid = true;
    1076           1 :                 req.ai_flags = hints->ai_flags;
    1077           1 :                 req.ai_family = hints->ai_family;
    1078           1 :                 req.ai_socktype = hints->ai_socktype;
    1079           1 :                 req.ai_protocol = hints->ai_protocol;
    1080             :         }
    1081             : 
    1082           2 :         iov[mh.msg_iovlen++] = (struct iovec) { .iov_base = &req, .iov_len = sizeof(AddrInfoRequest) };
    1083           2 :         if (node)
    1084           2 :                 iov[mh.msg_iovlen++] = (struct iovec) { .iov_base = (void*) node, .iov_len = req.node_len };
    1085           2 :         if (service)
    1086           1 :                 iov[mh.msg_iovlen++] = (struct iovec) { .iov_base = (void*) service, .iov_len = req.service_len };
    1087           2 :         mh.msg_iov = iov;
    1088             : 
    1089           2 :         if (sendmsg(resolve->fds[REQUEST_SEND_FD], &mh, MSG_NOSIGNAL) < 0) {
    1090           0 :                 sd_resolve_query_unref(q);
    1091           0 :                 return -errno;
    1092             :         }
    1093             : 
    1094           2 :         resolve->n_outstanding++;
    1095             : 
    1096           2 :         if (_q)
    1097           1 :                 *_q = q;
    1098             : 
    1099           2 :         return 0;
    1100             : }
    1101             : 
    1102           1 : static int getaddrinfo_done(sd_resolve_query* q) {
    1103           1 :         assert(q);
    1104           1 :         assert(q->done);
    1105           1 :         assert(q->getaddrinfo_handler);
    1106             : 
    1107           1 :         errno = q->_errno;
    1108           1 :         h_errno = q->_h_errno;
    1109             : 
    1110           1 :         return q->getaddrinfo_handler(q, q->ret, q->addrinfo, q->userdata);
    1111             : }
    1112             : 
    1113           1 : _public_ int sd_resolve_getnameinfo(
    1114             :                 sd_resolve *resolve,
    1115             :                 sd_resolve_query**_q,
    1116             :                 const struct sockaddr *sa, socklen_t salen,
    1117             :                 int flags,
    1118             :                 uint64_t get,
    1119             :                 sd_resolve_getnameinfo_handler_t callback,
    1120             :                 void *userdata) {
    1121             : 
    1122           1 :         NameInfoRequest req = {};
    1123           1 :         struct msghdr mh = {};
    1124             :         struct iovec iov[2];
    1125             :         sd_resolve_query *q;
    1126             :         int r;
    1127             : 
    1128           1 :         assert_return(resolve, -EINVAL);
    1129           1 :         assert_return(sa, -EINVAL);
    1130           1 :         assert_return(salen >= sizeof(struct sockaddr), -EINVAL);
    1131           1 :         assert_return(salen <= sizeof(union sockaddr_union), -EINVAL);
    1132           1 :         assert_return((get & ~SD_RESOLVE_GET_BOTH) == 0, -EINVAL);
    1133           1 :         assert_return(callback, -EINVAL);
    1134           1 :         assert_return(!resolve_pid_changed(resolve), -ECHILD);
    1135             : 
    1136           1 :         r = alloc_query(resolve, !_q, &q);
    1137           1 :         if (r < 0)
    1138           0 :                 return r;
    1139             : 
    1140           1 :         q->type = REQUEST_NAMEINFO;
    1141           1 :         q->getnameinfo_handler = callback;
    1142           1 :         q->userdata = userdata;
    1143             : 
    1144           1 :         req.header.id = q->id;
    1145           1 :         req.header.type = REQUEST_NAMEINFO;
    1146           1 :         req.header.length = sizeof(NameInfoRequest) + salen;
    1147             : 
    1148           1 :         req.flags = flags;
    1149           1 :         req.sockaddr_len = salen;
    1150           1 :         req.gethost = !!(get & SD_RESOLVE_GET_HOST);
    1151           1 :         req.getserv = !!(get & SD_RESOLVE_GET_SERVICE);
    1152             : 
    1153           1 :         iov[0] = (struct iovec) { .iov_base = &req, .iov_len = sizeof(NameInfoRequest) };
    1154           1 :         iov[1] = (struct iovec) { .iov_base = (void*) sa, .iov_len = salen };
    1155             : 
    1156           1 :         mh.msg_iov = iov;
    1157           1 :         mh.msg_iovlen = 2;
    1158             : 
    1159           1 :         if (sendmsg(resolve->fds[REQUEST_SEND_FD], &mh, MSG_NOSIGNAL) < 0) {
    1160           0 :                 sd_resolve_query_unref(q);
    1161           0 :                 return -errno;
    1162             :         }
    1163             : 
    1164           1 :         resolve->n_outstanding++;
    1165             : 
    1166           1 :         if (_q)
    1167           1 :                 *_q = q;
    1168             : 
    1169           1 :         return 0;
    1170             : }
    1171             : 
    1172           1 : static int getnameinfo_done(sd_resolve_query *q) {
    1173             : 
    1174           1 :         assert(q);
    1175           1 :         assert(q->done);
    1176           1 :         assert(q->getnameinfo_handler);
    1177             : 
    1178           1 :         errno = q->_errno;
    1179           1 :         h_errno= q->_h_errno;
    1180             : 
    1181           1 :         return q->getnameinfo_handler(q, q->ret, q->host, q->serv, q->userdata);
    1182             : }
    1183             : 
    1184           1 : static int resolve_res(
    1185             :                 sd_resolve *resolve,
    1186             :                 sd_resolve_query **_q,
    1187             :                 QueryType qtype,
    1188             :                 const char *dname,
    1189             :                 int class, int type,
    1190             :                 sd_resolve_res_handler_t callback, void *userdata) {
    1191             : 
    1192           1 :         struct msghdr mh = {};
    1193             :         struct iovec iov[2];
    1194           1 :         ResRequest req = {};
    1195             :         sd_resolve_query *q;
    1196             :         int r;
    1197             : 
    1198           1 :         assert_return(resolve, -EINVAL);
    1199           1 :         assert_return(dname, -EINVAL);
    1200           1 :         assert_return(callback, -EINVAL);
    1201           1 :         assert_return(!resolve_pid_changed(resolve), -ECHILD);
    1202             : 
    1203           1 :         r = alloc_query(resolve, !_q, &q);
    1204           1 :         if (r < 0)
    1205           0 :                 return r;
    1206             : 
    1207           1 :         q->type = qtype;
    1208           1 :         q->res_handler = callback;
    1209           1 :         q->userdata = userdata;
    1210             : 
    1211           1 :         req.dname_len = strlen(dname) + 1;
    1212           1 :         req.class = class;
    1213           1 :         req.type = type;
    1214             : 
    1215           1 :         req.header.id = q->id;
    1216           1 :         req.header.type = qtype;
    1217           1 :         req.header.length = sizeof(ResRequest) + req.dname_len;
    1218             : 
    1219           1 :         iov[0] = (struct iovec) { .iov_base = &req, .iov_len = sizeof(ResRequest) };
    1220           1 :         iov[1] = (struct iovec) { .iov_base = (void*) dname, .iov_len = req.dname_len };
    1221             : 
    1222           1 :         mh.msg_iov = iov;
    1223           1 :         mh.msg_iovlen = 2;
    1224             : 
    1225           1 :         if (sendmsg(resolve->fds[REQUEST_SEND_FD], &mh, MSG_NOSIGNAL) < 0) {
    1226           0 :                 sd_resolve_query_unref(q);
    1227           0 :                 return -errno;
    1228             :         }
    1229             : 
    1230           1 :         resolve->n_outstanding++;
    1231             : 
    1232           1 :         if (_q)
    1233           1 :                 *_q = q;
    1234             : 
    1235           1 :         return 0;
    1236             : }
    1237             : 
    1238           1 : _public_ int sd_resolve_res_query(sd_resolve *resolve, sd_resolve_query** q, const char *dname, int class, int type, sd_resolve_res_handler_t callback, void *userdata) {
    1239           1 :         return resolve_res(resolve, q, REQUEST_RES_QUERY, dname, class, type, callback, userdata);
    1240             : }
    1241             : 
    1242           0 : _public_ int sd_resolve_res_search(sd_resolve *resolve, sd_resolve_query** q, const char *dname, int class, int type, sd_resolve_res_handler_t callback, void *userdata) {
    1243           0 :         return resolve_res(resolve, q, REQUEST_RES_SEARCH, dname, class, type, callback, userdata);
    1244             : }
    1245             : 
    1246           1 : static int res_query_done(sd_resolve_query* q) {
    1247           1 :         assert(q);
    1248           1 :         assert(q->done);
    1249           1 :         assert(q->res_handler);
    1250             : 
    1251           1 :         errno = q->_errno;
    1252           1 :         h_errno = q->_h_errno;
    1253             : 
    1254           1 :         return q->res_handler(q, q->ret, q->answer, q->userdata);
    1255             : }
    1256             : 
    1257           3 : _public_ sd_resolve_query* sd_resolve_query_ref(sd_resolve_query *q) {
    1258           3 :         assert_return(q, NULL);
    1259             : 
    1260           3 :         assert(q->n_ref >= 1);
    1261           3 :         q->n_ref++;
    1262             : 
    1263           3 :         return q;
    1264             : }
    1265             : 
    1266           4 : static void resolve_freeaddrinfo(struct addrinfo *ai) {
    1267          10 :         while (ai) {
    1268           2 :                 struct addrinfo *next = ai->ai_next;
    1269             : 
    1270           2 :                 free(ai->ai_addr);
    1271           2 :                 free(ai->ai_canonname);
    1272           2 :                 free(ai);
    1273           2 :                 ai = next;
    1274             :         }
    1275           4 : }
    1276             : 
    1277           5 : static void resolve_query_disconnect(sd_resolve_query *q) {
    1278             :         sd_resolve *resolve;
    1279             :         unsigned i;
    1280             : 
    1281           5 :         assert(q);
    1282             : 
    1283           5 :         if (!q->resolve)
    1284           1 :                 return;
    1285             : 
    1286           4 :         resolve = q->resolve;
    1287           4 :         assert(resolve->n_queries > 0);
    1288             : 
    1289           4 :         if (q->done) {
    1290           3 :                 assert(resolve->n_done > 0);
    1291           3 :                 resolve->n_done--;
    1292             :         }
    1293             : 
    1294           4 :         i = q->id % QUERIES_MAX;
    1295           4 :         assert(resolve->query_array[i] == q);
    1296           4 :         resolve->query_array[i] = NULL;
    1297           4 :         LIST_REMOVE(queries, resolve->queries, q);
    1298           4 :         resolve->n_queries--;
    1299             : 
    1300           4 :         q->resolve = NULL;
    1301           4 :         if (!q->floating)
    1302           3 :                 sd_resolve_unref(resolve);
    1303             : }
    1304             : 
    1305           4 : static void resolve_query_free(sd_resolve_query *q) {
    1306           4 :         assert(q);
    1307             : 
    1308           4 :         resolve_query_disconnect(q);
    1309             : 
    1310           4 :         resolve_freeaddrinfo(q->addrinfo);
    1311           4 :         free(q->host);
    1312           4 :         free(q->serv);
    1313           4 :         free(q->answer);
    1314           4 :         free(q);
    1315           4 : }
    1316             : 
    1317           7 : _public_ sd_resolve_query* sd_resolve_query_unref(sd_resolve_query* q) {
    1318           7 :         if (!q)
    1319           0 :                 return NULL;
    1320             : 
    1321           7 :         assert(q->n_ref >= 1);
    1322           7 :         q->n_ref--;
    1323             : 
    1324           7 :         if (q->n_ref <= 0)
    1325           4 :                 resolve_query_free(q);
    1326             : 
    1327           7 :         return NULL;
    1328             : }
    1329             : 
    1330           6 : _public_ int sd_resolve_query_is_done(sd_resolve_query *q) {
    1331           6 :         assert_return(q, -EINVAL);
    1332           6 :         assert_return(!resolve_pid_changed(q->resolve), -ECHILD);
    1333             : 
    1334           6 :         return q->done;
    1335             : }
    1336             : 
    1337           0 : _public_ void* sd_resolve_query_set_userdata(sd_resolve_query *q, void *userdata) {
    1338             :         void *ret;
    1339             : 
    1340           0 :         assert_return(q, NULL);
    1341           0 :         assert_return(!resolve_pid_changed(q->resolve), NULL);
    1342             : 
    1343           0 :         ret = q->userdata;
    1344           0 :         q->userdata = userdata;
    1345             : 
    1346           0 :         return ret;
    1347             : }
    1348             : 
    1349           0 : _public_ void* sd_resolve_query_get_userdata(sd_resolve_query *q) {
    1350           0 :         assert_return(q, NULL);
    1351           0 :         assert_return(!resolve_pid_changed(q->resolve), NULL);
    1352             : 
    1353           0 :         return q->userdata;
    1354             : }
    1355             : 
    1356           0 : _public_ sd_resolve *sd_resolve_query_get_resolve(sd_resolve_query *q) {
    1357           0 :         assert_return(q, NULL);
    1358           0 :         assert_return(!resolve_pid_changed(q->resolve), NULL);
    1359             : 
    1360           0 :         return q->resolve;
    1361             : }
    1362             : 
    1363           0 : static int io_callback(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
    1364           0 :         sd_resolve *resolve = userdata;
    1365             :         int r;
    1366             : 
    1367           0 :         assert(resolve);
    1368             : 
    1369           0 :         r = sd_resolve_process(resolve);
    1370           0 :         if (r < 0)
    1371           0 :                 return r;
    1372             : 
    1373           0 :         return 1;
    1374             : }
    1375             : 
    1376           0 : _public_ int sd_resolve_attach_event(sd_resolve *resolve, sd_event *event, int priority) {
    1377             :         int r;
    1378             : 
    1379           0 :         assert_return(resolve, -EINVAL);
    1380           0 :         assert_return(!resolve->event, -EBUSY);
    1381             : 
    1382           0 :         assert(!resolve->event_source);
    1383             : 
    1384           0 :         if (event)
    1385           0 :                 resolve->event = sd_event_ref(event);
    1386             :         else {
    1387           0 :                 r = sd_event_default(&resolve->event);
    1388           0 :                 if (r < 0)
    1389           0 :                         return r;
    1390             :         }
    1391             : 
    1392           0 :         r = sd_event_add_io(resolve->event, &resolve->event_source, resolve->fds[RESPONSE_RECV_FD], POLLIN, io_callback, resolve);
    1393           0 :         if (r < 0)
    1394           0 :                 goto fail;
    1395             : 
    1396           0 :         r = sd_event_source_set_priority(resolve->event_source, priority);
    1397           0 :         if (r < 0)
    1398           0 :                 goto fail;
    1399             : 
    1400           0 :         return 0;
    1401             : 
    1402             : fail:
    1403           0 :         sd_resolve_detach_event(resolve);
    1404           0 :         return r;
    1405             : }
    1406             : 
    1407           1 : _public_  int sd_resolve_detach_event(sd_resolve *resolve) {
    1408           1 :         assert_return(resolve, -EINVAL);
    1409             : 
    1410           1 :         if (!resolve->event)
    1411           1 :                 return 0;
    1412             : 
    1413           0 :         if (resolve->event_source) {
    1414           0 :                 sd_event_source_set_enabled(resolve->event_source, SD_EVENT_OFF);
    1415           0 :                 resolve->event_source = sd_event_source_unref(resolve->event_source);
    1416             :         }
    1417             : 
    1418           0 :         resolve->event = sd_event_unref(resolve->event);
    1419           0 :         return 1;
    1420             : }
    1421             : 
    1422           0 : _public_ sd_event *sd_resolve_get_event(sd_resolve *resolve) {
    1423           0 :         assert_return(resolve, NULL);
    1424             : 
    1425           0 :         return resolve->event;
    1426             : }

Generated by: LCOV version 1.11