| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // Copyright 2014 The go-ethereum Authors | 
					
						
							| 
									
										
										
										
											2015-07-22 18:48:40 +02:00
										 |  |  | // This file is part of the go-ethereum library. | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // | 
					
						
							| 
									
										
										
										
											2015-07-23 18:35:11 +02:00
										 |  |  | // The go-ethereum library is free software: you can redistribute it and/or modify | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // 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. | 
					
						
							|  |  |  | // | 
					
						
							| 
									
										
										
										
											2015-07-22 18:48:40 +02:00
										 |  |  | // The go-ethereum library is distributed in the hope that it will be useful, | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							| 
									
										
										
										
											2015-07-22 18:48:40 +02:00
										 |  |  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // GNU Lesser General Public License for more details. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // You should have received a copy of the GNU Lesser General Public License | 
					
						
							| 
									
										
										
										
											2015-07-22 18:48:40 +02:00
										 |  |  | // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-23 16:57:54 +01:00
										 |  |  | package p2p | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | import ( | 
					
						
							| 
									
										
										
										
											2020-02-13 11:10:03 +01:00
										 |  |  | 	"encoding/binary" | 
					
						
							| 
									
										
										
										
											2015-04-08 17:37:11 +02:00
										 |  |  | 	"errors" | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | 	"fmt" | 
					
						
							| 
									
										
										
										
											2015-04-08 17:37:11 +02:00
										 |  |  | 	"math/rand" | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | 	"net" | 
					
						
							| 
									
										
										
										
											2014-11-26 22:49:40 +01:00
										 |  |  | 	"reflect" | 
					
						
							| 
									
										
										
										
											2020-02-13 11:10:03 +01:00
										 |  |  | 	"strconv" | 
					
						
							|  |  |  | 	"strings" | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | 	"testing" | 
					
						
							|  |  |  | 	"time" | 
					
						
							| 
									
										
										
										
											2019-06-11 12:45:33 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/log" | 
					
						
							| 
									
										
										
										
											2020-02-13 11:10:03 +01:00
										 |  |  | 	"github.com/ethereum/go-ethereum/p2p/enode" | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/p2p/enr" | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var discard = Protocol{ | 
					
						
							|  |  |  | 	Name:   "discard", | 
					
						
							|  |  |  | 	Length: 1, | 
					
						
							|  |  |  | 	Run: func(p *Peer, rw MsgReadWriter) error { | 
					
						
							|  |  |  | 		for { | 
					
						
							|  |  |  | 			msg, err := rw.ReadMsg() | 
					
						
							|  |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				return err | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2015-02-19 01:52:03 +01:00
										 |  |  | 			fmt.Printf("discarding %d\n", msg.Code) | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | 			if err = msg.Discard(); err != nil { | 
					
						
							|  |  |  | 				return err | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-13 11:10:03 +01:00
										 |  |  | // uintID encodes i into a node ID. | 
					
						
							|  |  |  | func uintID(i uint16) enode.ID { | 
					
						
							|  |  |  | 	var id enode.ID | 
					
						
							|  |  |  | 	binary.BigEndian.PutUint16(id[:], i) | 
					
						
							|  |  |  | 	return id | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // newNode creates a node record with the given address. | 
					
						
							|  |  |  | func newNode(id enode.ID, addr string) *enode.Node { | 
					
						
							|  |  |  | 	var r enr.Record | 
					
						
							|  |  |  | 	if addr != "" { | 
					
						
							|  |  |  | 		// Set the port if present. | 
					
						
							|  |  |  | 		if strings.Contains(addr, ":") { | 
					
						
							|  |  |  | 			hs, ps, err := net.SplitHostPort(addr) | 
					
						
							|  |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				panic(fmt.Errorf("invalid address %q", addr)) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			port, err := strconv.Atoi(ps) | 
					
						
							|  |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				panic(fmt.Errorf("invalid port in %q", addr)) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			r.Set(enr.TCP(port)) | 
					
						
							|  |  |  | 			r.Set(enr.UDP(port)) | 
					
						
							|  |  |  | 			addr = hs | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		// Set the IP. | 
					
						
							|  |  |  | 		ip := net.ParseIP(addr) | 
					
						
							|  |  |  | 		if ip == nil { | 
					
						
							|  |  |  | 			panic(fmt.Errorf("invalid IP %q", addr)) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		r.Set(enr.IP(ip)) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return enode.SignNull(&r, id) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-24 09:58:04 +01:00
										 |  |  | func testPeer(protos []Protocol) (func(), *conn, *Peer, <-chan error) { | 
					
						
							| 
									
										
										
										
											2015-05-16 00:38:28 +02:00
										 |  |  | 	fd1, fd2 := net.Pipe() | 
					
						
							| 
									
										
										
										
											2020-02-13 11:10:03 +01:00
										 |  |  | 	c1 := &conn{fd: fd1, node: newNode(randomID(), ""), transport: newTestTransport(&newkey().PublicKey, fd1)} | 
					
						
							|  |  |  | 	c2 := &conn{fd: fd2, node: newNode(randomID(), ""), transport: newTestTransport(&newkey().PublicKey, fd2)} | 
					
						
							| 
									
										
										
										
											2015-02-19 01:52:03 +01:00
										 |  |  | 	for _, p := range protos { | 
					
						
							| 
									
										
										
										
											2015-05-16 00:38:28 +02:00
										 |  |  | 		c1.caps = append(c1.caps, p.cap()) | 
					
						
							|  |  |  | 		c2.caps = append(c2.caps, p.cap()) | 
					
						
							| 
									
										
										
										
											2015-02-19 01:52:03 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-11 12:45:33 +02:00
										 |  |  | 	peer := newPeer(log.Root(), c1, protos) | 
					
						
							| 
									
										
										
										
											2017-02-24 09:58:04 +01:00
										 |  |  | 	errc := make(chan error, 1) | 
					
						
							|  |  |  | 	go func() { | 
					
						
							|  |  |  | 		_, err := peer.run() | 
					
						
							|  |  |  | 		errc <- err | 
					
						
							|  |  |  | 	}() | 
					
						
							| 
									
										
										
										
											2015-02-19 01:52:03 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-16 00:38:28 +02:00
										 |  |  | 	closer := func() { c2.close(errors.New("close func called")) } | 
					
						
							|  |  |  | 	return closer, c2, peer, errc | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func TestPeerProtoReadMsg(t *testing.T) { | 
					
						
							|  |  |  | 	proto := Protocol{ | 
					
						
							|  |  |  | 		Name:   "a", | 
					
						
							|  |  |  | 		Length: 5, | 
					
						
							|  |  |  | 		Run: func(peer *Peer, rw MsgReadWriter) error { | 
					
						
							| 
									
										
										
										
											2015-03-19 15:11:02 +01:00
										 |  |  | 			if err := ExpectMsg(rw, 2, []uint{1}); err != nil { | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | 				t.Error(err) | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2015-03-19 15:11:02 +01:00
										 |  |  | 			if err := ExpectMsg(rw, 3, []uint{2}); err != nil { | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | 				t.Error(err) | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2015-03-19 15:11:02 +01:00
										 |  |  | 			if err := ExpectMsg(rw, 4, []uint{3}); err != nil { | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | 				t.Error(err) | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | 			} | 
					
						
							|  |  |  | 			return nil | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-27 03:06:55 +00:00
										 |  |  | 	closer, rw, _, errc := testPeer([]Protocol{proto}) | 
					
						
							| 
									
										
										
										
											2015-04-08 17:37:11 +02:00
										 |  |  | 	defer closer() | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-19 15:11:02 +01:00
										 |  |  | 	Send(rw, baseProtocolLength+2, []uint{1}) | 
					
						
							|  |  |  | 	Send(rw, baseProtocolLength+3, []uint{2}) | 
					
						
							|  |  |  | 	Send(rw, baseProtocolLength+4, []uint{3}) | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | 	select { | 
					
						
							|  |  |  | 	case err := <-errc: | 
					
						
							| 
									
										
										
										
											2017-02-24 09:58:04 +01:00
										 |  |  | 		if err != errProtocolReturned { | 
					
						
							|  |  |  | 			t.Errorf("peer returned error: %v", err) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | 	case <-time.After(2 * time.Second): | 
					
						
							|  |  |  | 		t.Errorf("receive timeout") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func TestPeerProtoEncodeMsg(t *testing.T) { | 
					
						
							|  |  |  | 	proto := Protocol{ | 
					
						
							|  |  |  | 		Name:   "a", | 
					
						
							|  |  |  | 		Length: 2, | 
					
						
							|  |  |  | 		Run: func(peer *Peer, rw MsgReadWriter) error { | 
					
						
							| 
									
										
										
										
											2015-03-19 15:11:02 +01:00
										 |  |  | 			if err := SendItems(rw, 2); err == nil { | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | 				t.Error("expected error for out-of-range msg code, got nil") | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2015-03-19 15:11:02 +01:00
										 |  |  | 			if err := SendItems(rw, 1, "foo", "bar"); err != nil { | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | 				t.Errorf("write error: %v", err) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			return nil | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-02-27 03:06:55 +00:00
										 |  |  | 	closer, rw, _, _ := testPeer([]Protocol{proto}) | 
					
						
							| 
									
										
										
										
											2015-04-08 17:37:11 +02:00
										 |  |  | 	defer closer() | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-19 15:11:02 +01:00
										 |  |  | 	if err := ExpectMsg(rw, 17, []string{"foo", "bar"}); err != nil { | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | 		t.Error(err) | 
					
						
							| 
									
										
										
										
											2015-01-05 17:10:42 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | func TestPeerPing(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2015-02-27 03:06:55 +00:00
										 |  |  | 	closer, rw, _, _ := testPeer(nil) | 
					
						
							| 
									
										
										
										
											2015-04-08 17:37:11 +02:00
										 |  |  | 	defer closer() | 
					
						
							| 
									
										
										
										
											2015-03-19 15:11:02 +01:00
										 |  |  | 	if err := SendItems(rw, pingMsg); err != nil { | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-03-19 15:11:02 +01:00
										 |  |  | 	if err := ExpectMsg(rw, pongMsg, nil); err != nil { | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | 		t.Error(err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | func TestPeerDisconnect(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2015-02-27 03:06:55 +00:00
										 |  |  | 	closer, rw, _, disc := testPeer(nil) | 
					
						
							| 
									
										
										
										
											2015-04-08 17:37:11 +02:00
										 |  |  | 	defer closer() | 
					
						
							| 
									
										
										
										
											2015-03-19 15:11:02 +01:00
										 |  |  | 	if err := SendItems(rw, discMsg, DiscQuitting); err != nil { | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | 		t.Fatal(err) | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-05-14 03:04:04 +02:00
										 |  |  | 	select { | 
					
						
							|  |  |  | 	case reason := <-disc: | 
					
						
							| 
									
										
										
										
											2017-02-24 09:58:04 +01:00
										 |  |  | 		if reason != DiscQuitting { | 
					
						
							|  |  |  | 			t.Errorf("run returned wrong reason: got %v, want %v", reason, DiscQuitting) | 
					
						
							| 
									
										
										
										
											2015-05-14 03:04:04 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	case <-time.After(500 * time.Millisecond): | 
					
						
							|  |  |  | 		t.Error("peer did not return") | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2014-11-26 22:49:40 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-08 17:37:11 +02:00
										 |  |  | // This test is supposed to verify that Peer can reliably handle | 
					
						
							|  |  |  | // multiple causes of disconnection occurring at the same time. | 
					
						
							|  |  |  | func TestPeerDisconnectRace(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2019-11-13 20:01:52 +09:00
										 |  |  | 	maybe := func() bool { return rand.Intn(2) == 1 } | 
					
						
							| 
									
										
										
										
											2015-04-08 17:37:11 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	for i := 0; i < 1000; i++ { | 
					
						
							|  |  |  | 		protoclose := make(chan error) | 
					
						
							|  |  |  | 		protodisc := make(chan DiscReason) | 
					
						
							|  |  |  | 		closer, rw, p, disc := testPeer([]Protocol{ | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				Name:   "closereq", | 
					
						
							|  |  |  | 				Run:    func(p *Peer, rw MsgReadWriter) error { return <-protoclose }, | 
					
						
							|  |  |  | 				Length: 1, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				Name:   "disconnect", | 
					
						
							|  |  |  | 				Run:    func(p *Peer, rw MsgReadWriter) error { p.Disconnect(<-protodisc); return nil }, | 
					
						
							|  |  |  | 				Length: 1, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Simulate incoming messages. | 
					
						
							|  |  |  | 		go SendItems(rw, baseProtocolLength+1) | 
					
						
							|  |  |  | 		go SendItems(rw, baseProtocolLength+2) | 
					
						
							|  |  |  | 		// Close the network connection. | 
					
						
							|  |  |  | 		go closer() | 
					
						
							|  |  |  | 		// Make protocol "closereq" return. | 
					
						
							|  |  |  | 		protoclose <- errors.New("protocol closed") | 
					
						
							|  |  |  | 		// Make protocol "disconnect" call peer.Disconnect | 
					
						
							|  |  |  | 		protodisc <- DiscAlreadyConnected | 
					
						
							|  |  |  | 		// In some cases, simulate something else calling peer.Disconnect. | 
					
						
							|  |  |  | 		if maybe() { | 
					
						
							|  |  |  | 			go p.Disconnect(DiscInvalidIdentity) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		// In some cases, simulate remote requesting a disconnect. | 
					
						
							|  |  |  | 		if maybe() { | 
					
						
							|  |  |  | 			go SendItems(rw, discMsg, DiscQuitting) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		select { | 
					
						
							|  |  |  | 		case <-disc: | 
					
						
							|  |  |  | 		case <-time.After(2 * time.Second): | 
					
						
							|  |  |  | 			// Peer.run should return quickly. If it doesn't the Peer | 
					
						
							|  |  |  | 			// goroutines are probably deadlocked. Call panic in order to | 
					
						
							|  |  |  | 			// show the stacks. | 
					
						
							|  |  |  | 			panic("Peer.run took to long to return.") | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | func TestNewPeer(t *testing.T) { | 
					
						
							|  |  |  | 	name := "nodename" | 
					
						
							|  |  |  | 	caps := []Cap{{"foo", 2}, {"bar", 3}} | 
					
						
							|  |  |  | 	id := randomID() | 
					
						
							|  |  |  | 	p := NewPeer(id, name, caps) | 
					
						
							|  |  |  | 	if p.ID() != id { | 
					
						
							|  |  |  | 		t.Errorf("ID mismatch: got %v, expected %v", p.ID(), id) | 
					
						
							| 
									
										
										
										
											2014-12-12 11:38:42 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | 	if p.Name() != name { | 
					
						
							|  |  |  | 		t.Errorf("Name mismatch: got %v, expected %v", p.Name(), name) | 
					
						
							| 
									
										
										
										
											2014-12-12 11:38:42 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | 	if !reflect.DeepEqual(p.Caps(), caps) { | 
					
						
							|  |  |  | 		t.Errorf("Caps mismatch: got %v, expected %v", p.Caps(), caps) | 
					
						
							| 
									
										
										
										
											2014-12-12 11:38:42 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | 	p.Disconnect(DiscAlreadyConnected) // Should not hang | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2015-06-26 15:48:50 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | func TestMatchProtocols(t *testing.T) { | 
					
						
							|  |  |  | 	tests := []struct { | 
					
						
							| 
									
										
										
										
											2015-06-26 20:45:13 +03:00
										 |  |  | 		Remote []Cap | 
					
						
							|  |  |  | 		Local  []Protocol | 
					
						
							| 
									
										
										
										
											2015-06-26 15:48:50 +03:00
										 |  |  | 		Match  map[string]protoRW | 
					
						
							|  |  |  | 	}{ | 
					
						
							|  |  |  | 		{ | 
					
						
							| 
									
										
										
										
											2015-06-26 20:45:13 +03:00
										 |  |  | 			// No remote capabilities | 
					
						
							|  |  |  | 			Local: []Protocol{{Name: "a"}}, | 
					
						
							| 
									
										
										
										
											2015-06-26 15:48:50 +03:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							| 
									
										
										
										
											2015-06-26 20:45:13 +03:00
										 |  |  | 			// No local protocols | 
					
						
							|  |  |  | 			Remote: []Cap{{Name: "a"}}, | 
					
						
							| 
									
										
										
										
											2015-06-26 15:48:50 +03:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			// No mutual protocols | 
					
						
							| 
									
										
										
										
											2015-06-26 20:45:13 +03:00
										 |  |  | 			Remote: []Cap{{Name: "a"}}, | 
					
						
							|  |  |  | 			Local:  []Protocol{{Name: "b"}}, | 
					
						
							| 
									
										
										
										
											2015-06-26 15:48:50 +03:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			// Some matches, some differences | 
					
						
							| 
									
										
										
										
											2015-06-26 20:45:13 +03:00
										 |  |  | 			Remote: []Cap{{Name: "local"}, {Name: "match1"}, {Name: "match2"}}, | 
					
						
							|  |  |  | 			Local:  []Protocol{{Name: "match1"}, {Name: "match2"}, {Name: "remote"}}, | 
					
						
							| 
									
										
										
										
											2015-06-26 15:48:50 +03:00
										 |  |  | 			Match:  map[string]protoRW{"match1": {Protocol: Protocol{Name: "match1"}}, "match2": {Protocol: Protocol{Name: "match2"}}}, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			// Various alphabetical ordering | 
					
						
							| 
									
										
										
										
											2015-06-26 20:45:13 +03:00
										 |  |  | 			Remote: []Cap{{Name: "aa"}, {Name: "ab"}, {Name: "bb"}, {Name: "ba"}}, | 
					
						
							|  |  |  | 			Local:  []Protocol{{Name: "ba"}, {Name: "bb"}, {Name: "ab"}, {Name: "aa"}}, | 
					
						
							| 
									
										
										
										
											2015-06-26 15:48:50 +03:00
										 |  |  | 			Match:  map[string]protoRW{"aa": {Protocol: Protocol{Name: "aa"}}, "ab": {Protocol: Protocol{Name: "ab"}}, "ba": {Protocol: Protocol{Name: "ba"}}, "bb": {Protocol: Protocol{Name: "bb"}}}, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			// No mutual versions | 
					
						
							| 
									
										
										
										
											2015-06-26 20:45:13 +03:00
										 |  |  | 			Remote: []Cap{{Version: 1}}, | 
					
						
							|  |  |  | 			Local:  []Protocol{{Version: 2}}, | 
					
						
							| 
									
										
										
										
											2015-06-26 15:48:50 +03:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			// Multiple versions, single common | 
					
						
							| 
									
										
										
										
											2015-06-26 20:45:13 +03:00
										 |  |  | 			Remote: []Cap{{Version: 1}, {Version: 2}}, | 
					
						
							|  |  |  | 			Local:  []Protocol{{Version: 2}, {Version: 3}}, | 
					
						
							| 
									
										
										
										
											2015-06-26 15:48:50 +03:00
										 |  |  | 			Match:  map[string]protoRW{"": {Protocol: Protocol{Version: 2}}}, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			// Multiple versions, multiple common | 
					
						
							| 
									
										
										
										
											2015-06-26 20:45:13 +03:00
										 |  |  | 			Remote: []Cap{{Version: 1}, {Version: 2}, {Version: 3}, {Version: 4}}, | 
					
						
							|  |  |  | 			Local:  []Protocol{{Version: 2}, {Version: 3}}, | 
					
						
							| 
									
										
										
										
											2015-06-26 15:48:50 +03:00
										 |  |  | 			Match:  map[string]protoRW{"": {Protocol: Protocol{Version: 3}}}, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			// Various version orderings | 
					
						
							| 
									
										
										
										
											2015-06-26 20:45:13 +03:00
										 |  |  | 			Remote: []Cap{{Version: 4}, {Version: 1}, {Version: 3}, {Version: 2}}, | 
					
						
							|  |  |  | 			Local:  []Protocol{{Version: 2}, {Version: 3}, {Version: 1}}, | 
					
						
							| 
									
										
										
										
											2015-06-26 15:48:50 +03:00
										 |  |  | 			Match:  map[string]protoRW{"": {Protocol: Protocol{Version: 3}}}, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			// Versions overriding sub-protocol lengths | 
					
						
							| 
									
										
										
										
											2015-06-26 20:45:13 +03:00
										 |  |  | 			Remote: []Cap{{Version: 1}, {Version: 2}, {Version: 3}, {Name: "a"}}, | 
					
						
							|  |  |  | 			Local:  []Protocol{{Version: 1, Length: 1}, {Version: 2, Length: 2}, {Version: 3, Length: 3}, {Name: "a"}}, | 
					
						
							| 
									
										
										
										
											2015-06-26 15:48:50 +03:00
										 |  |  | 			Match:  map[string]protoRW{"": {Protocol: Protocol{Version: 3}}, "a": {Protocol: Protocol{Name: "a"}, offset: 3}}, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for i, tt := range tests { | 
					
						
							| 
									
										
										
										
											2015-06-26 20:45:13 +03:00
										 |  |  | 		result := matchProtocols(tt.Local, tt.Remote, nil) | 
					
						
							| 
									
										
										
										
											2015-06-26 15:48:50 +03:00
										 |  |  | 		if len(result) != len(tt.Match) { | 
					
						
							|  |  |  | 			t.Errorf("test %d: negotiation mismatch: have %v, want %v", i, len(result), len(tt.Match)) | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		// Make sure all negotiated protocols are needed and correct | 
					
						
							|  |  |  | 		for name, proto := range result { | 
					
						
							|  |  |  | 			match, ok := tt.Match[name] | 
					
						
							|  |  |  | 			if !ok { | 
					
						
							|  |  |  | 				t.Errorf("test %d, proto '%s': negotiated but shouldn't have", i, name) | 
					
						
							|  |  |  | 				continue | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if proto.Name != match.Name { | 
					
						
							|  |  |  | 				t.Errorf("test %d, proto '%s': name mismatch: have %v, want %v", i, name, proto.Name, match.Name) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if proto.Version != match.Version { | 
					
						
							|  |  |  | 				t.Errorf("test %d, proto '%s': version mismatch: have %v, want %v", i, name, proto.Version, match.Version) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if proto.offset-baseProtocolLength != match.offset { | 
					
						
							|  |  |  | 				t.Errorf("test %d, proto '%s': offset mismatch: have %v, want %v", i, name, proto.offset-baseProtocolLength, match.offset) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		// Make sure no protocols missed negotiation | 
					
						
							| 
									
										
										
										
											2017-01-06 15:52:03 +01:00
										 |  |  | 		for name := range tt.Match { | 
					
						
							| 
									
										
										
										
											2015-06-26 15:48:50 +03:00
										 |  |  | 			if _, ok := result[name]; !ok { | 
					
						
							|  |  |  | 				t.Errorf("test %d, proto '%s': not negotiated, should have", i, name) | 
					
						
							|  |  |  | 				continue | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } |