forked from aergoio/aergo
/
handshake.go
112 lines (95 loc) · 3.27 KB
/
handshake.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
/*
* @file
* @copyright defined in aergo/LICENSE.txt
*/
//go:generate mockgen -source=handshake.go -package=p2pmock -destination=../p2pmock/mock_handshake.go
package p2pcommon
import (
"context"
"encoding/binary"
"github.com/aergoio/aergo/types"
"io"
"time"
)
type HandshakeResult struct {
MsgRW MsgReadWriter
Meta PeerMeta
BestBlockHash types.BlockID
BestBlockNo types.BlockNo
Hidden bool
Certificates []*AgentCertificateV1
}
// HSHandlerFactory is creator of HSHandler
type HSHandlerFactory interface {
CreateHSHandler(outbound bool, pid types.PeerID) HSHandler
}
// HSHandler handles whole process of connect, handshake, create of remote Peer
type HSHandler interface {
// Handle peer handshake till ttl, and return msgrw for this connection, and status of remote peer.
Handle(s io.ReadWriteCloser, ttl time.Duration) (*HandshakeResult, error)
}
type VersionedManager interface {
FindBestP2PVersion(versions []P2PVersion) P2PVersion
GetVersionedHandshaker(version P2PVersion, peerID types.PeerID, rwc io.ReadWriteCloser) (VersionedHandshaker, error)
GetBestChainID() *types.ChainID
GetChainID(no types.BlockNo) *types.ChainID
}
// VersionedHandshaker do handshake related to chain, and return msgreadwriter for a protocol version.
// It is used inside HSHandler
type VersionedHandshaker interface {
DoForOutbound(ctx context.Context) (*HandshakeResult, error)
DoForInbound(ctx context.Context) (*HandshakeResult, error)
GetMsgRW() MsgReadWriter
}
// HSHeader is legacy type of data which peer send first to listening peer in wire handshake
type HSHeader struct {
Magic uint32
Version P2PVersion
}
func (h HSHeader) Marshal() []byte {
b := make([]byte, V030HSHeaderLength)
binary.BigEndian.PutUint32(b, h.Magic)
binary.BigEndian.PutUint32(b[4:], uint32(h.Version))
return b
}
func (h *HSHeader) Unmarshal(b []byte) {
h.Magic = binary.BigEndian.Uint32(b)
h.Version = P2PVersion(binary.BigEndian.Uint32(b[4:]))
}
// HSHeadReq is data which peer send first to listening peer in wire handshake
type HSHeadReq struct {
Magic uint32
// Versions are p2p versions which the connecting peer can support.
Versions []P2PVersion
}
func (h HSHeadReq) Marshal() []byte {
verCount := len(h.Versions)
b := make([]byte, HSMagicLength+HSVerCntLength+HSVersionLength*verCount)
offset := 0
binary.BigEndian.PutUint32(b[offset:], h.Magic)
offset += HSMagicLength
binary.BigEndian.PutUint32(b[offset:], uint32(verCount))
offset += HSVerCntLength
for _, version := range h.Versions {
binary.BigEndian.PutUint32(b[offset:], version.Uint32())
offset += HSVersionLength
}
return b
}
// HSHeadResp is data which listening peer send back to connecting peer as response
type HSHeadResp struct {
// Magic will be same as the magic in HSHeadReq if wire handshake is successful, or 0 if not.
Magic uint32
// RespCode is different meaning by value of Magic. It is p2p version which listening peer will use, if wire handshake is successful, or errCode otherwise.
RespCode uint32
}
func (h HSHeadResp) Marshal() []byte {
b := make([]byte, V030HSHeaderLength)
binary.BigEndian.PutUint32(b, h.Magic)
binary.BigEndian.PutUint32(b[4:], h.RespCode)
return b
}
func (h *HSHeadResp) Unmarshal(b []byte) {
h.Magic = binary.BigEndian.Uint32(b)
h.RespCode = binary.BigEndian.Uint32(b[4:])
}