| 
									
										
										
										
											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 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2014-11-04 13:21:44 +01:00
										 |  |  | 	"bytes" | 
					
						
							| 
									
										
										
										
											2015-03-04 12:03:43 +01:00
										 |  |  | 	"encoding/hex" | 
					
						
							| 
									
										
										
										
											2014-12-12 11:39:07 +01:00
										 |  |  | 	"fmt" | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | 	"io" | 
					
						
							| 
									
										
										
										
											2014-12-12 11:39:07 +01:00
										 |  |  | 	"runtime" | 
					
						
							| 
									
										
										
										
											2015-03-04 12:03:43 +01:00
										 |  |  | 	"strings" | 
					
						
							| 
									
										
										
										
											2014-10-23 16:57:54 +01:00
										 |  |  | 	"testing" | 
					
						
							| 
									
										
										
										
											2014-12-12 11:39:07 +01:00
										 |  |  | 	"time" | 
					
						
							| 
									
										
										
										
											2014-10-23 16:57:54 +01:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-12-12 11:39:07 +01:00
										 |  |  | func ExampleMsgPipe() { | 
					
						
							|  |  |  | 	rw1, rw2 := MsgPipe() | 
					
						
							|  |  |  | 	go func() { | 
					
						
							| 
									
										
										
										
											2015-03-19 15:11:02 +01:00
										 |  |  | 		Send(rw1, 8, [][]byte{{0, 0}}) | 
					
						
							|  |  |  | 		Send(rw1, 5, [][]byte{{1, 1}}) | 
					
						
							| 
									
										
										
										
											2014-12-12 11:39:07 +01:00
										 |  |  | 		rw1.Close() | 
					
						
							|  |  |  | 	}() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for { | 
					
						
							|  |  |  | 		msg, err := rw2.ReadMsg() | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			break | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-03-19 15:11:02 +01:00
										 |  |  | 		var data [][]byte | 
					
						
							| 
									
										
										
										
											2014-12-12 11:39:07 +01:00
										 |  |  | 		msg.Decode(&data) | 
					
						
							|  |  |  | 		fmt.Printf("msg: %d, %x\n", msg.Code, data[0]) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Output: | 
					
						
							|  |  |  | 	// msg: 8, 0000 | 
					
						
							|  |  |  | 	// msg: 5, 0101 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func TestMsgPipeUnblockWrite(t *testing.T) { | 
					
						
							|  |  |  | loop: | 
					
						
							|  |  |  | 	for i := 0; i < 100; i++ { | 
					
						
							|  |  |  | 		rw1, rw2 := MsgPipe() | 
					
						
							|  |  |  | 		done := make(chan struct{}) | 
					
						
							|  |  |  | 		go func() { | 
					
						
							| 
									
										
										
										
											2015-03-19 15:11:02 +01:00
										 |  |  | 			if err := SendItems(rw1, 1); err == nil { | 
					
						
							| 
									
										
										
										
											2014-12-12 11:39:07 +01:00
										 |  |  | 				t.Error("EncodeMsg returned nil error") | 
					
						
							|  |  |  | 			} else if err != ErrPipeClosed { | 
					
						
							| 
									
										
										
										
											2016-04-15 11:06:57 +02:00
										 |  |  | 				t.Errorf("EncodeMsg returned wrong error: got %v, want %v", err, ErrPipeClosed) | 
					
						
							| 
									
										
										
										
											2014-12-12 11:39:07 +01:00
										 |  |  | 			} | 
					
						
							|  |  |  | 			close(done) | 
					
						
							|  |  |  | 		}() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// this call should ensure that EncodeMsg is waiting to | 
					
						
							|  |  |  | 		// deliver sometimes. if this isn't done, Close is likely to | 
					
						
							|  |  |  | 		// be executed before EncodeMsg starts and then we won't test | 
					
						
							|  |  |  | 		// all the cases. | 
					
						
							|  |  |  | 		runtime.Gosched() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		rw2.Close() | 
					
						
							|  |  |  | 		select { | 
					
						
							|  |  |  | 		case <-done: | 
					
						
							|  |  |  | 		case <-time.After(200 * time.Millisecond): | 
					
						
							|  |  |  | 			t.Errorf("write didn't unblock") | 
					
						
							|  |  |  | 			break loop | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // This test should panic if concurrent close isn't implemented correctly. | 
					
						
							|  |  |  | func TestMsgPipeConcurrentClose(t *testing.T) { | 
					
						
							|  |  |  | 	rw1, _ := MsgPipe() | 
					
						
							|  |  |  | 	for i := 0; i < 10; i++ { | 
					
						
							|  |  |  | 		go rw1.Close() | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | func TestEOFSignal(t *testing.T) { | 
					
						
							|  |  |  | 	rb := make([]byte, 10) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// empty reader | 
					
						
							|  |  |  | 	eof := make(chan struct{}, 1) | 
					
						
							|  |  |  | 	sig := &eofSignal{new(bytes.Buffer), 0, eof} | 
					
						
							|  |  |  | 	if n, err := sig.Read(rb); n != 0 || err != io.EOF { | 
					
						
							|  |  |  | 		t.Errorf("Read returned unexpected values: (%v, %v)", n, err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	select { | 
					
						
							|  |  |  | 	case <-eof: | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		t.Error("EOF chan not signaled") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// count before error | 
					
						
							|  |  |  | 	eof = make(chan struct{}, 1) | 
					
						
							|  |  |  | 	sig = &eofSignal{bytes.NewBufferString("aaaaaaaa"), 4, eof} | 
					
						
							|  |  |  | 	if n, err := sig.Read(rb); n != 4 || err != nil { | 
					
						
							|  |  |  | 		t.Errorf("Read returned unexpected values: (%v, %v)", n, err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	select { | 
					
						
							|  |  |  | 	case <-eof: | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		t.Error("EOF chan not signaled") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// error before count | 
					
						
							|  |  |  | 	eof = make(chan struct{}, 1) | 
					
						
							|  |  |  | 	sig = &eofSignal{bytes.NewBufferString("aaaa"), 999, eof} | 
					
						
							|  |  |  | 	if n, err := sig.Read(rb); n != 4 || err != nil { | 
					
						
							|  |  |  | 		t.Errorf("Read returned unexpected values: (%v, %v)", n, err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if n, err := sig.Read(rb); n != 0 || err != io.EOF { | 
					
						
							|  |  |  | 		t.Errorf("Read returned unexpected values: (%v, %v)", n, err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	select { | 
					
						
							|  |  |  | 	case <-eof: | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		t.Error("EOF chan not signaled") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// no signal if neither occurs | 
					
						
							|  |  |  | 	eof = make(chan struct{}, 1) | 
					
						
							|  |  |  | 	sig = &eofSignal{bytes.NewBufferString("aaaaaaaaaaaaaaaaaaaaa"), 999, eof} | 
					
						
							|  |  |  | 	if n, err := sig.Read(rb); n != 10 || err != nil { | 
					
						
							|  |  |  | 		t.Errorf("Read returned unexpected values: (%v, %v)", n, err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	select { | 
					
						
							|  |  |  | 	case <-eof: | 
					
						
							|  |  |  | 		t.Error("unexpected EOF signal") | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2015-03-04 12:03:43 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | func unhex(str string) []byte { | 
					
						
							| 
									
										
										
										
											2015-12-23 01:48:55 +01:00
										 |  |  | 	r := strings.NewReplacer("\t", "", " ", "", "\n", "") | 
					
						
							|  |  |  | 	b, err := hex.DecodeString(r.Replace(str)) | 
					
						
							| 
									
										
										
										
											2015-03-04 12:03:43 +01:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		panic(fmt.Sprintf("invalid hex string: %q", str)) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return b | 
					
						
							|  |  |  | } |