00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #include <oasys/util/OptParser.h>
00018 #include <oasys/util/StringBuffer.h>
00019 #include "bundling/BundleDaemon.h"
00020 #include "IPDiscovery.h"
00021 #include "IPAnnounce.h"
00022
00023 extern int errno;
00024
00025 namespace dtn {
00026
00027 IPDiscovery::IPDiscovery(const std::string& name)
00028 : Discovery(name,"ip"),
00029 oasys::Thread("IPDiscovery")
00030 {
00031 remote_addr_ = 0xffffffff;
00032 local_addr_ = INADDR_ANY;
00033 mcast_ttl_ = 1;
00034 port_ = 0;
00035 shutdown_ = false;
00036 }
00037
00038 bool
00039 IPDiscovery::configure(int argc, const char* argv[])
00040 {
00041 if (oasys::Thread::started())
00042 {
00043 log_warn("reconfiguration of IPDiscovery not supported");
00044 return false;
00045 }
00046
00047 oasys::OptParser p;
00048
00049 bool portSet = false;
00050 bool unicast = false;
00051 p.addopt(new oasys::UInt16Opt("port",&port_,"","",&portSet));
00052 p.addopt(new oasys::InAddrOpt("addr",&remote_addr_));
00053 p.addopt(new oasys::InAddrOpt("local_addr",&local_addr_));
00054 p.addopt(new oasys::UIntOpt("multicast_ttl",&mcast_ttl_));
00055 p.addopt(new oasys::BoolOpt("unicast",&unicast));
00056
00057 const char* invalid;
00058 if (! p.parse(argc,argv,&invalid))
00059 {
00060 log_err("bad option for IP discovery: %s",invalid);
00061 return false;
00062 }
00063
00064 if (! portSet)
00065 {
00066 log_err("must specify port");
00067 return false;
00068 }
00069
00070
00071
00072 if (! unicast)
00073 {
00074 socket_.set_remote_addr(remote_addr_);
00075 in_addr_t mcast_addr = inet_addr("224.0.0.0");
00076
00077 if (mcast_addr & remote_addr_ == mcast_addr)
00078 {
00079 socket_.params_.multicast_ = true;
00080 socket_.params_.mcast_ttl_ = mcast_ttl_;
00081 }
00082
00083 else
00084 {
00085 socket_.params_.broadcast_ = true;
00086 }
00087 }
00088
00089
00090 socket_.set_notifier(new oasys::Notifier(socket_.logpath()));
00091
00092
00093 oasys::StringBuffer buf("%s:%d",intoa(local_addr_),port_);
00094 local_.assign(buf.c_str());
00095
00096 oasys::StringBuffer to("%s:%d",intoa(remote_addr_),port_);
00097 to_addr_.assign(to.c_str());
00098
00099 if (socket_.bind(local_addr_,port_) != 0)
00100 {
00101 log_err("bind failed");
00102 return false;
00103 }
00104
00105 log_debug("starting thread");
00106 start();
00107
00108 return true;
00109 }
00110
00111 void
00112 IPDiscovery::run()
00113 {
00114 oasys::ScratchBuffer<u_char*> buf(1024);
00115 u_char* bp = buf.buf(1024);
00116
00117 size_t len = 0;
00118 int cc = 0;
00119
00120 while (true)
00121 {
00122 if (shutdown_) break;
00123
00124
00125 u_int min_diff = INT_MAX;
00126 u_int min_int = INT_MAX;
00127 for (iterator iter = list_.begin(); iter != list_.end(); iter++)
00128 {
00129 IPAnnounce* announce = dynamic_cast<IPAnnounce*>(*iter);
00130 if (announce->interval_remaining() == 0)
00131 {
00132 len = announce->format_advertisement(bp,1024);
00133 cc = socket_.sendto((char*)bp,len,0,remote_addr_,port_);
00134 if (cc != (int) len)
00135 {
00136 log_err("sendto failed: %s (%d)",
00137 strerror(errno),errno);
00138
00139
00140 return;
00141 }
00142 }
00143 else
00144 if (announce->interval_remaining() < min_diff)
00145 {
00146 min_diff = announce->interval_remaining();
00147 }
00148
00149 if (announce->interval() < min_int)
00150 {
00151 min_int = announce->interval();
00152 }
00153 }
00154
00155
00156
00157 u_int timeout = (min_diff >= min_int) ? min_int :
00158 (min_int - min_diff);
00159
00160 cc = socket_.poll_sockfd(POLLIN,NULL,timeout);
00161
00162 if (shutdown_) break;
00163
00164
00165 if (cc == oasys::IOTIMEOUT || cc == oasys::IOINTR)
00166 {
00167 continue;
00168 }
00169 else if (cc < 0)
00170 {
00171 log_err("poll error (%d): %s (%d)",
00172 cc, strerror(errno), errno);
00173 return;
00174 }
00175 else if (cc == 1)
00176 {
00177 in_addr_t remote_addr;
00178 u_int16_t remote_port;
00179
00180 cc = socket_.recvfrom((char*)bp,1024,0,&remote_addr,&remote_port);
00181 if (cc < 0)
00182 {
00183 log_err("error on recvfrom (%d): %s (%d)",cc,
00184 strerror(errno),errno);
00185 return;
00186 }
00187
00188 EndpointID remote_eid;
00189 u_int8_t cl_type;
00190 std::string nexthop;
00191 if (!parse_advertisement(bp,cc,remote_addr,cl_type,nexthop,
00192 remote_eid))
00193 {
00194 log_warn("unable to parse beacon from %s:%d",
00195 intoa(remote_addr),remote_port);
00196 return;
00197 }
00198
00199 if (remote_eid.equals(BundleDaemon::instance()->local_eid()))
00200 {
00201 log_debug("ignoring beacon from self (%s:%d)",
00202 intoa(remote_addr),remote_port);
00203 continue;
00204 }
00205
00206
00207 handle_neighbor_discovered(
00208 IPDiscovery::type_to_str((IPDiscovery::cl_type_t)cl_type),
00209 nexthop, remote_eid);
00210 }
00211 else
00212 {
00213 PANIC("unexpected result from poll (%d)",cc);
00214 }
00215 }
00216 }
00217
00218 bool
00219 IPDiscovery::parse_advertisement(u_char* bp, size_t len,
00220 in_addr_t remote_addr, u_int8_t& cl_type,
00221 std::string& nexthop, EndpointID& remote_eid)
00222 {
00223 if (len <= sizeof(DiscoveryHeader))
00224 return false;
00225
00226 DiscoveryHeader* hdr = (DiscoveryHeader*) bp;
00227 size_t length = ntohs(hdr->length);
00228 if (len < length)
00229 return false;
00230
00231 in_addr_t cl_addr;
00232 u_int16_t cl_port;
00233
00234 cl_type = hdr->cl_type;
00235 cl_addr = (hdr->inet_addr == INADDR_ANY) ? remote_addr : hdr->inet_addr;
00236 cl_port = ntohs(hdr->inet_port);
00237
00238 oasys::StringBuffer buf("%s:%d",intoa(cl_addr),cl_port);
00239 nexthop.assign(buf.c_str());
00240
00241 size_t name_len = ntohs(hdr->name_len);
00242 std::string eidstr(hdr->sender_name,name_len);
00243
00244 return remote_eid.assign(eidstr);
00245 }
00246
00247 }