args.hxx

Go to the documentation of this file.
00001 // Copyright (C) 2003-2006 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,
00018 // Boston, MA  02110-1301, USA.
00019 
00020 #ifndef QOLYESTER_DAEMON_UTL_ARGS_HXX
00021 # define QOLYESTER_DAEMON_UTL_ARGS_HXX 1
00022 
00023 # include <unistd.h>
00024 # include <getopt.h>
00025 # include <cstdarg>
00026 # include <sstream>
00027 # include <list>
00028 # include <set>
00029 # include <map>
00030 # include <fstream>
00031 
00032 # include "cst/constants.hh"
00033 # include "net/ipaddress.hh"
00034 # include "set/interfaces.hh"
00035 # include "sys/interfaceinfo.hh"
00036 # include "set/gate.hh"
00037 # include "utl/log.hh"
00038 # include "utl/syslog.hh"
00039 
00040 namespace olsr {
00041 
00042   extern ifaceset_t             iface_set;
00043   extern const std::string      progname;
00044   extern const std::string      shortname;
00045   extern const std::string      version;
00046   extern std::ostream           dump;
00047   extern std::ostream           dump_state;
00048   extern std::ostream           dump_prof;
00049   extern std::ostream           dump_hello;
00050   extern std::ostream           dump_tc;
00051 # ifdef QOLYESTER_ENABLE_MID
00052   extern std::ostream           dump_mid;
00053 # endif
00054 # ifdef QOLYESTER_ENABLE_HNA
00055   extern std::ostream           dump_hna;
00056 # endif
00057   extern gateset_t              gate_set;
00058 
00059   static std::string usage()
00060   {
00061     std::ostringstream  os;
00062     os <<
00063 # ifdef QOLYESTER_ENABLE_MID
00064       "usage: qolsrd -i NAME[=ADDR][,NAME[=ADDR]...]\n"
00065 # else // !QOLYESTER_ENABLE_MID
00066       "usage: qolsrd -i NAME[=ADDR]\n"
00067 # endif
00068 # ifdef QOLYESTER_ENABLE_HNA
00069        << "             [-o address/plen[,address/plen...]]\n"
00070 # endif
00071 # ifdef QOLYESTER_ENABLE_TCRED
00072        << "             [-w willingness] [-t tcredundancy]\n"
00073 # else // !QOLYESTER_ENABLE_TCRED
00074        << "             [-w willingness]\n"
00075 # endif
00076 # ifdef QOLYESTER_ENABLE_MPRRED
00077        << "             [-m mprcoverage] [-h] [-n]\n"
00078 # else // !QOLYESTER_ENABLE_MPRRED
00079        << "             [-h] [-n]\n"
00080 # endif
00081        << "Options:\n"
00082 # ifdef QOLYESTER_ENABLE_VIRTUAL
00083 #  ifdef QOLYESTER_ENABLE_MID
00084        << "  -i, --interfaces=NAME[=ADDR][;FILE],...  use these OLSR interfaces (optionally\n"
00085        << "                                          with the specified address\n"
00086        << "                                          and the specified socket file)\n"
00087 #  else // !QOLYESTER_ENABLE_MID
00088        << "  -i, --interface=NAME[=ADDR][;FILE]    use this OLSR interface (optionally\n"
00089        << "                                          with the specified addressi\n"
00090        << "                                          and the specified socket file)\n"
00091 #  endif
00092        << "      --switch-sock=FILE                use this as the default switch\n"
00093        << "                                          socket\n"
00094 # else // !QOLYESTER_ENABLE_VIRTUAL
00095 #  ifdef QOLYESTER_ENABLE_MID
00096        << "  -i, --interfaces=NAME[=ADDR],...      use these OLSR interfaces (optionally\n"
00097        << "                                          with the specified address)\n"
00098 #  else // !QOLYESTER_ENABLE_MID
00099        << "  -i, --interface=NAME[=ADDR]          use this OLSR interface (optionally\n"
00100        << "                                          with the specified address)\n"
00101 #  endif
00102 # endif
00103 # ifdef QOLYESTER_ENABLE_HNA
00104        << "  -o, --other-networks=ADDR/PREFIX,...  use these non-OLSR networks\n"
00105 # endif
00106        << "  -w, --willingness=WILL                node willingness to be an MPR\n"
00107        << "                                          WILL must be `never', `low',\n"
00108        << "                                          `default', `high', `always' or\n"
00109        << "                                          an integer between 0 (never) and\n"
00110        << "                                          7 (always), the default is 3\n"
00111 # ifdef QOLYESTER_ENABLE_TCRED
00112        << "  -t, --tc-redundancy=REDUNDANCY        TC information redundancy\n"
00113        << "                                          REDUNDANCY must be either `mprsel',\n"
00114        << "                                          `mprsel+mpr' or `symset',\n"
00115        << "                                          the default is `mprsel'\n"
00116 # endif
00117 # ifdef QOLYESTER_ENABLE_MPRRED
00118        << "  -m, --mpr-coverage=COVERAGE           MPR coverage, COVERAGE must be a\n"
00119        << "                                          positive integer\n"
00120 # endif
00121 
00122        << "      --hello-interval=MSEC             set the HELLO emission interval in ms\n"
00123        << "      --refresh-interval=MSEC           set the refresh interval in ms\n"
00124        << "      --tc-interval=MSEC                set the TC emission interval in ms\n"
00125 # ifdef QOLYESTER_ENABLE_MID
00126        << "      --mid-interval=MSEC               set the MID emission interval in ms\n"
00127 # endif
00128 # ifdef QOLYESTER_ENABLE_HNA
00129        << "      --hna-interval=MSEC               set the HNA emission interval in ms\n"
00130 # endif
00131 # ifdef QOLYESTER_ENABLE_MID
00132        << "      --mid-hold-time=MSEC              set the MID information holding time\n"
00133        << "                                          in ms\n"
00134 # endif
00135 # ifdef QOLYESTER_ENABLE_HNA
00136        << "      --hna-hold-time=MSEC              set the HNA information holding time\n"
00137        << "                                          in ms\n"
00138 # endif
00139 
00140        << "      --neighb-hold-time=MSEC           set the neighbor holding time in ms\n"
00141        << "      --top-hold-time=MSEC              set the topology holding time in ms\n"
00142        << "      --dup-hold-time=MSEC              set the duplicates holding time in ms\n"
00143        << "      --max-jitter-time=MSEC            set the maximum jitter time in ms\n"
00144 
00145 # ifdef QOLYESTER_ENABLE_LINKHYS
00146        << "      --hello-grace=FLOAT               set the HELLO interval grace\n"
00147        << "                                          the default is "
00148        << cst::hello_grace << '\n'
00149        << "      --hyst-threshold-high=FLOAT       set the high threshold for link\n"
00150        << "                                          hysteresis (default is "
00151        << cst::hyst_threshold_high << ")\n"
00152        << "      --hyst-threshold-low=FLOAT        set the low threshold for link\n"
00153        << "                                          hysteresis (default is "
00154        << cst::hyst_threshold_low << ")\n"
00155        << "      --hyst-scaling=FLOAT              set the scaling for link hysteresis\n"
00156        << "                                          (default is "
00157        << cst::hyst_scaling << ")\n"
00158 # endif
00159 
00160        << "      --error-file=FILE                 print errors to FILE, default stderr\n"
00161        << "      --warning-file=FILE               print warnings to FILE, default stderr\n"
00162        << "      --notice-file=FILE                print notices to FILE, default stderr\n"
00163        << "      --dump-file=FILE                  print dumps to FILE, default stderr\n"
00164 # ifdef DEBUG
00165        << "      --debug-file=FILE                 print debug to FILE, default stderr\n"
00166 # endif
00167        << "      --all-file=FILE                   print all dumps to FILE, other\n"
00168        << "                                          --*-file options override this\n"
00169        << "  -h, --help                            list available command (this page)\n"
00170        << "  -n, --no-detach                       prevent going background\n"
00171 # ifndef QOLYESTER_ENABLE_VIRTUAL
00172        << "      --no-tables                       prevent management of routing tables\n"
00173 # endif // !QOLYESTER_ENABLE_VIRTUAL
00174        << "                                          (for testing only)\n"
00175        << "      --version                         display version information and exit\n"
00176        << "      --dump-hello                      dump HELLO messages\n"
00177        << "      --dump-tc                         dump TC messages\n"
00178 # ifdef QOLYESTER_ENABLE_MID
00179        << "      --dump-mid                        dump MID messages\n"
00180 # endif
00181 # ifdef QOLYESTER_ENABLE_HNA
00182        << "      --dump-hna                        dump HNA messages\n"
00183 # endif
00184        << "      --dump-all                        dump all known messages\n"
00185        << "      --dump-state                      dump the state every second\n"
00186        << "      --dump-prof                       print seconds spent computing\n"
00187        << "                                          in each event loop\n"
00188        << "      --dump-interval=MSEC              state dumping interval in ms\n"
00189 # ifdef DEBUG
00190        << "      --debug-trace=FILE                activate debug trace mode\n"
00191        << "                                          and log into FILE\n"
00192 # endif
00193        << "  -v, --verbose                         show debugging messages\n"
00194        << "                                          (use several times to show more)\n"
00195        << "  -T, --timestamps                      show timestamps in messages\n"
00196        << "  -S, --syslog                          send messages to syslog by default\n"
00197        << "                                          (when using -n)\n"
00198 # if QOLYESTER_FAMILY_INET == 6
00199        << "      --dirty-promisc-hack              enable and disable promiscuous\n"
00200        << "                                          mode to make buggy chipsets work\n"
00201 # endif
00202        << "      --queue-size=N                    specify sending queue size per\n"
00203        << "                                          interface (defaults to "
00204        << cst::def_queue_size << ")\n"
00205       ;
00206     return os.str();
00207   }
00208 
00209   static std::string putversion()
00210   {
00211     std::ostringstream  os;
00212     os << "This is " << progname << " version " << version << ",\n"
00213        << "  an implementation of the OLSR protocol in C++.\n"
00214        << "  Using IPv" << (address_t::family == AF_INET ?
00215                             4 :
00216                             address_t::family == AF_INET6 ?
00217                             6 :
00218                             0) << " address format\n"
00219        << "  Optional features:\n"
00220 # if !defined(QOLYESTER_ENABLE_LINKHYS) && !defined(QOLYESTER_ENABLE_MID) && \
00221      !defined(QOLYESTER_ENABLE_HNA) && !defined(QOLYESTER_ENABLE_TCRED) && \
00222      !defined(QOLYESTER_ENABLE_MPRRED) && !defined(QOLYESTER_ENABLE_VIRTUAL)
00223       "    (none)\n"
00224 # else
00225 #  if defined(QOLYESTER_ENABLE_LINKHYS)
00226       "    Link-Hysteresis\n"
00227 #  endif
00228 #  if defined(QOLYESTER_ENABLE_MID)
00229       "    MID\n"
00230 #  endif
00231 #  if defined(QOLYESTER_ENABLE_HNA)
00232       "    HNA\n"
00233 #  endif
00234 #  if defined(QOLYESTER_ENABLE_TCRED)
00235       "    TC-redundancy\n"
00236 #  endif
00237 #  if defined(QOLYESTER_ENABLE_MPRRED)
00238       "    MPR-coverage\n"
00239 #  endif
00240 #  ifdef QOLYESTER_ENABLE_VIRTUAL
00241       "    Virtual Interfaces\n"
00242 #  endif
00243 # endif
00244       ;
00245     return os.str();
00246   }
00247 
00248   static void die(const char* format, ...)
00249   {
00250     va_list     list;
00251     va_start(list, format);
00252     vfprintf(stderr, format, list);
00253     va_end(list);
00254     exit(1);
00255   }
00256 
00257 # define ARG_VERSION            256
00258 # define ARG_DUMPSTATE          257
00259 # define ARG_DUMPHELLO          258
00260 # define ARG_DUMPTC             259
00261 # define ARG_DUMPMID            260
00262 # define ARG_DUMPHNA            261
00263 # define ARG_DUMPALL            262
00264 # define ARG_ERRORFILE          263
00265 # define ARG_WARNINGFILE        264
00266 # define ARG_NOTICEFILE         265
00267 # define ARG_DUMPFILE           266
00268 # define ARG_DEBUGFILE          267
00269 # define ARG_DUMPPROF           268
00270 # define ARG_NOTABLES           270
00271 # define ARG_SWSOCK             271
00272 # define ARG_ALLFILE            272
00273 # define ARG_DEBUGTRACE         273
00274 
00275 # define ARG_HELLOINTERVAL      274
00276 # define ARG_REFRESHINTERVAL    275
00277 # define ARG_TCINTERVAL         276
00278 # define ARG_MIDINTERVAL        277
00279 # define ARG_HNAINTERVAL        278
00280 # define ARG_MIDHOLDTIME        279
00281 # define ARG_HNAHOLDTIME        280
00282 # define ARG_NEIGHBHOLDTIME     281
00283 # define ARG_TOPHOLDTIME        282
00284 # define ARG_DUPHOLDTIME        283
00285 # define ARG_MAXJITTERTIME      284
00286 # define ARG_DUMPINTERVAL       287
00287 
00288 # define ARG_DIRTYPROMISCHACK   288
00289 
00290 # define ARG_QUEUESIZE          289
00291 
00292 # define ARG_HELLOGRACE         290
00293 # define ARG_HYSTHI             291
00294 # define ARG_HYSTLO             292
00295 # define ARG_HYSTSCALING        293
00296 
00297   namespace utl {
00298 
00299     namespace internal {
00300 # ifdef QOLYESTER_ENABLE_VIRTUAL
00301       struct IfTuple{
00302         IfTuple(const std::string& n,
00303                 const std::string& a,
00304                 const std::string& s)
00305           : name(n),
00306             addr(a.empty() ? address_t() : a),
00307             sock(s) {}
00308         std::string     name;
00309         address_t       addr;
00310         std::string     sock;
00311       };
00312 # else // !QOLYESTER_ENABLE_VIRTUAL
00313       struct IfTuple{
00314         IfTuple(const std::string& n,
00315                 const std::string& a)
00316           : name(n),
00317             addr(a.empty() ? address_t() : a) {}
00318         std::string     name;
00319         address_t       addr;
00320       };
00321 # endif
00322     } // namespace internal
00323 
00324   } // namespace utl
00325 
00326 } // namespace olsr
00327 
00328 namespace std {
00329 
00330   template <>
00331   struct less< ::olsr::utl::internal::IfTuple> {
00332     bool        operator()(const ::olsr::utl::internal::IfTuple& a,
00333                            const ::olsr::utl::internal::IfTuple& b) const {
00334       return a.name < b.name;
00335     }
00336   };
00337 
00338 } // namespace std
00339 
00340 namespace olsr {
00341 
00342   namespace utl {
00343 
00344     void parse_args(int& argc, char**& argv)
00345     {
00346       ::option  opts[] = {
00347 
00348 # ifdef QOLYESTER_ENABLE_MID
00349         { "interfaces", 1, NULL, 'i' },
00350 # else
00351         { "interface", 1, NULL, 'i' },
00352 # endif
00353 
00354 # ifdef QOLYESTER_ENABLE_HNA
00355         { "other-networks", 1, NULL, 'o' },
00356 # endif
00357 
00358         { "willingness", 1, NULL, 'w' },
00359 
00360 # ifdef QOLYESTER_ENABLE_TCRED
00361         { "tc-redundancy", 1, NULL, 't' },
00362 # endif
00363 
00364 # ifdef QOLYESTER_ENABLE_MPRRED
00365         { "mpr-coverage", 1, NULL, 'm' },
00366 # endif
00367 
00368         { "hello-interval", 1, NULL, ARG_HELLOINTERVAL },
00369         { "refresh-interval", 1, NULL, ARG_REFRESHINTERVAL },
00370         { "tc-interval", 1, NULL, ARG_TCINTERVAL },
00371 
00372 # ifdef QOLYESTER_ENABLE_MID
00373         { "mid-interval", 1, NULL, ARG_MIDINTERVAL },
00374         { "mid-hold-time", 1, NULL, ARG_MIDHOLDTIME },
00375 # endif
00376 
00377 # ifdef QOLYESTER_ENABLE_HNA
00378         { "hna-interval", 1, NULL, ARG_HNAINTERVAL },
00379         { "hna-hold-time", 1, NULL, ARG_HNAHOLDTIME },
00380 # endif
00381 
00382         { "neighb-hold-time", 1, NULL, ARG_NEIGHBHOLDTIME },
00383         { "top-hold-time", 1, NULL, ARG_TOPHOLDTIME },
00384         { "dup-hold-time", 1, NULL, ARG_DUPHOLDTIME },
00385 
00386         { "max-jitter-time", 1, NULL, ARG_MAXJITTERTIME },
00387 
00388 # ifdef QOLYESTER_ENABLE_LINKHYS
00389         { "hello-grace", 1, NULL, ARG_HELLOGRACE },
00390         { "hyst-threshold-high", 1, NULL, ARG_HYSTHI },
00391         { "hyst-threshold-low", 1, NULL, ARG_HYSTLO },
00392         { "hyst-scaling", 1, NULL, ARG_HYSTSCALING },
00393 # endif
00394 
00395         { "error-file", 1, NULL, ARG_ERRORFILE },
00396         { "warning-file", 1, NULL, ARG_WARNINGFILE },
00397         { "notice-file", 1, NULL, ARG_NOTICEFILE },
00398         { "dump-file", 1, NULL, ARG_DUMPFILE },
00399 # ifdef DEBUG
00400         { "debug-file", 1, NULL, ARG_DEBUGFILE },
00401 # endif
00402         { "all-file", 1, NULL, ARG_ALLFILE },
00403 
00404         { "help", 0, NULL, 'h' },
00405         { "verbose", 0, NULL, 'v' },
00406         { "syslog", 0, NULL, 'S' },
00407         { "timestamps", 0, NULL, 'T' },
00408         { "no-detach", 0, NULL, 'n' },
00409         { "version", 0, NULL, ARG_VERSION },
00410 
00411         { "dump-hello", 0, NULL, ARG_DUMPHELLO },
00412         { "dump-tc", 0, NULL, ARG_DUMPTC },
00413 
00414 # ifdef QOLYESTER_ENABLE_MID
00415         { "dump-mid", 0, NULL, ARG_DUMPMID },
00416 # endif
00417 
00418 # ifdef QOLYESTER_ENABLE_HNA
00419         { "dump-hna", 0, NULL, ARG_DUMPHNA },
00420 # endif
00421 
00422         { "dump-state", 0, NULL, ARG_DUMPSTATE },
00423         { "dump-all", 0, NULL, ARG_DUMPALL },
00424         { "dump-prof", 0, NULL, ARG_DUMPPROF },
00425 
00426         { "dump-interval", 1, NULL, ARG_DUMPINTERVAL },
00427         { "no-tables", 0, NULL, ARG_NOTABLES },
00428 
00429 # ifdef QOLYESTER_ENABLE_VIRTUAL
00430         { "switch-sock", 1, NULL, ARG_SWSOCK },
00431 # endif
00432 
00433         { "debug-trace", 1, NULL, ARG_DEBUGTRACE },
00434 # if QOLYESTER_FAMILY_INET == 6
00435         { "dirty-promisc-hack", 0, NULL, ARG_DIRTYPROMISCHACK },
00436 # endif
00437         { "queue-size", 1, NULL, ARG_QUEUESIZE },
00438         { NULL, 0, NULL, 0 }
00439       };
00440 
00441       int       opt_ind = 0;
00442       int       val;
00443 
00444       typedef internal::IfTuple                 iftuple_t;
00445       typedef std::pair<std::string, unsigned>  gate_t;
00446 
00447       std::list<iftuple_t>      ifaces;
00448       std::set<iftuple_t>       ifacechecks;
00449       std::list<gate_t>         gates;
00450 
00451       std::string       all_file;
00452 
00453 # ifdef DEBUG
00454       std::ostringstream        cmdline;
00455 
00456       for (unsigned i = 0; i < (unsigned) argc; ++i)
00457         cmdline << ' ' << argv[i];
00458 # endif // !DEBUG
00459 
00460       while ((val = getopt_long(argc, argv, "i:"
00461 # ifdef QOLYESTER_ENABLE_HNA
00462                                 "o:"
00463 # endif
00464                                 "w:"
00465 # ifdef QOLYESTER_ENABLE_TCRED
00466                                 "t:"
00467 # endif
00468 # ifdef QOLYESTER_ENABLE_MPRRED
00469                                 "m:"
00470 # endif
00471                                 "hnSTv", opts, &opt_ind)) >= 0) {
00472 
00473         switch (val) {
00474         case ARG_ERRORFILE:
00475           if (!error_file.empty())
00476             die("Multiple --error-file parameters\n");
00477           error_file = optarg;
00478           break;
00479         case ARG_WARNINGFILE:
00480           if (!warning_file.empty())
00481             die("Multiple --warning-file parameters\n");
00482           warning_file = optarg;
00483           break;
00484         case ARG_NOTICEFILE:
00485           if (!notice_file.empty())
00486             die("Multiple --notice-file parameters\n");
00487           notice_file = optarg;
00488           break;
00489         case ARG_DUMPFILE:
00490           if (!dump_file.empty())
00491             die("Multiple --dump-file parameters\n");
00492           dump_file = optarg;
00493           break;
00494 # ifdef DEBUG
00495         case ARG_DEBUGFILE:
00496           if (!debug_file.empty())
00497             die("Multiple --debug-file parameters\n");
00498           debug_file = optarg;
00499           break;
00500 # endif
00501         case ARG_ALLFILE:
00502           if (!all_file.empty())
00503             die("Multiple --all-file parameters\n");
00504           all_file = optarg;
00505           break;
00506         case ARG_DUMPPROF:
00507           do_dump_prof = true;
00508           break;
00509         case ARG_DUMPALL:
00510           do_dump_hello = do_dump_tc
00511 # ifdef QOLYESTER_ENABLE_MID
00512             = do_dump_mid
00513 # endif
00514 # ifdef QOLYESTER_ENABLE_HNA
00515             = do_dump_hna
00516 # endif
00517             = true;
00518           break;
00519 # ifdef QOLYESTER_ENABLE_HNA
00520         case ARG_DUMPHNA:
00521           do_dump_hna = true;
00522           break;
00523 # endif
00524 # ifdef QOLYESTER_ENABLE_MID
00525         case ARG_DUMPMID:
00526           do_dump_mid = true;
00527           break;
00528 # endif
00529         case ARG_DUMPTC:
00530           do_dump_tc = true;
00531           break;
00532         case ARG_DUMPSTATE:
00533           do_dump_state = true;
00534           break;
00535         case ARG_DUMPHELLO:
00536           do_dump_hello = true;
00537           break;
00538 # ifndef QOLYESTER_ENABLE_VIRTUAL
00539         case ARG_NOTABLES:
00540           notables = true;
00541           break;
00542 # else // QOLYESTER_ENABLE_VIRTUAL
00543         case ARG_SWSOCK:
00544           switch_sockname = optarg;
00545           break;
00546 # endif
00547 # ifndef DEBUG
00548         case ARG_DEBUGTRACE:
00549           die("Debug trace mode only available when compiled "
00550               "with --enable-debug.\n");
00551           break;
00552 # else // DEBUG
00553         case ARG_DEBUGTRACE:
00554           debugtrace = true;
00555           debugtrace_file = optarg;
00556           break;
00557 # endif
00558 # if QOLYESTER_FAMILY_INET == 6
00559         case ARG_DIRTYPROMISCHACK:
00560           dirty_promisc_hack = true;
00561           break;
00562 # endif
00563 
00564 # define GETNUMBER(Variable, Option)                    \
00565   do {                                                  \
00566     char*       p;                                      \
00567     unsigned    val = strtoul(optarg, &p, 10);          \
00568     if (p == optarg || *p != 0 || val == 0)             \
00569       die("Parse error in --" Option ": %s\n", optarg); \
00570     cst:: Variable = val;                               \
00571   } while (0)
00572 
00573 # define GETFLOAT(Variable, Option)                     \
00574   do {                                                  \
00575     char*       p;                                      \
00576     double      val = strtod(optarg, &p);               \
00577     if (p == optarg || *p != 0 || val == 0)             \
00578       die("Parse error in --" Option ": %s\n", optarg); \
00579     cst:: Variable = val;                               \
00580   } while (0)
00581 
00582         case ARG_QUEUESIZE:
00583           GETNUMBER(queue_size, "queue-size");
00584           break;
00585         case ARG_HELLOINTERVAL:
00586           GETNUMBER(hello_interval, "hello-interval");
00587           break;
00588         case ARG_REFRESHINTERVAL:
00589           GETNUMBER(refresh_interval, "refresh-interval");
00590           break;
00591         case ARG_TCINTERVAL:
00592           GETNUMBER(tc_interval, "tc-interval");
00593           break;
00594 # ifdef QOLYESTER_ENABLE_LINKHYS
00595         case ARG_HELLOGRACE:
00596           GETFLOAT(hello_grace, "hello-grace");
00597           break;
00598         case ARG_HYSTHI:
00599           GETFLOAT(hyst_threshold_high, "hyst-threshold-high");
00600           break;
00601         case ARG_HYSTLO:
00602           GETFLOAT(hyst_threshold_low, "hyst-threshold-low");
00603           break;
00604         case ARG_HYSTSCALING:
00605           GETFLOAT(hyst_scaling, "hyst-scaling");
00606           break;
00607 # endif
00608 
00609 # ifdef QOLYESTER_ENABLE_MID
00610         case ARG_MIDINTERVAL:
00611           GETNUMBER(mid_interval, "mid-interval");
00612           break;
00613         case ARG_MIDHOLDTIME:
00614           GETNUMBER(mid_hold_time, "mid-hold-time");
00615           break;
00616 # endif
00617 # ifdef QOLYESTER_ENABLE_HNA
00618         case ARG_HNAINTERVAL:
00619           GETNUMBER(hna_interval, "hna-interval");
00620           break;
00621         case ARG_HNAHOLDTIME:
00622           GETNUMBER(hna_hold_time, "hna-hold-time");
00623           break;
00624 # endif
00625         case ARG_NEIGHBHOLDTIME:
00626           GETNUMBER(neighb_hold_time, "neighb-hold-time");
00627           break;
00628         case ARG_TOPHOLDTIME:
00629           GETNUMBER(top_hold_time, "top-hold-time");
00630           break;
00631         case ARG_DUPHOLDTIME:
00632           GETNUMBER(dup_hold_time, "dup-hold-time");
00633           break;
00634         case ARG_MAXJITTERTIME:
00635           GETNUMBER(maxjitter, "max-jitter-time");
00636           break;
00637         case ARG_DUMPINTERVAL:
00638           GETNUMBER(dump_interval, "dump-interval");
00639           break;
00640 # undef GETNUMBER
00641 # undef GETFLOAT
00642 
00643         case ARG_VERSION:
00644           dump << putversion() << std::flush;
00645           exit(0);
00646           break;
00647         case 'n':
00648           nodetach = true;
00649           break;
00650         case 'i':
00651 # ifdef QOLYESTER_ENABLE_VIRTUAL
00652 
00653           /*
00654            * The following is a determinized finite state automaton to
00655            * parse the interface specification argument.  This allows
00656            * to specify interface name, optional address to use and
00657            * switch socket to connect to, in the following format:
00658            *
00659            * ^(([A-Za-z]+[0-9]+)(=(([^,;\\]|\\.)+))?(;(([^,\\]|\\.)+))?)(,(([A-Za-z]+[0-9]+)(=(([^,;\\]|\\.)+))?(;(([^,\\]|\\.)+))?))*$
00660            *
00661            * Then name is \2, address is \4 and socket is \7 and so on.
00662            */
00663 
00664           {
00665             enum State { a, b, cdaeaf, db, dc, ddeaf, de, eb, ec, edf, ee,
00666                          accept, reset, error };
00667 
00668             State       state = a;
00669 
00670             std::string s(optarg);
00671             unsigned    i = 0;
00672 
00673             std::string name;
00674             std::string addr;
00675             std::string sock;
00676 
00677             do {
00678 
00679               if (i == s.length()) {
00680                 if (state == cdaeaf ||
00681                     state == ddeaf  ||
00682                     state == edf)
00683                   state = accept;
00684                 else
00685                   state = error;
00686               }
00687 
00688               switch (state) {
00689               case a:
00690                 if (islower(s[i]) || isupper(s[i])) {
00691                   name.append(1, s[i++]);
00692                   state = b;
00693                 } else
00694                   state = error;
00695                 break;
00696               case b:
00697                 if (islower(s[i]) || isupper(s[i]))
00698                   name.append(1, s[i++]);
00699                 else if (isdigit(s[i])) {
00700                   name.append(1, s[i++]);
00701                   state = cdaeaf;
00702                 } else
00703                   state = error;
00704                 break;
00705               case cdaeaf:
00706                 if (isdigit(s[i]))
00707                   name.append(1, s[i++]);
00708                 else if (s[i] == '=') {
00709                   ++i;
00710                   state = db;
00711                 } else if (s[i] == ';') {
00712                   ++i;
00713                   state = eb;
00714                 } else if (s[i] == ',') {
00715                   ++i;
00716                   state = reset;
00717                 } else
00718                   state = error;
00719                 break;
00720               case db:
00721                 if (s[i] == '\\') {
00722                   ++i;
00723                   state = dc;
00724                 } else if (s[i] != ',' && s[i] != ';') {
00725                   addr.append(1, s[i++]);
00726                   state = ddeaf;
00727                 } else
00728                   state = error;
00729                 break;
00730               case dc:
00731                 addr.append(1, s[i++]);
00732                 state = ddeaf;
00733                 break;
00734               case ddeaf:
00735                 if (s[i] == ';') {
00736                   ++i;
00737                   state = eb;
00738                 } else if (s[i] == ',') {
00739                   ++i;
00740                   state = reset;
00741                 } else if (s[i] == '\\') {
00742                   ++i;
00743                   state = de;
00744                 } else
00745                   addr.append(1, s[i++]);
00746                 break;
00747               case de:
00748                 addr.append(1, s[i++]);
00749                 state = ddeaf;
00750                 break;
00751               case eb:
00752                 if (s[i] == '\\') {
00753                   ++i;
00754                   state = ec;
00755                 } else if (s[i] != ',') {
00756                   sock.append(1, s[i++]);
00757                   state = edf;
00758                 } else
00759                   state = error;
00760                 break;
00761               case ec:
00762                 sock.append(1, s[i++]);
00763                 state = edf;
00764                 break;
00765               case edf:
00766                 if (s[i] == ',') {
00767                   ++i;
00768                   state = reset;
00769                 } else if (s[i] == '\\') {
00770                   ++i;
00771                   state = ee;
00772                 } else
00773                   sock.append(1, s[i++]);
00774                 break;
00775               case ee:
00776                 addr.append(1, s[i++]);
00777                 state = edf;
00778                 break;
00779               case reset:
00780                 state = a;
00781               case accept:
00782                 {
00783                   iftuple_t     t(name, addr, sock);
00784                   if (ifacechecks.find(t) != ifacechecks.end())
00785                     die("Cannot use %s twice\n", name.c_str());
00786                   ifacechecks.insert(t);
00787                   ifaces.push_back(t);
00788                 }
00789                 name.clear();
00790                 addr.clear();
00791                 sock.clear();
00792               case error:
00793                 break;
00794               }
00795 
00796             } while (state != accept && state != error);
00797 
00798             if (state != accept)
00799               die("Parse error in --interfaces : %s\n", optarg);
00800           }
00801 # else // !QOLYESTER_ENABLE_VIRTUAL
00802 
00803           /*
00804            * The following is a determinized finite state automaton to
00805            * parse the interface specification argument.  This allows
00806            * to specify interface name and optional address to use, in
00807            * the following format:
00808            *
00809            * ^(([A-Za-z]+[0-9]+)(=(([^,;\\]|\\.)+))?)(,(([A-Za-z]+[0-9]+)(=(([^,;\\]|\\.)+))?))*$
00810            *
00811            * Then name is \2 and address is \4 and so on.
00812            */
00813 
00814           {
00815             enum State { a, b, cdaf, db, dc, ddf, de, accept, reset, error };
00816 
00817             State       state = a;
00818 
00819             std::string s(optarg);
00820             unsigned    i = 0;
00821 
00822             std::string name;
00823             std::string addr;
00824 
00825             do {
00826 
00827               if (i == s.length()) {
00828                 if (state == cdaf ||
00829                     state == ddf)
00830                   state = accept;
00831                 else
00832                   state = error;
00833               }
00834 
00835               switch (state) {
00836               case a:
00837                 if (islower(s[i]) || isupper(s[i])) {
00838                   name.append(1, s[i++]);
00839                   state = b;
00840                 } else
00841                   state = error;
00842                 break;
00843               case b:
00844                 if (islower(s[i]) || isupper(s[i]))
00845                   name.append(1, s[i++]);
00846                 else if (isdigit(s[i])) {
00847                   name.append(1, s[i++]);
00848                   state = cdaf;
00849                 } else
00850                   state = error;
00851                 break;
00852               case cdaf:
00853                 if (isdigit(s[i]))
00854                   name.append(1, s[i++]);
00855                 else if (s[i] == '=') {
00856                   ++i;
00857                   state = db;
00858 # ifdef QOLYESTER_ENABLE_MID
00859                 } else if (s[i] == ',') {
00860                   ++i;
00861                   state = reset;
00862 # endif
00863                 } else
00864                   state = error;
00865                 break;
00866               case db:
00867                 if (s[i] == '\\') {
00868                   ++i;
00869                   state = dc;
00870 # ifdef QOLYESTER_ENABLE_MID
00871                 } else if (s[i] != ',' && s[i] != ';') {
00872 # else
00873                 } else if (s[i] != ';') {
00874 # endif
00875                   addr.append(1, s[i++]);
00876                   state = ddf;
00877                 } else
00878                   state = error;
00879                 break;
00880               case dc:
00881                 addr.append(1, s[i++]);
00882                 state = ddf;
00883                 break;
00884               case ddf:
00885                 if (s[i] == '\\') {
00886                   ++i;
00887                   state = de;
00888 # ifdef QOLYESTER_ENABLE_MID
00889                 } else if (s[i] == ',') {
00890                   ++i;
00891                   state = reset;
00892 # endif
00893                 } else
00894                   addr.append(1, s[i++]);
00895                 break;
00896               case de:
00897                 addr.append(1, s[i++]);
00898                 state = ddf;
00899                 break;
00900               case reset:
00901                 state = a;
00902               case accept:
00903                 {
00904                   iftuple_t     t(name, addr);
00905                   if (ifacechecks.find(t) != ifacechecks.end())
00906                     die("Cannot use %s twice\n", name.c_str());
00907                   ifacechecks.insert(t);
00908                   ifaces.push_back(t);
00909                 }
00910                 name.clear();
00911                 addr.clear();
00912               case error:
00913                 break;
00914               }
00915 
00916             } while (state != accept && state != error);
00917 
00918             if (state != accept)
00919               die("Parse error in --interfaces : %s\n", optarg);
00920           }
00921 # endif
00922           break;
00923 # ifdef QOLYESTER_ENABLE_HNA
00924         case 'o':
00925           {
00926             char* p = optarg;
00927 
00928             while (true) {
00929               char*     s = index(p, '/');
00930 
00931               if (s == NULL)
00932                 die("Parse error in --other-networks: %s\n", p);
00933 
00934               std::string       addr(p, 0, s - p);
00935               char*     ptr;
00936               unsigned  prefix = strtoul(s + 1, &ptr, 10);
00937 
00938               if (ptr == s + 1)
00939                 die("Parse error in --other-networks: %s\n", p);
00940 
00941               gates.push_back(std::pair<std::string, unsigned>(addr, prefix));
00942 
00943               p = index(p, ',');
00944 
00945               if (p == NULL)
00946                 break;
00947 
00948               ++p;
00949             }
00950           }
00951           break;
00952 # endif // ! QOLYESTER_ENABLE_HNA
00953         case 'w':
00954           {
00955             char*       p = optarg;
00956             willingness = strtoul(p, &p, 10);
00957             if (p != optarg && *p == '\0') {
00958               if (willingness > WILL_ALWAYS)
00959                 die("Parse error in --willingness: %s\n", optarg);
00960               break;
00961             }
00962 
00963             std::string s(optarg);
00964             if (s == "never")
00965               willingness = WILL_NEVER;
00966             else if (s == "low")
00967               willingness = WILL_LOW;
00968             else if (s == "default")
00969               willingness = WILL_DEFAULT;
00970             else if (s == "high")
00971               willingness = WILL_HIGH;
00972             else if (s == "always")
00973               willingness = WILL_ALWAYS;
00974             else
00975               die("Parse error in --willingness: %s\n", optarg);
00976           }
00977           break;
00978 # ifdef QOLYESTER_ENABLE_TCRED
00979         case 't':
00980           {
00981             std::string s(optarg);
00982 
00983             if (s == "mprsel")
00984               tc_redundancy = mprselset;
00985             else if (s == "mprsel+mpr")
00986               tc_redundancy = mprselset_mprset;
00987             else if (s == "whole")
00988               tc_redundancy = wholeset;
00989             else
00990               die("Parse error in --tc-redundancy: %s\n", optarg);
00991           }
00992           break;
00993 # endif // ! QOLYESTER_ENABLE_TCRED
00994 # ifdef QOLYESTER_ENABLE_MPRRED
00995         case 'm':
00996           {
00997             char*       p = optarg;
00998             mprcoverage = strtoul(p, &p, 10);
00999             if (p == optarg || *p != '\0')
01000               die("Parse error in --mpr-coverage: %s\n", optarg);
01001           }
01002           break;
01003 # endif // ! QOLYESTER_ENABLE_MPRRED
01004         case 'h':
01005           dump << usage() << std::flush;
01006           exit(1);
01007           break;
01008         case 'S':
01009           use_syslog = true;
01010           break;
01011         case 'T':
01012           timestamps = true;
01013           break;
01014         case 'v':
01015           ++current_log_level;
01016           break;
01017         default:
01018           dump << usage() << std::flush;
01019           exit(1);
01020           break;
01021         }
01022 
01023       }
01024 
01025       argc -= optind;
01026       argv += optind;
01027 
01028       if (argc > 0) {
01029         error << "Invalid argument" << (argc > 1 ? "s:" : ":");
01030         for (int i = 0; i < argc; ++i)
01031           error << ' ' << argv[i];
01032         error << std::endl;
01033         dump << usage() << std::flush;
01034         exit(1);
01035       }
01036 
01037       if (cst::hyst_threshold_high < cst::hyst_threshold_low) {
01038         error << "Invalid link hysteresis threshold values" << std::endl;
01039         exit(1);
01040       }
01041 
01042       if (!all_file.empty()) {
01043         if (error_file.empty())
01044           error_file = all_file;
01045         if (warning_file.empty())
01046           warning_file = all_file;
01047         if (notice_file.empty())
01048           notice_file = all_file;
01049         if (dump_file.empty())
01050           dump_file = all_file;
01051 # ifdef DEBUG
01052         if (debug_file.empty())
01053           debug_file = all_file;
01054 # endif
01055       }
01056 
01057       typedef std::map<std::string, std::filebuf*>      bufmap_t;
01058 
01059       bufmap_t  buf_map;
01060 
01061       // Process file outputs
01062       // ====================
01063       //
01064       // The idea here is that dump and debug are ostreams with
01065       // LevelBufs as streambufs.
01066       //
01067       //    ostream
01068       //       |
01069       //       V
01070       //    LevelBuf
01071       //       |
01072       //       V
01073       //    streambuf
01074       //
01075       // In addition, error, warning and notice are ostreams with an
01076       // additional StringPrefixBuf between the LevelBuf and the
01077       // streambuf.
01078       //
01079       //    ostream
01080       //       |
01081       //       V
01082       //    LevelBuf
01083       //       |
01084       //       V
01085       //    StringPrefixBuf
01086       //       |
01087       //       V
01088       //    streambuf
01089       //
01090       // If the user asked to redirect the corresponding output from
01091       // standard output to some file, replace the original streambuf
01092       // with a filebuf.
01093       //
01094       //    ostream
01095       //       |
01096       //       V
01097       //    LevelBuf
01098       //       |
01099       //       V
01100       //  [ StringPrefixBuf
01101       //       |
01102       //       V            ]
01103       //    filebuf
01104       //
01105       // If the user requested timestamps, a TimestampBuf has to be
01106       // added before the ultimate filebuf or streambuf.
01107       //
01108       //    ostream
01109       //       |
01110       //       V
01111       //    LevelBuf
01112       //       |
01113       //       V
01114       //  [ StringPrefixBuf
01115       //       |
01116       //       V            ]
01117       //  [ TimestampBuf
01118       //       |
01119       //       V            ]
01120       //  { filebuf | streambuf }
01121       //
01122 
01123 # define PROC_BUF(Name, Buf)                                            \
01124       do {                                                              \
01125         bufmap_t::iterator      x = buf_map.find( Name ## _file);       \
01126         if (x == buf_map.end()) {                                       \
01127           std::filebuf* b = new std::filebuf;                           \
01128           b->open( Name ## _file.c_str(),                               \
01129                    std::ios_base::out | std::ios_base::app);            \
01130           if (!b->is_open())                                            \
01131             die("Could not open \"%s\" for writing: %s\n",              \
01132                 Name ## _file.c_str(), strerror(errno));                \
01133           x = buf_map.insert(bufmap_t::                                 \
01134                              value_type( Name ## _file, b)).first;      \
01135         }                                                               \
01136         Buf ->set_streambuf(x->second);                                 \
01137       } while (false)
01138 
01139 # define SPB    StringPrefixBuf
01140 # define PROC_LOG_PREFIXED(Name)                                        \
01141       do {                                                              \
01142         if (! Name ## _file.empty()) {                                  \
01143           assert(dynamic_cast<LevelBuf*>( Name .rdbuf()) != 0);         \
01144           LevelBuf*     b = static_cast<LevelBuf*>( Name .rdbuf());     \
01145           assert(dynamic_cast< SPB *>(b->get_streambuf()) != 0);        \
01146           SPB * sb = static_cast< SPB *>(b->get_streambuf());           \
01147           if (timestamps) {                                             \
01148             TimestampBuf*       tb =                                    \
01149               new TimestampBuf(sb->get_streambuf());                    \
01150             PROC_BUF( Name , tb);                                       \
01151             sb->set_streambuf(tb);                                      \
01152           } else                                                        \
01153             PROC_BUF( Name , sb);                                       \
01154         } else if (timestamps) {                                        \
01155           assert(dynamic_cast<LevelBuf*>( Name .rdbuf()) != 0);         \
01156           LevelBuf*     b = static_cast<LevelBuf*>( Name .rdbuf());     \
01157           assert(dynamic_cast< SPB *>(b->get_streambuf()) != 0);        \
01158           SPB * sb = static_cast< SPB *>(b->get_streambuf());           \
01159           TimestampBuf* tb = new TimestampBuf(sb->get_streambuf());     \
01160           sb->set_streambuf(tb);                                        \
01161         }                                                               \
01162       } while (false)
01163 
01164 # define PROC_LOG(Name)                                                 \
01165       do {                                                              \
01166         if (! Name ## _file.empty()) {                                  \
01167           assert(dynamic_cast<LevelBuf*>( Name .rdbuf()) != 0);         \
01168           LevelBuf*     b = static_cast<LevelBuf*>( Name .rdbuf());     \
01169           if (timestamps) {                                             \
01170             TimestampBuf*       tb =                                    \
01171               new TimestampBuf(b->get_streambuf());                     \
01172             PROC_BUF( Name , tb);                                       \
01173             b->set_streambuf(tb);                                       \
01174           } else                                                        \
01175             PROC_BUF( Name , b);                                        \
01176         } else if (timestamps) {                                        \
01177           assert(dynamic_cast<LevelBuf*>( Name .rdbuf()) != 0);         \
01178           LevelBuf*     b = static_cast<LevelBuf*>( Name .rdbuf());     \
01179           TimestampBuf* tb = new TimestampBuf(b->get_streambuf());      \
01180           b->set_streambuf(tb);                                         \
01181         }                                                               \
01182       } while (false)
01183 
01184       PROC_LOG_PREFIXED(error);
01185       PROC_LOG_PREFIXED(warning);
01186       PROC_LOG_PREFIXED(notice);
01187       PROC_LOG(dump);
01188 
01189 # ifdef DEBUG
01190       PROC_LOG(debug);
01191 # endif
01192 
01193 # undef PROC_LOG
01194 # undef PROC_LOG_PREFIXED
01195 # undef SPB
01196 # undef PROC_BUF
01197 
01198       // Now copy all that pretty stuff to various dump_* ostreams
01199       // from dump.
01200 
01201       dump_state.rdbuf(dump.rdbuf());
01202       dump_prof.rdbuf(dump.rdbuf());
01203       dump_hello.rdbuf(dump.rdbuf());
01204       dump_tc.rdbuf(dump.rdbuf());
01205 # ifdef QOLYESTER_ENABLE_MID
01206       dump_mid.rdbuf(dump.rdbuf());
01207 # endif
01208 # ifdef QOLYESTER_ENABLE_HNA
01209       dump_hna.rdbuf(dump.rdbuf());
01210 # endif
01211 
01212 # ifdef DEBUG
01213 
01214       // Prepare the debugtrace logging facility.  We want all
01215       // possible logging output with timestamps output to a file
01216       // specified along with the --debug-trace option.
01217 
01218       if (debugtrace) {
01219 
01220         // First, open the output file.
01221 
01222         std::filebuf*   b = new std::filebuf;
01223         b->open(debugtrace_file.c_str(),
01224                 std::ios_base::out | std::ios_base::app);
01225 
01226         if (!b->is_open())
01227           die("Could not open \"%s\" for writing: %s\n",
01228               debugtrace_file.c_str(), strerror(errno));
01229 
01230         // Second, create the TimestampBuf with the new filebuf.
01231 
01232         TimestampBuf*   tb = new TimestampBuf(b);
01233 
01234         // Third, use a YBuf to duplicate the flow at its source
01235         // (before the original LevelBuf) and feed it to another
01236         // LevelBuf and possibly to a StringPrefixBuf and ultimately
01237         // to the TimestampBuf.
01238         //
01239         //    ostream
01240         //       |
01241         //       V
01242         //    YBuf ---> LevelBuf
01243         //       |         |
01244         //       |         V
01245         //       |    [ StringPrefixBuf
01246         //       |         |
01247         //       |         V            ]
01248         //       |    [ TimestampBuf
01249         //       |         |
01250         //       |         V            ]
01251         //       |    { filebuf | streambuf }
01252         //       V
01253         //    LevelBuf
01254         //       |
01255         //       V
01256         //  [ StringPrefixBuf
01257         //       |
01258         //       V            ]
01259         //    TimestampBuf
01260         //       |
01261         //       V
01262         //    filebuf
01263         //
01264         // The reason why we want to divert the flow before the
01265         // LevelBuf is that the current log level settings for the
01266         // original and the debugtrace are different (the one for
01267         // debugtrace is the highest possible, to ensure that
01268         // everything is logged).
01269         //
01270 
01271 # define SPB    StringPrefixBuf
01272 # define SP     StringPrefixer
01273 # define PROC_LOG_PREFIXED(Name, Level, Prefix)                         \
01274         do {                                                            \
01275           SPB *         spb = new SPB (tb, SP( Prefix ));               \
01276           LevelBuf*     lb = new LevelBuf( Level , spb,                 \
01277                                            debugtrace_log_level);       \
01278           Name .rdbuf(new YBuf( Name .rdbuf(), lb));                    \
01279         } while (false)
01280 
01281 # define PROC_LOG(Name, Level)                                          \
01282         do {                                                            \
01283           LevelBuf*     lb = new LevelBuf( Level , tb,                  \
01284                                            debugtrace_log_level);       \
01285           Name .rdbuf(new YBuf( Name .rdbuf(), lb));                    \
01286         } while (false)
01287 
01288         PROC_LOG_PREFIXED(error, 0, "ERROR: ");
01289         PROC_LOG_PREFIXED(warning, 1, "WARNING: ");
01290         PROC_LOG_PREFIXED(notice, 2, "NOTICE: ");
01291         PROC_LOG(dump, 3);
01292         PROC_LOG(debug, 5);
01293 
01294 # undef PROC_LOG
01295 # undef PROC_LOG_PREFIXED
01296 # undef SP
01297 # undef SPB
01298 
01299         // Now process the various dump_* for debugtrace.  If we have
01300         // been requested to do_dump_*, then we want to behave exactly
01301         // as dump.  Otherwise, we want dump_* to flow out
01302         // debugtrace's LevelBuf.
01303 
01304 # define PROC_DTLOG(Name)                                       \
01305         do {                                                    \
01306           if (do_dump_ ## Name )                                \
01307             dump_ ## Name .rdbuf(dump.rdbuf());                 \
01308           else {                                                \
01309             assert(dynamic_cast<YBuf*>(dump.rdbuf()) != 0);     \
01310             YBuf*       yb = static_cast<YBuf*>(dump.rdbuf());  \
01311             LevelBuf*   lb =                                    \
01312               static_cast<LevelBuf*>(yb->get_streambuf2());     \
01313             dump_ ## Name .rdbuf(lb);                           \
01314             do_dump_ ## Name = true;                            \
01315           }                                                     \
01316         } while (false)
01317 
01318         PROC_DTLOG(state);
01319         PROC_DTLOG(prof);
01320         PROC_DTLOG(hello);
01321         PROC_DTLOG(tc);
01322 # ifdef QOLYESTER_ENABLE_MID
01323         PROC_DTLOG(mid);
01324 # endif
01325 # ifdef QOLYESTER_ENABLE_HNA
01326         PROC_DTLOG(hna);
01327 # endif
01328 
01329 # undef PROC_DTLOG
01330       }
01331 # endif // !DEBUG
01332 
01333       if (use_syslog)
01334         output_syslog();
01335 
01336       dump << up << putversion() << std::flush << down;
01337 
01338 # ifdef DEBUG
01339       if (debugtrace)
01340         debug << up(500) << "Command line:" << cmdline.str()
01341               << std::endl << down(500);
01342 # endif // !DEBUG
01343 
01344       for (std::list<iftuple_t>::const_iterator i = ifaces.begin();
01345            i != ifaces.end(); ++i)
01346 # ifdef QOLYESTER_ENABLE_VIRTUAL
01347         iface_set.insert(iface_t(ifaceinfo_t(i->name,
01348                                              i->addr,
01349                                              i->sock.empty() ?
01350                                              switch_sockname : i->sock)));
01351 # else // !QOLYESTER_ENABLE_VIRTUAL
01352         if (i->addr != address_t())
01353           iface_set.insert(iface_t(ifaceinfo_t(i->name),
01354                                    i->addr));
01355         else
01356           iface_set.insert(ifaceinfo_t(i->name));
01357 # endif
01358 # ifdef QOLYESTER_ENABLE_HNA
01359       for (std::list<std::pair<std::string, unsigned> >::const_iterator i =
01360              gates.begin();
01361            i != gates.end(); ++i)
01362         gate_set.insert(set::GateEntry(address_t::network(i->first, i->second),
01363                                        i->second));
01364 # endif // ! QOLYESTER_ENABLE_HNA
01365     }
01366 
01367     void output_syslog()
01368     {
01369       // process syslog outputs
01370 
01371       openlog(shortname.c_str(), LOG_NDELAY | LOG_PID, LOG_DAEMON);
01372 
01373       // Redirect all stderr output to syslog with correct priorities
01374       // If there is a TimestampBuf before the last streambuf, remove
01375       // it (and destroy it).
01376 
01377 # define SPB    StringPrefixBuf
01378 # define PROC_LOG_PREFIXED(Name, Level)                                    \
01379       do {                                                                 \
01380         if ( Name ## _file.empty()) {                                      \
01381           std::streambuf*       b;                                         \
01382                                                                            \
01383           if(debugtrace) {                                                 \
01384             assert(dynamic_cast<YBuf*>( Name .rdbuf()) != 0);              \
01385             YBuf*       yb = static_cast<YBuf*>( Name .rdbuf());           \
01386             b = yb->get_streambuf1();                                      \
01387           } else                                                           \
01388             b = Name .rdbuf();                                             \
01389                                                                            \
01390           assert(dynamic_cast<LevelBuf*>(b) != 0);                         \
01391           LevelBuf*     lb = static_cast<LevelBuf*>(b);                    \
01392           assert(dynamic_cast< SPB *>(lb->get_streambuf()) != 0);          \
01393           SPB * sb = static_cast<SPB *>(lb->get_streambuf());              \
01394                                                                            \
01395           if (timestamps) {                                                \
01396             assert(dynamic_cast<TimestampBuf*>(sb->get_streambuf()) != 0); \
01397             delete static_cast<TimestampBuf*>(sb->get_streambuf());        \
01398           }                                                                \
01399                                                                            \
01400           sb->set_streambuf(new utl::SyslogBuf( Level ));                  \
01401         }                                                                  \
01402       } while (false)
01403 
01404 # define PROC_LOG(Name, Level)                                             \
01405       do {                                                                 \
01406         if ( Name ## _file.empty()) {                                      \
01407           std::streambuf*       b;                                         \
01408                                                                            \
01409           if(debugtrace) {                                                 \
01410             assert(dynamic_cast<YBuf*>( Name .rdbuf()) != 0);              \
01411             YBuf*       yb = static_cast<YBuf*>( Name .rdbuf());           \
01412             b = yb->get_streambuf1();                                      \
01413           } else                                                           \
01414             b = Name .rdbuf();                                             \
01415                                                                            \
01416           assert(dynamic_cast<LevelBuf*>(b) != 0);                         \
01417           LevelBuf*     lb = static_cast<LevelBuf*>(b);                    \
01418                                                                            \
01419           if (timestamps) {                                                \
01420             assert(dynamic_cast<TimestampBuf*>(lb->get_streambuf()) != 0); \
01421             delete static_cast<TimestampBuf*>(lb->get_streambuf());        \
01422           }                                                                \
01423                                                                            \
01424           lb->set_streambuf(new utl::SyslogBuf( Level ));                  \
01425         }                                                                  \
01426       } while (false)
01427 
01428       PROC_LOG_PREFIXED(error, LOG_ERR);
01429       PROC_LOG_PREFIXED(warning, LOG_WARNING);
01430       PROC_LOG_PREFIXED(notice, LOG_NOTICE);
01431       PROC_LOG(dump, LOG_INFO);
01432 # ifdef DEBUG
01433       PROC_LOG(debug, LOG_DEBUG);
01434 # endif
01435 
01436 # undef PROC_LOG
01437 # undef PROC_LOG_PREFIXED
01438 # undef SPB
01439 
01440     }
01441 
01442     // The following is a buffer to be used for std::cerr buffering.
01443 
01444     namespace {
01445       char cerr_buffer[4096];
01446     }
01447 
01448     void start_output()
01449     {
01450       // First of all, we want to enable std::cerr complete buffering, to
01451       // avoid having a write(2) issued for each line.  We want to flush
01452       // explicitly the ostream and have the write(2) issued as rarely as
01453       // possible.  In fact no buffering happens at streambuf level since
01454       // std::cerr is ultimately using stderr's buffering, hence the use
01455       // of setvbuf.
01456 
01457       setvbuf(stderr, cerr_buffer, _IOFBF, sizeof cerr_buffer);
01458 
01459       // We want exceptions to be thrown each time something bad happens
01460       // with output.  As "bad" we mean "filesystem full".
01461 
01462       error.exceptions(std::ostream::badbit);
01463       warning.exceptions(std::ostream::badbit);
01464       notice.exceptions(std::ostream::badbit);
01465       dump.exceptions(std::ostream::badbit);
01466       dump_state.exceptions(std::ostream::badbit);
01467       dump_prof.exceptions(std::ostream::badbit);
01468       dump_hello.exceptions(std::ostream::badbit);
01469       dump_tc.exceptions(std::ostream::badbit);
01470       dump_mid.exceptions(std::ostream::badbit);
01471       dump_hna.exceptions(std::ostream::badbit);
01472 #ifdef DEBUG
01473       debug.exceptions(std::ostream::badbit);
01474 #endif
01475 
01476       atexit(stop_output);
01477     }
01478 
01479     void stop_output()
01480     {
01481       error.exceptions(std::ostream::goodbit);
01482       warning.exceptions(std::ostream::goodbit);
01483       notice.exceptions(std::ostream::goodbit);
01484       dump.exceptions(std::ostream::goodbit);
01485       dump_state.exceptions(std::ostream::goodbit);
01486       dump_prof.exceptions(std::ostream::goodbit);
01487       dump_hello.exceptions(std::ostream::goodbit);
01488       dump_tc.exceptions(std::ostream::goodbit);
01489       dump_mid.exceptions(std::ostream::goodbit);
01490       dump_hna.exceptions(std::ostream::goodbit);
01491 #ifdef DEBUG
01492       debug.exceptions(std::ostream::goodbit);
01493 #endif
01494     }
01495 
01496   } // namespace utl
01497 
01498 } // namespace olsr
01499 
01500 #endif // ! QOLYESTER_DAEMON_UTL_ARGS_HXX

Generated on Mon Sep 10 17:02:11 2007 for Qolyester daemon by  doxygen 1.5.1