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 | 	return packet, nil | ||||||
| } | } | ||||||
|  |  | ||||||
| type tempError interface { | func isTemporaryError(err error) bool { | ||||||
| 	Temporary() bool | 	tempErr, ok := err.(interface { | ||||||
|  | 		Temporary() bool | ||||||
|  | 	}) | ||||||
|  | 	return ok && tempErr.Temporary() || isPacketTooBig(err) | ||||||
| } | } | ||||||
|  |  | ||||||
| // readLoop runs in its own goroutine. it handles incoming UDP packets. | // readLoop runs in its own goroutine. it handles incoming UDP packets. | ||||||
| @@ -466,7 +469,7 @@ func (t *udp) readLoop() { | |||||||
| 	buf := make([]byte, 1280) | 	buf := make([]byte, 1280) | ||||||
| 	for { | 	for { | ||||||
| 		nbytes, from, err := t.conn.ReadFromUDP(buf) | 		nbytes, from, err := t.conn.ReadFromUDP(buf) | ||||||
| 		if tempErr, ok := err.(tempError); ok && tempErr.Temporary() { | 		if isTemporaryError(err) { | ||||||
| 			// Ignore temporary read errors. | 			// Ignore temporary read errors. | ||||||
| 			glog.V(logger.Debug).Infof("Temporary read error: %v", err) | 			glog.V(logger.Debug).Infof("Temporary read error: %v", err) | ||||||
| 			continue | 			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" | 	"errors" | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"io" | 	"io" | ||||||
| 	logpkg "log" |  | ||||||
| 	"math/rand" | 	"math/rand" | ||||||
| 	"net" | 	"net" | ||||||
| 	"os" |  | ||||||
| 	"path/filepath" | 	"path/filepath" | ||||||
| 	"reflect" | 	"reflect" | ||||||
| 	"runtime" | 	"runtime" | ||||||
| @@ -34,12 +32,62 @@ import ( | |||||||
| 	"testing" | 	"testing" | ||||||
| 	"time" | 	"time" | ||||||
|  |  | ||||||
|  | 	"github.com/davecgh/go-spew/spew" | ||||||
| 	"github.com/ethereum/go-ethereum/crypto" | 	"github.com/ethereum/go-ethereum/crypto" | ||||||
| 	"github.com/ethereum/go-ethereum/logger" |  | ||||||
| ) | ) | ||||||
|  |  | ||||||
| func init() { | 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 | // 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