|
1 /* |
|
2 * Copyright 2007 Intel Corporation |
|
3 * |
|
4 * Licensed under the Apache License, Version 2.0 (the "License"); |
|
5 * you may not use this file except in compliance with the License. |
|
6 * You may obtain a copy of the License at |
|
7 * |
|
8 * http://www.apache.org/licenses/LICENSE-2.0 |
|
9 * |
|
10 * Unless required by applicable law or agreed to in writing, software |
|
11 * distributed under the License is distributed on an "AS IS" BASIS, |
|
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
13 * See the License for the specific language governing permissions and |
|
14 * limitations under the License. |
|
15 */ |
|
16 |
|
17 #ifdef HAVE_CONFIG_H |
|
18 # include <dtn-config.h> |
|
19 #endif |
|
20 |
|
21 #ifdef OASYS_BONJOUR_ENABLED |
|
22 |
|
23 #include "BonjourDiscovery.h" |
|
24 #include "bundling/BundleDaemon.h" |
|
25 #include "conv_layers/TCPConvergenceLayer.h" |
|
26 |
|
27 #define ADDRESS_KEY "local_eid" |
|
28 |
|
29 namespace dtn { |
|
30 |
|
31 //---------------------------------------------------------------------- |
|
32 BonjourDiscovery::BonjourDiscovery(const std::string& name) |
|
33 : Discovery(name, "bonjour"), |
|
34 oasys::Thread("BonjourDiscovery"), |
|
35 notifier_("/dtn/discovery/bonjour"), |
|
36 shutdown_(false) |
|
37 { |
|
38 } |
|
39 |
|
40 //---------------------------------------------------------------------- |
|
41 BonjourDiscovery::~BonjourDiscovery() |
|
42 { |
|
43 // XXX/demmer call DNSServiceRefDeallocate?? |
|
44 } |
|
45 |
|
46 //---------------------------------------------------------------------- |
|
47 bool |
|
48 BonjourDiscovery::configure(int argc, const char* argv[]) |
|
49 { |
|
50 (void)argc; |
|
51 (void)argv; |
|
52 |
|
53 start(); |
|
54 return true; |
|
55 } |
|
56 |
|
57 //---------------------------------------------------------------------- |
|
58 void |
|
59 BonjourDiscovery::shutdown() |
|
60 { |
|
61 shutdown_ = true; |
|
62 notifier_.notify(); |
|
63 } |
|
64 |
|
65 //---------------------------------------------------------------------- |
|
66 void |
|
67 BonjourDiscovery::run() |
|
68 { |
|
69 DNSServiceRef register_svc, browse_svc; |
|
70 DNSServiceErrorType err; |
|
71 |
|
72 const EndpointID& local_eid = BundleDaemon::instance()->local_eid(); |
|
73 char txt[255]; |
|
74 TXTRecordRef record; |
|
75 TXTRecordCreate(&record, 255, &txt); |
|
76 err = TXTRecordSetValue(&record, ADDRESS_KEY, local_eid.length(), local_eid.data()); |
|
77 |
|
78 if (err != kDNSServiceErr_NoError) { |
|
79 log_err("KURTIS error in DNSServiceRegister: %s", dns_service_strerror(err)); |
|
80 return; |
|
81 } |
|
82 |
|
83 // call DNSServiceRegister to announce the tcp service listening |
|
84 // on the default port |
|
85 err = DNSServiceRegister(®ister_svc, |
|
86 0 /* interface */, |
|
87 0 /* flags */, |
|
88 NULL /* name */, |
|
89 "_dtn._tcp" /* regtype */, |
|
90 NULL /* domain */, |
|
91 NULL /* host */, |
|
92 htons(TCPConvergenceLayer::TCPCL_DEFAULT_PORT), |
|
93 TXTRecordGetLength(&record) /* txtLen */, |
|
94 TXTRecordGetBytesPtr(&record) /* txtRecord */, |
|
95 register_reply_callback /* callback */, |
|
96 this /* context */); |
|
97 |
|
98 TXTRecordDeallocate(&record); |
|
99 |
|
100 if (err != kDNSServiceErr_NoError) { |
|
101 log_err("error in DNSServiceRegister: %s", dns_service_strerror(err)); |
|
102 return; |
|
103 } |
|
104 |
|
105 log_notice("DNSServiceRegister succeeded"); |
|
106 svc_vec_.push_back(register_svc); |
|
107 |
|
108 // kick off a browse for other services on the local network |
|
109 err = DNSServiceBrowse(&browse_svc, |
|
110 0 /* flags */, |
|
111 0 /* interface */, |
|
112 "_dtn._tcp" /* regtype */, |
|
113 NULL /* domain */, |
|
114 browse_callback /* callback */, |
|
115 this /* context */); |
|
116 |
|
117 if (err != kDNSServiceErr_NoError) { |
|
118 log_err("error in DNSServiceBrowse: %s", dns_service_strerror(err)); |
|
119 return; |
|
120 } |
|
121 |
|
122 log_notice("DNSServiceBrowse succeeded"); |
|
123 svc_vec_.push_back(browse_svc); |
|
124 |
|
125 int notifier_fd = notifier_.read_fd(); |
|
126 |
|
127 while (1) { |
|
128 retry: |
|
129 int num_pollfds = svc_vec_.size() + 1; |
|
130 struct pollfd pollfds[num_pollfds]; |
|
131 |
|
132 for (int i = 0; i < num_pollfds - 1; ++i) { |
|
133 pollfds[i].fd = DNSServiceRefSockFD(svc_vec_[i]); |
|
134 if (pollfds[i].fd == -1) { |
|
135 log_crit("DNSServiceRefSockFD failed -- removing svc %d!!", i); |
|
136 svc_vec_.erase(svc_vec_.begin() + i); |
|
137 goto retry; |
|
138 } |
|
139 pollfds[i].events = POLLIN; |
|
140 pollfds[i].revents = 0; |
|
141 } |
|
142 |
|
143 pollfds[num_pollfds - 1].fd = notifier_fd; |
|
144 pollfds[num_pollfds - 1].events = POLLIN; |
|
145 pollfds[num_pollfds - 1].revents = 0; |
|
146 |
|
147 int cc = oasys::IO::poll_multiple(pollfds, num_pollfds, -1, NULL, |
|
148 logpath_); |
|
149 if (cc <= 0) { |
|
150 log_err("unexpected return from poll_multiple: %d", cc); |
|
151 return; |
|
152 } |
|
153 |
|
154 if (shutdown_) { |
|
155 log_debug("shutdown_ bit set, exiting"); |
|
156 break; |
|
157 } |
|
158 |
|
159 for (int i = 0; i < num_pollfds - 1; ++i) { |
|
160 if (pollfds[i].revents != 0) { |
|
161 log_debug("calling DNSServiceProcessResult for svc %d (fd %d)", |
|
162 i, pollfds[i].fd); |
|
163 DNSServiceProcessResult(svc_vec_[i]); |
|
164 } |
|
165 } |
|
166 } |
|
167 } |
|
168 |
|
169 //---------------------------------------------------------------------- |
|
170 const char* |
|
171 BonjourDiscovery::dns_service_strerror(DNSServiceErrorType err) |
|
172 { |
|
173 switch(err) { |
|
174 case kDNSServiceErr_NoError: return "kDNSServiceErr_NoError"; |
|
175 case kDNSServiceErr_Unknown: return "kDNSServiceErr_Unknown"; |
|
176 case kDNSServiceErr_NoSuchName: return "kDNSServiceErr_NoSuchName"; |
|
177 case kDNSServiceErr_NoMemory: return "kDNSServiceErr_NoMemory"; |
|
178 case kDNSServiceErr_BadParam: return "kDNSServiceErr_BadParam"; |
|
179 case kDNSServiceErr_BadReference: return "kDNSServiceErr_BadReference"; |
|
180 case kDNSServiceErr_BadState: return "kDNSServiceErr_BadState"; |
|
181 case kDNSServiceErr_BadFlags: return "kDNSServiceErr_BadFlags"; |
|
182 case kDNSServiceErr_Unsupported: return "kDNSServiceErr_Unsupported"; |
|
183 case kDNSServiceErr_NotInitialized: return "kDNSServiceErr_NotInitialized"; |
|
184 case kDNSServiceErr_AlreadyRegistered: return "kDNSServiceErr_AlreadyRegistered"; |
|
185 case kDNSServiceErr_NameConflict: return "kDNSServiceErr_NameConflict"; |
|
186 case kDNSServiceErr_Invalid: return "kDNSServiceErr_Invalid"; |
|
187 case kDNSServiceErr_Firewall: return "kDNSServiceErr_Firewall"; |
|
188 case kDNSServiceErr_Incompatible: return "kDNSServiceErr_Incompatible"; |
|
189 case kDNSServiceErr_BadInterfaceIndex: return "kDNSServiceErr_BadInterfaceIndex"; |
|
190 case kDNSServiceErr_Refused: return "kDNSServiceErr_Refused"; |
|
191 case kDNSServiceErr_NoSuchRecord: return "kDNSServiceErr_NoSuchRecord"; |
|
192 case kDNSServiceErr_NoAuth: return "kDNSServiceErr_NoAuth"; |
|
193 case kDNSServiceErr_NoSuchKey: return "kDNSServiceErr_NoSuchKey"; |
|
194 case kDNSServiceErr_NATTraversal: return "kDNSServiceErr_NATTraversal"; |
|
195 case kDNSServiceErr_DoubleNAT: return "kDNSServiceErr_DoubleNAT"; |
|
196 case kDNSServiceErr_BadTime: return "kDNSServiceErr_BadTime"; |
|
197 default: |
|
198 static char buf[32]; |
|
199 snprintf(buf, sizeof(buf), "%d", err); |
|
200 return buf; |
|
201 } |
|
202 } |
|
203 |
|
204 //---------------------------------------------------------------------- |
|
205 void |
|
206 BonjourDiscovery::remove_svc(DNSServiceRef sdRef) |
|
207 { |
|
208 SvcVector::iterator iter; |
|
209 for (iter = svc_vec_.begin(); iter != svc_vec_.end(); ++iter) { |
|
210 if (*iter == sdRef) { |
|
211 svc_vec_.erase(iter); |
|
212 return; |
|
213 } |
|
214 } |
|
215 |
|
216 log_err("remove_svc: can't find sdRef %p in vector!!", sdRef); |
|
217 } |
|
218 |
|
219 //---------------------------------------------------------------------- |
|
220 void |
|
221 BonjourDiscovery::handle_register_reply(DNSServiceRef sdRef, |
|
222 DNSServiceFlags flags, |
|
223 DNSServiceErrorType errorCode, |
|
224 const char *name, |
|
225 const char *regtype, |
|
226 const char *domain) |
|
227 { |
|
228 (void)flags; |
|
229 (void)errorCode; |
|
230 (void)name; |
|
231 (void)regtype; |
|
232 (void)domain; |
|
233 |
|
234 log_debug("handle_register_reply(%s, %s, %s): %s", |
|
235 name, regtype, domain, dns_service_strerror(errorCode)); |
|
236 |
|
237 remove_svc(sdRef); |
|
238 } |
|
239 |
|
240 //---------------------------------------------------------------------- |
|
241 void |
|
242 BonjourDiscovery::handle_browse(DNSServiceRef sdRef, |
|
243 DNSServiceFlags flags, |
|
244 uint32_t interfaceIndex, |
|
245 DNSServiceErrorType errorCode, |
|
246 const char *name, |
|
247 const char *regtype, |
|
248 const char *domain) |
|
249 { |
|
250 (void)sdRef; |
|
251 (void)interfaceIndex; |
|
252 |
|
253 if (errorCode != kDNSServiceErr_NoError) { |
|
254 log_warn("handle_browse(%s, %s, %s): error %s", |
|
255 name, regtype, domain, dns_service_strerror(errorCode)); |
|
256 return; |
|
257 } |
|
258 |
|
259 if (flags & kDNSServiceFlagsAdd) { |
|
260 log_info("browse found new entry: %s.%s.%s (if %d) -- setting up resolver", |
|
261 name, regtype, domain, interfaceIndex); |
|
262 DNSServiceRef svc; |
|
263 DNSServiceErrorType err; |
|
264 |
|
265 err = DNSServiceResolve(&svc, 0, interfaceIndex, name, regtype, domain, |
|
266 (DNSServiceResolveReply)resolve_callback, this); |
|
267 if (err != kDNSServiceErr_NoError) { |
|
268 log_err("error in DNSServiceResolve: %s", |
|
269 dns_service_strerror(err)); |
|
270 return; |
|
271 } |
|
272 |
|
273 svc_vec_.push_back(svc); |
|
274 } else { |
|
275 log_info("browse found old entry: %s.%s.%s", |
|
276 name, regtype, domain); |
|
277 } |
|
278 } |
|
279 |
|
280 //---------------------------------------------------------------------- |
|
281 void |
|
282 BonjourDiscovery::handle_resolve(DNSServiceRef sdRef, |
|
283 DNSServiceFlags flags, |
|
284 uint32_t interfaceIndex, |
|
285 DNSServiceErrorType errorCode, |
|
286 const char *fullname, |
|
287 const char *hosttarget, |
|
288 uint16_t port, |
|
289 uint16_t txtlen, |
|
290 const char* txtRecord) |
|
291 { |
|
292 EndpointID remote_eid; |
|
293 oasys::StaticStringBuffer<64> buf; |
|
294 unsigned char value_len; |
|
295 char* value; |
|
296 |
|
297 (void)sdRef; |
|
298 (void)flags; |
|
299 (void)interfaceIndex; |
|
300 |
|
301 if (errorCode != kDNSServiceErr_NoError) { |
|
302 log_warn("handle_resolve(%s, %s): error %s", |
|
303 fullname, hosttarget, dns_service_strerror(errorCode)); |
|
304 goto done; |
|
305 } |
|
306 |
|
307 if (txtlen == 0) { |
|
308 log_warn("handle_resolve(%s, %s): zero-length txt record", |
|
309 fullname, hosttarget); |
|
310 goto done; |
|
311 } |
|
312 |
|
313 if (!TXTRecordContainsKey(txtlen, txtRecord, ADDRESS_KEY)){ |
|
314 log_warn("handle_resolve(%s, %s): no ADDRESS_KEY field found in txt record", |
|
315 fullname, hosttarget); |
|
316 goto done; |
|
317 } |
|
318 |
|
319 value = (char*) TXTRecordGetValuePtr(txtlen, txtRecord, ADDRESS_KEY, &value_len); |
|
320 |
|
321 remote_eid.assign(value, static_cast<size_t>(value_len)); |
|
322 if (!remote_eid.valid()) { |
|
323 log_warn("handle_resolve(%s, %s): %s not a valid eid", |
|
324 fullname, hosttarget, remote_eid.c_str()); |
|
325 goto done; |
|
326 } |
|
327 |
|
328 if (remote_eid.equals(BundleDaemon::instance()->local_eid())) { |
|
329 log_info("handle_resolve(%s, %s): ignoring resolution of local eid %s", |
|
330 fullname, hosttarget, remote_eid.c_str()); |
|
331 goto done; |
|
332 } |
|
333 |
|
334 log_debug("handle_resolve: name %s host %s port %u txt %s if %d: err %s", |
|
335 fullname, hosttarget, ntohs(port), remote_eid.c_str(), |
|
336 interfaceIndex, dns_service_strerror(errorCode)); |
|
337 |
|
338 buf.appendf("%s:%u", hosttarget, htons(port)); |
|
339 |
|
340 // XXX/demmer in the future this should check for udp as well |
|
341 log_debug("calling handle_neighbor_discovered for next hop %s", buf.c_str()); |
|
342 handle_neighbor_discovered("tcp", buf.c_str(), remote_eid); |
|
343 |
|
344 done: |
|
345 remove_svc(sdRef); |
|
346 } |
|
347 |
|
348 } // namespace dtn |
|
349 |
|
350 #endif /* OASYS_BONJOUR_ENABLED */ |