Fix datarace for WebRTCPeer.lastReceive

The race condition occurs because concurrent goroutines are
intermixing reads and writes of `WebRTCPeer.lastReceive`.

Spotted when integrating Snowflake inside OONI in
https://github.com/ooni/probe-cli/pull/373.
This commit is contained in:
Simone Basso 2021-06-14 10:46:46 +02:00 committed by Cecylia Bocovich
parent e84bc81e31
commit ed2d5df87d

View file

@ -23,6 +23,8 @@ type WebRTCPeer struct {
recvPipe *io.PipeReader recvPipe *io.PipeReader
writePipe *io.PipeWriter writePipe *io.PipeWriter
mu sync.Mutex // protects the following:
lastReceive time.Time lastReceive time.Time
open chan struct{} // Channel to notify when datachannel opens open chan struct{} // Channel to notify when datachannel opens
@ -89,12 +91,17 @@ func (c *WebRTCPeer) Close() error {
// Should also update the DataChannel in underlying go-webrtc's to make Closes // Should also update the DataChannel in underlying go-webrtc's to make Closes
// more immediate / responsive. // more immediate / responsive.
func (c *WebRTCPeer) checkForStaleness() { func (c *WebRTCPeer) checkForStaleness() {
c.mu.Lock()
c.lastReceive = time.Now() c.lastReceive = time.Now()
c.mu.Unlock()
for { for {
if c.closed { if c.closed {
return return
} }
if time.Since(c.lastReceive) > SnowflakeTimeout { c.mu.Lock()
lastReceive := c.lastReceive
c.mu.Unlock()
if time.Since(lastReceive) > SnowflakeTimeout {
log.Printf("WebRTC: No messages received for %v -- closing stale connection.", log.Printf("WebRTC: No messages received for %v -- closing stale connection.",
SnowflakeTimeout) SnowflakeTimeout)
c.Close() c.Close()
@ -173,7 +180,9 @@ func (c *WebRTCPeer) preparePeerConnection(config *webrtc.Configuration) error {
log.Printf("c.writePipe.CloseWithError returned error: %v", inerr) log.Printf("c.writePipe.CloseWithError returned error: %v", inerr)
} }
} }
c.mu.Lock()
c.lastReceive = time.Now() c.lastReceive = time.Now()
c.mu.Unlock()
}) })
c.transport = dc c.transport = dc
c.open = make(chan struct{}) c.open = make(chan struct{})