utils.rs 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. // TODO: this is literally a copy of examples/utils.rs, but without an allow dead code attribute.
  2. // The include logic does not allow having attributes in included files.
  3. use getopts::{Matches, Options};
  4. use std::env;
  5. use std::fs::File;
  6. use std::io;
  7. use std::io::Write;
  8. use std::process;
  9. use std::str::{self, FromStr};
  10. use std::time::{SystemTime, UNIX_EPOCH};
  11. use smoltcp::phy::{Device, FaultInjector, Tracer};
  12. use smoltcp::phy::{PcapMode, PcapWriter};
  13. use smoltcp::time::Duration;
  14. pub fn create_options() -> (Options, Vec<&'static str>) {
  15. let mut opts = Options::new();
  16. opts.optflag("h", "help", "print this help menu");
  17. (opts, Vec::new())
  18. }
  19. pub fn parse_options(options: &Options, free: Vec<&str>) -> Matches {
  20. match options.parse(env::args().skip(1)) {
  21. Err(err) => {
  22. println!("{}", err);
  23. process::exit(1)
  24. }
  25. Ok(matches) => {
  26. if matches.opt_present("h") || matches.free.len() != free.len() {
  27. let brief = format!(
  28. "Usage: {} [OPTION]... {}",
  29. env::args().nth(0).unwrap(),
  30. free.join(" ")
  31. );
  32. print!("{}", options.usage(&brief));
  33. process::exit(if matches.free.len() != free.len() {
  34. 1
  35. } else {
  36. 0
  37. })
  38. }
  39. matches
  40. }
  41. }
  42. }
  43. pub fn add_middleware_options(opts: &mut Options, _free: &mut Vec<&str>) {
  44. opts.optopt("", "pcap", "Write a packet capture file", "FILE");
  45. opts.optopt(
  46. "",
  47. "drop-chance",
  48. "Chance of dropping a packet (%)",
  49. "CHANCE",
  50. );
  51. opts.optopt(
  52. "",
  53. "corrupt-chance",
  54. "Chance of corrupting a packet (%)",
  55. "CHANCE",
  56. );
  57. opts.optopt(
  58. "",
  59. "size-limit",
  60. "Drop packets larger than given size (octets)",
  61. "SIZE",
  62. );
  63. opts.optopt(
  64. "",
  65. "tx-rate-limit",
  66. "Drop packets after transmit rate exceeds given limit \
  67. (packets per interval)",
  68. "RATE",
  69. );
  70. opts.optopt(
  71. "",
  72. "rx-rate-limit",
  73. "Drop packets after transmit rate exceeds given limit \
  74. (packets per interval)",
  75. "RATE",
  76. );
  77. opts.optopt(
  78. "",
  79. "shaping-interval",
  80. "Sets the interval for rate limiting (ms)",
  81. "RATE",
  82. );
  83. }
  84. pub fn parse_middleware_options<D>(
  85. matches: &mut Matches,
  86. device: D,
  87. loopback: bool,
  88. ) -> FaultInjector<Tracer<PcapWriter<D, Box<dyn Write>>>>
  89. where
  90. D: for<'a> Device<'a>,
  91. {
  92. let drop_chance = matches
  93. .opt_str("drop-chance")
  94. .map(|s| u8::from_str(&s).unwrap())
  95. .unwrap_or(0);
  96. let corrupt_chance = matches
  97. .opt_str("corrupt-chance")
  98. .map(|s| u8::from_str(&s).unwrap())
  99. .unwrap_or(0);
  100. let size_limit = matches
  101. .opt_str("size-limit")
  102. .map(|s| usize::from_str(&s).unwrap())
  103. .unwrap_or(0);
  104. let tx_rate_limit = matches
  105. .opt_str("tx-rate-limit")
  106. .map(|s| u64::from_str(&s).unwrap())
  107. .unwrap_or(0);
  108. let rx_rate_limit = matches
  109. .opt_str("rx-rate-limit")
  110. .map(|s| u64::from_str(&s).unwrap())
  111. .unwrap_or(0);
  112. let shaping_interval = matches
  113. .opt_str("shaping-interval")
  114. .map(|s| u64::from_str(&s).unwrap())
  115. .unwrap_or(0);
  116. let pcap_writer: Box<dyn io::Write>;
  117. if let Some(pcap_filename) = matches.opt_str("pcap") {
  118. pcap_writer = Box::new(File::create(pcap_filename).expect("cannot open file"))
  119. } else {
  120. pcap_writer = Box::new(io::sink())
  121. }
  122. let seed = SystemTime::now()
  123. .duration_since(UNIX_EPOCH)
  124. .unwrap()
  125. .subsec_nanos();
  126. let device = PcapWriter::new(
  127. device,
  128. pcap_writer,
  129. if loopback {
  130. PcapMode::TxOnly
  131. } else {
  132. PcapMode::Both
  133. },
  134. );
  135. let device = Tracer::new(device, |_timestamp, _printer| {
  136. #[cfg(feature = "log")]
  137. trace!("{}", _printer);
  138. });
  139. let mut device = FaultInjector::new(device, seed);
  140. device.set_drop_chance(drop_chance);
  141. device.set_corrupt_chance(corrupt_chance);
  142. device.set_max_packet_size(size_limit);
  143. device.set_max_tx_rate(tx_rate_limit);
  144. device.set_max_rx_rate(rx_rate_limit);
  145. device.set_bucket_interval(Duration::from_millis(shaping_interval));
  146. device
  147. }