tracer.rs 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. use core::fmt;
  2. use crate::{Result, wire::pretty_print::{PrettyIndent, PrettyPrint}};
  3. use crate::phy::{self, DeviceCapabilities, Device, Medium};
  4. use crate::time::Instant;
  5. /// A tracer device.
  6. ///
  7. /// A tracer is a device that pretty prints all packets traversing it
  8. /// using the provided writer function, and then passes them to another
  9. /// device.
  10. pub struct Tracer<D: for<'a> Device<'a>> {
  11. inner: D,
  12. writer: fn(Instant, Packet),
  13. }
  14. impl<D: for<'a> Device<'a>> Tracer<D> {
  15. /// Create a tracer device.
  16. pub fn new(inner: D, writer: fn(timestamp: Instant, packet: Packet)) -> Tracer<D> {
  17. Tracer { inner, writer }
  18. }
  19. /// Get a reference to the underlying device.
  20. ///
  21. /// Even if the device offers reading through a standard reference, it is inadvisable to
  22. /// directly read from the device as doing so will circumvent the tracing.
  23. pub fn get_ref(&self) -> &D {
  24. &self.inner
  25. }
  26. /// Get a mutable reference to the underlying device.
  27. ///
  28. /// It is inadvisable to directly read from the device as doing so will circumvent the tracing.
  29. pub fn get_mut(&mut self) -> &mut D {
  30. &mut self.inner
  31. }
  32. /// Return the underlying device, consuming the tracer.
  33. pub fn into_inner(self) -> D {
  34. self.inner
  35. }
  36. }
  37. impl<'a, D> Device<'a> for Tracer<D>
  38. where D: for<'b> Device<'b>,
  39. {
  40. type RxToken = RxToken<<D as Device<'a>>::RxToken>;
  41. type TxToken = TxToken<<D as Device<'a>>::TxToken>;
  42. fn capabilities(&self) -> DeviceCapabilities { self.inner.capabilities() }
  43. fn receive(&'a mut self) -> Option<(Self::RxToken, Self::TxToken)> {
  44. let &mut Self { ref mut inner, writer, .. } = self;
  45. let medium = inner.capabilities().medium;
  46. inner.receive().map(|(rx_token, tx_token)| {
  47. let rx = RxToken { token: rx_token, writer, medium };
  48. let tx = TxToken { token: tx_token, writer, medium };
  49. (rx, tx)
  50. })
  51. }
  52. fn transmit(&'a mut self) -> Option<Self::TxToken> {
  53. let &mut Self { ref mut inner, writer } = self;
  54. let medium = inner.capabilities().medium;
  55. inner.transmit().map(|tx_token| {
  56. TxToken { token: tx_token, medium, writer }
  57. })
  58. }
  59. }
  60. #[doc(hidden)]
  61. pub struct RxToken<Rx: phy::RxToken> {
  62. token: Rx,
  63. writer: fn(Instant, Packet),
  64. medium: Medium,
  65. }
  66. impl<Rx: phy::RxToken> phy::RxToken for RxToken<Rx> {
  67. fn consume<R, F>(self, timestamp: Instant, f: F) -> Result<R>
  68. where F: FnOnce(&mut [u8]) -> R
  69. {
  70. let Self { token, writer, medium } = self;
  71. token.consume(timestamp, |buffer| {
  72. writer(timestamp, Packet{
  73. buffer,
  74. medium,
  75. prefix: "<- ",
  76. });
  77. f(buffer)
  78. })
  79. }
  80. }
  81. #[doc(hidden)]
  82. pub struct TxToken<Tx: phy::TxToken> {
  83. token: Tx,
  84. writer: fn(Instant, Packet),
  85. medium: Medium,
  86. }
  87. impl<Tx: phy::TxToken> phy::TxToken for TxToken<Tx> {
  88. fn consume<R, F>(self, timestamp: Instant, len: usize, f: F) -> Result<R>
  89. where F: FnOnce(&mut [u8]) -> R
  90. {
  91. let Self { token, writer, medium } = self;
  92. token.consume(timestamp, len, |buffer| {
  93. let result = f(buffer);
  94. writer(timestamp, Packet{
  95. buffer,
  96. medium,
  97. prefix: "-> ",
  98. });
  99. result
  100. })
  101. }
  102. }
  103. pub struct Packet<'a> {
  104. buffer: &'a [u8],
  105. medium: Medium,
  106. prefix: &'static str,
  107. }
  108. impl<'a> fmt::Display for Packet<'a> {
  109. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  110. let mut indent = PrettyIndent::new(self.prefix);
  111. match self.medium {
  112. #[cfg(feature = "medium-ethernet")]
  113. Medium::Ethernet => crate::wire::EthernetFrame::<&'static [u8]>::pretty_print(&self.buffer, f, &mut indent),
  114. #[cfg(feature = "medium-ip")]
  115. Medium::Ip => match crate::wire::IpVersion::of_packet(&self.buffer) {
  116. #[cfg(feature = "proto-ipv4")]
  117. Ok(crate::wire::IpVersion::Ipv4) => crate::wire::Ipv4Packet::<&'static [u8]>::pretty_print(&self.buffer, f, &mut indent),
  118. #[cfg(feature = "proto-ipv6")]
  119. Ok(crate::wire::IpVersion::Ipv6) => crate::wire::Ipv6Packet::<&'static [u8]>::pretty_print(&self.buffer, f, &mut indent),
  120. _ => f.write_str("unrecognized IP version")
  121. }
  122. }
  123. }
  124. }