Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members

hello.hxx

Go to the documentation of this file.
00001 // Copyright (C) 2003, 2004, 2005 Laboratoire de Recherche en Informatique
00002 
00003 // This file is part of Qolyester.
00004 
00005 // Qolyester is free software; you can redistribute it and/or
00006 // modify it under the terms of the GNU General Public License
00007 // as published by the Free Software Foundation; either version 2
00008 // of the License, or (at your option) any later version.
00009 
00010 // Qolyester is distributed in the hope that it will be useful,
00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013 // GNU General Public License for more details.
00014 
00015 // You should have received a copy of the GNU General Public License
00016 // along with this program; if not, write to the Free Software
00017 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00018 
00019 #ifndef QOLYESTER_DAEMON_MSG_HELLO_HXX
00020 # define QOLYESTER_DAEMON_MSG_HELLO_HXX 1
00021 
00022 # include <ostream>
00023 # include <list>
00024 
00025 # include "alg/mainaddrof.hh"
00026 # include "utl/vtime.hh"
00027 # include "set/neighbors.hh"
00028 
00029 # include "hello.hh"
00030 
00031 namespace olsr {
00032 
00033   extern std::ostream   dump_hello;
00034   extern bool           do_dump_hello;
00035   extern cproxy_t       cproxy;
00036   extern thnset_t       thn_set;
00037 
00038   namespace msg {
00039 
00040     // Dump method for the HELLO message.
00041 
00042     // A few words on this:
00043 
00044     // As HELLO messages can be partial (i.e. not all the link set is
00045     // advertised at once because of possible lack of space), we have
00046     // to keep track of the last time a link was advertised on a given
00047     // interface.  Moreover, we want to include links by order of
00048     // increasing last time of advertisement, in order to prioritize
00049     // older -- in terms of advertised time -- links.
00050 
00051     // To achieve these goals, we maintain a special data structure in
00052     // linkset_t that allows for each interface separately to keep the
00053     // neighbors sorted in order of inscreasing last advertisement
00054     // time.  We consider the neighbors and not the links for a simple
00055     // reason: a link cannot exist by itself, it is always associated
00056     // to a neighbor -- be it an asymmetrical one -- and we need
00057     // information about the associated neighbor.  Moreover, one
00058     // neighbor cannot have more than exactly one link with one local
00059     // interface.
00060 
00061     bool
00062     HELLOMessage::dump(utl::Data& d, const address_t& interface) const {
00063 
00064       // Check if there is space left for at least one message.
00065       if (d.size() < Message::min_length + min_length)
00066         return true; // try again immediately
00067 
00068       if (do_dump_hello) {
00069         dump_hello << "HELLO preparation (" << interface << ") "
00070                    << Message::seqnum << " {\n";
00071       }
00072 
00073       // Fill Message header fields (raw->size is set at the end)
00074 
00075       Message::raw*     mraw = reinterpret_cast<Message::raw*>(d.raw());
00076 
00077       mraw->type     = HELLO_MESSAGE;                   // Message Type
00078       mraw->vtime    = utl::Vtime(cst::neighb_hold_time);       // VTime
00079       // mraw->size  = 0;                               // set later
00080       main_addr.dump(mraw->addr);                       // Main address
00081       mraw->ttl      = 1;                               // Time To Live
00082       mraw->hopcount = 0;                               // Hop Count
00083       mraw->seqnum   = htons(Message::seqnum);          // Sequence number
00084 
00085       // Fill HELLOMessage header fields
00086 
00087       raw*              hraw = reinterpret_cast<raw*>(mraw->data);
00088 
00089       hraw->reserved    = 0;
00090       hraw->htime       = utl::Vtime(cst::hello_interval);
00091       hraw->willingness = willingness;
00092 
00093       d += sizeof *mraw + sizeof *hraw;
00094 
00095       // We are now ready to build the body of the HELLO message.
00096       // We must first classify the links by linkcodes.
00097       // We need one set per linkcode.
00098 
00099       typedef std::pair<address_t,
00100                         cproxy_t::hello_linkset_t::iterator>    lpair_t;
00101       typedef std::list<lpair_t>        linklist_t;
00102 
00103       typedef enum {
00104         nu = NOT_NEIGH << 2 | UNSPEC_LINK,
00105         na = NOT_NEIGH << 2 | ASYM_LINK,
00106         nl = NOT_NEIGH << 2 | LOST_LINK,
00107 
00108         su = SYM_NEIGH << 2 | UNSPEC_LINK,
00109         sa = SYM_NEIGH << 2 | ASYM_LINK,
00110         ss = SYM_NEIGH << 2 | SYM_LINK,
00111         sl = SYM_NEIGH << 2 | LOST_LINK,
00112 
00113         mu = MPR_NEIGH << 2 | UNSPEC_LINK,
00114         ma = MPR_NEIGH << 2 | ASYM_LINK,
00115         ms = MPR_NEIGH << 2 | SYM_LINK,
00116         ml = MPR_NEIGH << 2 | LOST_LINK
00117       }                                                         linkcode_t;
00118 
00119       linklist_t        nu_list;
00120       linklist_t        na_list;
00121       linklist_t        nl_list;
00122 
00123       linklist_t        su_list;
00124       linklist_t        sa_list;
00125       linklist_t        ss_list;
00126       linklist_t        sl_list;
00127 
00128       linklist_t        mu_list;
00129       linklist_t        ma_list;
00130       linklist_t        ms_list;
00131       linklist_t        ml_list;
00132 
00133       // Now we have to iterate on the neighbors (using
00134       // linkset_t::mnset_iterator gives the neighbors in stamp order
00135       // for the current interface, so we get older stamped first).
00136       // We also check whether we can add the link.  We check the
00137       // potential link expiration on the next run to return proper
00138       // value (true if we need another HELLO message right away or
00139       // false if we can wait till the next generation.
00140 
00141       ::size_t  bytes_so_far = 0;
00142       bool      ret          = false;
00143 
00144       std::set<address_t>       already_advertised;
00145 
00146       for (cproxy_t::hello_linkset_t::iterator l =
00147              cproxy.hello_linkset().begin(interface);
00148            l != cproxy.hello_linkset().end(interface); ++l) {
00149 
00150         // We don't want to advertise links too often either, so we
00151         // check if this link has just been sent in a previous run of
00152         // the HELLOMessage::dump() method.  As neighbors are iterated
00153         // on in increasing stamp time, we can safely stop iterating
00154         // here if this message has just been stamped.
00155         if (cproxy.hello_linkset().stamp(l) == timeval_t::now())
00156           break; // the remaining have just been advertised
00157 
00158         // Check if there is enough space left in the packet.
00159         if (d.size() - bytes_so_far < ADDRESS_SIZE) {
00160           // Check if the refresh interval would expire for this
00161           // neighbor if we wait till the next iteration.  If yes,
00162           // return true to force immediate additional message
00163           // emission.
00164           if (cproxy.hello_linkset().expired(l, cst::refresh_interval,
00165                                              timeval_t::in(cst::hello_interval))) {
00166             ret = true;
00167             break;
00168           }
00169 
00170           // If the refresh interval would not expire, continue
00171           // checking the following entries.
00172           continue;
00173         }
00174 
00175         // Compute the Link Code
00176         cproxy_t::neighborset_t::iterator       n =
00177           cproxy.neighborset().find(set::Neighbor::make_key(l->main_addr()));
00178 
00179         assert(n != cproxy.neighborset().end());
00180 
00181         int     link_type = 0;
00182 
00183         if (l->local_addr() != interface) {
00184           // Check if there are links for this neighbor from this interface
00185           std::pair<set::Neighbor::linkset_t::const_iterator,
00186                     set::Neighbor::linkset_t::const_iterator>   er =
00187             n->find_lifaces(interface);
00188 
00189           // If there exists at least one link from this interface to
00190           // the neighbor, we will advertise it in due time, skip this
00191           // link.
00192           if (er.first != er.second ||
00193               already_advertised.find(n->main_addr()) != already_advertised.end()) {
00194             cproxy.hello_linkset().set_stamp(l);
00195             continue;
00196           }
00197 
00198           already_advertised.insert(n->main_addr());
00199 
00200           link_type = UNSPEC_LINK;
00201         } else {
00202 # ifdef QOLYESTER_ENABLE_LINKHYS
00203           if (!l->losttime().is_past())
00204             link_type = LOST_LINK;
00205           else if (l->pending())
00206             continue;
00207           else
00208 # endif // !QOLYESTER_ENABLE_LINKHYS
00209           if (!l->symtime().is_past())
00210             link_type = SYM_LINK;
00211           else if (!l->asymtime().is_past())
00212             link_type = ASYM_LINK;
00213           else
00214             link_type = LOST_LINK;
00215         }
00216 
00217         // Get the neighbor type code.
00218         int     neighbor_type = 0;
00219 
00220         if (n->is_mpr())
00221           neighbor_type = MPR_NEIGH;
00222         else if (n->is_sym())
00223           neighbor_type = SYM_NEIGH;
00224         else
00225           neighbor_type = NOT_NEIGH;
00226 
00227         if (do_dump_hello) {
00228           dump_hello << "  " << (link_type != UNSPEC_LINK ?
00229                                  l->remote_addr() :
00230                                  n->main_addr()) << " ";
00231           switch (link_type) {
00232           case UNSPEC_LINK: dump_hello << "U "; break;
00233           case   ASYM_LINK: dump_hello << "A "; break;
00234           case    SYM_LINK: dump_hello << "S "; break;
00235           case   LOST_LINK: dump_hello << "L "; break;
00236           }
00237           switch (neighbor_type) {
00238           case NOT_NEIGH: dump_hello << "N\n"; break;
00239           case SYM_NEIGH: dump_hello << "S\n"; break;
00240           case MPR_NEIGH: dump_hello << "M\n"; break;
00241           }
00242         }
00243 
00244         // We use a pointer to the apropriate set, depending on the
00245         // link code.  We can avoid the indirection here using a
00246         // preprocessor macro, but the indirection is affordable and
00247         // preferable to the additional code generated.
00248         linklist_t*     list_ptr = 0;
00249 
00250         switch (linkcode_t(neighbor_type << 2 | link_type)) {
00251 
00252         case nu: list_ptr = &nu_list; break;
00253         case na: list_ptr = &na_list; break;
00254         case nl: list_ptr = &nl_list; break;
00255 
00256         case su: list_ptr = &su_list; break;
00257         case sa: list_ptr = &sa_list; break;
00258         case ss: list_ptr = &ss_list; break;
00259         case sl: list_ptr = &sl_list; break;
00260 
00261         case mu: list_ptr = &mu_list; break;
00262         case ma: list_ptr = &ma_list; break;
00263         case ms: list_ptr = &ms_list; break;
00264         case ml: list_ptr = &ml_list; break;
00265 
00266           // We want to catch this case and make it understandable.
00267         default: list_ptr = 0; assert(list_ptr != 0);
00268         }
00269 
00270         // If this is the first link entry of this link code, we must
00271         // take into account the link message header that would be
00272         // added.
00273         if (list_ptr->empty())
00274           // Check for free space.
00275           if (d.size() - bytes_so_far <
00276               sizeof (linksetraw) + ADDRESS_SIZE) {
00277             // If there is not enough room, check if we can delay the
00278             // advertisement of this link until the next iteration.
00279             if (cproxy.hello_linkset().expired(l, cst::refresh_interval,
00280                                                timeval_t::in(cst::hello_interval)))
00281               ret = true;
00282             // Same as before, we still can add some links.
00283             continue;
00284           } else
00285             bytes_so_far += sizeof (linksetraw) + ADDRESS_SIZE;
00286         else
00287           bytes_so_far += ADDRESS_SIZE;
00288 
00289         // If there is no link on this interface for the given
00290         // neighbor (the link code is UNSPEC_LINK), we advertise the
00291         // neighbor's main address, otherwise, we advertise the remote
00292         // interface address.
00293         if (link_type == UNSPEC_LINK)
00294           list_ptr->push_back(lpair_t(n->main_addr(), l));
00295         else
00296           list_ptr->push_back(lpair_t(l->remote_addr(), l));
00297       }
00298 
00299       if (do_dump_hello)
00300         dump_hello << "}" << std::endl;
00301 
00302       // Here comes the macro to generate each link message.  We could
00303       // replace this with a function, in order to spare code size.
00304 
00305 # define PROC_XX_SET(Code)                                                \
00306       do {                                                                \
00307         if (Code ## _list.empty())                                        \
00308           break;                                                          \
00309                                                                           \
00310         linksetraw*     lraw = reinterpret_cast<linksetraw*>(d.raw());    \
00311                                                                           \
00312         lraw->linkcode = linkcode_t(Code);                                \
00313         lraw->reserved = 0;                                               \
00314                                                                           \
00315         d += sizeof *lraw;                                                \
00316                                                                           \
00317         for (linklist_t::iterator i  = Code ## _list.begin();             \
00318                                   i != Code ## _list.end();               \
00319              d += ADDRESS_SIZE, ++i) {                                    \
00320           i->first.dump(d.raw());                                         \
00321           cproxy.hello_linkset().set_stamp(i->second);                    \
00322         }                                                                 \
00323                                                                           \
00324         lraw->linkmessagesize = htons(d.raw() -                           \
00325                                       reinterpret_cast<u_int8_t*>(lraw)); \
00326       } while (0)
00327 
00328       PROC_XX_SET(nu);
00329       PROC_XX_SET(na);
00330       PROC_XX_SET(nl);
00331 
00332       PROC_XX_SET(su);
00333       PROC_XX_SET(sa);
00334       PROC_XX_SET(ss);
00335       PROC_XX_SET(sl);
00336 
00337       PROC_XX_SET(mu);
00338       PROC_XX_SET(ma);
00339       PROC_XX_SET(ms);
00340       PROC_XX_SET(ml);
00341 
00342       mraw->size = htons(d.raw() - reinterpret_cast<u_int8_t*>(mraw));
00343 
00344       return ret;
00345     }
00346 
00347     // Parsing routine for HELLO messages.
00348     void HELLOMessage::parse(const utl::ConstData& d,
00349                              const Message::header& mh) {
00350 
00351       // Extract the message header.
00352       const raw*        h = reinterpret_cast<const raw*>(d.raw());
00353 
00354       if (do_dump_hello) {
00355         dump_hello << "HELLO from " << mh.originator
00356                    << " (" << mh.sender << " -> " << mh.receiver
00357                    << ") M(" << mh.mseqnum << ") P("
00358                    << mh.pseqnum << ") Ht(" << (float) utl::Vtime(h->htime) << ") {\n";
00359       }
00360 
00361       utl::ConstData    payload = d + sizeof (raw);
00362 
00363       int                               link_type  = UNSPEC_LINK;
00364       int                               neigh_type = NOT_NEIGH;
00365       typedef std::set<address_t>       thns_t;
00366       thns_t                            thns;
00367 
00368       // Process the link messages.
00369       for (const linksetraw* lraw =
00370              reinterpret_cast<const linksetraw*>(payload.raw());
00371 
00372            payload.size() > 0;
00373 
00374            payload += ntohs(lraw->linkmessagesize),
00375 
00376              lraw = reinterpret_cast<const linksetraw*>
00377              ((lraw->data - sizeof (linksetraw) +
00378                ntohs(lraw->linkmessagesize)))) {
00379         // Extract link message size.
00380         unsigned        len = (ntohs(lraw->linkmessagesize) -
00381                                sizeof (linksetraw)) / ADDRESS_SIZE;
00382         const u_int8_t  (*addrs)[ADDRESS_SIZE] =
00383           reinterpret_cast<const u_int8_t (*)[ADDRESS_SIZE]>(lraw->data);
00384 
00385         // Extract link and neighbor codes.
00386         u_int8_t        ltype = lraw->linkcode & 0x3;
00387         u_int8_t        ntype = lraw->linkcode >> 2 & 0x03;
00388 
00389         // Process the address list.
00390         for (unsigned i = 0; i < len; ++i) {
00391           // Extract link and main addresses.
00392           address_t     addr(addrs[i], ADDRESS_SIZE);
00393           address_t     maddr = alg::main_addr_of(addr);
00394 
00395           if (do_dump_hello) {
00396             dump_hello << "  " << addr << " ";
00397             switch (ltype) {
00398             case UNSPEC_LINK: dump_hello << "U "; break;
00399             case   ASYM_LINK: dump_hello << "A "; break;
00400             case    SYM_LINK: dump_hello << "S "; break;
00401             case   LOST_LINK: dump_hello << "L "; break;
00402             }
00403             switch (ntype) {
00404             case NOT_NEIGH: dump_hello << "N\n"; break;
00405             case SYM_NEIGH: dump_hello << "S\n"; break;
00406             case MPR_NEIGH: dump_hello << "M\n"; break;
00407             }
00408           }
00409 
00410           if (addr == mh.receiver) {
00411             // This is the information about the local node.  We
00412             // extract here information about the link state between
00413             // the local and the neighbor nodes.
00414             link_type  = ltype;
00415             neigh_type = ntype;
00416           } else {
00417             // This is another node, most probably a 2-hop neighbor.
00418             if (addr != maddr)
00419               // In case this is not the main address of this 2-hop
00420               // node, remove any possible previous information from
00421               // the 2-hop neighbor set in case we did not known the
00422               // multiple interface association of the 2-hop node at
00423               // the time of addition.
00424               thn_set.erase(set::TwoHopNeighbor::make_key(mh.originator,
00425                                                           addr));
00426             if (ntype == SYM_NEIGH || ntype == MPR_NEIGH) {
00427               // If the 2-hop node is a symmetric neighbor of the
00428               // 1-hop node, add an entry in the 2-hop neighbor set.
00429               thns.insert(maddr);
00430             } else {
00431               // Otherwise, remove any association between the two
00432               // nodes from the 2-hop neighbor set.
00433               thn_set.erase(set::TwoHopNeighbor::make_key(mh.originator,
00434                                                           maddr));
00435             }
00436           }
00437         }
00438       }
00439 
00440       if (do_dump_hello)
00441         dump_hello << "}" << std::endl;
00442 
00443       // Now that we have processed all the message,
00444       cproxy_t::neighborset_t::iterator n =
00445 # ifdef QOLYESTER_ENABLE_LINKHYS
00446         cproxy.insert_link(mh, link_type, h->willingness,
00447                            utl::Vtime(h->htime)).first;
00448 # else // !QOLYESTER_ENABLE_LINKHYS
00449         cproxy.insert_link(mh, link_type, h->willingness).first;
00450 # endif
00451 
00452       if (link_type != UNSPEC_LINK)
00453         if (neigh_type == MPR_NEIGH)
00454           cproxy.set_mprsel(n, mh.validity);
00455         else if (neigh_type == SYM_NEIGH)
00456           cproxy.unset_mprsel(n);
00457 
00458       if (n->is_sym()) { // process this neighbor for THN
00459 
00460         for (thns_t::const_iterator i = thns.begin(); i != thns.end(); ++i)
00461           thn_set.insert(set::TwoHopNeighbor(mh.originator, *i, mh.validity));
00462 
00463       }
00464 
00465     }
00466 
00467   } // namespace msg
00468 
00469 } // namespace olsr
00470 
00471 #endif // ! QOLYESTER_DAEMON_MSG_HELLO_HXX

Generated on Thu Jul 28 21:21:47 2005 for Qolyester daemon by  doxygen 1.4.1