00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #ifdef HAVE_CONFIG_H
00018 # include <dtn-config.h>
00019 #endif
00020
00021 #ifdef OASYS_BONJOUR_ENABLED
00022
00023 #include "BonjourDiscovery.h"
00024 #include "bundling/BundleDaemon.h"
00025 #include "conv_layers/TCPConvergenceLayer.h"
00026
00027 #define ADDRESS_KEY "local_eid"
00028
00029 namespace dtn {
00030
00031
00032 BonjourDiscovery::BonjourDiscovery(const std::string& name)
00033 : Discovery(name, "bonjour"),
00034 oasys::Thread("BonjourDiscovery"),
00035 notifier_("/dtn/discovery/bonjour"),
00036 shutdown_(false)
00037 {
00038 }
00039
00040
00041 BonjourDiscovery::~BonjourDiscovery()
00042 {
00043
00044 }
00045
00046
00047 bool
00048 BonjourDiscovery::configure(int argc, const char* argv[])
00049 {
00050 (void)argc;
00051 (void)argv;
00052
00053 start();
00054 return true;
00055 }
00056
00057
00058 void
00059 BonjourDiscovery::shutdown()
00060 {
00061 shutdown_ = true;
00062 notifier_.notify();
00063 }
00064
00065
00066 void
00067 BonjourDiscovery::run()
00068 {
00069 DNSServiceRef register_svc, browse_svc;
00070 DNSServiceErrorType err;
00071
00072 const EndpointID& local_eid = BundleDaemon::instance()->local_eid();
00073 char txt[255];
00074 TXTRecordRef record;
00075 TXTRecordCreate(&record, 255, &txt);
00076 err = TXTRecordSetValue(&record, ADDRESS_KEY, local_eid.length(), local_eid.data());
00077
00078 if (err != kDNSServiceErr_NoError) {
00079 log_err("KURTIS error in DNSServiceRegister: %s", dns_service_strerror(err));
00080 return;
00081 }
00082
00083
00084
00085 err = DNSServiceRegister(®ister_svc,
00086 0 ,
00087 0 ,
00088 NULL ,
00089 "_dtn._tcp" ,
00090 NULL ,
00091 NULL ,
00092 htons(TCPConvergenceLayer::TCPCL_DEFAULT_PORT),
00093 TXTRecordGetLength(&record) ,
00094 TXTRecordGetBytesPtr(&record) ,
00095 register_reply_callback ,
00096 this );
00097
00098 TXTRecordDeallocate(&record);
00099
00100 if (err != kDNSServiceErr_NoError) {
00101 log_err("error in DNSServiceRegister: %s", dns_service_strerror(err));
00102 return;
00103 }
00104
00105 log_notice("DNSServiceRegister succeeded");
00106 svc_vec_.push_back(register_svc);
00107
00108
00109 err = DNSServiceBrowse(&browse_svc,
00110 0 ,
00111 0 ,
00112 "_dtn._tcp" ,
00113 NULL ,
00114 browse_callback ,
00115 this );
00116
00117 if (err != kDNSServiceErr_NoError) {
00118 log_err("error in DNSServiceBrowse: %s", dns_service_strerror(err));
00119 return;
00120 }
00121
00122 log_notice("DNSServiceBrowse succeeded");
00123 svc_vec_.push_back(browse_svc);
00124
00125 int notifier_fd = notifier_.read_fd();
00126
00127 while (1) {
00128 retry:
00129 int num_pollfds = svc_vec_.size() + 1;
00130 struct pollfd pollfds[num_pollfds];
00131
00132 for (int i = 0; i < num_pollfds - 1; ++i) {
00133 pollfds[i].fd = DNSServiceRefSockFD(svc_vec_[i]);
00134 if (pollfds[i].fd == -1) {
00135 log_crit("DNSServiceRefSockFD failed -- removing svc %d!!", i);
00136 svc_vec_.erase(svc_vec_.begin() + i);
00137 goto retry;
00138 }
00139 pollfds[i].events = POLLIN;
00140 pollfds[i].revents = 0;
00141 }
00142
00143 pollfds[num_pollfds - 1].fd = notifier_fd;
00144 pollfds[num_pollfds - 1].events = POLLIN;
00145 pollfds[num_pollfds - 1].revents = 0;
00146
00147 int cc = oasys::IO::poll_multiple(pollfds, num_pollfds, -1, NULL,
00148 logpath_);
00149 if (cc <= 0) {
00150 log_err("unexpected return from poll_multiple: %d", cc);
00151 return;
00152 }
00153
00154 if (shutdown_) {
00155 log_debug("shutdown_ bit set, exiting");
00156 break;
00157 }
00158
00159 for (int i = 0; i < num_pollfds - 1; ++i) {
00160 if (pollfds[i].revents != 0) {
00161 log_debug("calling DNSServiceProcessResult for svc %d (fd %d)",
00162 i, pollfds[i].fd);
00163 DNSServiceProcessResult(svc_vec_[i]);
00164 }
00165 }
00166 }
00167 }
00168
00169
00170 const char*
00171 BonjourDiscovery::dns_service_strerror(DNSServiceErrorType err)
00172 {
00173 switch(err) {
00174 case kDNSServiceErr_NoError: return "kDNSServiceErr_NoError";
00175 case kDNSServiceErr_Unknown: return "kDNSServiceErr_Unknown";
00176 case kDNSServiceErr_NoSuchName: return "kDNSServiceErr_NoSuchName";
00177 case kDNSServiceErr_NoMemory: return "kDNSServiceErr_NoMemory";
00178 case kDNSServiceErr_BadParam: return "kDNSServiceErr_BadParam";
00179 case kDNSServiceErr_BadReference: return "kDNSServiceErr_BadReference";
00180 case kDNSServiceErr_BadState: return "kDNSServiceErr_BadState";
00181 case kDNSServiceErr_BadFlags: return "kDNSServiceErr_BadFlags";
00182 case kDNSServiceErr_Unsupported: return "kDNSServiceErr_Unsupported";
00183 case kDNSServiceErr_NotInitialized: return "kDNSServiceErr_NotInitialized";
00184 case kDNSServiceErr_AlreadyRegistered: return "kDNSServiceErr_AlreadyRegistered";
00185 case kDNSServiceErr_NameConflict: return "kDNSServiceErr_NameConflict";
00186 case kDNSServiceErr_Invalid: return "kDNSServiceErr_Invalid";
00187 case kDNSServiceErr_Firewall: return "kDNSServiceErr_Firewall";
00188 case kDNSServiceErr_Incompatible: return "kDNSServiceErr_Incompatible";
00189 case kDNSServiceErr_BadInterfaceIndex: return "kDNSServiceErr_BadInterfaceIndex";
00190 case kDNSServiceErr_Refused: return "kDNSServiceErr_Refused";
00191 case kDNSServiceErr_NoSuchRecord: return "kDNSServiceErr_NoSuchRecord";
00192 case kDNSServiceErr_NoAuth: return "kDNSServiceErr_NoAuth";
00193 case kDNSServiceErr_NoSuchKey: return "kDNSServiceErr_NoSuchKey";
00194 case kDNSServiceErr_NATTraversal: return "kDNSServiceErr_NATTraversal";
00195 case kDNSServiceErr_DoubleNAT: return "kDNSServiceErr_DoubleNAT";
00196 case kDNSServiceErr_BadTime: return "kDNSServiceErr_BadTime";
00197 default:
00198 static char buf[32];
00199 snprintf(buf, sizeof(buf), "%d", err);
00200 return buf;
00201 }
00202 }
00203
00204
00205 void
00206 BonjourDiscovery::remove_svc(DNSServiceRef sdRef)
00207 {
00208 SvcVector::iterator iter;
00209 for (iter = svc_vec_.begin(); iter != svc_vec_.end(); ++iter) {
00210 if (*iter == sdRef) {
00211 svc_vec_.erase(iter);
00212 return;
00213 }
00214 }
00215
00216 log_err("remove_svc: can't find sdRef %p in vector!!", sdRef);
00217 }
00218
00219
00220 void
00221 BonjourDiscovery::handle_register_reply(DNSServiceRef sdRef,
00222 DNSServiceFlags flags,
00223 DNSServiceErrorType errorCode,
00224 const char *name,
00225 const char *regtype,
00226 const char *domain)
00227 {
00228 (void)flags;
00229 (void)errorCode;
00230 (void)name;
00231 (void)regtype;
00232 (void)domain;
00233
00234 log_debug("handle_register_reply(%s, %s, %s): %s",
00235 name, regtype, domain, dns_service_strerror(errorCode));
00236
00237 remove_svc(sdRef);
00238 }
00239
00240
00241 void
00242 BonjourDiscovery::handle_browse(DNSServiceRef sdRef,
00243 DNSServiceFlags flags,
00244 uint32_t interfaceIndex,
00245 DNSServiceErrorType errorCode,
00246 const char *name,
00247 const char *regtype,
00248 const char *domain)
00249 {
00250 (void)sdRef;
00251 (void)interfaceIndex;
00252
00253 if (errorCode != kDNSServiceErr_NoError) {
00254 log_warn("handle_browse(%s, %s, %s): error %s",
00255 name, regtype, domain, dns_service_strerror(errorCode));
00256 return;
00257 }
00258
00259 if (flags & kDNSServiceFlagsAdd) {
00260 log_info("browse found new entry: %s.%s.%s (if %d) -- setting up resolver",
00261 name, regtype, domain, interfaceIndex);
00262 DNSServiceRef svc;
00263 DNSServiceErrorType err;
00264
00265 err = DNSServiceResolve(&svc, 0, interfaceIndex, name, regtype, domain,
00266 (DNSServiceResolveReply)resolve_callback, this);
00267 if (err != kDNSServiceErr_NoError) {
00268 log_err("error in DNSServiceResolve: %s",
00269 dns_service_strerror(err));
00270 return;
00271 }
00272
00273 svc_vec_.push_back(svc);
00274 } else {
00275 log_info("browse found old entry: %s.%s.%s",
00276 name, regtype, domain);
00277 }
00278 }
00279
00280
00281 void
00282 BonjourDiscovery::handle_resolve(DNSServiceRef sdRef,
00283 DNSServiceFlags flags,
00284 uint32_t interfaceIndex,
00285 DNSServiceErrorType errorCode,
00286 const char *fullname,
00287 const char *hosttarget,
00288 uint16_t port,
00289 uint16_t txtlen,
00290 const char* txtRecord)
00291 {
00292 EndpointID remote_eid;
00293 oasys::StaticStringBuffer<64> buf;
00294 unsigned char value_len;
00295 char* value;
00296
00297 (void)sdRef;
00298 (void)flags;
00299 (void)interfaceIndex;
00300
00301 if (errorCode != kDNSServiceErr_NoError) {
00302 log_warn("handle_resolve(%s, %s): error %s",
00303 fullname, hosttarget, dns_service_strerror(errorCode));
00304 goto done;
00305 }
00306
00307 if (txtlen == 0) {
00308 log_warn("handle_resolve(%s, %s): zero-length txt record",
00309 fullname, hosttarget);
00310 goto done;
00311 }
00312
00313 if (!TXTRecordContainsKey(txtlen, txtRecord, ADDRESS_KEY)){
00314 log_warn("handle_resolve(%s, %s): no ADDRESS_KEY field found in txt record",
00315 fullname, hosttarget);
00316 goto done;
00317 }
00318
00319 value = (char*) TXTRecordGetValuePtr(txtlen, txtRecord, ADDRESS_KEY, &value_len);
00320
00321 remote_eid.assign(value, static_cast<size_t>(value_len));
00322 if (!remote_eid.valid()) {
00323 log_warn("handle_resolve(%s, %s): %s not a valid eid",
00324 fullname, hosttarget, remote_eid.c_str());
00325 goto done;
00326 }
00327
00328 if (remote_eid.equals(BundleDaemon::instance()->local_eid())) {
00329 log_info("handle_resolve(%s, %s): ignoring resolution of local eid %s",
00330 fullname, hosttarget, remote_eid.c_str());
00331 goto done;
00332 }
00333
00334 log_debug("handle_resolve: name %s host %s port %u txt %s if %d: err %s",
00335 fullname, hosttarget, ntohs(port), remote_eid.c_str(),
00336 interfaceIndex, dns_service_strerror(errorCode));
00337
00338 buf.appendf("%s:%u", hosttarget, htons(port));
00339
00340
00341 log_debug("calling handle_neighbor_discovered for next hop %s", buf.c_str());
00342 handle_neighbor_discovered("tcp", buf.c_str(), remote_eid);
00343
00344 done:
00345 remove_svc(sdRef);
00346 }
00347
00348 }
00349
00350 #endif