Merge pull request #2146 from fjl/discover-win32-large-packets
p2p/discover: fix Windows-specific issue for larger-than-buffer packets
This commit is contained in:
		| @@ -453,8 +453,11 @@ func encodePacket(priv *ecdsa.PrivateKey, ptype byte, req interface{}) ([]byte, | ||||
| 	return packet, nil | ||||
| } | ||||
|  | ||||
| type tempError interface { | ||||
| 	Temporary() bool | ||||
| func isTemporaryError(err error) bool { | ||||
| 	tempErr, ok := err.(interface { | ||||
| 		Temporary() bool | ||||
| 	}) | ||||
| 	return ok && tempErr.Temporary() || isPacketTooBig(err) | ||||
| } | ||||
|  | ||||
| // readLoop runs in its own goroutine. it handles incoming UDP packets. | ||||
| @@ -466,7 +469,7 @@ func (t *udp) readLoop() { | ||||
| 	buf := make([]byte, 1280) | ||||
| 	for { | ||||
| 		nbytes, from, err := t.conn.ReadFromUDP(buf) | ||||
| 		if tempErr, ok := err.(tempError); ok && tempErr.Temporary() { | ||||
| 		if isTemporaryError(err) { | ||||
| 			// Ignore temporary read errors. | ||||
| 			glog.V(logger.Debug).Infof("Temporary read error: %v", err) | ||||
| 			continue | ||||
|   | ||||
							
								
								
									
										26
									
								
								p2p/discover/udp_notwindows.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								p2p/discover/udp_notwindows.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,26 @@ | ||||
| // Copyright 2016 The go-ethereum Authors | ||||
| // This file is part of the go-ethereum library. | ||||
| // | ||||
| // The go-ethereum library is free software: you can redistribute it and/or modify | ||||
| // it under the terms of the GNU Lesser General Public License as published by | ||||
| // the Free Software Foundation, either version 3 of the License, or | ||||
| // (at your option) any later version. | ||||
| // | ||||
| // The go-ethereum library is distributed in the hope that it will be useful, | ||||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||
| // GNU Lesser General Public License for more details. | ||||
| // | ||||
| // You should have received a copy of the GNU Lesser General Public License | ||||
| // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. | ||||
|  | ||||
| //+build !windows | ||||
|  | ||||
| package discover | ||||
|  | ||||
| // reports whether err indicates that a UDP packet didn't | ||||
| // fit the receive buffer. There is no such error on | ||||
| // non-Windows platforms. | ||||
| func isPacketTooBig(err error) bool { | ||||
| 	return false | ||||
| } | ||||
| @@ -23,10 +23,8 @@ import ( | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	logpkg "log" | ||||
| 	"math/rand" | ||||
| 	"net" | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
| 	"reflect" | ||||
| 	"runtime" | ||||
| @@ -34,12 +32,62 @@ import ( | ||||
| 	"testing" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/davecgh/go-spew/spew" | ||||
| 	"github.com/ethereum/go-ethereum/crypto" | ||||
| 	"github.com/ethereum/go-ethereum/logger" | ||||
| ) | ||||
|  | ||||
| func init() { | ||||
| 	logger.AddLogSystem(logger.NewStdLogSystem(os.Stdout, logpkg.LstdFlags, logger.ErrorLevel)) | ||||
| 	spew.Config.DisableMethods = true | ||||
| } | ||||
|  | ||||
| // This test checks that isPacketTooBig correctly identifies | ||||
| // errors that result from receiving a UDP packet larger | ||||
| // than the supplied receive buffer. | ||||
| func TestIsPacketTooBig(t *testing.T) { | ||||
| 	listener, err := net.ListenPacket("udp", "127.0.0.1:0") | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	defer listener.Close() | ||||
| 	sender, err := net.Dial("udp", listener.LocalAddr().String()) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	defer sender.Close() | ||||
|  | ||||
| 	sendN := 1800 | ||||
| 	recvN := 300 | ||||
| 	for i := 0; i < 20; i++ { | ||||
| 		go func() { | ||||
| 			buf := make([]byte, sendN) | ||||
| 			for i := range buf { | ||||
| 				buf[i] = byte(i) | ||||
| 			} | ||||
| 			sender.Write(buf) | ||||
| 		}() | ||||
|  | ||||
| 		buf := make([]byte, recvN) | ||||
| 		listener.SetDeadline(time.Now().Add(1 * time.Second)) | ||||
| 		n, _, err := listener.ReadFrom(buf) | ||||
| 		if err != nil { | ||||
| 			if nerr, ok := err.(net.Error); ok && nerr.Timeout() { | ||||
| 				continue | ||||
| 			} | ||||
| 			if !isPacketTooBig(err) { | ||||
| 				t.Fatal("unexpected read error:", spew.Sdump(err)) | ||||
| 			} | ||||
| 			continue | ||||
| 		} | ||||
| 		if n != recvN { | ||||
| 			t.Fatalf("short read: %d, want %d", n, recvN) | ||||
| 		} | ||||
| 		for i := range buf { | ||||
| 			if buf[i] != byte(i) { | ||||
| 				t.Fatalf("error in pattern") | ||||
| 				break | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // shared test variables | ||||
|   | ||||
							
								
								
									
										40
									
								
								p2p/discover/udp_windows.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								p2p/discover/udp_windows.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,40 @@ | ||||
| // Copyright 2016 The go-ethereum Authors | ||||
| // This file is part of the go-ethereum library. | ||||
| // | ||||
| // The go-ethereum library is free software: you can redistribute it and/or modify | ||||
| // it under the terms of the GNU Lesser General Public License as published by | ||||
| // the Free Software Foundation, either version 3 of the License, or | ||||
| // (at your option) any later version. | ||||
| // | ||||
| // The go-ethereum library is distributed in the hope that it will be useful, | ||||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||
| // GNU Lesser General Public License for more details. | ||||
| // | ||||
| // You should have received a copy of the GNU Lesser General Public License | ||||
| // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. | ||||
|  | ||||
| //+build windows | ||||
|  | ||||
| package discover | ||||
|  | ||||
| import ( | ||||
| 	"net" | ||||
| 	"os" | ||||
| 	"syscall" | ||||
| ) | ||||
|  | ||||
| const _WSAEMSGSIZE = syscall.Errno(10040) | ||||
|  | ||||
| // reports whether err indicates that a UDP packet didn't | ||||
| // fit the receive buffer. On Windows, WSARecvFrom returns | ||||
| // code WSAEMSGSIZE and no data if this happens. | ||||
| func isPacketTooBig(err error) bool { | ||||
| 	if opErr, ok := err.(*net.OpError); ok { | ||||
| 		if scErr, ok := opErr.Err.(*os.SyscallError); ok { | ||||
| 			return scErr.Err == _WSAEMSGSIZE | ||||
| 		} | ||||
| 		return opErr.Err == _WSAEMSGSIZE | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
		Reference in New Issue
	
	Block a user