X-Git-Url: http://git.openwrt.org/openwrt/feeds.git?a=blobdiff_plain;f=service.c;h=b693b3127b4cf54f08e49cb2df6d4d9550d5495b;hb=HEAD;hp=993e7cfd10d7a089b73b331e696affe14878732d;hpb=c3c168c1cc39539f5ec452ab2f556e78bfa92917;p=project%2Fmdnsd.git diff --git a/service.c b/service.c index 993e7cf..b693b31 100644 --- a/service.c +++ b/service.c @@ -17,6 +17,7 @@ #include #include +#include #include #include @@ -34,9 +35,11 @@ #include "announce.h" enum { + SERVICE_INSTANCE, SERVICE_SERVICE, SERVICE_PORT, SERVICE_TXT, + SERVICE_HOSTNAME, __SERVICE_MAX, }; @@ -46,6 +49,7 @@ struct service { time_t t; const char *id; + const char *instance; const char *service; const uint8_t *txt; int txt_len; @@ -54,26 +58,41 @@ struct service { }; static const struct blobmsg_policy service_policy[__SERVICE_MAX] = { + [SERVICE_INSTANCE] = { .name = "instance", .type = BLOBMSG_TYPE_STRING }, [SERVICE_SERVICE] = { .name = "service", .type = BLOBMSG_TYPE_STRING }, [SERVICE_PORT] = { .name = "port", .type = BLOBMSG_TYPE_INT32 }, [SERVICE_TXT] = { .name = "txt", .type = BLOBMSG_TYPE_ARRAY }, + [SERVICE_HOSTNAME] = { .name = "hostname", .type = BLOBMSG_TYPE_STRING }, }; static void service_update(struct vlist_tree *tree, struct vlist_node *node_new, struct vlist_node *node_old); +static void +hostname_update(struct vlist_tree *tree, struct vlist_node *node_new, + struct vlist_node *node_old); + static struct blob_buf b; static VLIST_TREE(services, avl_strcmp, service_update, false, false); -char *sdudp = "_services._dns-sd._udp.local"; +VLIST_TREE(hostnames, avl_strcmp, hostname_update, false, false); static int service_init_announce; +/** + * service_instance_name - construct Service Instance Name as in RFC 6763 + * + * RFC 6763 specifies Service Instance Names in the following way: + * + * Service Instance Name = . . + * + * @s: service to generate service instance name for + */ static const char * -service_name(const char *domain) +service_instance_name(struct service *s) { static char buffer[256]; - snprintf(buffer, sizeof(buffer), "%s.%s", mdns_hostname, domain); + snprintf(buffer, sizeof(buffer), "%s.%s", s->instance, s->service); return buffer; } @@ -110,16 +129,18 @@ service_timeout(struct service *s) { time_t t = monotonic_time(); - if (t - s->t <= TOUT_LOOKUP) + if (t - s->t <= TOUT_LOOKUP) { + DBG(2, "t=%" PRId64 ", s->t=%" PRId64 ", t - s->t = %" PRId64 "\n", (int64_t)t, (int64_t)s->t, (int64_t)(t - s->t)); return 0; + } return t; } static void -service_reply_single(struct interface *iface, struct service *s, int ttl, int force) +service_reply_single(struct interface *iface, struct sockaddr *to, struct service *s, int ttl, int force) { - const char *host = service_name(s->service); + const char *host = service_instance_name(s); char *service = strstr(host, "._"); time_t t = service_timeout(s); @@ -132,29 +153,32 @@ service_reply_single(struct interface *iface, struct service *s, int ttl, int fo s->t = t; dns_init_answer(); - service_add_ptr(service_name(s->service), ttl); - dns_send_answer(iface, service); + service_add_ptr(service_instance_name(s), ttl); + dns_send_answer(iface, to, service); dns_init_answer(); service_add_srv(s, ttl); if (s->txt && s->txt_len) dns_add_answer(TYPE_TXT, (uint8_t *) s->txt, s->txt_len, ttl); - dns_send_answer(iface, host); + dns_send_answer(iface, to, host); } void -service_reply(struct interface *iface, const char *match, int ttl) +service_reply(struct interface *iface, struct sockaddr *to, const char *instance, const char *service_domain, int ttl) { struct service *s; vlist_for_each_element(&services, s, node) { - if (!match || !strcmp(s->service, match)) - service_reply_single(iface, s, ttl, 0); + if (instance && strcmp(s->instance, instance)) + continue; + if (service_domain && strcmp(s->service, service_domain)) + continue; + service_reply_single(iface, to, s, ttl, 0); } } void -service_announce_services(struct interface *iface, int ttl) +service_announce_services(struct interface *iface, struct sockaddr *to, int ttl) { struct service *s; @@ -163,18 +187,12 @@ service_announce_services(struct interface *iface, int ttl) if (ttl) { dns_init_answer(); service_add_ptr(s->service, ttl); - dns_send_answer(iface, sdudp); + dns_send_answer(iface, to, C_DNS_SD); } - service_reply_single(iface, s, ttl, 0); + service_reply_single(iface, to, s, ttl, 0); } } -void -service_announce(struct interface *iface, int ttl) -{ - service_announce_services(iface, ttl); -} - static void service_update(struct vlist_tree *tree, struct vlist_node *node_new, struct vlist_node *node_old) @@ -187,7 +205,7 @@ service_update(struct vlist_tree *tree, struct vlist_node *node_new, if (service_init_announce) vlist_for_each_element(&interfaces, iface, node) { s->t = 0; - service_reply_single(iface, s, announce_ttl, 1); + service_reply_single(iface, NULL, s, announce_ttl, 1); } return; } @@ -195,22 +213,67 @@ service_update(struct vlist_tree *tree, struct vlist_node *node_new, s = container_of(node_old, struct service, node); if (!node_new && service_init_announce) vlist_for_each_element(&interfaces, iface, node) - service_reply_single(iface, s, 0, 1); + service_reply_single(iface, NULL, s, 0, 1); free(s); } +static void +hostname_update(struct vlist_tree *tree, struct vlist_node *node_new, + struct vlist_node *node_old) +{ + struct interface *iface; + struct hostname *h; + + if (!node_old) { + h = container_of(node_new, struct hostname, node); + vlist_for_each_element(&interfaces, iface, node) + dns_reply_a(iface, NULL, announce_ttl, h->hostname); + return; + } + + h = container_of(node_old, struct hostname, node); + if (!node_new) + vlist_for_each_element(&interfaces, iface, node) + dns_reply_a(iface, NULL, 0, h->hostname); + + free(h); +} + +static void +service_load_hostname(struct blob_attr *b) +{ + struct hostname *h; + char *hostname, *d_hostname; + + hostname = blobmsg_get_string(b); + h = calloc_a(sizeof(*h), &d_hostname, strlen(hostname) + 1); + if (!h) + return; + + h->hostname = strcpy(d_hostname, hostname); + + vlist_add(&hostnames, &h->node, h->hostname); +} + static void service_load_blob(struct blob_attr *b) { struct blob_attr *txt, *_tb[__SERVICE_MAX]; struct service *s; - char *d_service, *d_id; + char *d_instance, *d_service, *d_id; uint8_t *d_txt; int rem2; int txt_len = 0; + unsigned int n; blobmsg_parse(service_policy, ARRAY_SIZE(service_policy), _tb, blobmsg_data(b), blobmsg_data_len(b)); + + if (_tb[SERVICE_HOSTNAME]) { + service_load_hostname(_tb[SERVICE_HOSTNAME]); + return; + } + if (!_tb[SERVICE_PORT] || !_tb[SERVICE_SERVICE]) return; @@ -218,15 +281,21 @@ service_load_blob(struct blob_attr *b) blobmsg_for_each_attr(txt, _tb[SERVICE_TXT], rem2) txt_len += 1 + strlen(blobmsg_get_string(txt)); + n = strlen(blobmsg_name(b)); s = calloc_a(sizeof(*s), - &d_id, strlen(blobmsg_name(b)) + 1, + &d_id, n + 1, + &d_instance, _tb[SERVICE_INSTANCE] ? strlen(blobmsg_get_string(_tb[SERVICE_INSTANCE])) + 1 : 0, &d_service, strlen(blobmsg_get_string(_tb[SERVICE_SERVICE])) + 1, &d_txt, txt_len); if (!s) return; s->port = blobmsg_get_u32(_tb[SERVICE_PORT]); - s->id = strcpy(d_id, blobmsg_name(b)); + s->id = strncpy(d_id, blobmsg_name(b), n); + if (_tb[SERVICE_INSTANCE]) + s->instance = strcpy(d_instance, blobmsg_get_string(_tb[SERVICE_INSTANCE])); + else + s->instance = umdns_host_label; s->service = strcpy(d_service, blobmsg_get_string(_tb[SERVICE_SERVICE])); s->active = 1; s->t = 0; @@ -261,9 +330,12 @@ service_load(char *path) for (i = 0; i < gl.gl_pathc; i++) { blob_buf_init(&b, 0); - if (blobmsg_add_json_from_file(&b, gl.gl_pathv[i])) + if (blobmsg_add_json_from_file(&b, gl.gl_pathv[i])) { blob_for_each_attr(cur, b.head, rem) service_load_blob(cur); + } else { + fprintf(stderr, "Error reading %s JSON\n", gl.gl_pathv[i]); + } } globfree(&gl); } @@ -277,7 +349,8 @@ service_init_cb(struct ubus_request *req, int type, struct blob_attr *msg) get_hostname(); vlist_update(&services); - service_load("/tmp/run/mdns/*"); + vlist_update(&hostnames); + service_load("/etc/umdns/*"); blob_for_each_attr(cur, msg, rem) { struct blob_attr *cur2; @@ -321,6 +394,7 @@ service_init_cb(struct ubus_request *req, int type, struct blob_attr *msg) } } vlist_flush(&services); + vlist_flush(&hostnames); } void