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 #include <climits>
00022
00023 #include <oasys/util/OptParser.h>
00024 #include <oasys/util/StringBuffer.h>
00025 #include "bundling/BundleDaemon.h"
00026 #include "IPDiscovery.h"
00027 #include "IPAnnounce.h"
00028
00029 extern int errno;
00030
00031 namespace dtn {
00032
00033 const u_int32_t IPDiscovery::DEFAULT_DST_ADDR = 0xffffffff;
00034 const u_int32_t IPDiscovery::DEFAULT_SRC_ADDR = INADDR_ANY;
00035 const u_int IPDiscovery::DEFAULT_MCAST_TTL = 1;
00036
00037 IPDiscovery::IPDiscovery(const std::string& name)
00038 : Discovery(name,"ip"),
00039 oasys::Thread("IPDiscovery"),
00040 socket_("/dtn/discovery/ip/sock")
00041 {
00042 remote_addr_ = DEFAULT_DST_ADDR;
00043 local_addr_ = DEFAULT_SRC_ADDR;
00044 mcast_ttl_ = DEFAULT_MCAST_TTL;
00045 port_ = 0;
00046 shutdown_ = false;
00047 persist_ = false;
00048 }
00049
00050 bool
00051 IPDiscovery::configure(int argc, const char* argv[])
00052 {
00053 if (oasys::Thread::started())
00054 {
00055 log_warn("reconfiguration of IPDiscovery not supported");
00056 return false;
00057 }
00058
00059 oasys::OptParser p;
00060
00061 bool portSet = false;
00062 bool unicast = false;
00063 p.addopt(new oasys::UInt16Opt("port",&port_,"","",&portSet));
00064 p.addopt(new oasys::InAddrOpt("addr",&remote_addr_));
00065 p.addopt(new oasys::InAddrOpt("local_addr",&local_addr_));
00066 p.addopt(new oasys::UIntOpt("multicast_ttl",&mcast_ttl_));
00067 p.addopt(new oasys::BoolOpt("unicast",&unicast));
00068 p.addopt(new oasys::BoolOpt("continue_on_error",&persist_));
00069
00070 const char* invalid;
00071 if (! p.parse(argc,argv,&invalid))
00072 {
00073 log_err("bad option for IP discovery: %s",invalid);
00074 return false;
00075 }
00076
00077 if (! portSet)
00078 {
00079 log_err("must specify port");
00080 return false;
00081 }
00082
00083 socket_.set_remote_addr(remote_addr_);
00084
00085
00086
00087 static in_addr_t mcast_mask = inet_addr("224.0.0.0");
00088 if (unicast)
00089 {
00090 log_debug("configuring unicast socket for address %s", intoa(remote_addr_));
00091 }
00092 else if ((remote_addr_ == 0xffffffff) ||
00093 ((remote_addr_ & mcast_mask) != mcast_mask))
00094 {
00095 log_debug("configuring broadcast socket for address %s", intoa(remote_addr_));
00096 socket_.params_.broadcast_ = true;
00097 }
00098 else
00099 {
00100 log_debug("configuring multicast socket for address %s", intoa(remote_addr_));
00101 socket_.params_.multicast_ = true;
00102 socket_.params_.mcast_ttl_ = mcast_ttl_;
00103 }
00104
00105
00106 socket_.set_notifier(new oasys::Notifier(socket_.logpath()));
00107
00108
00109 oasys::StringBuffer buf("%s:%d",intoa(local_addr_),port_);
00110 local_.assign(buf.c_str());
00111
00112 oasys::StringBuffer to("%s:%d",intoa(remote_addr_),port_);
00113 to_addr_.assign(to.c_str());
00114
00115 log_debug("starting thread");
00116 start();
00117
00118 return true;
00119 }
00120
00121 void
00122 IPDiscovery::run()
00123 {
00124 log_debug("discovery thread running");
00125 oasys::ScratchBuffer<u_char*> buf(1024);
00126 u_char* bp = buf.buf(1024);
00127
00128
00129
00130 bool ok = (socket_.bind(local_addr_,port_) == 0);
00131 if (persist_)
00132 {
00133 oasys::Notifier* intr = socket_.get_notifier();
00134 while (! ok)
00135 {
00136
00137 intr->wait(NULL,10000);
00138
00139 if (shutdown_) return;
00140
00141 ok = (socket_.bind(local_addr_,port_) == 0);
00142 }
00143 }
00144 else
00145 if (! ok)
00146 {
00147 log_err("bind failed");
00148 return;
00149 }
00150
00151 size_t len = 0;
00152 int cc = 0;
00153
00154 while (true)
00155 {
00156 if (shutdown_) break;
00157
00158
00159 u_int min_diff = INT_MAX;
00160 for (iterator iter = list_.begin(); iter != list_.end(); iter++)
00161 {
00162 IPAnnounce* announce = dynamic_cast<IPAnnounce*>(*iter);
00163 u_int remaining = announce->interval_remaining();
00164 if (remaining == 0)
00165 {
00166 oasys::UDPClient alt;
00167 oasys::UDPClient* sock = NULL;
00168
00169
00170
00171 if (socket_.local_addr() == announce->cl_addr())
00172 sock = &socket_;
00173 else
00174 {
00175 alt.params_ = socket_.params_;
00176 socket_.set_remote_addr(remote_addr_);
00177 if (alt.bind(announce->cl_addr(),port_) != 0)
00178 {
00179 log_err("failed to bind to %s:%u -- %s (%d)",
00180 intoa(announce->cl_addr()),port_,
00181 strerror(errno),errno);
00182 continue;
00183 }
00184 sock = &alt;
00185 }
00186 log_debug("announce ready for sending");
00187 len = announce->format_advertisement(bp,1024);
00188 cc = sock->sendto((char*)bp,len,0,remote_addr_,port_);
00189 if (cc != (int) len)
00190 {
00191 log_err("sendto failed: %s (%d)",
00192 strerror(errno),errno);
00193
00194
00195 if (!persist_) return;
00196 }
00197 min_diff = announce->interval();
00198 alt.close();
00199 }
00200 else
00201 {
00202 log_debug("announce not ready: %u ms remaining", remaining);
00203 if (remaining < min_diff) {
00204 min_diff = announce->interval_remaining();
00205 }
00206 }
00207 }
00208
00209
00210
00211 u_int timeout = min_diff;
00212
00213 log_debug("polling on socket: timeout %u", timeout);
00214 cc = socket_.poll_sockfd(POLLIN,NULL,timeout);
00215
00216 if (shutdown_) {
00217 log_debug("shutdown bit set, exiting thread");
00218 break;
00219 }
00220
00221
00222 if (cc == oasys::IOTIMEOUT || cc == oasys::IOINTR)
00223 {
00224 continue;
00225 }
00226 else if (cc < 0)
00227 {
00228 log_err("poll error (%d): %s (%d)",
00229 cc, strerror(errno), errno);
00230 return;
00231 }
00232 else if (cc == 1)
00233 {
00234 in_addr_t remote_addr;
00235 u_int16_t remote_port;
00236
00237 cc = socket_.recvfrom((char*)bp,1024,0,&remote_addr,&remote_port);
00238 if (cc < 0)
00239 {
00240 log_err("error on recvfrom (%d): %s (%d)",cc,
00241 strerror(errno),errno);
00242 if (!persist_) return;
00243 else continue;
00244 }
00245
00246 EndpointID remote_eid;
00247 u_int8_t cl_type;
00248 std::string nexthop;
00249 if (!parse_advertisement(bp,cc,remote_addr,cl_type,nexthop,
00250 remote_eid))
00251 {
00252 log_warn("unable to parse beacon from %s:%d",
00253 intoa(remote_addr),remote_port);
00254 if (!persist_) return;
00255 else continue;
00256 }
00257
00258 if (remote_eid.equals(BundleDaemon::instance()->local_eid()))
00259 {
00260 log_debug("ignoring beacon from self (%s:%d)",
00261 intoa(remote_addr),remote_port);
00262 continue;
00263 }
00264
00265
00266 handle_neighbor_discovered(
00267 IPDiscovery::type_to_str((IPDiscovery::cl_type_t)cl_type),
00268 nexthop, remote_eid);
00269 }
00270 else
00271 {
00272 PANIC("unexpected result from poll (%d)",cc);
00273 }
00274 }
00275 }
00276
00277 bool
00278 IPDiscovery::parse_advertisement(u_char* bp, size_t len,
00279 in_addr_t remote_addr, u_int8_t& cl_type,
00280 std::string& nexthop, EndpointID& remote_eid)
00281 {
00282 if (len <= sizeof(DiscoveryHeader))
00283 return false;
00284
00285 DiscoveryHeader* hdr = (DiscoveryHeader*) bp;
00286 size_t length = ntohs(hdr->length);
00287 if (len < length)
00288 return false;
00289
00290 in_addr_t cl_addr;
00291 u_int16_t cl_port;
00292
00293 cl_type = hdr->cl_type;
00294 cl_addr = (hdr->inet_addr == INADDR_ANY) ? remote_addr : hdr->inet_addr;
00295 cl_port = ntohs(hdr->inet_port);
00296
00297 oasys::StringBuffer buf("%s:%d",intoa(cl_addr),cl_port);
00298 nexthop.assign(buf.c_str());
00299
00300 size_t name_len = ntohs(hdr->name_len);
00301 std::string eidstr(hdr->sender_name,name_len);
00302
00303 return remote_eid.assign(eidstr);
00304 }
00305
00306 }