@@ -29,6 +29,7 @@ import (
29
29
"fmt"
30
30
"hash"
31
31
"io"
32
+ "io/ioutil"
32
33
mrand "math/rand"
33
34
"net"
34
35
"sync"
@@ -40,6 +41,7 @@ import (
40
41
"github.com/ethereum/go-ethereum/crypto/sha3"
41
42
"github.com/ethereum/go-ethereum/p2p/discover"
42
43
"github.com/ethereum/go-ethereum/rlp"
44
+ "github.com/golang/snappy"
43
45
)
44
46
45
47
const (
@@ -68,6 +70,10 @@ const (
68
70
discWriteTimeout = 1 * time .Second
69
71
)
70
72
73
+ // errPlainMessageTooLarge is returned if a decompressed message length exceeds
74
+ // the allowed 24 bits (i.e. length >= 16MB).
75
+ var errPlainMessageTooLarge = errors .New ("message length >= 16MB" )
76
+
71
77
// rlpx is the transport protocol used by actual (non-test) connections.
72
78
// It wraps the frame encoder with locks and read/write deadlines.
73
79
type rlpx struct {
@@ -127,6 +133,9 @@ func (t *rlpx) doProtoHandshake(our *protoHandshake) (their *protoHandshake, err
127
133
if err := <- werr ; err != nil {
128
134
return nil , fmt .Errorf ("write error: %v" , err )
129
135
}
136
+ // If the protocol version supports Snappy encoding, upgrade immediately
137
+ t .rw .snappy = their .Version >= snappyProtocolVersion
138
+
130
139
return their , nil
131
140
}
132
141
@@ -556,6 +565,8 @@ type rlpxFrameRW struct {
556
565
macCipher cipher.Block
557
566
egressMAC hash.Hash
558
567
ingressMAC hash.Hash
568
+
569
+ snappy bool
559
570
}
560
571
561
572
func newRLPXFrameRW (conn io.ReadWriter , s secrets ) * rlpxFrameRW {
@@ -583,6 +594,17 @@ func newRLPXFrameRW(conn io.ReadWriter, s secrets) *rlpxFrameRW {
583
594
func (rw * rlpxFrameRW ) WriteMsg (msg Msg ) error {
584
595
ptype , _ := rlp .EncodeToBytes (msg .Code )
585
596
597
+ // if snappy is enabled, compress message now
598
+ if rw .snappy {
599
+ if msg .Size > maxUint24 {
600
+ return errPlainMessageTooLarge
601
+ }
602
+ payload , _ := ioutil .ReadAll (msg .Payload )
603
+ payload = snappy .Encode (nil , payload )
604
+
605
+ msg .Payload = bytes .NewReader (payload )
606
+ msg .Size = uint32 (len (payload ))
607
+ }
586
608
// write header
587
609
headbuf := make ([]byte , 32 )
588
610
fsize := uint32 (len (ptype )) + msg .Size
@@ -668,6 +690,26 @@ func (rw *rlpxFrameRW) ReadMsg() (msg Msg, err error) {
668
690
}
669
691
msg .Size = uint32 (content .Len ())
670
692
msg .Payload = content
693
+
694
+ // if snappy is enabled, verify and decompress message
695
+ if rw .snappy {
696
+ payload , err := ioutil .ReadAll (msg .Payload )
697
+ if err != nil {
698
+ return msg , err
699
+ }
700
+ size , err := snappy .DecodedLen (payload )
701
+ if err != nil {
702
+ return msg , err
703
+ }
704
+ if size > int (maxUint24 ) {
705
+ return msg , errPlainMessageTooLarge
706
+ }
707
+ payload , err = snappy .Decode (nil , payload )
708
+ if err != nil {
709
+ return msg , err
710
+ }
711
+ msg .Size , msg .Payload = uint32 (size ), bytes .NewReader (payload )
712
+ }
671
713
return msg , nil
672
714
}
673
715
0 commit comments