chiark / gitweb /
resolve: update sd-resolve to match the other APIs in style and functionality
[elogind.git] / src / libsystemd / sd-resolve / test-resolve.c
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 <string.h>
23 #include <sys/types.h>
24 #include <sys/socket.h>
25 #include <arpa/inet.h>
26 #include <stdio.h>
27 #include <netinet/in.h>
28 #include <arpa/nameser.h>
29 #include <resolv.h>
30 #include <assert.h>
31 #include <signal.h>
32 #include <errno.h>
33
34 #include "sd-resolve.h"
35 #include "resolve-util.h"
36 #include "macro.h"
37
38 int main(int argc, char *argv[]) {
39         int r = 1;
40         _cleanup_resolve_unref_ sd_resolve *resolve = NULL;
41         _cleanup_resolve_addrinfo_free_ struct addrinfo *ai = NULL;
42         _cleanup_free_ unsigned char *srv = NULL;
43         sd_resolve_query *q1 = NULL, *q2 = NULL, *q3 = NULL;
44         struct addrinfo hints = {};
45         struct sockaddr_in sa = {};
46         _cleanup_free_ char *host = NULL, *serv = NULL;
47
48         assert_se(sd_resolve_new(&resolve) >= 0);
49
50         /* Make a name -> address query */
51         hints.ai_family = PF_UNSPEC;
52         hints.ai_socktype = SOCK_STREAM;
53         hints.ai_flags = AI_CANONNAME;
54
55         r = sd_resolve_getaddrinfo(resolve, argc >= 2 ? argv[1] : "www.heise.de", NULL, &hints, &q1);
56         if (r < 0)
57                 log_error("sd_resolve_getaddrinfo(): %s\n", strerror(-r));
58
59         /* Make an address -> name query */
60         sa.sin_family = AF_INET;
61         sa.sin_addr.s_addr = inet_addr(argc >= 3 ? argv[2] : "193.99.144.71");
62         sa.sin_port = htons(80);
63
64         r = sd_resolve_getnameinfo(resolve, (struct sockaddr*) &sa, sizeof(sa), 0, true, true, &q2);
65         if (r < 0)
66                 log_error("sd_resolve_getnameinfo(): %s\n", strerror(-r));
67
68         /* Make a res_query() call */
69         r = sd_resolve_res_query(resolve, "_xmpp-client._tcp.gmail.com", C_IN, T_SRV, &q3);
70         if (r < 0)
71                 log_error("sd_resolve_res_query(): %s\n", strerror(-r));
72
73         /* Wait until the three queries are completed */
74         while (sd_resolve_is_done(q1) == 0 ||
75                sd_resolve_is_done(q2) == 0 ||
76                sd_resolve_is_done(q3) == 0) {
77
78                 r = sd_resolve_wait(resolve, (uint64_t) -1);
79                 if (r < 0) {
80                         log_error("sd_resolve_wait(): %s\n", strerror(-r));
81                         assert_not_reached("sd_resolve_wait() failed");
82                 }
83         }
84
85         /* Interpret the result of the name -> addr query */
86         r = sd_resolve_getaddrinfo_done(q1, &ai);
87         if (r != 0)
88                 log_error("error: %s %i\n", gai_strerror(r), r);
89         else {
90                 struct addrinfo *i;
91
92                 for (i = ai; i; i = i->ai_next) {
93                         char t[256];
94                         const char *p = NULL;
95
96                         if (i->ai_family == PF_INET)
97                                 p = inet_ntop(AF_INET, &((struct sockaddr_in*) i->ai_addr)->sin_addr, t, sizeof(t));
98                         else if (i->ai_family == PF_INET6)
99                                 p = inet_ntop(AF_INET6, &((struct sockaddr_in6*) i->ai_addr)->sin6_addr, t, sizeof(t));
100
101                         printf("%s\n", p);
102                 }
103
104                 printf("canonical name: %s\n", strna(ai->ai_canonname));
105         }
106
107         /* Interpret the result of the addr -> name query */
108         r = sd_resolve_getnameinfo_done(q2, &host, &serv);
109         if (r)
110                 log_error("error: %s %i\n", gai_strerror(r), r);
111         else
112                 printf("%s -- %s\n", host, serv);
113
114         /* Interpret the result of the SRV lookup */
115         r = sd_resolve_res_done(q3, &srv);
116         if (r < 0)
117                 log_error("error: %s %i\n", strerror(-r), r);
118         else if (r == 0)
119                 log_error("No reply for SRV lookup\n");
120         else {
121                 int qdcount;
122                 int ancount;
123                 int len;
124                 const unsigned char *pos = srv + sizeof(HEADER);
125                 unsigned char *end = srv + r;
126                 HEADER *head = (HEADER *)srv;
127                 char name[256];
128
129                 qdcount = ntohs(head->qdcount);
130                 ancount = ntohs(head->ancount);
131
132                 printf("%d answers for srv lookup:\n", ancount);
133
134                 /* Ignore the questions */
135                 while (qdcount-- > 0 && (len = dn_expand(srv, end, pos, name, 255)) >= 0) {
136                         assert(len >= 0);
137                         pos += len + QFIXEDSZ;
138                 }
139
140                 /* Parse the answers */
141                 while (ancount-- > 0 && (len = dn_expand(srv, end, pos, name, 255)) >= 0) {
142                         /* Ignore the initial string */
143                         uint16_t pref, weight, port;
144                         assert(len >= 0);
145                         pos += len;
146                         /* Ignore type, ttl, class and dlen */
147                         pos += 10;
148
149                         GETSHORT(pref, pos);
150                         GETSHORT(weight, pos);
151                         GETSHORT(port, pos);
152                         len = dn_expand(srv, end, pos, name, 255);
153                         printf("\tpreference: %2d weight: %2d port: %d host: %s\n",
154                                         pref, weight, port, name);
155
156                         pos += len;
157                 }
158         }
159
160         r = 0;
161
162         return r;
163 }