]>
Commit | Line | Data |
---|---|---|
592119bc PL |
1 | /* |
2 | * mDNS registration handler. This file is part of Shairport. | |
3 | * Copyright (c) Paul Lietar 2013 | |
4 | * All rights reserved. | |
5 | * | |
6 | * Permission is hereby granted, free of charge, to any person | |
7 | * obtaining a copy of this software and associated documentation | |
8 | * files (the "Software"), to deal in the Software without | |
9 | * restriction, including without limitation the rights to use, | |
10 | * copy, modify, merge, publish, distribute, sublicense, and/or | |
11 | * sell copies of the Software, and to permit persons to whom the | |
12 | * Software is furnished to do so, subject to the following conditions: | |
13 | * | |
14 | * The above copyright notice and this permission notice shall be | |
15 | * included in all copies or substantial portions of the Software. | |
16 | * | |
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |
18 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES | |
19 | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | |
20 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT | |
21 | * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | |
22 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
23 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | |
24 | * OTHER DEALINGS IN THE SOFTWARE. | |
25 | */ | |
26 | ||
064bd293 MB |
27 | #include "mdns.h" |
28 | #include "common.h" | |
29 | #include <ifaddrs.h> | |
30 | #include <net/if.h> | |
31 | #include <netinet/in.h> | |
592119bc | 32 | #include <string.h> |
592119bc | 33 | #include <sys/socket.h> |
064bd293 | 34 | #include <sys/types.h> |
592119bc | 35 | #include <unistd.h> |
592119bc PL |
36 | |
37 | #include "tinysvcmdns.h" | |
38 | ||
39 | static struct mdnsd *svr = NULL; | |
40 | ||
6c1625e6 | 41 | static int mdns_tinysvcmdns_register(char *ap1name, __attribute__((unused)) char *ap2name, int port, |
fd880056 MB |
42 | __attribute__((unused)) char **txt_records, |
43 | __attribute__((unused)) char **secondary_txt_records) { | |
87a0475c MB |
44 | struct ifaddrs *ifalist; |
45 | struct ifaddrs *ifa; | |
46 | ||
47 | svr = mdnsd_start(); | |
48 | if (svr == NULL) { | |
49 | warn("tinysvcmdns: mdnsd_start() failed"); | |
50 | return -1; | |
51 | } | |
52 | ||
53 | // Thanks to Paul Lietar for this | |
54 | // room for name + .local + NULL | |
55 | char hostname[100 + 6]; | |
56 | gethostname(hostname, 99); | |
57 | // according to POSIX, this may be truncated without a final NULL ! | |
58 | hostname[99] = 0; | |
59 | ||
60 | // will not work if the hostname doesn't end in .local | |
61 | char *hostend = hostname + strlen(hostname); | |
62 | if ((strlen(hostname) < strlen(".local")) || (strcmp(hostend - 6, ".local") != 0)) { | |
63 | strcat(hostname, ".local"); | |
64 | } | |
65 | ||
66 | if (getifaddrs(&ifalist) < 0) { | |
67 | warn("tinysvcmdns: getifaddrs() failed"); | |
68 | return -1; | |
69 | } | |
70 | ||
71 | ifa = ifalist; | |
72 | ||
73 | // Look for an ipv4/ipv6 non-loopback interface to use as the main one. | |
74 | for (ifa = ifalist; ifa != NULL; ifa = ifa->ifa_next) { | |
2cab35cd | 75 | // only check for the named interface, if specified |
cf29625d MB |
76 | if ((config.interface == NULL) || (strcmp(config.interface, ifa->ifa_name) == 0)) { |
77 | ||
78 | if (!(ifa->ifa_flags & IFF_LOOPBACK) && ifa->ifa_addr && | |
79 | ifa->ifa_addr->sa_family == AF_INET) { | |
2cab35cd MB |
80 | uint32_t main_ip = ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr; |
81 | ||
82 | mdnsd_set_hostname(svr, hostname, main_ip); // TTL should be 120 seconds | |
83 | break; | |
84 | } else if (!(ifa->ifa_flags & IFF_LOOPBACK) && ifa->ifa_addr && | |
85 | ifa->ifa_addr->sa_family == AF_INET6) { | |
86 | struct in6_addr *addr = &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr; | |
87 | ||
88 | mdnsd_set_hostname_v6(svr, hostname, addr); // TTL should be 120 seconds | |
89 | break; | |
90 | } | |
592119bc | 91 | } |
87a0475c MB |
92 | } |
93 | ||
94 | if (ifa == NULL) { | |
95 | warn("tinysvcmdns: no non-loopback ipv4 or ipv6 interface found"); | |
96 | return -1; | |
97 | } | |
98 | ||
99 | // Skip the first one, it was already added by set_hostname | |
100 | for (ifa = ifa->ifa_next; ifa != NULL; ifa = ifa->ifa_next) { | |
101 | if (ifa->ifa_flags & IFF_LOOPBACK) // Skip loop-back interfaces | |
cf29625d | 102 | continue; |
2cab35cd | 103 | // only check for the named interface, if specified |
cf29625d | 104 | if ((config.interface == NULL) || (strcmp(config.interface, ifa->ifa_name) == 0)) { |
2cab35cd | 105 | switch (ifa->ifa_addr->sa_family) { |
cf29625d MB |
106 | case AF_INET: { // ipv4 |
107 | uint32_t ip = ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr; | |
108 | struct rr_entry *a_e = | |
109 | rr_create_a(create_nlabel(hostname), ip); // TTL should be 120 seconds | |
110 | mdnsd_add_rr(svr, a_e); | |
111 | } break; | |
112 | case AF_INET6: { // ipv6 | |
113 | struct in6_addr *addr = &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr; | |
114 | struct rr_entry *aaaa_e = | |
115 | rr_create_aaaa(create_nlabel(hostname), addr); // TTL should be 120 seconds | |
116 | mdnsd_add_rr(svr, aaaa_e); | |
117 | } break; | |
2cab35cd | 118 | } |
592119bc | 119 | } |
87a0475c | 120 | } |
592119bc | 121 | |
87a0475c | 122 | freeifaddrs(ifa); |
592119bc | 123 | |
87a0475c MB |
124 | char *txtwithoutmetadata[] = {MDNS_RECORD_WITHOUT_METADATA, NULL}; |
125 | #ifdef CONFIG_METADATA | |
126 | char *txtwithmetadata[] = {MDNS_RECORD_WITH_METADATA, NULL}; | |
127 | #endif | |
128 | char **txt; | |
592119bc | 129 | |
75f3f912 | 130 | #ifdef CONFIG_METADATA |
6ae067af | 131 | if (config.metadata_enabled) |
87a0475c MB |
132 | txt = txtwithmetadata; |
133 | else | |
75f3f912 MB |
134 | #endif |
135 | ||
87a0475c | 136 | txt = txtwithoutmetadata; |
064bd293 | 137 | |
52376ff4 | 138 | if (config.regtype == NULL) |
139 | die("tinysvcmdns: regtype is null"); | |
140 | ||
064bd293 | 141 | char *extendedregtype = malloc(strlen(config.regtype) + strlen(".local") + 1); |
46412eb1 | 142 | |
064bd293 | 143 | if (extendedregtype == NULL) |
bfadbf38 | 144 | die("tinysvcmdns: could not allocated memory to request a Zeroconf service"); |
592119bc | 145 | |
064bd293 MB |
146 | strcpy(extendedregtype, config.regtype); |
147 | strcat(extendedregtype, ".local"); | |
148 | ||
149 | struct mdns_service *svc = | |
6c1625e6 | 150 | mdnsd_register_svc(svr, ap1name, extendedregtype, port, NULL, |
bfadbf38 | 151 | (const char **)txt); // TTL should be 75 minutes, i.e. 4500 seconds |
87a0475c | 152 | mdns_service_destroy(svc); |
064bd293 | 153 | |
bfadbf38 | 154 | free(extendedregtype); |
592119bc | 155 | |
87a0475c | 156 | return 0; |
592119bc PL |
157 | } |
158 | ||
159 | static void mdns_tinysvcmdns_unregister(void) { | |
87a0475c MB |
160 | if (svr) { |
161 | mdnsd_stop(svr); | |
162 | svr = NULL; | |
163 | } | |
592119bc PL |
164 | } |
165 | ||
87a0475c MB |
166 | mdns_backend mdns_tinysvcmdns = {.name = "tinysvcmdns", |
167 | .mdns_register = mdns_tinysvcmdns_register, | |
139c18bf | 168 | .mdns_unregister = mdns_tinysvcmdns_unregister, |
72079ada MB |
169 | .mdns_dacp_monitor_start = NULL, |
170 | .mdns_dacp_monitor_set_id = NULL, | |
171 | .mdns_dacp_monitor_stop = NULL}; |