Skip to content

Commit

Permalink
listen: accept concurrency
Browse files Browse the repository at this point in the history
Though some amount of concurrency (namely the ipfs handshake) was
nominally moved out of the hot-path of the `Accept` call-- the
setupConn function call was still causing it to happen because
the transport was setup-- which wrote to the connection before it
was fully setup.

Accept concurrency is not an infinite resource though-- we must be
careful to rate limit and make sure that malicious connection
attempts do not get the process stuck, or OOM it. It should only
slow it down.
  • Loading branch information
jbenet committed May 13, 2015
1 parent bbe2a64 commit 8d52ed2
Showing 1 changed file with 22 additions and 7 deletions.
29 changes: 22 additions & 7 deletions listener.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,13 @@ import (
tec "github.com/jbenet/go-temp-err-catcher"
)

// AcceptConcurrency is how many connections can simultaneously be
// in process of being accepted. Handshakes can sometimes occurr as
// part of this process, so it may take some time. It is imporant to
// rate limit lest a malicious influx of connections would cause our
// node to consume all its resources accepting new connections.
var AcceptConcurrency = 200

type Listener struct {
netList net.Listener
groups groupSet
Expand Down Expand Up @@ -73,6 +80,9 @@ func (l *Listener) accept() {
// Using the lib: https://godoc.org/github.com/jbenet/go-temp-err-catcher
var catcher tec.TempErrCatcher

// rate limit concurrency
limit := make(chan struct{}, AcceptConcurrency)

// loop forever accepting connections
for {
conn, err := l.netList.Accept()
Expand All @@ -85,13 +95,18 @@ func (l *Listener) accept() {
}

// add conn to swarm and listen for incoming streams
// log.Printf("accepted conn %s\n", conn.RemoteAddr())
conn2, err := l.swarm.addConn(conn, true)
if err != nil {
l.acceptErr <- err
continue
}
conn2.groups.AddSet(&l.groups) // add out groups
// do this in a goroutine to avoid blocking the Accept loop.
// note that this does not rate limit accepts.
limit <- struct{}{} // sema down
go func(conn net.Conn) {
defer func() { <-limit }() // sema up

conn2, err := l.swarm.addConn(conn, true)
if err != nil {
l.acceptErr <- err
}
conn2.groups.AddSet(&l.groups) // add out groups
}(conn)
}
}

Expand Down

0 comments on commit 8d52ed2

Please sign in to comment.