IPDiscovery.cc

Go to the documentation of this file.
00001 /*
00002  *    Copyright 2006 Baylor University
00003  * 
00004  *    Licensed under the Apache License, Version 2.0 (the "License");
00005  *    you may not use this file except in compliance with the License.
00006  *    You may obtain a copy of the License at
00007  * 
00008  *        http://www.apache.org/licenses/LICENSE-2.0
00009  * 
00010  *    Unless required by applicable law or agreed to in writing, software
00011  *    distributed under the License is distributed on an "AS IS" BASIS,
00012  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  *    See the License for the specific language governing permissions and
00014  *    limitations under the License.
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     // Assume everything is broadcast unless unicast flag is set
00071     // or if multicast address is set
00072     if (! unicast)
00073     {
00074         socket_.set_remote_addr(remote_addr_);
00075         in_addr_t mcast_addr = inet_addr("224.0.0.0");
00076         // infer multicast option from remote address
00077         if (mcast_addr & remote_addr_ == mcast_addr)
00078         {
00079             socket_.params_.multicast_ = true;
00080             socket_.params_.mcast_ttl_ = mcast_ttl_;
00081         }
00082         // everything else is assumed broadcast
00083         else
00084         {
00085             socket_.params_.broadcast_ = true;
00086         }
00087     }
00088 
00089     // allow new announce registration to upset poll() in run() below
00090     socket_.set_notifier(new oasys::Notifier(socket_.logpath()));
00091 
00092     // configure base class variables 
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         // only send out beacon(s) once per interval
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                     // quit thread on error
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         // figure out whatever time is left (if poll has already fired within
00156         // interval ms) and set up poll timeout
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         // if timeout, then flip back around and send beacons
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             // distribute to all beacons registered for this CL type
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 } // namespace dtn

Generated on Thu Jun 7 16:56:50 2007 for DTN Reference Implementation by  doxygen 1.5.1