ubus.c 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  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. #include <sys/types.h>
  14. #include <arpa/inet.h>
  15. #include <stdio.h>
  16. #include <libubus.h>
  17. #include <libubox/avl.h>
  18. #include <libubox/uloop.h>
  19. #include "ubus.h"
  20. #include "cache.h"
  21. static struct ubus_auto_conn conn;
  22. static struct blob_buf b;
  23. static int
  24. mdns_reload(struct ubus_context *ctx, struct ubus_object *obj,
  25. struct ubus_request_data *req, const char *method,
  26. struct blob_attr *msg)
  27. {
  28. return 0;
  29. }
  30. static int
  31. mdns_scan(struct ubus_context *ctx, struct ubus_object *obj,
  32. struct ubus_request_data *req, const char *method,
  33. struct blob_attr *msg)
  34. {
  35. cache_scan();
  36. return 0;
  37. }
  38. static void
  39. mdns_add_records(char *name)
  40. {
  41. struct cache_record *r, *q = avl_find_element(&records, name, r, avl);
  42. char *txt;
  43. char buffer[MAX_NAME_LEN];
  44. if (!q)
  45. return;
  46. do {
  47. r = q;
  48. switch (r->type) {
  49. case TYPE_TXT:
  50. if (r->txt && strlen(r->txt)) {
  51. txt = r->txt;
  52. do {
  53. blobmsg_add_string(&b, "txt", txt);
  54. txt = &txt[strlen(txt) + 1];
  55. } while (*txt);
  56. }
  57. break;
  58. case TYPE_SRV:
  59. if (r->port)
  60. blobmsg_add_u32(&b, "port", r->port);
  61. break;
  62. case TYPE_A:
  63. if ((r->rdlength == 4) && inet_ntop(AF_INET, r->rdata, buffer, INET6_ADDRSTRLEN))
  64. blobmsg_add_string(&b, "ipv4", buffer);
  65. break;
  66. case TYPE_AAAA:
  67. if ((r->rdlength == 16) && inet_ntop(AF_INET6, r->rdata, buffer, INET6_ADDRSTRLEN))
  68. blobmsg_add_string(&b, "ipv6", buffer);
  69. break;
  70. }
  71. q = avl_next_element(r, avl);
  72. } while (q && !strcmp(r->record, q->record));
  73. }
  74. static int
  75. mdns_browse(struct ubus_context *ctx, struct ubus_object *obj,
  76. struct ubus_request_data *req, const char *method,
  77. struct blob_attr *msg)
  78. {
  79. struct cache_entry *s, *q;
  80. char buffer[MAX_NAME_LEN];
  81. void *c1 = NULL, *c2;
  82. blob_buf_init(&b, 0);
  83. avl_for_each_element(&entries, s, avl) {
  84. char *local;
  85. if (*((char *) s->avl.key) != '_')
  86. continue;
  87. snprintf(buffer, MAX_NAME_LEN, s->avl.key);
  88. local = strstr(buffer, ".local");
  89. if (local)
  90. *local = '\0';
  91. if (!strcmp(buffer, "_tcp") || !strcmp(buffer, "_udp"))
  92. continue;
  93. if (!c1) {
  94. char *type = cache_lookup_name(buffer);
  95. c1 = blobmsg_open_table(&b, buffer);
  96. if (type)
  97. blobmsg_add_string(&b, ".desc", type);
  98. }
  99. snprintf(buffer, MAX_NAME_LEN, s->entry);
  100. local = strstr(buffer, "._");
  101. if (local)
  102. *local = '\0';
  103. c2 = blobmsg_open_table(&b, buffer);
  104. strncat(buffer, ".local", MAX_NAME_LEN);
  105. mdns_add_records(buffer);
  106. mdns_add_records(s->entry);
  107. blobmsg_close_table(&b, c2);
  108. q = avl_next_element(s, avl);
  109. if (!q || avl_is_last(&entries, &s->avl) || strcmp(s->avl.key, q->avl.key)) {
  110. blobmsg_close_table(&b, c1);
  111. c1 = NULL;
  112. }
  113. }
  114. ubus_send_reply(ctx, req, b.head);
  115. return UBUS_STATUS_OK;
  116. }
  117. static int
  118. mdns_hosts(struct ubus_context *ctx, struct ubus_object *obj,
  119. struct ubus_request_data *req, const char *method,
  120. struct blob_attr *msg)
  121. {
  122. struct cache_entry *s;
  123. char buffer[MAX_NAME_LEN];
  124. void *c;
  125. blob_buf_init(&b, 0);
  126. avl_for_each_element(&entries, s, avl) {
  127. char *local;
  128. if (*((char *) s->avl.key) == '_')
  129. continue;
  130. snprintf(buffer, MAX_NAME_LEN, s->entry);
  131. local = strstr(buffer, "._");
  132. if (local)
  133. *local = '\0';
  134. c = blobmsg_open_table(&b, buffer);
  135. strncat(buffer, ".local", MAX_NAME_LEN);
  136. mdns_add_records(buffer);
  137. mdns_add_records(s->entry);
  138. blobmsg_close_table(&b, c);
  139. }
  140. ubus_send_reply(ctx, req, b.head);
  141. return UBUS_STATUS_OK;
  142. }
  143. static const struct ubus_method mdns_methods[] = {
  144. UBUS_METHOD_NOARG("scan", mdns_scan),
  145. UBUS_METHOD_NOARG("browse", mdns_browse),
  146. UBUS_METHOD_NOARG("hosts", mdns_hosts),
  147. UBUS_METHOD_NOARG("reload", mdns_reload),
  148. };
  149. static struct ubus_object_type mdns_object_type =
  150. UBUS_OBJECT_TYPE("mdns", mdns_methods);
  151. static struct ubus_object mdns_object = {
  152. .name = "mdns",
  153. .type = &mdns_object_type,
  154. .methods = mdns_methods,
  155. .n_methods = ARRAY_SIZE(mdns_methods),
  156. };
  157. static void
  158. ubus_connect_handler(struct ubus_context *ctx)
  159. {
  160. int ret;
  161. ret = ubus_add_object(ctx, &mdns_object);
  162. if (ret)
  163. fprintf(stderr, "Failed to add object: %s\n", ubus_strerror(ret));
  164. }
  165. void
  166. ubus_startup(void)
  167. {
  168. conn.cb = ubus_connect_handler;
  169. ubus_auto_connect(&conn);
  170. }