Skip to content

Commit

Permalink
don't race on ignore ping frames
Browse files Browse the repository at this point in the history
Instead of using locking, that will cause read and write frames
to wait for each others and introduce a risk of deadlocking, use
atomic operations to check the new option to ignore ping SPDY
frames for idling.

Signed-off-by: Antonio Ojea <antonio.ojea.garcia@gmail.com>
  • Loading branch information
aojea committed Jun 18, 2021
1 parent 96c6c1c commit 83610fa
Showing 1 changed file with 27 additions and 6 deletions.
33 changes: 27 additions & 6 deletions connection.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"net"
"net/http"
"sync"
"sync/atomic"
"time"

"github.com/moby/spdystream/spdy"
Expand All @@ -40,6 +41,25 @@ const (
QUEUE_SIZE = 50
)

// atomicBool uses load/store operations on an int32 to simulate an atomic boolean.
type atomicBool struct {
v int32
}

// set sets the int32 to the given boolean.
func (a *atomicBool) set(value bool) {
if value {
atomic.StoreInt32(&a.v, 1)
return
}
atomic.StoreInt32(&a.v, 0)
}

// get returns true if the int32 == 1
func (a *atomicBool) get() bool {
return atomic.LoadInt32(&a.v) == 1
}

type StreamHandler func(stream *Stream)

type AuthHandler func(header http.Header, slot uint8, parent uint32) bool
Expand All @@ -52,7 +72,7 @@ type idleAwareFramer struct {
setTimeoutLock sync.Mutex
setTimeoutChan chan time.Duration
timeout time.Duration
ignorePingFrames bool
ignorePingFrames *atomicBool
}

func newIdleAwareFramer(framer *spdy.Framer) *idleAwareFramer {
Expand All @@ -61,7 +81,8 @@ func newIdleAwareFramer(framer *spdy.Framer) *idleAwareFramer {
resetChan: make(chan struct{}, 2),
// setTimeoutChan needs to be buffered to avoid deadlocks when calling setIdleTimeout at about
// the same time the connection is being closed
setTimeoutChan: make(chan time.Duration, 1),
setTimeoutChan: make(chan time.Duration, 1),
ignorePingFrames: &atomicBool{0},
}
return iaf
}
Expand Down Expand Up @@ -159,7 +180,7 @@ func (i *idleAwareFramer) WriteFrame(frame spdy.Frame) error {
return err
}

if i.ignorePingFrames {
if i.ignorePingFrames.get() {
_, ok := frame.(*spdy.PingFrame)
if ok {
return nil
Expand All @@ -177,7 +198,7 @@ func (i *idleAwareFramer) ReadFrame() (spdy.Frame, error) {
return nil, err
}

if i.ignorePingFrames {
if i.ignorePingFrames.get() {
_, ok := frame.(*spdy.PingFrame)
if ok {
return frame, nil
Expand All @@ -193,11 +214,11 @@ func (i *idleAwareFramer) ReadFrame() (spdy.Frame, error) {
}

func (i *idleAwareFramer) setIdleTimeout(timeout time.Duration, ignorePingFrames bool) {
i.ignorePingFrames.set(ignorePingFrames)

i.setTimeoutLock.Lock()
defer i.setTimeoutLock.Unlock()

i.ignorePingFrames = ignorePingFrames

if i.setTimeoutChan == nil {
return
}
Expand Down

0 comments on commit 83610fa

Please sign in to comment.