[tor-commits] [goptlib/master] Use net.Error to distinguish temporary Accept errors.

dcf at torproject.org dcf at torproject.org
Sun Dec 15 05:53:13 UTC 2013


commit 3030f080eecf72b0e896236fca5fabd245c00bdb
Author: David Fifield <david at bamsoftware.com>
Date:   Sat Dec 14 21:06:07 2013 -0800

    Use net.Error to distinguish temporary Accept errors.
    
    The underlying net.Listener.Accept that SocksListener.AcceptSocks
    depends on may return different kinds of errors. AcceptSocks adds its
    own special errors on top. For some of these errors, we want to try the
    accept again, for instance if there was an EOF or timeout while reading
    the SOCKS request. For others, we want to stop accepting altogher, in
    particular when the underlying listener is closed. (It is very important
    to give up in that case, or else you enter a tight loop with Accept
    always failing immediately).
    
    The permanent errors we care about are of type net.OpError, which
    provides a Temporary method.
    http://golang.org/pkg/net/#Error
    With a type assertion, we can see if an error is of this type and
    whether it is temporary. Compare with this commit in net.http:
    https://code.google.com/p/go/source/detail?name=95448425041c
    and net.Error is mentioned in this blog post:
    http://blog.golang.org/error-handling-and-go
    
    I ran into this while trying to interact with a pluggable transport
    using socat.
    	socat -v - SOCKS4A:127.0.0.1:X.X.X.X:YYYY,socksport=3128
    socat sets the userid to your username ("david"), which tails to be
    parsed as a key=value string. This was causing the accept loop to
    terminate as if the listening socket had been closed.
---
 examples/dummy-client/dummy-client.go |    5 ++++-
 examples/dummy-server/dummy-server.go |    5 ++++-
 pt.go                                 |   10 ++++++++--
 socks.go                              |   25 ++++++++++++++++++++++++-
 4 files changed, 40 insertions(+), 5 deletions(-)

diff --git a/examples/dummy-client/dummy-client.go b/examples/dummy-client/dummy-client.go
index 876fc87..01d843b 100644
--- a/examples/dummy-client/dummy-client.go
+++ b/examples/dummy-client/dummy-client.go
@@ -70,7 +70,10 @@ func acceptLoop(ln *pt.SocksListener) error {
 	for {
 		conn, err := ln.AcceptSocks()
 		if err != nil {
-			return err
+			if e, ok := err.(net.Error); ok && !e.Temporary() {
+				return err
+			}
+			continue
 		}
 		go handler(conn)
 	}
diff --git a/examples/dummy-server/dummy-server.go b/examples/dummy-server/dummy-server.go
index dd8dff7..d9fd5f8 100644
--- a/examples/dummy-server/dummy-server.go
+++ b/examples/dummy-server/dummy-server.go
@@ -67,7 +67,10 @@ func acceptLoop(ln net.Listener) error {
 	for {
 		conn, err := ln.Accept()
 		if err != nil {
-			return err
+			if e, ok := err.(net.Error); ok && !e.Temporary() {
+				return err
+			}
+			continue
 		}
 		go handler(conn)
 	}
diff --git a/pt.go b/pt.go
index 4b2220a..f58edbc 100644
--- a/pt.go
+++ b/pt.go
@@ -22,7 +22,10 @@
 // 		for {
 // 			conn, err := ln.AcceptSocks()
 // 			if err != nil {
-// 				return err
+// 				if e, ok := err.(net.Error); ok && !e.Temporary() {
+// 					return err
+// 				}
+// 				continue
 // 			}
 // 			go handler(conn)
 // 		}
@@ -64,7 +67,10 @@
 // 		for {
 // 			conn, err := ln.Accept()
 // 			if err != nil {
-// 				return err
+// 				if e, ok := err.(net.Error); ok && !e.Temporary() {
+// 					return err
+// 				}
+// 				continue
 // 			}
 // 			go handler(conn)
 // 		}
diff --git a/socks.go b/socks.go
index 7a2b1c8..f34f78f 100644
--- a/socks.go
+++ b/socks.go
@@ -73,7 +73,11 @@ func (conn *SocksConn) Reject() error {
 // 	for {
 // 		conn, err := ln.AcceptSocks()
 // 		if err != nil {
-// 			break
+// 			log.Printf("accept error: %s", err)
+// 			if e, ok := err.(net.Error); ok && !e.Temporary() {
+// 				break
+// 			}
+// 			continue
 // 		}
 // 		go handleConn(conn)
 // 	}
@@ -105,6 +109,25 @@ func (ln *SocksListener) Accept() (net.Conn, error) {
 // Call Accept on the wrapped net.Listener, do SOCKS negotiation, and return a
 // SocksConn. After accepting, you must call either conn.Grant or conn.Reject
 // (presumably after trying to connect to conn.Req.Target).
+//
+// Errors returned by AcceptSocks may be temporary (for example, EOF while
+// reading the request, or a badly formatted userid string), or permanent (e.g.,
+// the underlying socket is closed). You can determine whether an error is
+// temporary and take appropriate action with a type conversion to net.Error.
+// For example:
+//
+// 	for {
+// 		conn, err := ln.AcceptSocks()
+// 		if err != nil {
+// 			if e, ok := err.(net.Error); ok && !e.Temporary() {
+// 				log.Printf("permanent accept error; giving up: %s", err)
+// 				break
+// 			}
+// 			log.Printf("temporary accept error; trying again: %s", err)
+// 			continue
+// 		}
+// 		go handleConn(conn)
+// 	}
 func (ln *SocksListener) AcceptSocks() (*SocksConn, error) {
 	c, err := ln.Listener.Accept()
 	if err != nil {





More information about the tor-commits mailing list