00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
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 }
00323
00324 }
00325
00326 }
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 }
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
00655
00656
00657
00658
00659
00660
00661
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
00805
00806
00807
00808
00809
00810
00811
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
01062
01063
01064
01065
01066
01067
01068
01069
01070
01071
01072
01073
01074
01075
01076
01077
01078
01079
01080
01081
01082
01083
01084
01085
01086
01087
01088
01089
01090
01091
01092
01093
01094
01095
01096
01097
01098
01099
01100
01101
01102
01103
01104
01105
01106
01107
01108
01109
01110
01111
01112
01113
01114
01115
01116
01117
01118
01119
01120
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
01199
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
01215
01216
01217
01218 if (debugtrace) {
01219
01220
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
01231
01232 TimestampBuf* tb = new TimestampBuf(b);
01233
01234
01235
01236
01237
01238
01239
01240
01241
01242
01243
01244
01245
01246
01247
01248
01249
01250
01251
01252
01253
01254
01255
01256
01257
01258
01259
01260
01261
01262
01263
01264
01265
01266
01267
01268
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
01300
01301
01302
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
01370
01371 openlog(shortname.c_str(), LOG_NDELAY | LOG_PID, LOG_DAEMON);
01372
01373
01374
01375
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
01443
01444 namespace {
01445 char cerr_buffer[4096];
01446 }
01447
01448 void start_output()
01449 {
01450
01451
01452
01453
01454
01455
01456
01457 setvbuf(stderr, cerr_buffer, _IOFBF, sizeof cerr_buffer);
01458
01459
01460
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 }
01497
01498 }
01499
01500 #endif // ! QOLYESTER_DAEMON_UTL_ARGS_HXX