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/unique_id/hash.hh>
00056 # endif // HAVE_OPENSSL
00057 # include <wipal/wifi/unique_id/timestamp.hh>
00058 # include <wipal/wifi/unique_id/addr_timestamp.hh>
00059 # include <wipal/wifi/unique_id/source_bssid_timestamp.hh>
00060 # include <wipal/wifi/unique_id/seqctl_timestamp.hh>
00061 # include <wipal/wifi/unique_id/seqctl_bssid_timestamp.hh>
00062 # include <wipal/wifi/unique_id/seqctl_dest_bssid_timestamp.hh>
00063 # include <wipal/wifi/unique_id/seqctl_source_bssid_timestamp.hh>
00064
00065
00066 namespace wpl
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("precision")) std::cerr << help_x;
00164 if (internals.count("phy_tstamps")) std::cerr << help_y
00165 << help_Y;
00166 }
00167 if (opts.count("ui"))
00168 {
00169 const opt::list& ui = opt::get<opt::list>(opts["ui"]);
00170
00171 if (ui.count("headers")) std::cerr << help_c
00172 << help_C;
00173 if (ui.count("errors")) std::cerr << help_e
00174 << help_E;
00175 if (ui.count("hex_summary")) std::cerr << help_f
00176 << help_F;
00177 if (ui.count("indices")) std::cerr << help_i
00178 << help_I;
00179 if (ui.count("microseconds")) std::cerr << help_u
00180 << help_U;
00181 std::cerr << help_q;
00182 }
00183 std::cerr << help_g << help_h << help_v;
00184
00185 # define WP_help_attr_string(R, Unused, A) \
00186 " " BOOST_PP_STRINGIZE(A) ":\t" \
00187 BOOST_PP_CAT(WP_ATTR_HELP_, A) "\n"
00188
00189 if (opts.count("misc") and
00190 opt::get<opt::list>(opts["misc"]).count("attributes"))
00191 std::cerr << "\nAvailable attributes:\n"
00192 BOOST_PP_SEQ_FOR_EACH(WP_help_attr_string, ~, WP_ATTRIBUTES);
00193
00194 # undef WP_help_attr_string
00195
00196 # define WP_help_linktypes_string(R, Unused, LT) \
00197 " " BOOST_PP_STRINGIZE(BOOST_PP_TUPLE_ELEM(2, 0, LT)) "\n"
00198
00199 std::cerr << "\nSupported PCAP link types:\n"
00200 BOOST_PP_SEQ_FOR_EACH(WP_help_linktypes_string, ~, WP_LINKTYPES);
00201
00202 # undef WP_help_linktypes_string
00203 }
00204
00205
00206
00207
00208
00209
00210 inline
00211 void
00212 version(const std::string& progname)
00213 {
00214 std::cerr << progname
00215 << ", from package " << PACKAGE_NAME
00216 << ", version " << PACKAGE_VERSION
00217 << '.' << std::endl;
00218 }
00219
00220
00221
00222
00223
00224
00225 inline
00226 std::pair<unsigned, unsigned>
00227 make_reference(const std::string& s)
00228 {
00229 static const std::string err = ("Invalid reference frame "
00230 "format. Format is "
00231 "``<unsigned>-<unsigned>''");
00232 std::vector<std::string> v;
00233
00234 boost::split(v, s, boost::is_any_of("-"));
00235 if (v.size() != 2)
00236 throw std::invalid_argument (err);
00237 try
00238 {
00239 return std::make_pair(boost::lexical_cast<unsigned> (v[0]),
00240 boost::lexical_cast<unsigned> (v[1]));
00241 }
00242 catch (const boost::bad_lexical_cast&)
00243 {
00244 throw std::invalid_argument (err);
00245 }
00246 }
00247
00248 }
00249
00250
00251
00252
00253
00254 inline
00255 void
00256 parse(int argc,
00257 char* const* argv,
00258 opt::list& opts,
00259 count ninputs,
00260 count noutputs)
00261 {
00262 using opt::get;
00263
00264 opts.add((opt::name ("proc") -= opt::list
00265 ((opt::name("input") -= input(),
00266 opt::name("output") -= output())),
00267 opt::name ("internals") -= opt::list
00268 ((opt::name ("debug") -= false))));
00269
00270 int o;
00271
00272 try
00273 {
00274 while ((o = getopt(argc, argv,
00275 "8a:bcCdeEfFghiIm:nNpPqr:s:touUvx:yY")) != -1)
00276 switch (o)
00277 {
00278 case '8':
00279 opts["misc"]["cmp"] = cmp_802;
00280 break;
00281
00282 case 'a':
00283 opts["misc"]["attributes"] = std::string (optarg);
00284 break;
00285
00286 case 'b':
00287 opts["misc"]["cmp"] = cmp_bytes;
00288 break;
00289
00290 case 'c':
00291 opts["ui"]["headers"] = false;
00292 break;
00293
00294 case 'C':
00295 opts["ui"]["headers"] = true;
00296 break;
00297
00298 case 'd':
00299 opts["misc"]["cmp"] = cmp_default;
00300 break;
00301
00302 case 'e':
00303 opts["ui"]["errors"] = false;
00304 break;
00305
00306 case 'E':
00307 opts["ui"]["errors"] = true;
00308 break;
00309
00310 case 'f':
00311 opts["ui"]["hex_summary"] = short80211;
00312 break;
00313
00314 case 'F':
00315 opts["ui"]["hex_summary"] = full;
00316 break;
00317
00318 case 'g':
00319 opts["internals"]["debug"] = true;
00320 break;
00321
00322 case 'h':
00323 internals::usage(argv[0], opts, ninputs, noutputs);
00324 exit(EXIT_SUCCESS);
00325 break;
00326
00327 case 'i':
00328 opts["ui"]["indices"] = false;
00329 break;
00330
00331 case 'I':
00332 opts["ui"]["indices"] = true;
00333 break;
00334
00335 case 'm':
00336 opts["misc"]["mac_map"] = std::string (optarg);
00337 break;
00338
00339 case 'n':
00340 opts["internals"]["endianness"] = tool::end::little;
00341 break;
00342
00343 case 'N':
00344 opts["internals"]["endianness"] = tool::end::big;
00345 break;
00346
00347 case 'o':
00348 opts["misc"]["cmp"] = cmp_score;
00349 break;
00350
00351 case 'p':
00352 opts["internals"]["ignore_noisy_prism"] = false;
00353 break;
00354
00355 case 'P':
00356 opts["internals"]["ignore_noisy_prism"] = true;
00357 break;
00358
00359 case 'q':
00360 {
00361 opt::list& ui = get<opt::list>(opts["ui"]);
00362
00363 if (ui.count("errors")) ui["errors"] = false;
00364 if (ui.count("indices")) ui["indices"] = false;
00365 if (ui.count("headers")) ui["headers"] = false;
00366 if (ui.count("microseconds")) ui["microseconds"] = false;
00367 if (ui.count("summary")) ui["summary"] = false;
00368 if (ui.count("hex_summary")) ui["hex_summary"] = nohex;
00369 }
00370 break;
00371
00372 case 'r':
00373 {
00374 typedef std::set< std::pair<unsigned, unsigned> > blist_type;
00375
00376 get<blist_type>(opts["internals"]["ref_blacklist"]).
00377 insert(internals::make_reference(optarg));
00378 }
00379 break;
00380
00381 case 's':
00382 opts["misc"]["essid_map"] = std::string (optarg);
00383 break;
00384
00385 case 't':
00386 opts["misc"]["cmp"] = cmp_time;
00387 break;
00388
00389 case 'u':
00390 opts["ui"]["microseconds"] = false;
00391 break;
00392
00393 case 'U':
00394 opts["ui"]["microseconds"] = true;
00395 break;
00396
00397 case 'v':
00398 internals::version(argv[0]);
00399 exit(EXIT_SUCCESS);
00400
00401 case 'x':
00402 opts["internals"]["precision"] =
00403 boost::lexical_cast<unsigned>(optarg);
00404 break;
00405
00406 case 'y':
00407 opts["internals"]["phy_tstamps"] = false;
00408 break;
00409
00410 case 'Y':
00411 opts["internals"]["phy_tstamps"] = true;
00412 break;
00413
00414 default:
00415 internals::usage(argv[0], opts, ninputs, noutputs);
00416 exit(EXIT_FAILURE);
00417 }
00418 }
00419 catch (const opt::invalid_option& e)
00420 {
00421 std::cerr
00422 << argv[0] << " invalid option -- " << char (o) << std::endl;
00423 internals::usage(argv[0], opts, ninputs, noutputs);
00424 exit(EXIT_FAILURE);
00425 }
00426
00427 if (opts.count("internals") and
00428 get<opt::list>(opts["internals"]).count("mapping"))
00429 {
00430 const std::string n = get<std::string>(opts["misc"]["mac_map"]);
00431
00432 opts["internals"]["mapping"] = wifi::addr_mapping (n);
00433 }
00434
00435 assert(ninputs != args::arbitrary or noutputs != args::arbitrary);
00436
00437 if (ninputs == args::arbitrary)
00438 ninputs = args::count (argc - optind - noutputs);
00439 if (noutputs == args::arbitrary)
00440 noutputs = args::count (argc - optind - ninputs);
00441 if (ninputs < 0 or noutputs < 0 or optind + ninputs + noutputs != argc)
00442 {
00443 std::cerr << argv[0] << ": wrong number of arguments." << std::endl;
00444 internals::usage(argv[0], opts, ninputs, noutputs);
00445 exit(EXIT_FAILURE);
00446 }
00447
00448 input& in = get<input>(opts["proc"]["input"]);
00449 output& out = get<output>(opts["proc"]["output"]);
00450
00451 for (int i = 0; i < ninputs; ++i)
00452 in.push_back(argv[optind + i]);
00453 for (int i = 0; i < noutputs; ++i)
00454 out.push_back(argv[optind + ninputs + i]);
00455
00456 if (get<bool>(opts["internals"]["debug"]))
00457 std::cerr << "DEBUG: args::parse() finished.\n"
00458 << "DEBUG: Options:\n" << opts;
00459 }
00460
00461
00462
00463
00464
00465
00466 template <class Fun>
00467 int
00468 dispatch_unique_id(opt::list& options, Fun fun)
00469 {
00470 assert(options.count("misc"));
00471 assert(opt::get<opt::list>(options["misc"]).count("attributes"));
00472
00473 const std::string& attr = opt::get<std::string>(options["misc"]
00474 ["attributes"]);
00475
00476 if (false)
00477 ;
00478 # define WP_dispatch_unique_id_else(R, Unused, A) \
00479 else if (attr == BOOST_PP_STRINGIZE(A)) \
00480 return fun.template operator () \
00481 <wifi::BOOST_PP_CAT(A, _id)>(options);
00482
00483 BOOST_PP_SEQ_FOR_EACH(WP_dispatch_unique_id_else, ~, WP_ATTRIBUTES)
00484
00485 # undef WP_dispatch_unique_id_else
00486
00487 throw std::invalid_argument ("Invalid distinctive attributes");
00488 }
00489
00490
00491
00492
00493
00494
00495 inline
00496 void
00497 unsupported_linktype(const pkt::type t)
00498 {
00499 std::ostringstream os;
00500
00501 # define WP_linktype_string(R, Unused, I, LT) \
00502 BOOST_PP_IF(I, ", ", "") \
00503 BOOST_PP_STRINGIZE(BOOST_PP_TUPLE_ELEM(2, 0, LT))
00504
00505 os << "Unsupported PCAP link type: " << t << " - expected one of ["
00506 BOOST_PP_SEQ_FOR_EACH_I(WP_linktype_string, ~, WP_LINKTYPES) "]";
00507
00508 # undef WP_linktype_string
00509
00510 throw std::invalid_argument (os.str());
00511 }
00512
00513
00514
00515
00516
00517 inline
00518 void
00519 check_options(opt::list& o, const pkt::type t)
00520 {
00521
00522 if (o.count("internals") and
00523 o["internals"].get<opt::list>().count("ignore_noisy_prism") and
00524 o["internals"]["ignore_noisy_prism"].get<bool>() and
00525 t != pkt::PRISM_HEADER)
00526 throw std::invalid_argument ("Expected PRISM_HEADER because of '-P', "
00527 "got " +
00528 boost::lexical_cast<std::string>(t));
00529
00530
00531 if (o.count("ui") and o["ui"].get<opt::list>().count("hex_summary"))
00532 ensure_80211(t);
00533
00534 if (o.count("misc") and o["misc"].get<opt::list>().count("attributes"))
00535 {
00536 const std::string& attr = (o["misc"]["attributes"]
00537 .get<std::string>());
00538
00539
00540 if (attr == "hsh_en2")
00541 {
00542 if (t != pkt::EN10MB)
00543 throw std::invalid_argument ("Expected EN10MB because of "
00544 "\"-a hsh_en2\", got " +
00545 boost::lexical_cast<std::string>
00546 (t));
00547 }
00548
00549 else if (t == pkt::EN10MB)
00550 throw std::invalid_argument ("EN10MB traces only works with "
00551 "\"-a hsh_en2\"");
00552 }
00553 }
00554
00555
00556
00557
00558
00559 inline
00560 void
00561 ensure_80211(const pkt::type t)
00562 {
00563 switch (t)
00564 {
00565 case pkt::IEEE802_11:
00566 case pkt::IEEE802_11_RADIO:
00567 case pkt::IEEE802_11_RADIO_AVS:
00568 case pkt::PRISM_HEADER:
00569 return;
00570
00571 default:
00572 throw std::invalid_argument ("Expected a link type that includes "
00573 "IEEE 802.11 frames, got " +
00574 boost::lexical_cast<std::string>(t));
00575 }
00576 }
00577
00578 namespace def
00579 {
00580
00581 inline
00582 tool::end::endianness
00583 endianness()
00584 {
00585 return tool::end::guess;
00586 }
00587
00588 inline
00589 std::set< std::pair<unsigned, unsigned> >
00590 ref_blacklist()
00591 {
00592 return std::set< std::pair<unsigned, unsigned> > ();
00593 }
00594
00595 inline
00596 tool::undefined_type
00597 mapping()
00598 {
00599 return tool::undefined_type ();
00600 }
00601
00602 inline
00603 bool
00604 ignore_noisy_prism()
00605 {
00606 return false;
00607 }
00608
00609 inline
00610 std::string
00611 mac_map()
00612 {
00613 return "MAC.map";
00614 }
00615
00616 inline
00617 std::string
00618 essid_map()
00619 {
00620 return "ESSID.map";
00621 }
00622
00623 inline
00624 std::string
00625 attributes()
00626 {
00627 return BOOST_PP_STRINGIZE(WP_DEFAULT_ATTRIBUTES);
00628 }
00629
00630 inline
00631 comp_method
00632 cmp()
00633 {
00634 return cmp_default;
00635 }
00636
00637 inline
00638 bool
00639 ui_errors()
00640 {
00641 return false;
00642 }
00643
00644 inline
00645 bool
00646 ui_indices()
00647 {
00648 return true;
00649 }
00650
00651 inline
00652 bool
00653 ui_headers()
00654 {
00655 return isatty(STDOUT_FILENO);
00656 }
00657
00658 inline
00659 bool
00660 ui_microseconds()
00661 {
00662 return false;
00663 }
00664
00665 inline
00666 hex_summary
00667 ui_hex_summary()
00668 {
00669 return nohex;
00670 }
00671
00672 inline
00673 bool
00674 ui_summary()
00675 {
00676 return true;
00677 }
00678
00679 inline
00680 unsigned
00681 precision()
00682 {
00683 return 106;
00684 }
00685
00686 inline
00687 bool
00688 phy_tstamps()
00689 {
00690 return true;
00691 }
00692
00693 }
00694
00695 }
00696
00697 }
00698
00699 #endif // TOOL_ARGS_HXX_
00700