00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
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 }
00297
00298 }
00299
00300 }
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 }
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
00586
00587
00588
00589
00590
00591
00592
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
00736
00737
00738
00739
00740
00741
00742
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
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
01184
01185 openlog(shortname.c_str(), LOG_NDELAY | LOG_PID, LOG_DAEMON);
01186
01187
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 }
01255
01256 }
01257
01258 #endif // ! QOLYESTER_DAEMON_UTL_ARGS_HXX