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

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

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