Bug 1355947 - Add NatDelegate to TestNat; r=bwc
authorDan Minor <dminor@mozilla.com>
Tue, 13 Jun 2017 10:08:45 -0400
changeset 600770 d0d40af45f9f9407ea3dc232a01157aa7c19efaa
parent 600769 d084672cc9fc4315ddbb50e86f6ef32c2f2c01c7
child 600771 0e4269675a0e98c50256cba9ccf5173e61c7f777
push id65868
push userbmo:rail@mozilla.com
push dateTue, 27 Jun 2017 20:33:55 +0000
reviewersbwc
bugs1355947
milestone56.0a1
Bug 1355947 - Add NatDelegate to TestNat; r=bwc This allows tests to implement different packet handling schemes without having to extend or modify TestNat itself. MozReview-Commit-ID: 6DlESF3hfX6
media/mtransport/test_nr_socket.cpp
media/mtransport/test_nr_socket.h
--- a/media/mtransport/test_nr_socket.cpp
+++ b/media/mtransport/test_nr_socket.cpp
@@ -306,16 +306,20 @@ void TestNrSocket::process_delayed_cb(NR
 
   delete op;
 }
 
 int TestNrSocket::sendto(const void *msg, size_t len,
                          int flags, nr_transport_addr *to) {
   MOZ_ASSERT(internal_socket_->my_addr().protocol != IPPROTO_TCP);
 
+  if (nat_->nat_delegate_ && nat_->nat_delegate_->on_sendto(nat_, msg, len, flags, to)) {
+    return 0;
+  }
+
   UCHAR *buf = static_cast<UCHAR*>(const_cast<void*>(msg));
   if (nat_->block_stun_ &&
       nr_is_stun_message(buf, len)) {
     return 0;
   }
 
   /* TODO: improve the functionality of this in bug 1253657 */
   if (!nat_->enabled_ || nat_->is_an_internal_tuple(*to)) {
@@ -512,16 +516,21 @@ int TestNrSocket::connect(nr_transport_a
                              __LINE__);
   }
 
   return r;
 }
 
 int TestNrSocket::write(const void *msg, size_t len, size_t *written) {
   UCHAR *buf = static_cast<UCHAR*>(const_cast<void*>(msg));
+
+  if (nat_->nat_delegate_ && nat_->nat_delegate_->on_write(nat_, msg, len, written)) {
+    return R_INTERNAL;
+  }
+
   if (nat_->block_stun_ && nr_is_stun_message(buf, len)) {
     // Should cause this socket to be abandoned
     r_log(LOG_GENERIC, LOG_DEBUG,
           "TestNrSocket %s dropping outgoing TCP "
           "because it is configured to drop STUN",
           my_addr().as_string);
     return R_INTERNAL;
   }
@@ -572,16 +581,20 @@ int TestNrSocket::read(void *buf, size_t
       port_mappings_.front()->last_used_ = PR_IntervalNow();
     }
   }
 
   if (r) {
     return r;
   }
 
+  if (nat_->nat_delegate_ && nat_->nat_delegate_->on_read(nat_, buf, maxlen, len)) {
+    return R_INTERNAL;
+  }
+
   if (nat_->block_tcp_ && !tls_) {
     // Should cause this socket to be abandoned
     return R_INTERNAL;
   }
 
   UCHAR *cbuf = static_cast<UCHAR*>(const_cast<void*>(buf));
   if (nat_->block_stun_ && nr_is_stun_message(cbuf, *len)) {
     // Should cause this socket to be abandoned
--- a/media/mtransport/test_nr_socket.h
+++ b/media/mtransport/test_nr_socket.h
@@ -108,16 +108,31 @@ class TestNrSocket;
 
 /**
  * A group of TestNrSockets that behave as if they were behind the same NAT.
  * @note We deliberately avoid addref/release of TestNrSocket here to avoid
  *       masking lifetime errors elsewhere.
 */
 class TestNat {
   public:
+
+    /**
+      * This allows TestNat traffic to be passively inspected.
+      * If a non-zero (error) value is returned, the packet will be dropped,
+      * allowing for tests to extend how packet manipulation is done by
+      * TestNat with having to modify TestNat itself.
+    */
+    class NatDelegate {
+    public:
+      virtual int on_read(TestNat *nat, void *buf, size_t maxlen, size_t *len) = 0;
+      virtual int on_sendto(TestNat *nat, const void *msg, size_t len,
+                    int flags, nr_transport_addr *to) = 0;
+      virtual int on_write(TestNat *nat, const void *msg, size_t len, size_t *written) = 0;
+    };
+
     typedef enum {
       /** For mapping, one port is used for all destinations.
        *  For filtering, allow any external address/port. */
       ENDPOINT_INDEPENDENT,
 
       /** For mapping, one port for each destination address (for any port).
        *  For filtering, allow incoming traffic from addresses that outgoing
        *  traffic has been sent to. */
@@ -135,16 +150,17 @@ class TestNat {
       mapping_type_(ENDPOINT_INDEPENDENT),
       mapping_timeout_(30000),
       allow_hairpinning_(false),
       refresh_on_ingress_(false),
       block_udp_(false),
       block_stun_(false),
       block_tcp_(false),
       delay_stun_resp_ms_(0),
+      nat_delegate_(nullptr),
       sockets_() {}
 
     bool has_port_mappings() const;
 
     // Helps determine whether we're hairpinning
     bool is_my_external_tuple(const nr_transport_addr &addr) const;
     bool is_an_internal_tuple(const nr_transport_addr &addr) const;
 
@@ -169,16 +185,18 @@ class TestNat {
     bool allow_hairpinning_;
     bool refresh_on_ingress_;
     bool block_udp_;
     bool block_stun_;
     bool block_tcp_;
     /* Note: this can only delay a single response so far (bug 1253657) */
     uint32_t delay_stun_resp_ms_;
 
+    NatDelegate* nat_delegate_;
+
   private:
     std::set<TestNrSocket*> sockets_;
 
     ~TestNat(){}
 };
 
 /**
  * Subclass of NrSocketBase that can simulate things like being behind a NAT,