github.com/decred/dcrlnd@v0.7.6/watchtower/wtwire/message.go (about) 1 package wtwire 2 3 import ( 4 "bytes" 5 "encoding/binary" 6 "fmt" 7 "io" 8 ) 9 10 // MaxMessagePayload is the maximum bytes a message can be regardless of other 11 // individual limits imposed by messages themselves. 12 const MaxMessagePayload = 65535 // 65KB 13 14 // MessageType is the unique 2 byte big-endian integer that indicates the type 15 // of message on the wire. All messages have a very simple header which 16 // consists simply of 2-byte message type. We omit a length field, and checksum 17 // as the Watchtower Protocol is intended to be encapsulated within a 18 // confidential+authenticated cryptographic messaging protocol. 19 type MessageType uint16 20 21 // The currently defined message types within this current version of the 22 // Watchtower protocol. 23 const ( 24 // MsgInit identifies an encoded Init message. 25 MsgInit MessageType = 600 26 27 // MsgError identifies an encoded Error message. 28 MsgError MessageType = 601 29 30 // MsgCreateSession identifies an encoded CreateSession message. 31 MsgCreateSession MessageType = 602 32 33 // MsgCreateSessionReply identifies an encoded CreateSessionReply message. 34 MsgCreateSessionReply MessageType = 603 35 36 // MsgStateUpdate identifies an encoded StateUpdate message. 37 MsgStateUpdate MessageType = 604 38 39 // MsgStateUpdateReply identifies an encoded StateUpdateReply message. 40 MsgStateUpdateReply MessageType = 605 41 42 // MsgDeleteSession identifies an encoded DeleteSession message. 43 MsgDeleteSession MessageType = 606 44 45 // MsgDeleteSessionReply identifies an encoded DeleteSessionReply 46 // message. 47 MsgDeleteSessionReply MessageType = 607 48 ) 49 50 // String returns a human readable description of the message type. 51 func (m MessageType) String() string { 52 switch m { 53 case MsgInit: 54 return "Init" 55 case MsgCreateSession: 56 return "MsgCreateSession" 57 case MsgCreateSessionReply: 58 return "MsgCreateSessionReply" 59 case MsgStateUpdate: 60 return "MsgStateUpdate" 61 case MsgStateUpdateReply: 62 return "MsgStateUpdateReply" 63 case MsgDeleteSession: 64 return "MsgDeleteSession" 65 case MsgDeleteSessionReply: 66 return "MsgDeleteSessionReply" 67 case MsgError: 68 return "Error" 69 default: 70 return "<unknown>" 71 } 72 } 73 74 // Serializable is an interface which defines a lightning wire serializable 75 // object. 76 type Serializable interface { 77 // Decode reads the bytes stream and converts it to the object. 78 Decode(io.Reader, uint32) error 79 80 // Encode converts object to the bytes stream and write it into the 81 // write buffer. 82 Encode(io.Writer, uint32) error 83 } 84 85 // Message is an interface that defines a lightning wire protocol message. The 86 // interface is general in order to allow implementing types full control over 87 // the representation of its data. 88 type Message interface { 89 Serializable 90 91 // MsgType returns a MessageType that uniquely identifies the message to 92 // be encoded. 93 MsgType() MessageType 94 95 // MaxMessagePayload is the maximum serialized length that a particular 96 // message type can take. 97 MaxPayloadLength(uint32) uint32 98 } 99 100 // makeEmptyMessage creates a new empty message of the proper concrete type 101 // based on the passed message type. 102 func makeEmptyMessage(msgType MessageType) (Message, error) { 103 var msg Message 104 105 switch msgType { 106 case MsgInit: 107 msg = &Init{} 108 case MsgCreateSession: 109 msg = &CreateSession{} 110 case MsgCreateSessionReply: 111 msg = &CreateSessionReply{} 112 case MsgStateUpdate: 113 msg = &StateUpdate{} 114 case MsgStateUpdateReply: 115 msg = &StateUpdateReply{} 116 case MsgDeleteSession: 117 msg = &DeleteSession{} 118 case MsgDeleteSessionReply: 119 msg = &DeleteSessionReply{} 120 case MsgError: 121 msg = &Error{} 122 default: 123 return nil, fmt.Errorf("unknown message type [%d]", msgType) 124 } 125 126 return msg, nil 127 } 128 129 // WriteMessage writes a lightning Message to w including the necessary header 130 // information and returns the number of bytes written. 131 func WriteMessage(w io.Writer, msg Message, pver uint32) (int, error) { 132 totalBytes := 0 133 134 // Encode the message payload itself into a temporary buffer. 135 // TODO(roasbeef): create buffer pool 136 var bw bytes.Buffer 137 if err := msg.Encode(&bw, pver); err != nil { 138 return totalBytes, err 139 } 140 payload := bw.Bytes() 141 lenp := len(payload) 142 143 // Enforce maximum overall message payload. 144 if lenp > MaxMessagePayload { 145 return totalBytes, fmt.Errorf("message payload is too large - "+ 146 "encoded %d bytes, but maximum message payload is %d bytes", 147 lenp, MaxMessagePayload) 148 } 149 150 // Enforce maximum message payload on the message type. 151 mpl := msg.MaxPayloadLength(pver) 152 if uint32(lenp) > mpl { 153 return totalBytes, fmt.Errorf("message payload is too large - "+ 154 "encoded %d bytes, but maximum message payload of "+ 155 "type %v is %d bytes", lenp, msg.MsgType(), mpl) 156 } 157 158 // With the initial sanity checks complete, we'll now write out the 159 // message type itself. 160 var mType [2]byte 161 binary.BigEndian.PutUint16(mType[:], uint16(msg.MsgType())) 162 n, err := w.Write(mType[:]) 163 totalBytes += n 164 if err != nil { 165 return totalBytes, err 166 } 167 168 // With the message type written, we'll now write out the raw payload 169 // itself. 170 n, err = w.Write(payload) 171 totalBytes += n 172 173 return totalBytes, err 174 } 175 176 // ReadMessage reads, validates, and parses the next Watchtower message from r 177 // for the provided protocol version. 178 func ReadMessage(r io.Reader, pver uint32) (Message, error) { 179 // First, we'll read out the first two bytes of the message so we can 180 // create the proper empty message. 181 var mType [2]byte 182 if _, err := io.ReadFull(r, mType[:]); err != nil { 183 return nil, err 184 } 185 186 msgType := MessageType(binary.BigEndian.Uint16(mType[:])) 187 188 // Now that we know the target message type, we can create the proper 189 // empty message type and decode the message into it. 190 msg, err := makeEmptyMessage(msgType) 191 if err != nil { 192 return nil, err 193 } 194 if err := msg.Decode(r, pver); err != nil { 195 return nil, err 196 } 197 198 return msg, nil 199 }