[tor-commits] [goptlib/master] Add tests for net.Error temporary error handling in AcceptSocks.

dcf at torproject.org dcf at torproject.org
Wed Jun 24 18:50:22 UTC 2015


commit 2a2a9b7cbff0dc9ff452a39a4199cec264e76dfe
Author: David Fifield <david at bamsoftware.com>
Date:   Wed Jun 24 01:38:04 2015 -0700

    Add tests for net.Error temporary error handling in AcceptSocks.
    
    See https://trac.torproject.org/projects/tor/ticket/14135. We're going
    to make the recommended way to check for an error from AcceptSocks match
    the way in the golang standard library:
    	if e, ok := err.(net.Error); ok && e.Temporary() {
    		continue
    	} else {
    		break
    	}
    The new tests check that 1) AcceptSocks faithfully represents an
    underlying Accept error with respect to its net.Error-ness and its
    Temporary-ness, and 2) errors that happen post-Accept in AcceptSocks are
    either silently swallowed or else reported as a Temporary net.Error.
    
    The test fails at the moment: "socks_test.go:267: AcceptSocks returned
    non-net.Error: unexpected EOF".
---
 socks_test.go |  107 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 107 insertions(+)

diff --git a/socks_test.go b/socks_test.go
index 18d141a..7fee46a 100644
--- a/socks_test.go
+++ b/socks_test.go
@@ -2,8 +2,11 @@ package pt
 
 import (
 	"bytes"
+	"errors"
+	"io"
 	"net"
 	"testing"
+	"time"
 )
 
 func TestReadSocks4aConnect(t *testing.T) {
@@ -160,3 +163,107 @@ func TestSendSocks4aResponse(t *testing.T) {
 		}
 	}
 }
+
+var fakeListenerDistinguishedError = errors.New("distinguished error")
+
+// fakeListener is a fake dummy net.Listener that returns the given net.Conn and
+// error the first time Accept is called. After the first call, it returns
+// (nil, fakeListenerDistinguishedError).
+type fakeListener struct {
+	c   net.Conn
+	err error
+}
+
+func (ln *fakeListener) Accept() (net.Conn, error) {
+	c := ln.c
+	err := ln.err
+	ln.c = nil
+	ln.err = fakeListenerDistinguishedError
+	return c, err
+}
+
+func (ln *fakeListener) Close() error {
+	return nil
+}
+
+func (ln *fakeListener) Addr() net.Addr {
+	return &net.TCPAddr{IP: net.ParseIP("127.0.0.1"), Port: 0, Zone: ""}
+}
+
+// A trivial net.Error that lets you control whether it is considered Temporary.
+type netError struct {
+	errString string
+	temporary bool
+}
+
+func (e *netError) Error() string {
+	return e.errString
+}
+
+func (e *netError) Temporary() bool {
+	return e.temporary
+}
+
+func (e *netError) Timeout() bool {
+	return false
+}
+
+// The purpose of ignoreDeadlineConn is to wrap net.Pipe so that the deadline
+// functions don't return an error ("net.Pipe does not support deadlines").
+type ignoreDeadlineConn struct {
+	net.Conn
+}
+
+func (c *ignoreDeadlineConn) SetDeadline(t time.Time) error {
+	return nil
+}
+
+func (c *ignoreDeadlineConn) SetReadDeadline(t time.Time) error {
+	return nil
+}
+
+func (c *ignoreDeadlineConn) SetWriteDeadline(t time.Time) error {
+	return nil
+}
+
+func TestAcceptErrors(t *testing.T) {
+	// Check that AcceptSocks accurately reflects net.Errors returned by the
+	// underlying call to Accept. This is important for the handling of
+	// Temporary and non-Temporary errors. The loop iterates over
+	// non-net.Error, non-Temporary net.Error, and Temporary net.Error.
+	for _, expectedErr := range []error{io.EOF, &netError{"non-temp", false}, &netError{"temp", true}} {
+		ln := NewSocksListener(&fakeListener{nil, expectedErr})
+		_, err := ln.AcceptSocks()
+		if expectedNerr, ok := expectedErr.(net.Error); ok {
+			nerr, ok := err.(net.Error)
+			if !ok {
+				t.Errorf("AcceptSocks returned non-net.Error %v", nerr)
+			} else {
+				if expectedNerr.Temporary() != expectedNerr.Temporary() {
+					t.Errorf("AcceptSocks did not keep Temporary status of net.Error: %v", nerr)
+				}
+			}
+		}
+	}
+
+	c1, c2 := net.Pipe()
+	go func() {
+		// Bogus request: SOCKS 5 then EOF.
+		c2.Write([]byte("\x05\x01\x00"))
+		c2.Close()
+	}()
+	ln := NewSocksListener(&fakeListener{c: &ignoreDeadlineConn{c1}, err: nil})
+	_, err := ln.AcceptSocks()
+	// The error in parsing the SOCKS request must be either silently
+	// ignored, or else must be a Temporary net.Error. I.e., it must not be
+	// the io.ErrUnexpectedEOF caused by the short request.
+	if err == fakeListenerDistinguishedError {
+		// Was silently ignored.
+	} else if nerr, ok := err.(net.Error); ok {
+		if !nerr.Temporary() {
+			t.Errorf("AcceptSocks returned non-Temporary net.Error: %v", nerr)
+		}
+	} else {
+		t.Errorf("AcceptSocks returned non-net.Error: %v", err)
+	}
+}



More information about the tor-commits mailing list