github.com/annchain/OG@v0.0.9/p2p/peer.go (about) 1 // Copyright 2014 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package p2p 18 19 import ( 20 "errors" 21 "fmt" 22 "github.com/annchain/OG/arefactor/common/goroutine" 23 "github.com/annchain/OG/p2p/enr" 24 "io" 25 "net" 26 "sort" 27 "sync" 28 "time" 29 30 "github.com/annchain/OG/common/mclock" 31 "github.com/annchain/OG/p2p/onode" 32 ) 33 34 var ( 35 ErrShuttingDown = errors.New("shutting down") 36 ) 37 38 const ( 39 baseProtocolVersion = 5 40 baseProtocolLength = MsgCodeType(16) 41 baseProtocolMaxMsgSize = 2 * 1024 42 43 snappyProtocolVersion = 5 44 45 pingInterval = 15 * time.Second 46 ) 47 48 const ( 49 // devp2p message codes 50 handshakeMsg = 0x00 51 discMsg = 0x01 52 pingMsg = 0x02 53 pongMsg = 0x03 54 ) 55 56 // PeerEventType is the type of peer events emitted by a p2p.Server 57 type PeerEventType string 58 59 const ( 60 // PeerEventTypeAdd is the type of event emitted when a peer is added 61 // to a p2p.Server 62 PeerEventTypeAdd PeerEventType = "add" 63 64 // PeerEventTypeDrop is the type of event emitted when a peer is 65 // dropped from a p2p.Server 66 PeerEventTypeDrop PeerEventType = "drop" 67 68 // PeerEventTypeMsgSend is the type of event emitted when a 69 // message is successfully sent to a peer 70 PeerEventTypeMsgSend PeerEventType = "msgsend" 71 72 // PeerEventTypeMsgRecv is the type of event emitted when a 73 // message is received from a peer 74 PeerEventTypeMsgRecv PeerEventType = "msgrecv" 75 ) 76 77 // PeerEvent is an event emitted when peers are either added or dropped from 78 // a p2p.Server or when a message is sent or received on a peer connection 79 type PeerEvent struct { 80 Type PeerEventType `json:"type"` 81 Peer onode.ID `json:"peer"` 82 Error string `json:"error,omitempty"` 83 Protocol string `json:"protocol,omitempty"` 84 MsgCode *uint64 `json:"msg_code,omitempty"` 85 MsgSize *uint32 `json:"msg_size,omitempty"` 86 } 87 88 // Sender represents a connected remote node. 89 type Peer struct { 90 rw *conn 91 running map[string]*protoRW 92 created mclock.AbsTime 93 94 wg sync.WaitGroup 95 protoErr chan error 96 closed chan struct{} 97 disc chan DiscReason 98 99 // events receives message send / receive events if set 100 //events *event.Feed 101 } 102 103 // NewPeer returns a peer for testing purposes. 104 func NewPeer(id onode.ID, name string, caps []Cap) *Peer { 105 pipe, _ := net.Pipe() 106 node := onode.SignNull(new(enr.Record), id) 107 108 conn := &conn{fd: pipe, transport: nil, node: node, caps: caps, name: name} 109 peer := newPeer(conn, nil) 110 close(peer.closed) // ensures Disconnect doesn't block 111 return peer 112 } 113 114 // ID returns the node's public key. 115 func (p *Peer) ID() onode.ID { 116 return p.rw.node.ID() 117 } 118 119 // Node returns the peer's node descriptor. 120 func (p *Peer) Node() *onode.Node { 121 return p.rw.node 122 } 123 124 // Name returns the node name that the remote node advertised. 125 func (p *Peer) Name() string { 126 return p.rw.name 127 } 128 129 // Caps returns the capabilities (supported subprotocols) of the remote peer. 130 func (p *Peer) Caps() []Cap { 131 // TODO: maybe return copy 132 return p.rw.caps 133 } 134 135 // RemoteAddr returns the remote address of the network connection. 136 func (p *Peer) RemoteAddr() net.Addr { 137 return p.rw.fd.RemoteAddr() 138 } 139 140 // LocalAddr returns the local address of the network connection. 141 func (p *Peer) LocalAddr() net.Addr { 142 return p.rw.fd.LocalAddr() 143 } 144 145 // Disconnect terminates the peer connection with the given reason. 146 // It returns immediately and does not wait until the connection is closed. 147 func (p *Peer) Disconnect(reason DiscReason) { 148 select { 149 case p.disc <- reason: 150 case <-p.closed: 151 } 152 } 153 154 // String implements fmt.Stringer. 155 func (p *Peer) String() string { 156 id := p.ID() 157 return fmt.Sprintf("Sender %x %v", id[:8], p.RemoteAddr()) 158 } 159 160 // Inbound returns true if the peer is an inbound connection 161 func (p *Peer) Inbound() bool { 162 return p.rw.is(inboundConn) 163 } 164 165 func newPeer(conn *conn, protocols []Protocol) *Peer { 166 protomap := matchProtocols(protocols, conn.caps, conn) 167 p := &Peer{ 168 rw: conn, 169 running: protomap, 170 created: mclock.Now(), 171 disc: make(chan DiscReason), 172 protoErr: make(chan error, len(protomap)+1), // protocols + pingLoop 173 closed: make(chan struct{}), 174 } 175 return p 176 } 177 178 func (p *Peer) run() (remoteRequested bool, err error) { 179 var ( 180 writeStart = make(chan struct{}, 1) 181 writeErr = make(chan error, 1) 182 readErr = make(chan error, 1) 183 reason DiscReason // sent to the peer 184 ) 185 p.wg.Add(2) 186 readFunction := func() { p.readLoop(readErr) } 187 goroutine.New(readFunction) 188 goroutine.New(p.pingLoop) 189 190 // Start all protocol handlers. 191 writeStart <- struct{}{} 192 p.startProtocols(writeStart, writeErr) 193 194 // Wait for an error or disconnect. 195 loop: 196 for { 197 select { 198 case err = <-writeErr: 199 // A write finished. Allow the next write to start if 200 // there was no error. 201 if err != nil { 202 reason = DiscNetworkError 203 break loop 204 } 205 writeStart <- struct{}{} 206 case err = <-readErr: 207 if r, ok := err.(DiscReason); ok { 208 remoteRequested = true 209 reason = r 210 } else { 211 reason = DiscNetworkError 212 } 213 break loop 214 case err = <-p.protoErr: 215 reason = discReasonForError(err) 216 break loop 217 case err = <-p.disc: 218 reason = discReasonForError(err) 219 break loop 220 } 221 } 222 log.WithField("id ", p.ID().TerminalString()).Debug("reason ", reason, remoteRequested, err) 223 close(p.closed) 224 p.rw.close(reason) 225 p.wg.Wait() 226 return remoteRequested, err 227 } 228 229 func (p *Peer) pingLoop() { 230 ping := time.NewTimer(pingInterval) 231 defer p.wg.Done() 232 defer ping.Stop() 233 for { 234 select { 235 case <-ping.C: 236 if err := Send(p.rw, pingMsg, nil); err != nil { 237 p.protoErr <- err 238 return 239 } 240 ping.Reset(pingInterval) 241 case <-p.closed: 242 return 243 } 244 } 245 } 246 247 func (p *Peer) readLoop(errc chan<- error) { 248 defer p.wg.Done() 249 for { 250 msg, err := p.rw.ReadMsg() 251 if err != nil { 252 errc <- err 253 return 254 } 255 msg.ReceivedAt = time.Now() 256 if err = p.handle(msg); err != nil { 257 errc <- err 258 return 259 } 260 } 261 } 262 263 func (p *Peer) handle(msg Msg) error { 264 switch { 265 case msg.Code == pingMsg: 266 msg.Discard() 267 sendFunc := func() { Send(p.rw, pongMsg, nil) } 268 goroutine.New(sendFunc) 269 case msg.Code == discMsg: 270 var reason DiscReason 271 // This is the last message. We don't need to discard or 272 // check errors because, the connection will be closed after it. 273 //rlp.Decode(msg.Payload, &reason) 274 data, _ := msg.GetPayLoad() 275 reason.UnmarshalMsg(data) 276 return reason 277 case msg.Code < baseProtocolLength: 278 // ignore other base protocol messages 279 return msg.Discard() 280 default: 281 // it's a subprotocol message 282 proto, err := p.getProto(msg.Code) 283 if err != nil { 284 return fmt.Errorf("msg code out of range: %v", msg.Code) 285 } 286 select { 287 case proto.in <- msg: 288 return nil 289 case <-p.closed: 290 return io.EOF 291 } 292 } 293 return nil 294 } 295 296 func countMatchingProtocols(protocols []Protocol, caps []Cap) int { 297 n := 0 298 for _, cap := range caps { 299 for _, proto := range protocols { 300 if proto.Name == cap.Name && proto.Version == cap.Version { 301 n++ 302 } 303 } 304 } 305 return n 306 } 307 308 // matchProtocols creates structures for matching named subprotocols. 309 func matchProtocols(protocols []Protocol, caps []Cap, rw MsgReadWriter) map[string]*protoRW { 310 sort.Sort(CapsByNameAndVersion(caps)) 311 offset := baseProtocolLength 312 result := make(map[string]*protoRW) 313 314 outer: 315 for _, cap := range caps { 316 for _, proto := range protocols { 317 if proto.Name == cap.Name && proto.Version == cap.Version { 318 // If an old protocol version matched, revert it 319 if old := result[cap.Name]; old != nil { 320 offset -= old.Length 321 } 322 // Assign the new match 323 result[cap.Name] = &protoRW{Protocol: proto, offset: offset, in: make(chan Msg), w: rw} 324 offset += proto.Length 325 326 continue outer 327 } 328 } 329 } 330 return result 331 } 332 333 func (p *Peer) startProtocols(writeStart <-chan struct{}, writeErr chan<- error) { 334 p.wg.Add(len(p.running)) 335 for _, proto := range p.running { 336 proto := proto 337 proto.closed = p.closed 338 proto.wstart = writeStart 339 proto.werr = writeErr 340 var rw MsgReadWriter = proto 341 /* 342 if p.events != nil { 343 rw = newMsgEventer(rw, p.events, p.ID(), proto.Name) 344 } 345 */ 346 log.Trace(fmt.Sprintf("Starting protocol %s/%d", proto.Name, proto.Version)) 347 runFunc := func() { 348 err := proto.Run(p, rw) 349 if err == nil { 350 log.Trace(fmt.Sprintf("Protocol %s/%d returned", proto.Name, proto.Version)) 351 err = errProtocolReturned 352 } else if err != io.EOF { 353 log.Debug(fmt.Sprintf("Protocol %s/%d failed", proto.Name, proto.Version), "err", err) 354 } 355 p.protoErr <- err 356 p.wg.Done() 357 } 358 goroutine.New(runFunc) 359 } 360 } 361 362 // getProto finds the protocol responsible for handling 363 // the given message code. 364 func (p *Peer) getProto(code MsgCodeType) (*protoRW, error) { 365 for _, proto := range p.running { 366 if code >= proto.offset && code < proto.offset+proto.Length { 367 return proto, nil 368 } 369 } 370 return nil, newPeerError(errInvalidMsgCode, "%d", code) 371 } 372 373 type protoRW struct { 374 Protocol 375 in chan Msg // receives read messages 376 closed <-chan struct{} // receives when peer is shutting down 377 wstart <-chan struct{} // receives when write may start 378 werr chan<- error // for write results 379 offset MsgCodeType 380 w MsgWriter 381 } 382 383 func (rw *protoRW) WriteMsg(msg Msg) (err error) { 384 if msg.Code >= rw.Length { 385 return newPeerError(errInvalidMsgCode, "not handled") 386 } 387 msg.Code += rw.offset 388 select { 389 case <-rw.wstart: 390 err = rw.w.WriteMsg(msg) 391 // Report write status back to Sender.run. It will initiate 392 // shutdown if the error is non-nil and unblock the next write 393 // otherwise. The calling protocol code should exit for errors 394 // as well but we don't want to rely on that. 395 rw.werr <- err 396 case <-rw.closed: 397 err = ErrShuttingDown 398 } 399 return err 400 } 401 402 func (rw *protoRW) ReadMsg() (Msg, error) { 403 select { 404 case msg := <-rw.in: 405 msg.Code -= rw.offset 406 return msg, nil 407 case <-rw.closed: 408 return Msg{}, io.EOF 409 } 410 } 411 412 // PeerInfo represents a short summary of the information known about a connected 413 // peer. Sub-protocol independent fields are contained and initialized here, with 414 // protocol specifics delegated to all connected sub-protocols. 415 type PeerInfo struct { 416 Onode string `json:"onode"` //node url 417 ID string `json:"id"` // Unique node identifier (also the encryption key) 418 ShortId string `json:"short_id"` 419 Name string `json:"name"` // Name of the node, including client type, version, OS, custom data 420 Caps []string `json:"caps"` // Sum-protocols advertised by this particular peer 421 Network struct { 422 LocalAddress string `json:"localAddress"` // Local endpoint of the TCP data connection 423 RemoteAddress string `json:"remoteAddress"` // Remote endpoint of the TCP data connection 424 Inbound bool `json:"inbound"` 425 Trusted bool `json:"trusted"` 426 Static bool `json:"static"` 427 } `json:"network"` 428 Protocols map[string]interface{} `json:"protocols"` // Sub-protocol specific metadata fields 429 } 430 431 // Info gathers and returns a collection of metadata known about a peer. 432 func (p *Peer) Info() *PeerInfo { 433 // Gather the protocol capabilities 434 var caps []string 435 for _, cap := range p.Caps() { 436 caps = append(caps, cap.String()) 437 } 438 // Assemble the generic peer metadata 439 info := &PeerInfo{ 440 Onode: p.Node().String(), 441 ID: p.ID().String(), 442 ShortId: p.ID().TerminalString(), 443 Name: p.Name(), 444 Caps: caps, 445 Protocols: make(map[string]interface{}), 446 } 447 info.Network.LocalAddress = p.LocalAddr().String() 448 info.Network.RemoteAddress = p.RemoteAddr().String() 449 info.Network.Inbound = p.rw.is(inboundConn) 450 info.Network.Trusted = p.rw.is(trustedConn) 451 info.Network.Static = p.rw.is(staticDialedConn) 452 453 // Gather all the running protocol infos 454 for _, proto := range p.running { 455 protoInfo := interface{}("unknown") 456 if query := proto.Protocol.PeerInfo; query != nil { 457 if metadata := query(p.ID()); metadata != nil { 458 protoInfo = metadata 459 } else { 460 protoInfo = "handshake" 461 } 462 } 463 info.Protocols[proto.Name] = protoInfo 464 } 465 return info 466 }