00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #ifndef TOOL_ARGS_HXX_
00023 # define TOOL_ARGS_HXX_
00024
00025 # include <iostream>
00026 # include <stdexcept>
00027 # include <cstdlib>
00028 # include <cassert>
00029 # include <sstream>
00030
00031 extern "C"
00032 {
00033 # include <unistd.h>
00034 }
00035
00036 # include <boost/preprocessor/seq/for_each.hpp>
00037 # include <boost/preprocessor/stringize.hpp>
00038 # include <boost/preprocessor/cat.hpp>
00039 # include <boost/preprocessor/tuple/elem.hpp>
00040 # include <boost/preprocessor/control/if.hpp>
00041 # include <boost/preprocessor/seq/for_each_i.hpp>
00042
00043 # include <boost/algorithm/string/split.hpp>
00044 # include <boost/algorithm/string/classification.hpp>
00045
00046 # include <boost/lexical_cast.hpp>
00047
00048 # include <wipal/tool/args.hh>
00049 # include <wipal/wifi/addr_mapping.hh>
00050
00051 # ifdef HAVE_CONFIG_H
00052 # include <config.hh>
00053 # endif
00054 # ifdef HAVE_OPENSSL
00055 # include <wipal/wifi/frame/unique_id/hash.hh>
00056 # endif // HAVE_OPENSSL
00057 # include <wipal/wifi/frame/unique_id/timestamp.hh>
00058 # include <wipal/wifi/frame/unique_id/addr_timestamp.hh>
00059 # include <wipal/wifi/frame/unique_id/source_bssid_timestamp.hh>
00060 # include <wipal/wifi/frame/unique_id/seqctl_timestamp.hh>
00061 # include <wipal/wifi/frame/unique_id/seqctl_bssid_timestamp.hh>
00062 # include <wipal/wifi/frame/unique_id/seqctl_dest_bssid_timestamp.hh>
00063 # include <wipal/wifi/frame/unique_id/seqctl_source_bssid_timestamp.hh>
00064
00065
00066 namespace tool
00067 {
00068
00069 namespace args
00070 {
00071
00072 namespace internals
00073 {
00074
00075
00076
00077
00078
00079 struct help_string
00080 {
00081 help_string(const std::string& c,
00082 const std::string& h): c_ (c), h_ (h)
00083 {
00084 }
00085
00086 std::ostream& print(std::ostream& os) const
00087 {
00088 return os << " -" << c_ << " " << h_ << '\n';
00089 }
00090
00091 private:
00092 std::string c_;
00093 std::string h_;
00094 };
00095
00096 inline
00097 std::ostream&
00098 operator << (std::ostream& os, const help_string& hs)
00099 {
00100 return hs.print(os);
00101 }
00102
00103 # define WP_args_declare_help_string(R, Unused, Opt) \
00104 extern \
00105 const help_string \
00106 BOOST_PP_CAT(help_, BOOST_PP_TUPLE_ELEM(2, 0, Opt));
00107
00108 BOOST_PP_SEQ_FOR_EACH(WP_args_declare_help_string, ~, WP_ARGS_OPTIONS)
00109
00110 # undef WP_args_declare_help_string
00111
00112
00113
00114
00115
00116
00117 inline
00118 void
00119 usage(const std::string& progname,
00120 const opt::list& opts,
00121 const count& ninputs,
00122 const count& noutputs)
00123 {
00124 std::cerr << "Invocation:\n\t" << progname << " [options]";
00125 switch (ninputs)
00126 {
00127 case 0: break;
00128 case 1: std::cerr << " <input>"; break;
00129 case 2: std::cerr << " <input-1> <input-2>"; break;
00130 default: std::cerr << " <inputs...>"; break;
00131 }
00132 switch (noutputs)
00133 {
00134 case 0: break;
00135 case 1: std::cerr << " <output>"; break;
00136 default: std::cerr << " <outputs...>"; break;
00137 }
00138
00139 std::cerr << "\n\nOptions:\n";
00140 if (opts.count("misc"))
00141 {
00142 const opt::list& misc = opt::get<opt::list>(opts["misc"]);
00143
00144 if (misc.count("cmp")) std::cerr << help_8
00145 << help_b
00146 << help_d
00147 << help_o
00148 << help_t;
00149 if (misc.count("attributes")) std::cerr << help_a;
00150 if (misc.count("mac_map")) std::cerr << help_m;
00151 if (misc.count("essid_map")) std::cerr << help_s;
00152 }
00153 if (opts.count("internals"))
00154 {
00155 const opt::list& internals = opt::get<opt::list>(opts
00156 ["internals"]);
00157
00158 if (internals.count("endianness")) std::cerr << help_n
00159 << help_N;
00160 if (internals.count("ignore_noisy_prism")) std::cerr << help_p
00161 << help_P;
00162 if (internals.count("ref_blacklist")) std::cerr << help_r;
00163 if (internals.count("phy_tstamps")) std::cerr << help_y
00164 << help_Y;
00165 }
00166 if (opts.count("ui"))
00167 {
00168 const opt::list& ui = opt::get<opt::list>(opts["ui"]);
00169
00170 if (ui.count("headers")) std::cerr << help_c
00171 << help_C;
00172 if (ui.count("errors")) std::cerr << help_e
00173 << help_E;
00174 if (ui.count("indices")) std::cerr << help_i
00175 << help_I;
00176 if (ui.count("microseconds")) std::cerr << help_u
00177 << help_U;
00178 std::cerr << help_q;
00179 }
00180 std::cerr << help_g << help_h << help_v;
00181
00182 # define WP_help_attr_string(R, Unused, A) \
00183 " " BOOST_PP_STRINGIZE(A) ":\t" \
00184 BOOST_PP_CAT(WP_ATTR_HELP_, A) "\n"
00185
00186 if (opts.count("misc") and
00187 opt::get<opt::list>(opts["misc"]).count("attributes"))
00188 std::cerr << "\nAvailable attributes:\n"
00189 BOOST_PP_SEQ_FOR_EACH(WP_help_attr_string, ~, WP_ATTRIBUTES);
00190
00191 # undef WP_help_attr_string
00192
00193 # define WP_help_linktypes_string(R, Unused, LT) \
00194 " " BOOST_PP_STRINGIZE(BOOST_PP_TUPLE_ELEM(2, 0, LT)) "\n"
00195
00196 std::cerr << "\nSupported PCAP link types:\n"
00197 BOOST_PP_SEQ_FOR_EACH(WP_help_linktypes_string, ~, WP_LINKTYPES);
00198
00199 # undef WP_help_linktypes_string
00200 }
00201
00202
00203
00204
00205
00206
00207 inline
00208 void
00209 version(const std::string& progname)
00210 {
00211 std::cerr << progname << "\n"
00212 "Trace Tools, version " << PACKAGE_VERSION << '.' << std::endl;
00213 }
00214
00215
00216
00217
00218
00219
00220 inline
00221 std::pair<unsigned, unsigned>
00222 make_reference(const std::string& s)
00223 {
00224 static const std::string err = ("Invalid reference frame "
00225 "format. Format is "
00226 "``<unsigned>-<unsigned>''");
00227 std::vector<std::string> v;
00228
00229 boost::split(v, s, boost::is_any_of("-"));
00230 if (v.size() != 2)
00231 throw std::invalid_argument (err);
00232 try
00233 {
00234 return std::make_pair(boost::lexical_cast<unsigned> (v[0]),
00235 boost::lexical_cast<unsigned> (v[1]));
00236 }
00237 catch (const boost::bad_lexical_cast&)
00238 {
00239 throw std::invalid_argument (err);
00240 }
00241 }
00242
00243 }
00244
00245
00246
00247
00248
00249 inline
00250 void
00251 parse(int argc,
00252 char* const* argv,
00253 opt::list& opts,
00254 count ninputs,
00255 count noutputs)
00256 {
00257 using opt::get;
00258
00259 opts.add((opt::name ("proc") -= opt::list
00260 ((opt::name("input") -= input(),
00261 opt::name("output") -= output())),
00262 opt::name ("internals") -= opt::list
00263 ((opt::name ("debug") -= false))));
00264
00265 int o;
00266
00267 try
00268 {
00269 while ((o = getopt(argc, argv,
00270 "8a:bcCdeEghiIm:nNpPqr:s:touUvx:yY")) != -1)
00271 switch (o)
00272 {
00273 case '8':
00274 opts["misc"]["cmp"] = cmp_802;
00275 break;
00276
00277 case 'a':
00278 opts["misc"]["attributes"] = std::string (optarg);
00279 break;
00280
00281 case 'b':
00282 opts["misc"]["cmp"] = cmp_bytes;
00283 break;
00284
00285 case 'c':
00286 opts["ui"]["headers"] = false;
00287 break;
00288
00289 case 'C':
00290 opts["ui"]["headers"] = true;
00291 break;
00292
00293 case 'd':
00294 opts["misc"]["cmp"] = cmp_default;
00295 break;
00296
00297 case 'e':
00298 opts["ui"]["errors"] = false;
00299 break;
00300
00301 case 'E':
00302 opts["ui"]["errors"] = true;
00303 break;
00304
00305 case 'g':
00306 opts["internals"]["debug"] = true;
00307 break;
00308
00309 case 'h':
00310 internals::usage(argv[0], opts, ninputs, noutputs);
00311 exit(EXIT_SUCCESS);
00312 break;
00313
00314 case 'i':
00315 opts["ui"]["indices"] = false;
00316 break;
00317
00318 case 'I':
00319 opts["ui"]["indices"] = true;
00320 break;
00321
00322 case 'm':
00323 opts["misc"]["mac_map"] = std::string (optarg);
00324 break;
00325
00326 case 'n':
00327 opts["internals"]["endianness"] = endian::little;
00328 break;
00329
00330 case 'N':
00331 opts["internals"]["endianness"] = endian::big;
00332 break;
00333
00334 case 'o':
00335 opts["misc"]["cmp"] = cmp_score;
00336 break;
00337
00338 case 'p':
00339 opts["internals"]["ignore_noisy_prism"] = false;
00340 break;
00341
00342 case 'P':
00343 opts["internals"]["ignore_noisy_prism"] = true;
00344 break;
00345
00346 case 'q':
00347 {
00348 opt::list& ui = get<opt::list>(opts["ui"]);
00349
00350 if (ui.count("errors")) ui["errors"] = false;
00351 if (ui.count("indices")) ui["indices"] = false;
00352 if (ui.count("headers")) ui["headers"] = false;
00353 if (ui.count("microseconds")) ui["microseconds"] = false;
00354 if (ui.count("summary")) ui["summary"] = false;
00355 }
00356 break;
00357
00358 case 'r':
00359 {
00360 typedef std::set< std::pair<unsigned, unsigned> > blist_type;
00361
00362 get<blist_type>(opts["internals"]["ref_blacklist"]).
00363 insert(internals::make_reference(optarg));
00364 }
00365 break;
00366
00367 case 's':
00368 opts["misc"]["essid_map"] = std::string (optarg);
00369 break;
00370
00371 case 't':
00372 opts["misc"]["cmp"] = cmp_time;
00373 break;
00374
00375 case 'u':
00376 opts["ui"]["microseconds"] = false;
00377 break;
00378
00379 case 'U':
00380 opts["ui"]["microseconds"] = true;
00381 break;
00382
00383 case 'v':
00384 internals::version(argv[0]);
00385 exit(EXIT_SUCCESS);
00386
00387 case 'x':
00388 opts["internals"]["precision"] =
00389 boost::lexical_cast<unsigned>(optarg);
00390 break;
00391
00392 case 'y':
00393 opts["internals"]["phy_tstamps"] = false;
00394 break;
00395
00396 case 'Y':
00397 opts["internals"]["phy_tstamps"] = true;
00398 break;
00399
00400 default:
00401 internals::usage(argv[0], opts, ninputs, noutputs);
00402 exit(EXIT_FAILURE);
00403 }
00404 }
00405 catch (const opt::invalid_option& e)
00406 {
00407 std::cerr
00408 << argv[0] << " invalid option -- " << char (o) << std::endl;
00409 internals::usage(argv[0], opts, ninputs, noutputs);
00410 exit(EXIT_FAILURE);
00411 }
00412
00413 if (opts.count("internals") and
00414 get<opt::list>(opts["internals"]).count("mapping"))
00415 {
00416 const std::string n = get<std::string>(opts["misc"]["mac_map"]);
00417
00418 opts["internals"]["mapping"] = wifi::addr_mapping (n);
00419 }
00420
00421 assert(ninputs != args::arbitrary or noutputs != args::arbitrary);
00422
00423 if (ninputs == args::arbitrary)
00424 ninputs = args::count (argc - optind - noutputs);
00425 if (noutputs == args::arbitrary)
00426 noutputs = args::count (argc - optind - ninputs);
00427 if (ninputs < 0 or noutputs < 0 or optind + ninputs + noutputs != argc)
00428 {
00429 std::cerr << argv[0] << ": wrong number of arguments." << std::endl;
00430 internals::usage(argv[0], opts, ninputs, noutputs);
00431 exit(EXIT_FAILURE);
00432 }
00433
00434 input& in = get<input>(opts["proc"]["input"]);
00435 output& out = get<output>(opts["proc"]["output"]);
00436
00437 for (int i = 0; i < ninputs; ++i)
00438 in.push_back(argv[optind + i]);
00439 for (int i = 0; i < noutputs; ++i)
00440 out.push_back(argv[optind + ninputs + i]);
00441
00442 if (get<bool>(opts["internals"]["debug"]))
00443 std::cerr << "DEBUG: args::parse() finished.\n"
00444 << "DEBUG: Options:\n" << opts;
00445 }
00446
00447
00448
00449
00450
00451
00452 template <class Fun>
00453 int
00454 dispatch_unique_id(opt::list& options, Fun fun)
00455 {
00456 assert(options.count("misc"));
00457 assert(opt::get<opt::list>(options["misc"]).count("attributes"));
00458
00459 const std::string& attr = opt::get<std::string>(options["misc"]
00460 ["attributes"]);
00461
00462 if (false)
00463 ;
00464 # define WP_dispatch_unique_id_else(R, Unused, A) \
00465 else if (attr == BOOST_PP_STRINGIZE(A)) \
00466 return fun.template operator () \
00467 <wifi::frame::BOOST_PP_CAT(A, _id)>(options);
00468
00469 BOOST_PP_SEQ_FOR_EACH(WP_dispatch_unique_id_else, ~, WP_ATTRIBUTES)
00470
00471 # undef WP_dispatch_unique_id_else
00472
00473 throw std::invalid_argument ("Invalid distinctive attributes");
00474 }
00475
00476
00477
00478
00479
00480
00481 inline
00482 void
00483 unsupported_linktype(const pcapxx::descriptor<>::link_type lt)
00484 {
00485 std::ostringstream os;
00486
00487 # define WP_linktype_string(R, Unused, I, LT) \
00488 BOOST_PP_IF(I, ", ", "") \
00489 BOOST_PP_STRINGIZE(BOOST_PP_TUPLE_ELEM(2, 0, LT))
00490
00491 os << "Unsupported PCAP link type: " << lt << " - expected one of ["
00492 BOOST_PP_SEQ_FOR_EACH_I(WP_linktype_string, ~, WP_LINKTYPES) "]";
00493
00494 # undef WP_linktype_string
00495
00496 throw std::invalid_argument (os.str());
00497 }
00498
00499
00500
00501
00502
00503 inline
00504 void
00505 check_options(opt::list& o, const pcapxx::descriptor<>::link_type l)
00506 {
00507
00508 if (o.count("internals") and
00509 o["internals"].get<opt::list>().count("ignore_noisy_prism") and
00510 o["internals"]["ignore_noisy_prism"].get<bool>() and
00511 l != pcapxx::descriptor<>::PRISM_HEADER)
00512 throw std::invalid_argument ("Expected PRISM_HEADER because of '-P', "
00513 "got " +
00514 boost::lexical_cast<std::string>(l));
00515
00516 if (o.count("misc") and o["misc"].get<opt::list>().count("attributes"))
00517 {
00518 const std::string& attr = (o["misc"]["attributes"]
00519 .get<std::string>());
00520
00521
00522 if (attr == "hsh_en2")
00523 {
00524 if (l != pcapxx::descriptor<>::EN10MB)
00525 throw std::invalid_argument ("Expected EN10MB because of "
00526 "\"-a hsh_en2\", got " +
00527 boost::lexical_cast<std::string>
00528 (l));
00529 }
00530
00531 else if (l == pcapxx::descriptor<>::EN10MB)
00532 throw std::invalid_argument ("EN10MB traces only works with "
00533 "\"-a hsh_en2\"");
00534 }
00535 }
00536
00537
00538
00539
00540
00541 void
00542 ensure_80211(const pcapxx::descriptor<>::link_type lt)
00543 {
00544 switch (lt)
00545 {
00546 case pcapxx::descriptor<>::IEEE802_11:
00547 case pcapxx::descriptor<>::IEEE802_11_RADIO:
00548 case pcapxx::descriptor<>::IEEE802_11_RADIO_AVS:
00549 case pcapxx::descriptor<>::PRISM_HEADER:
00550 return;
00551
00552 default:
00553 throw std::invalid_argument ("Expected a link type that includes "
00554 "IEEE 802.11 frames, got " +
00555 boost::lexical_cast<std::string>(lt));
00556 }
00557 }
00558
00559 namespace def
00560 {
00561
00562 inline
00563 endian::endianness
00564 endianness()
00565 {
00566 return endian::guess;
00567 }
00568
00569 inline
00570 std::set< std::pair<unsigned, unsigned> >
00571 ref_blacklist()
00572 {
00573 return std::set< std::pair<unsigned, unsigned> > ();
00574 }
00575
00576 inline
00577 undefined_type
00578 mapping()
00579 {
00580 return undefined_type ();
00581 }
00582
00583 inline
00584 bool
00585 ignore_noisy_prism()
00586 {
00587 return false;
00588 }
00589
00590 inline
00591 std::string
00592 mac_map()
00593 {
00594 return "MAC.map";
00595 }
00596
00597 inline
00598 std::string
00599 essid_map()
00600 {
00601 return "ESSID.map";
00602 }
00603
00604 inline
00605 std::string
00606 attributes()
00607 {
00608 return BOOST_PP_STRINGIZE(WP_DEFAULT_ATTRIBUTES);
00609 }
00610
00611 inline
00612 comp_method
00613 cmp()
00614 {
00615 return cmp_default;
00616 }
00617
00618 inline
00619 bool
00620 ui_errors()
00621 {
00622 return false;
00623 }
00624
00625 inline
00626 bool
00627 ui_indices()
00628 {
00629 return true;
00630 }
00631
00632 inline
00633 bool
00634 ui_headers()
00635 {
00636 return isatty(STDOUT_FILENO);
00637 }
00638
00639 inline
00640 bool
00641 ui_microseconds()
00642 {
00643 return false;
00644 }
00645
00646 inline
00647 bool
00648 ui_summary()
00649 {
00650 return true;
00651 }
00652
00653 inline
00654 unsigned
00655 precision()
00656 {
00657 return 106;
00658 }
00659
00660 inline
00661 bool
00662 phy_tstamps()
00663 {
00664 return true;
00665 }
00666
00667 }
00668
00669 }
00670
00671 }
00672
00673 #endif // TOOL_ARGS_HXX_
00674