github.com/turingchain2020/turingchain@v1.1.21/system/p2p/dht/protocol/wrapper.go (about) 1 package protocol 2 3 import ( 4 "bytes" 5 "fmt" 6 "math/rand" 7 "runtime" 8 "time" 9 10 "github.com/libp2p/go-libp2p-core/helpers" 11 12 "github.com/turingchain2020/turingchain/common/log/log15" 13 "github.com/turingchain2020/turingchain/queue" 14 types2 "github.com/turingchain2020/turingchain/system/p2p/dht/types" 15 "github.com/turingchain2020/turingchain/types" 16 "github.com/libp2p/go-libp2p-core/crypto" 17 "github.com/libp2p/go-libp2p-core/network" 18 protobufCodec "github.com/multiformats/go-multicodec/protobuf" 19 ) 20 21 var log = log15.New("module", "p2p.protocol") 22 23 func init() { 24 rand.Seed(time.Now().UnixNano()) 25 } 26 27 // ReadStream reads message from stream. 28 func ReadStream(data types.Message, stream network.Stream) error { 29 decoder := protobufCodec.Multicodec(nil).Decoder(stream) 30 err := decoder.Decode(data) 31 if err != nil { 32 log.Error("ReadStream", "pid", stream.Conn().RemotePeer().Pretty(), "protocolID", stream.Protocol(), "decode err", err) 33 return err 34 } 35 return nil 36 } 37 38 // WriteStream writes message to stream. 39 func WriteStream(data types.Message, stream network.Stream) error { 40 enc := protobufCodec.Multicodec(nil).Encoder(stream) 41 err := enc.Encode(data) 42 if err != nil { 43 log.Error("WriteStream", "pid", stream.Conn().RemotePeer().Pretty(), "protocolID", stream.Protocol(), "encode err", err) 44 return err 45 } 46 return nil 47 } 48 49 // CloseStream closes the stream after writing, and waits for the EOF. 50 func CloseStream(stream network.Stream) { 51 if stream == nil { 52 return 53 } 54 go func() { 55 err := helpers.FullClose(stream) 56 if err != nil { 57 //just log it because it dose not matter 58 log.Debug("CloseStream", "err", err, "protocol ID", stream.Protocol()) 59 } 60 }() 61 } 62 63 // AuthenticateMessage authenticates p2p message. 64 func AuthenticateMessage(message types.Message, stream network.Stream) bool { 65 var sign, bin []byte 66 // store a temp ref to signature and remove it from message data 67 // sign is a string to allow easy reset to zero-value (empty string) 68 switch t := message.(type) { 69 case *types.P2PRequest: 70 sign = t.Headers.Sign 71 t.Headers.Sign = nil 72 // marshall data without the signature to protobuf3 binary format 73 bin = types.Encode(t) 74 // restore sig in message data (for possible future use) 75 t.Headers.Sign = sign 76 case *types.P2PResponse: 77 sign = t.Headers.Sign 78 t.Headers.Sign = nil 79 // marshall data without the signature to protobuf3 binary format 80 bin = types.Encode(t) 81 // restore sig in message data (for possible future use) 82 t.Headers.Sign = sign 83 default: 84 return false 85 } 86 87 // verify the data was authored by the signing peer identified by the public key 88 // and signature included in the message 89 return verifyData(bin, sign, stream.Conn().RemotePublicKey()) 90 } 91 92 // Verify incoming p2p message data integrity 93 // data: data to verify 94 // signature: author signature provided in the message payload 95 // pubKey: public key of remote peer 96 func verifyData(data []byte, signature []byte, pubKey crypto.PubKey) bool { 97 res, err := pubKey.Verify(data, signature) 98 if err != nil { 99 log.Error("Error authenticating data", "err", err) 100 return false 101 } 102 103 return res 104 } 105 106 // ReadStreamAndAuthenticate verifies the message after reading it from the stream. 107 func ReadStreamAndAuthenticate(message types.Message, stream network.Stream) error { 108 if err := ReadStream(message, stream); err != nil { 109 return err 110 } 111 if !AuthenticateMessage(message, stream) { 112 return types2.ErrWrongSignature 113 } 114 115 return nil 116 } 117 118 // signProtoMessage signs an outgoing p2p message payload. 119 func signProtoMessage(message types.Message, stream network.Stream) ([]byte, error) { 120 privKey := stream.Conn().LocalPrivateKey() 121 return privKey.Sign(types.Encode(message)) 122 } 123 124 // SignAndWriteStream signs the message before writing it to the stream. 125 func SignAndWriteStream(message types.Message, stream network.Stream) error { 126 switch t := message.(type) { 127 case *types.P2PRequest: 128 t.Headers = &types.P2PMessageHeaders{ 129 Version: types2.Version, 130 Timestamp: time.Now().Unix(), 131 Id: rand.Int63(), 132 } 133 sign, err := signProtoMessage(t, stream) 134 if err != nil { 135 return err 136 } 137 t.Headers.Sign = sign 138 case *types.P2PResponse: 139 t.Headers = &types.P2PMessageHeaders{ 140 Version: types2.Version, 141 Timestamp: time.Now().Unix(), 142 Id: rand.Int63(), 143 } 144 sign, err := signProtoMessage(t, stream) 145 if err != nil { 146 return err 147 } 148 t.Headers.Sign = sign 149 default: 150 log.Error("SignAndWriteStream wrong message type") 151 return types2.ErrInvalidMessageType 152 } 153 return WriteStream(message, stream) 154 } 155 156 // HandlerWithClose wraps handler with closing stream and recovering from panic. 157 func HandlerWithClose(f network.StreamHandler) network.StreamHandler { 158 return func(stream network.Stream) { 159 defer func() { 160 if r := recover(); r != nil { 161 log.Error("handle stream", "panic error", r) 162 fmt.Println(string(panicTrace(4))) 163 _ = stream.Reset() 164 } 165 }() 166 f(stream) 167 CloseStream(stream) 168 } 169 } 170 171 // HandlerWithWrite wraps handler with writing, closing stream and recovering from panic. 172 func HandlerWithWrite(f func(resp *types.P2PResponse) error) network.StreamHandler { 173 return func(stream network.Stream) { 174 var res types.P2PResponse 175 err := f(&res) 176 if err != nil { 177 res.Response = nil 178 res.Error = err.Error() 179 } 180 res.Headers = &types.P2PMessageHeaders{ 181 Version: types2.Version, 182 Timestamp: time.Now().Unix(), 183 Id: rand.Int63(), 184 } 185 if err := WriteStream(&res, stream); err != nil { 186 log.Error("HandlerWithWrite", "write stream error", err) 187 return 188 } 189 } 190 } 191 192 // HandlerWithRead wraps handler with reading, closing stream and recovering from panic. 193 func HandlerWithRead(f func(request *types.P2PRequest)) network.StreamHandler { 194 return func(stream network.Stream) { 195 var req types.P2PRequest 196 if err := ReadStream(&req, stream); err != nil { 197 log.Error("HandlerWithRead", "read stream error", err) 198 return 199 } 200 f(&req) 201 } 202 } 203 204 // HandlerWithAuth wraps HandlerWithRead with authenticating. 205 func HandlerWithAuth(f func(request *types.P2PRequest)) network.StreamHandler { 206 return func(stream network.Stream) { 207 var req types.P2PRequest 208 if err := ReadStream(&req, stream); err != nil { 209 log.Error("HandlerWithAuthAndSign", "read stream error", err) 210 return 211 } 212 if !AuthenticateMessage(&req, stream) { 213 return 214 } 215 f(&req) 216 } 217 } 218 219 // HandlerWithRW wraps handler with reading, writing, closing stream and recovering from panic. 220 func HandlerWithRW(f func(request *types.P2PRequest, response *types.P2PResponse) error) network.StreamHandler { 221 return func(stream network.Stream) { 222 var req types.P2PRequest 223 if err := ReadStream(&req, stream); err != nil { 224 log.Error("HandlerWithRW", "read stream error", err) 225 return 226 } 227 var res types.P2PResponse 228 err := f(&req, &res) 229 if err != nil { 230 res.Response = nil 231 res.Error = err.Error() 232 } 233 res.Headers = &types.P2PMessageHeaders{ 234 Version: types2.Version, 235 Timestamp: time.Now().Unix(), 236 Id: rand.Int63(), 237 } 238 if err := WriteStream(&res, stream); err != nil { 239 log.Error("HandlerWithAuthAndSign", "write stream error", err) 240 return 241 } 242 } 243 } 244 245 // HandlerWithAuthAndSign wraps HandlerWithRW with signing and authenticating. 246 func HandlerWithAuthAndSign(f func(request *types.P2PRequest, response *types.P2PResponse) error) network.StreamHandler { 247 return func(stream network.Stream) { 248 var req types.P2PRequest 249 if err := ReadStream(&req, stream); err != nil { 250 log.Error("HandlerWithAuthAndSign", "read stream error", err) 251 return 252 } 253 if !AuthenticateMessage(&req, stream) { 254 return 255 } 256 var res types.P2PResponse 257 err := f(&req, &res) 258 if err != nil { 259 res.Response = nil 260 res.Error = err.Error() 261 } 262 res.Headers = &types.P2PMessageHeaders{ 263 Version: types2.Version, 264 Timestamp: time.Now().Unix(), 265 Id: rand.Int63(), 266 } 267 sign, err := signProtoMessage(&res, stream) 268 if err != nil { 269 log.Error("HandlerWithAuthAndSign", "signProtoMessage error", err) 270 return 271 } 272 res.Headers.Sign = sign 273 if err := WriteStream(&res, stream); err != nil { 274 log.Error("HandlerWithAuthAndSign", "write stream error", err) 275 return 276 } 277 } 278 } 279 280 //TODO 281 // Any developer can define his own stream handler wrapper. 282 283 // EventHandlerWithRecover warps the event handler with recover for catching the panic while processing message. 284 func EventHandlerWithRecover(f func(m *queue.Message)) func(m *queue.Message) { 285 return func(m *queue.Message) { 286 defer func() { 287 if r := recover(); r != nil { 288 log.Error("handle event", "panic error", r) 289 fmt.Println(string(panicTrace(4))) 290 } 291 }() 292 f(m) 293 } 294 } 295 296 //TODO 297 // Any developer can define his own event handler wrapper. 298 299 // panicTrace traces panic stack info. 300 func panicTrace(kb int) []byte { 301 s := []byte("/src/runtime/panic.go") 302 e := []byte("\ngoroutine ") 303 line := []byte("\n") 304 stack := make([]byte, kb<<10) //4KB 305 length := runtime.Stack(stack, true) 306 start := bytes.Index(stack, s) 307 stack = stack[start:length] 308 start = bytes.Index(stack, line) + 1 309 stack = stack[start:] 310 end := bytes.LastIndex(stack, line) 311 if end != -1 { 312 stack = stack[:end] 313 } 314 end = bytes.Index(stack, e) 315 if end != -1 { 316 stack = stack[:end] 317 } 318 stack = bytes.TrimRight(stack, "\n") 319 return stack 320 }