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