VSS: Fix TSAN error related to internal variables

The VSS is used in tests, usually from the signaling thread, but all the
network emulation happens in the network thread. TSAN will then complain
about variable access from different threads without any synchronization.

Bug: b/204654931
Change-Id: I164f5d73e559f00e6bf390ef5e5f112bcc58ce11
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/237784
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Commit-Queue: Florent Castelli <orphis@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#35357}
diff --git a/rtc_base/virtual_socket_server.cc b/rtc_base/virtual_socket_server.cc
index 88c6eb9..5d36e3e 100644
--- a/rtc_base/virtual_socket_server.cc
+++ b/rtc_base/virtual_socket_server.cc
@@ -588,12 +588,15 @@
 }
 
 void VirtualSocketServer::SetSendingBlocked(bool blocked) {
-  if (blocked == sending_blocked_) {
-    // Unchanged; nothing to do.
-    return;
+  {
+    webrtc::MutexLock lock(&mutex_);
+    if (blocked == sending_blocked_) {
+      // Unchanged; nothing to do.
+      return;
+    }
+    sending_blocked_ = blocked;
   }
-  sending_blocked_ = blocked;
-  if (!sending_blocked_) {
+  if (!blocked) {
     // Sending was blocked, but is now unblocked. This signal gives sockets a
     // chance to fire SignalWriteEvent, and for TCP, send buffered data.
     SignalReadyToSend();
@@ -877,31 +880,27 @@
                                  const char* data,
                                  size_t data_size,
                                  const SocketAddress& remote_addr) {
-  ++sent_packets_;
-  if (sending_blocked_) {
-    socket->SetToBlocked();
-    return -1;
-  }
-
-  if (data_size > largest_seen_udp_payload_) {
-    if (data_size > 1000) {
-      RTC_LOG(LS_VERBOSE) << "Largest UDP seen is " << data_size;
+  {
+    webrtc::MutexLock lock(&mutex_);
+    ++sent_packets_;
+    if (sending_blocked_) {
+      socket->SetToBlocked();
+      return -1;
     }
-    largest_seen_udp_payload_ = data_size;
-  }
 
-  // See if we want to drop this packet.
-  if (data_size > max_udp_payload_) {
-    RTC_LOG(LS_VERBOSE) << "Dropping too large UDP payload of size "
-                        << data_size << ", UDP payload limit is "
-                        << max_udp_payload_;
-    // Return as if send was successful; packet disappears.
-    return data_size;
-  }
+    // See if we want to drop this packet.
+    if (data_size > max_udp_payload_) {
+      RTC_LOG(LS_VERBOSE) << "Dropping too large UDP payload of size "
+                          << data_size << ", UDP payload limit is "
+                          << max_udp_payload_;
+      // Return as if send was successful; packet disappears.
+      return data_size;
+    }
 
-  if (Random() < drop_prob_) {
-    RTC_LOG(LS_VERBOSE) << "Dropping packet: bad luck";
-    return static_cast<int>(data_size);
+    if (Random() < drop_prob_) {
+      RTC_LOG(LS_VERBOSE) << "Dropping packet: bad luck";
+      return static_cast<int>(data_size);
+    }
   }
 
   VirtualSocket* recipient = LookupBinding(remote_addr);
@@ -938,11 +937,13 @@
     // NOTE: There are better algorithms for maintaining such a queue (such as
     // "Derivative Random Drop"); however, this algorithm is a more accurate
     // simulation of what a normal network would do.
-
-    size_t packet_size = data_size + UDP_HEADER_SIZE;
-    if (network_size + packet_size > network_capacity_) {
-      RTC_LOG(LS_VERBOSE) << "Dropping packet: network capacity exceeded";
-      return static_cast<int>(data_size);
+    {
+      webrtc::MutexLock lock(&mutex_);
+      size_t packet_size = data_size + UDP_HEADER_SIZE;
+      if (network_size + packet_size > network_capacity_) {
+        RTC_LOG(LS_VERBOSE) << "Dropping packet: network capacity exceeded";
+        return static_cast<int>(data_size);
+      }
     }
 
     AddPacketToNetwork(socket, recipient, cur_time, data, data_size,
@@ -953,11 +954,14 @@
 }
 
 void VirtualSocketServer::SendTcp(VirtualSocket* socket) {
-  ++sent_packets_;
-  if (sending_blocked_) {
-    // Eventually the socket's buffer will fill and VirtualSocket::SendTcp will
-    // set EWOULDBLOCK.
-    return;
+  {
+    webrtc::MutexLock lock(&mutex_);
+    ++sent_packets_;
+    if (sending_blocked_) {
+      // Eventually the socket's buffer will fill and VirtualSocket::SendTcp
+      // will set EWOULDBLOCK.
+      return;
+    }
   }
 
   // TCP can't send more data than will fill up the receiver's buffer.
@@ -978,7 +982,7 @@
   socket->PurgeNetworkPackets(cur_time);
 
   while (true) {
-    size_t available = recv_buffer_capacity_ - recipient->recv_buffer_size();
+    size_t available = recv_buffer_capacity() - recipient->recv_buffer_size();
     size_t max_data_size =
         std::min<size_t>(available, TCP_MSS - TCP_HEADER_SIZE);
     size_t data_size = std::min(socket->send_buffer_size(), max_data_size);
@@ -991,7 +995,7 @@
     socket->UpdateSend(data_size);
   }
 
-  socket->MaybeSignalWriteEvent(send_buffer_capacity_);
+  socket->MaybeSignalWriteEvent(send_buffer_capacity());
 }
 
 void VirtualSocketServer::SendTcp(const SocketAddress& addr) {
@@ -1032,6 +1036,7 @@
 }
 
 uint32_t VirtualSocketServer::SendDelay(uint32_t size) {
+  webrtc::MutexLock lock(&mutex_);
   if (bandwidth_ == 0)
     return 0;
   else
@@ -1060,6 +1065,7 @@
 #endif  // <unused>
 
 void VirtualSocketServer::UpdateDelayDistribution() {
+  webrtc::MutexLock lock(&mutex_);
   delay_dist_ = CreateDistribution(delay_mean_, delay_stddev_, delay_samples_);
 }
 
@@ -1245,4 +1251,62 @@
   }
 }
 
+void VirtualSocketServer::set_bandwidth(uint32_t bandwidth) {
+  webrtc::MutexLock lock(&mutex_);
+  bandwidth_ = bandwidth;
+}
+void VirtualSocketServer::set_network_capacity(uint32_t capacity) {
+  webrtc::MutexLock lock(&mutex_);
+  network_capacity_ = capacity;
+}
+
+uint32_t VirtualSocketServer::send_buffer_capacity() const {
+  webrtc::MutexLock lock(&mutex_);
+  return send_buffer_capacity_;
+}
+void VirtualSocketServer::set_send_buffer_capacity(uint32_t capacity) {
+  webrtc::MutexLock lock(&mutex_);
+  send_buffer_capacity_ = capacity;
+}
+
+uint32_t VirtualSocketServer::recv_buffer_capacity() const {
+  webrtc::MutexLock lock(&mutex_);
+  return recv_buffer_capacity_;
+}
+void VirtualSocketServer::set_recv_buffer_capacity(uint32_t capacity) {
+  webrtc::MutexLock lock(&mutex_);
+  recv_buffer_capacity_ = capacity;
+}
+
+void VirtualSocketServer::set_delay_mean(uint32_t delay_mean) {
+  webrtc::MutexLock lock(&mutex_);
+  delay_mean_ = delay_mean;
+}
+void VirtualSocketServer::set_delay_stddev(uint32_t delay_stddev) {
+  webrtc::MutexLock lock(&mutex_);
+  delay_stddev_ = delay_stddev;
+}
+void VirtualSocketServer::set_delay_samples(uint32_t delay_samples) {
+  webrtc::MutexLock lock(&mutex_);
+  delay_samples_ = delay_samples;
+}
+
+void VirtualSocketServer::set_drop_probability(double drop_prob) {
+  RTC_DCHECK_GE(drop_prob, 0.0);
+  RTC_DCHECK_LE(drop_prob, 1.0);
+
+  webrtc::MutexLock lock(&mutex_);
+  drop_prob_ = drop_prob;
+}
+
+void VirtualSocketServer::set_max_udp_payload(size_t payload_size) {
+  webrtc::MutexLock lock(&mutex_);
+  max_udp_payload_ = payload_size;
+}
+
+uint32_t VirtualSocketServer::sent_packets() const {
+  webrtc::MutexLock lock(&mutex_);
+  return sent_packets_;
+}
+
 }  // namespace rtc
diff --git a/rtc_base/virtual_socket_server.h b/rtc_base/virtual_socket_server.h
index 77ddb76..8873f18 100644
--- a/rtc_base/virtual_socket_server.h
+++ b/rtc_base/virtual_socket_server.h
@@ -172,60 +172,39 @@
 
   // Limits the network bandwidth (maximum bytes per second).  Zero means that
   // all sends occur instantly.  Defaults to 0.
-  uint32_t bandwidth() const { return bandwidth_; }
-  void set_bandwidth(uint32_t bandwidth) { bandwidth_ = bandwidth; }
+  void set_bandwidth(uint32_t bandwidth) RTC_LOCKS_EXCLUDED(mutex_);
 
   // Limits the amount of data which can be in flight on the network without
   // packet loss (on a per sender basis).  Defaults to 64 KB.
-  uint32_t network_capacity() const { return network_capacity_; }
-  void set_network_capacity(uint32_t capacity) { network_capacity_ = capacity; }
+  void set_network_capacity(uint32_t capacity) RTC_LOCKS_EXCLUDED(mutex_);
 
   // The amount of data which can be buffered by tcp on the sender's side
-  uint32_t send_buffer_capacity() const { return send_buffer_capacity_; }
-  void set_send_buffer_capacity(uint32_t capacity) {
-    send_buffer_capacity_ = capacity;
-  }
+  uint32_t send_buffer_capacity() const RTC_LOCKS_EXCLUDED(mutex_);
+  void set_send_buffer_capacity(uint32_t capacity) RTC_LOCKS_EXCLUDED(mutex_);
 
   // The amount of data which can be buffered by tcp on the receiver's side
-  uint32_t recv_buffer_capacity() const { return recv_buffer_capacity_; }
-  void set_recv_buffer_capacity(uint32_t capacity) {
-    recv_buffer_capacity_ = capacity;
-  }
+  uint32_t recv_buffer_capacity() const RTC_LOCKS_EXCLUDED(mutex_);
+  void set_recv_buffer_capacity(uint32_t capacity) RTC_LOCKS_EXCLUDED(mutex_);
 
   // Controls the (transit) delay for packets sent in the network.  This does
   // not inclue the time required to sit in the send queue.  Both of these
   // values are measured in milliseconds.  Defaults to no delay.
-  uint32_t delay_mean() const { return delay_mean_; }
-  uint32_t delay_stddev() const { return delay_stddev_; }
-  uint32_t delay_samples() const { return delay_samples_; }
-  void set_delay_mean(uint32_t delay_mean) { delay_mean_ = delay_mean; }
-  void set_delay_stddev(uint32_t delay_stddev) { delay_stddev_ = delay_stddev; }
-  void set_delay_samples(uint32_t delay_samples) {
-    delay_samples_ = delay_samples;
-  }
+  void set_delay_mean(uint32_t delay_mean) RTC_LOCKS_EXCLUDED(mutex_);
+  void set_delay_stddev(uint32_t delay_stddev) RTC_LOCKS_EXCLUDED(mutex_);
+  void set_delay_samples(uint32_t delay_samples) RTC_LOCKS_EXCLUDED(mutex_);
 
   // If the (transit) delay parameters are modified, this method should be
   // called to recompute the new distribution.
-  void UpdateDelayDistribution();
+  void UpdateDelayDistribution() RTC_LOCKS_EXCLUDED(mutex_);
 
   // Controls the (uniform) probability that any sent packet is dropped.  This
   // is separate from calculations to drop based on queue size.
-  double drop_probability() { return drop_prob_; }
-  void set_drop_probability(double drop_prob) {
-    RTC_DCHECK_GE(drop_prob, 0.0);
-    RTC_DCHECK_LE(drop_prob, 1.0);
-    drop_prob_ = drop_prob;
-  }
+  void set_drop_probability(double drop_prob) RTC_LOCKS_EXCLUDED(mutex_);
 
   // Controls the maximum UDP payload for the networks simulated
   // by this server. Any UDP payload sent that is larger than this will
   // be dropped.
-  size_t max_udp_payload() { return max_udp_payload_; }
-  void set_max_udp_payload(size_t payload_size) {
-    max_udp_payload_ = payload_size;
-  }
-
-  size_t largest_seen_udp_payload() { return largest_seen_udp_payload_; }
+  void set_max_udp_payload(size_t payload_size) RTC_LOCKS_EXCLUDED(mutex_);
 
   // If `blocked` is true, subsequent attempts to send will result in -1 being
   // returned, with the socket error set to EWOULDBLOCK.
@@ -235,7 +214,7 @@
   //
   // This can be used to simulate the send buffer on a network interface being
   // full, and test functionality related to EWOULDBLOCK/SignalWriteEvent.
-  void SetSendingBlocked(bool blocked);
+  void SetSendingBlocked(bool blocked) RTC_LOCKS_EXCLUDED(mutex_);
 
   // SocketFactory:
   VirtualSocket* CreateSocket(int family, int type) override;
@@ -281,7 +260,7 @@
 
   // Number of packets that clients have attempted to send through this virtual
   // socket server. Intended to be used for test assertions.
-  uint32_t sent_packets() const { return sent_packets_; }
+  uint32_t sent_packets() const RTC_LOCKS_EXCLUDED(mutex_);
 
   // Assign IP and Port if application's address is unspecified. Also apply
   // `alternative_address_mapping_`.
@@ -319,13 +298,13 @@
               const SocketAddress& remote_addr);
 
   // Moves as much data as possible from the sender's buffer to the network
-  void SendTcp(VirtualSocket* socket);
+  void SendTcp(VirtualSocket* socket) RTC_LOCKS_EXCLUDED(mutex_);
 
   // Like above, but lookup sender by address.
-  void SendTcp(const SocketAddress& addr);
+  void SendTcp(const SocketAddress& addr) RTC_LOCKS_EXCLUDED(mutex_);
 
   // Computes the number of milliseconds required to send a packet of this size.
-  uint32_t SendDelay(uint32_t size);
+  uint32_t SendDelay(uint32_t size) RTC_LOCKS_EXCLUDED(mutex_);
 
   // Cancel attempts to connect to a socket that is being closed.
   void CancelConnects(VirtualSocket* socket);
@@ -416,30 +395,30 @@
   IPAddress default_source_address_v4_;
   IPAddress default_source_address_v6_;
 
-  uint32_t bandwidth_;
-  uint32_t network_capacity_;
-  uint32_t send_buffer_capacity_;
-  uint32_t recv_buffer_capacity_;
-  uint32_t delay_mean_;
-  uint32_t delay_stddev_;
-  uint32_t delay_samples_;
+  mutable webrtc::Mutex mutex_;
+
+  uint32_t bandwidth_ RTC_GUARDED_BY(mutex_);
+  uint32_t network_capacity_ RTC_GUARDED_BY(mutex_);
+  uint32_t send_buffer_capacity_ RTC_GUARDED_BY(mutex_);
+  uint32_t recv_buffer_capacity_ RTC_GUARDED_BY(mutex_);
+  uint32_t delay_mean_ RTC_GUARDED_BY(mutex_);
+  uint32_t delay_stddev_ RTC_GUARDED_BY(mutex_);
+  uint32_t delay_samples_ RTC_GUARDED_BY(mutex_);
 
   // Used for testing.
-  uint32_t sent_packets_ = 0;
+  uint32_t sent_packets_ RTC_GUARDED_BY(mutex_) = 0;
 
   std::map<rtc::IPAddress, int> delay_by_ip_;
   std::map<rtc::IPAddress, rtc::IPAddress> alternative_address_mapping_;
   std::unique_ptr<Function> delay_dist_;
 
-  double drop_prob_;
+  double drop_prob_ RTC_GUARDED_BY(mutex_);
   // The largest UDP payload permitted on this virtual socket server.
   // The default is the max size of IPv4 fragmented UDP packet payload:
   // 65535 bytes - 8 bytes UDP header - 20 bytes IP header.
-  size_t max_udp_payload_ = 65507;
-  // The largest UDP payload seen so far.
-  size_t largest_seen_udp_payload_ = 0;
+  size_t max_udp_payload_ RTC_GUARDED_BY(mutex_) = 65507;
 
-  bool sending_blocked_ = false;
+  bool sending_blocked_ RTC_GUARDED_BY(mutex_) = false;
   RTC_DISALLOW_COPY_AND_ASSIGN(VirtualSocketServer);
 };