• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/mdnsd/ubus.c

  1 /*
  2  * Copyright (C) 2014 John Crispin <blogic@openwrt.org>
  3  *
  4  * This program is free software; you can redistribute it and/or modify
  5  * it under the terms of the GNU Lesser General Public License version 2.1
  6  * as published by the Free Software Foundation
  7  *
  8  * This program is distributed in the hope that it will be useful,
  9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 11  * GNU General Public License for more details.
 12  */
 13 
 14 #include <sys/types.h>
 15 #include <arpa/inet.h>
 16 
 17 #include <stdio.h>
 18 
 19 #include <libubus.h>
 20 #include <libubox/vlist.h>
 21 #include <libubox/uloop.h>
 22 
 23 #include "util.h"
 24 #include "ubus.h"
 25 #include "cache.h"
 26 #include "service.h"
 27 #include "interface.h"
 28 
 29 static struct ubus_auto_conn conn;
 30 static struct blob_buf b;
 31 static struct ubus_subscriber udebug_sub;
 32 
 33 static int
 34 umdns_reload(struct ubus_context *ctx, struct ubus_object *obj,
 35                 struct ubus_request_data *req, const char *method,
 36                 struct blob_attr *msg)
 37 {
 38         service_init(1);
 39         return 0;
 40 }
 41 
 42 static int
 43 umdns_update(struct ubus_context *ctx, struct ubus_object *obj,
 44                 struct ubus_request_data *req, const char *method,
 45                 struct blob_attr *msg)
 46 {
 47         cache_update();
 48         return 0;
 49 }
 50 
 51 enum {
 52         BROWSE_SERVICE,
 53         BROWSE_ARRAY,
 54         BROWSE_ADDRESS,
 55         BROWSE_MAX
 56 };
 57 
 58 static const struct blobmsg_policy browse_policy[] = {
 59         [BROWSE_SERVICE]        = { "service", BLOBMSG_TYPE_STRING },
 60         [BROWSE_ARRAY]          = { "array", BLOBMSG_TYPE_BOOL },
 61         [BROWSE_ADDRESS]        = { "address", BLOBMSG_TYPE_BOOL },
 62 };
 63 
 64 static int
 65 umdns_browse(struct ubus_context *ctx, struct ubus_object *obj,
 66                 struct ubus_request_data *req, const char *method,
 67                 struct blob_attr *msg)
 68 {
 69         struct cache_service *s, *q;
 70         char *buffer = (char *) mdns_buf;
 71         struct blob_attr *data[BROWSE_MAX];
 72         void *c1 = NULL, *c2;
 73         char *service = NULL;
 74         int array = 0;
 75         bool address = true;
 76 
 77         blobmsg_parse(browse_policy, BROWSE_MAX, data, blob_data(msg), blob_len(msg));
 78         if (data[BROWSE_SERVICE])
 79                 service = blobmsg_get_string(data[BROWSE_SERVICE]);
 80         if (data[BROWSE_ARRAY])
 81                 array = blobmsg_get_u8(data[BROWSE_ARRAY]);
 82         if (data[BROWSE_ADDRESS])
 83                 address = blobmsg_get_bool(data[BROWSE_ADDRESS]);
 84 
 85         blob_buf_init(&b, 0);
 86         avl_for_each_element(&services, s, avl) {
 87                 const char *hostname = buffer;
 88                 char *local;
 89 
 90                 snprintf(buffer, MAX_NAME_LEN, "%s", (const char *) s->avl.key);
 91                 local = strstr(buffer, ".local");
 92                 if (local)
 93                         *local = '\0';
 94                 if (!strcmp(buffer, "_tcp") || !strcmp(buffer, "_udp"))
 95                         continue;
 96                 if (service && strcmp(buffer, service))
 97                         continue;
 98                 if (!c1) {
 99                         c1 = blobmsg_open_table(&b, buffer);
100                 }
101                 snprintf(buffer, MAX_NAME_LEN, "%s", s->entry);
102                 local = strstr(buffer, "._");
103                 if (local)
104                         *local = '\0';
105                 c2 = blobmsg_open_table(&b, buffer);
106                 strncat(buffer, ".local", MAX_NAME_LEN);
107                 if (s->iface)
108                         blobmsg_add_string(&b, "iface", s->iface->name);
109                 cache_dump_records(&b, s->entry, array, &hostname);
110                 if (address)
111                         cache_dump_records(&b, hostname, array, NULL);
112                 blobmsg_close_table(&b, c2);
113                 q = avl_next_element(s, avl);
114                 if (!q || avl_is_last(&services, &s->avl) || strcmp(s->avl.key, q->avl.key)) {
115                         blobmsg_close_table(&b, c1);
116                         c1 = NULL;
117                 }
118         }
119         ubus_send_reply(ctx, req, b.head);
120 
121         return UBUS_STATUS_OK;
122 }
123 
124 enum {
125         HOSTS_ARRAY,
126         __HOSTS_MAX
127 };
128 static const struct blobmsg_policy hosts_policy[] = {
129         [HOSTS_ARRAY] = { "array", BLOBMSG_TYPE_BOOL }
130 };
131 
132 static int
133 umdns_hosts(struct ubus_context *ctx, struct ubus_object *obj,
134                 struct ubus_request_data *req, const char *method,
135                 struct blob_attr *msg)
136 {
137         struct cache_record *prev = NULL;
138         struct blob_attr *tb[__HOSTS_MAX];
139         struct cache_record *r;
140         bool array = false;
141         void *c;
142 
143         blobmsg_parse(hosts_policy, __HOSTS_MAX, tb, blobmsg_data(msg), blobmsg_len(msg));
144         if (tb[HOSTS_ARRAY])
145                 array = blobmsg_get_bool(tb[HOSTS_ARRAY]);
146 
147         blob_buf_init(&b, 0);
148         avl_for_each_element(&records, r, avl) {
149                 if (r->type != TYPE_A && r->type != TYPE_AAAA)
150                         continue;
151                 /* Query each domain just once */
152                 if (!prev || strcmp(r->record, prev->record)) {
153                         c = blobmsg_open_table(&b, r->record);
154                         cache_dump_records(&b, r->record, array, NULL);
155                         blobmsg_close_table(&b, c);
156                 }
157                 prev = r;
158         }
159         ubus_send_reply(ctx, req, b.head);
160 
161         return UBUS_STATUS_OK;
162 }
163 
164 enum {
165         CFG_INTERFACES,
166         CFG_KEEP,
167         CFG_MAX
168 };
169 
170 static const struct blobmsg_policy config_policy[] = {
171         [CFG_INTERFACES]        = { "interfaces", BLOBMSG_TYPE_ARRAY },
172         [CFG_KEEP]              = { "keep", BLOBMSG_TYPE_BOOL },
173 };
174 
175 static int
176 umdns_set_config(struct ubus_context *ctx, struct ubus_object *obj,
177                     struct ubus_request_data *req, const char *method,
178                     struct blob_attr *msg)
179 {
180         struct blob_attr *data[CFG_MAX], *cur;
181         int rem, keep = false;
182 
183         blobmsg_parse(config_policy, CFG_MAX, data, blob_data(msg), blob_len(msg));
184         if (!data[CFG_INTERFACES])
185                 return UBUS_STATUS_INVALID_ARGUMENT;
186 
187         if (!blobmsg_check_attr_list(data[CFG_INTERFACES], BLOBMSG_TYPE_STRING))
188                 return UBUS_STATUS_INVALID_ARGUMENT;
189 
190         keep = data[CFG_KEEP] && blobmsg_get_bool(data[CFG_KEEP]);
191         if (!keep) {
192                 vlist_update(&interfaces);
193                 ubus_notify(ctx, obj, "set_config", NULL, 1000);
194         }
195 
196         blobmsg_for_each_attr(cur, data[CFG_INTERFACES], rem)
197                 interface_add(blobmsg_data(cur));
198 
199         if (!keep)
200                 vlist_flush(&interfaces);
201 
202         return 0;
203 }
204 
205 enum query_attr {
206         QUERY_QUESTION,
207         QUERY_IFACE,
208         QUERY_TYPE,
209         QUERY_MAX
210 };
211 
212 static const struct blobmsg_policy query_policy[QUERY_MAX] = {
213         [QUERY_QUESTION]= { "question", BLOBMSG_TYPE_STRING },
214         [QUERY_IFACE]   = { "interface", BLOBMSG_TYPE_STRING },
215         [QUERY_TYPE]    = { "type", BLOBMSG_TYPE_INT32 },
216 };
217 
218 static int
219 umdns_query(struct ubus_context *ctx, struct ubus_object *obj,
220                     struct ubus_request_data *req, const char *method,
221                     struct blob_attr *msg)
222 {
223         struct blob_attr *tb[QUERY_MAX], *c;
224         const char *question = C_DNS_SD;
225         const char *ifname;
226         int type = TYPE_ANY;
227 
228         blobmsg_parse(query_policy, QUERY_MAX, tb, blob_data(msg), blob_len(msg));
229 
230         if (!(c = tb[QUERY_IFACE]))
231                 return UBUS_STATUS_INVALID_ARGUMENT;
232 
233         ifname = blobmsg_get_string(c);
234 
235         if ((c = tb[QUERY_QUESTION]))
236                 question = blobmsg_get_string(c);
237 
238         if ((c = tb[QUERY_TYPE]))
239                 type = blobmsg_get_u32(c);
240 
241         struct interface *iface_v4 = interface_get(ifname, SOCK_MC_IPV4);
242         struct interface *iface_v6 = interface_get(ifname, SOCK_MC_IPV6);
243 
244         if (!iface_v4 && !iface_v6)
245                 return UBUS_STATUS_NOT_FOUND;
246 
247         if (!strcmp(method, "query")) {
248                 if (iface_v4)
249                         dns_send_question(iface_v4, NULL, question, type, 1);
250 
251                 if (iface_v6)
252                         dns_send_question(iface_v6, NULL, question, type, 1);
253 
254                 return UBUS_STATUS_OK;
255         } else if (!strcmp(method, "fetch")) {
256                 blob_buf_init(&b, 0);
257                 void *k = blobmsg_open_array(&b, "records");
258                 cache_dump_recursive(&b, question, type, iface_v4 ? iface_v4 : iface_v6);
259                 blobmsg_close_array(&b, k);
260                 ubus_send_reply(ctx, req, b.head);
261                 return UBUS_STATUS_OK;
262         } else {
263                 return UBUS_STATUS_INVALID_ARGUMENT;
264         }
265 }
266 
267 
268 static const struct ubus_method umdns_methods[] = {
269         UBUS_METHOD("set_config", umdns_set_config, config_policy),
270         UBUS_METHOD("query", umdns_query, query_policy),
271         UBUS_METHOD("fetch", umdns_query, query_policy),
272         UBUS_METHOD("browse", umdns_browse, browse_policy),
273         UBUS_METHOD_NOARG("update", umdns_update),
274         UBUS_METHOD("hosts", umdns_hosts, hosts_policy),
275         UBUS_METHOD_NOARG("reload", umdns_reload),
276 };
277 
278 static struct ubus_object_type umdns_object_type =
279         UBUS_OBJECT_TYPE("umdns", umdns_methods);
280 
281 static struct ubus_object umdns_object = {
282         .name = "umdns",
283         .type = &umdns_object_type,
284         .methods = umdns_methods,
285         .n_methods = ARRAY_SIZE(umdns_methods),
286 };
287 
288 static struct blob_attr *
289 find_attr(struct blob_attr *attr, const char *name, enum blobmsg_type type)
290 {
291         struct blobmsg_policy policy = { name, type };
292         struct blob_attr *ret;
293 
294         if (!attr)
295                 return NULL;
296 
297         blobmsg_parse_attr(&policy, 1, &ret, attr);
298 
299         return ret;
300 }
301 
302 static void
303 umdns_udebug_config_cb(struct blob_attr *data)
304 {
305         enum {
306                 CFG_ATTR_ENABLED,
307                 __CFG_ATTR_MAX
308         };
309         static const struct blobmsg_policy policy[__CFG_ATTR_MAX] = {
310                 [CFG_ATTR_ENABLED] = { "enabled", BLOBMSG_TYPE_STRING },
311         };
312         struct blob_attr *tb[__CFG_ATTR_MAX];
313         bool en;
314 
315         data = find_attr(data, "service", BLOBMSG_TYPE_TABLE);
316         data = find_attr(data, "umdns", BLOBMSG_TYPE_TABLE);
317         if (!data)
318                 return;
319 
320         blobmsg_parse_attr(policy, __CFG_ATTR_MAX, tb, data);
321         if (!tb[CFG_ATTR_ENABLED])
322                 return;
323 
324         en = !!atoi(blobmsg_get_string(tb[CFG_ATTR_ENABLED]));
325         umdns_udebug_set_enabled(en);
326 }
327 
328 static int
329 umdns_udebug_notify_cb(struct ubus_context *ctx, struct ubus_object *obj,
330                         struct ubus_request_data *req, const char *method,
331                         struct blob_attr *msg)
332 {
333         umdns_udebug_config_cb(msg);
334 
335         return 0;
336 }
337 
338 static void
339 umdns_udebug_req_cb(struct ubus_request *req, int type, struct blob_attr *msg)
340 {
341         umdns_udebug_config_cb(msg);
342 }
343 
344 static bool
345 umdns_udebug_sub_cb(struct ubus_context *ctx, struct ubus_subscriber *sub,
346                      const char *path)
347 {
348         return !strcmp(path, "udebug");
349 }
350 
351 
352 static void
353 ubus_connect_handler(struct ubus_context *ctx)
354 {
355         uint32_t id;
356         int ret;
357 
358         ret = ubus_add_object(ctx, &umdns_object);
359         if (ret)
360                 fprintf(stderr, "Failed to add object: %s\n", ubus_strerror(ret));
361 
362         udebug_sub.cb = umdns_udebug_notify_cb;
363         udebug_sub.new_obj_cb = umdns_udebug_sub_cb;
364         ubus_register_subscriber(&conn.ctx, &udebug_sub);
365         if (ubus_lookup_id(&conn.ctx, "udebug", &id) == 0) {
366                 ubus_subscribe(&conn.ctx, &udebug_sub, id);
367                 ubus_invoke(&conn.ctx, id, "get_config", NULL, umdns_udebug_req_cb, NULL, 1000);
368         }
369 }
370 
371 void
372 ubus_startup(void)
373 {
374         conn.cb = ubus_connect_handler;
375         ubus_auto_connect(&conn);
376 }
377 
378 int ubus_service_list(ubus_data_handler_t cb)
379 {
380         uint32_t id;
381         int ret;
382 
383         blob_buf_init(&b, 0);
384         ret = ubus_lookup_id(&conn.ctx, "service", &id);
385         if (ret)
386                 return ret;
387 
388         return ubus_invoke(&conn.ctx, id, "list", b.head, cb, NULL, 5 * 1000);
389 }
390 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt