Dmitri Shuralyov | 5d99779 | 2016-11-07 15:05:57 -0800 | [diff] [blame] | 1 | // Copyright 2013 The Go Authors. All rights reserved. |
Andrew Gerrand | beab8eb | 2013-08-14 11:00:04 +1000 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style |
| 3 | // license that can be found in the LICENSE file. |
| 4 | |
| 5 | // Package netutil provides network utility functions, complementing the more |
| 6 | // common ones in the net package. |
David Symonds | 8aa6e20 | 2014-12-09 14:17:11 +1100 | [diff] [blame] | 7 | package netutil // import "golang.org/x/net/netutil" |
Andrew Gerrand | beab8eb | 2013-08-14 11:00:04 +1000 | [diff] [blame] | 8 | |
Andrew Gerrand | ee2e27e | 2013-08-15 13:52:04 +1000 | [diff] [blame] | 9 | import ( |
| 10 | "net" |
| 11 | "sync" |
| 12 | ) |
Andrew Gerrand | beab8eb | 2013-08-14 11:00:04 +1000 | [diff] [blame] | 13 | |
| 14 | // LimitListener returns a Listener that accepts at most n simultaneous |
| 15 | // connections from the provided Listener. |
| 16 | func LimitListener(l net.Listener, n int) net.Listener { |
Brad Fitzpatrick | a479876 | 2014-05-22 11:59:35 -0700 | [diff] [blame] | 17 | return &limitListener{l, make(chan struct{}, n)} |
Andrew Gerrand | beab8eb | 2013-08-14 11:00:04 +1000 | [diff] [blame] | 18 | } |
| 19 | |
| 20 | type limitListener struct { |
| 21 | net.Listener |
Brad Fitzpatrick | a479876 | 2014-05-22 11:59:35 -0700 | [diff] [blame] | 22 | sem chan struct{} |
Andrew Gerrand | beab8eb | 2013-08-14 11:00:04 +1000 | [diff] [blame] | 23 | } |
| 24 | |
Brad Fitzpatrick | a479876 | 2014-05-22 11:59:35 -0700 | [diff] [blame] | 25 | func (l *limitListener) acquire() { l.sem <- struct{}{} } |
| 26 | func (l *limitListener) release() { <-l.sem } |
| 27 | |
Andrew Gerrand | beab8eb | 2013-08-14 11:00:04 +1000 | [diff] [blame] | 28 | func (l *limitListener) Accept() (net.Conn, error) { |
Brad Fitzpatrick | a479876 | 2014-05-22 11:59:35 -0700 | [diff] [blame] | 29 | l.acquire() |
Andrew Gerrand | beab8eb | 2013-08-14 11:00:04 +1000 | [diff] [blame] | 30 | c, err := l.Listener.Accept() |
| 31 | if err != nil { |
Brad Fitzpatrick | a479876 | 2014-05-22 11:59:35 -0700 | [diff] [blame] | 32 | l.release() |
Andrew Gerrand | beab8eb | 2013-08-14 11:00:04 +1000 | [diff] [blame] | 33 | return nil, err |
| 34 | } |
Brad Fitzpatrick | a479876 | 2014-05-22 11:59:35 -0700 | [diff] [blame] | 35 | return &limitListenerConn{Conn: c, release: l.release}, nil |
Andrew Gerrand | beab8eb | 2013-08-14 11:00:04 +1000 | [diff] [blame] | 36 | } |
| 37 | |
| 38 | type limitListenerConn struct { |
| 39 | net.Conn |
Brad Fitzpatrick | a479876 | 2014-05-22 11:59:35 -0700 | [diff] [blame] | 40 | releaseOnce sync.Once |
| 41 | release func() |
Andrew Gerrand | beab8eb | 2013-08-14 11:00:04 +1000 | [diff] [blame] | 42 | } |
| 43 | |
| 44 | func (l *limitListenerConn) Close() error { |
| 45 | err := l.Conn.Close() |
Brad Fitzpatrick | a479876 | 2014-05-22 11:59:35 -0700 | [diff] [blame] | 46 | l.releaseOnce.Do(l.release) |
Andrew Gerrand | beab8eb | 2013-08-14 11:00:04 +1000 | [diff] [blame] | 47 | return err |
| 48 | } |