mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-22 04:36:42 +00:00
write via proto.out channel
- read/write timeout constants moved to messenger - add writeLoop (temporarily a method on Peer) that feeds on a channel and writes to bufconn - add outgoing message channel to proto readwriter - outgoing message channel is a field of Peer and shared between protocols (no need to lock) - setting write timeout per message is no longer possible! - read and write loops share error channel. both watched by the dispatch loop in peer
This commit is contained in:
parent
1853903fc0
commit
7a33109e85
3 changed files with 51 additions and 32 deletions
|
|
@ -12,6 +12,16 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// maximum amount of time allowed for reading a message
|
||||||
|
msgReadTimeout = 5 * time.Second
|
||||||
|
// maximum amount of time allowed for writing a message
|
||||||
|
msgWriteTimeout = 5 * time.Second
|
||||||
|
// messages smaller than this many bytes will be read at
|
||||||
|
// once before passing them to a protocol.
|
||||||
|
wholePayloadSize = 64 * 1024
|
||||||
|
)
|
||||||
|
|
||||||
var magicToken = []byte{34, 64, 8, 145}
|
var magicToken = []byte{34, 64, 8, 145}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -37,6 +47,16 @@ func (p *Peer) readLoop(msgc chan<- Msg, errc chan<- error, unblock <-chan bool)
|
||||||
close(errc)
|
close(errc)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *Peer) writeLoop(msgc <-chan Msg, errc chan<- error) {
|
||||||
|
p.conn.SetWriteDeadline(time.Now().Add(msgWriteTimeout))
|
||||||
|
for msg := range msgc {
|
||||||
|
if err := writeMsg(p.bufconn, msg); err != nil {
|
||||||
|
errc <- newPeerError(errWrite, "%v", err)
|
||||||
|
}
|
||||||
|
p.bufconn.Flush()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func writeMsg(w io.Writer, msg Msg) error {
|
func writeMsg(w io.Writer, msg Msg) error {
|
||||||
// TODO: handle case when Size + len(code) + len(listhdr) overflows uint32
|
// TODO: handle case when Size + len(code) + len(listhdr) overflows uint32
|
||||||
code := ethutil.Encode(uint32(msg.Code))
|
code := ethutil.Encode(uint32(msg.Code))
|
||||||
|
|
@ -151,9 +171,8 @@ func (p *Peer) writeMsg(msg Msg, timeout time.Duration) error {
|
||||||
// no need to go through peer for writing , so do not need to embed peer as field
|
// no need to go through peer for writing , so do not need to embed peer as field
|
||||||
type proto struct {
|
type proto struct {
|
||||||
name string
|
name string
|
||||||
in chan Msg
|
in, out chan Msg
|
||||||
maxcode, offset uint64
|
maxcode, offset uint64
|
||||||
peer *Peer
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rw *proto) WriteMsg(msg Msg) error {
|
func (rw *proto) WriteMsg(msg Msg) error {
|
||||||
|
|
@ -161,7 +180,12 @@ func (rw *proto) WriteMsg(msg Msg) error {
|
||||||
return newPeerError(errInvalidMsgCode, "not handled")
|
return newPeerError(errInvalidMsgCode, "not handled")
|
||||||
}
|
}
|
||||||
msg.Code += rw.offset
|
msg.Code += rw.offset
|
||||||
return rw.peer.writeMsg(msg, msgWriteTimeout)
|
select {
|
||||||
|
case rw.out <- msg:
|
||||||
|
return nil
|
||||||
|
case <-time.After(msgWriteTimeout):
|
||||||
|
return newPeerError(errWrite, "messenger timeout")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rw *proto) EncodeMsg(code uint64, data ...interface{}) error {
|
func (rw *proto) EncodeMsg(code uint64, data ...interface{}) error {
|
||||||
|
|
|
||||||
26
p2p/peer.go
26
p2p/peer.go
|
|
@ -67,6 +67,7 @@ type Peer struct {
|
||||||
writeMu sync.Mutex
|
writeMu sync.Mutex
|
||||||
conn net.Conn
|
conn net.Conn
|
||||||
bufconn *bufio.ReadWriter
|
bufconn *bufio.ReadWriter
|
||||||
|
outgoingMsgC chan Msg
|
||||||
|
|
||||||
// These fields maintain the running protocols.
|
// These fields maintain the running protocols.
|
||||||
protocols []Protocol
|
protocols []Protocol
|
||||||
|
|
@ -132,6 +133,7 @@ func newPeer(conn net.Conn, protocols []Protocol, dialAddr *peerAddr) *Peer {
|
||||||
protoErr: make(chan error),
|
protoErr: make(chan error),
|
||||||
closed: make(chan struct{}),
|
closed: make(chan struct{}),
|
||||||
cryptoReady: make(chan struct{}),
|
cryptoReady: make(chan struct{}),
|
||||||
|
outgoingMsgC: make(chan Msg),
|
||||||
}
|
}
|
||||||
return p
|
return p
|
||||||
}
|
}
|
||||||
|
|
@ -204,16 +206,6 @@ func (p *Peer) String() string {
|
||||||
return fmt.Sprintf("Peer(%p %v %s)", p, p.conn.RemoteAddr(), kind)
|
return fmt.Sprintf("Peer(%p %v %s)", p, p.conn.RemoteAddr(), kind)
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
|
||||||
// maximum amount of time allowed for reading a message
|
|
||||||
msgReadTimeout = 5 * time.Second
|
|
||||||
// maximum amount of time allowed for writing a message
|
|
||||||
msgWriteTimeout = 5 * time.Second
|
|
||||||
// messages smaller than this many bytes will be read at
|
|
||||||
// once before passing them to a protocol.
|
|
||||||
wholePayloadSize = 64 * 1024
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
inactivityTimeout = 2 * time.Second
|
inactivityTimeout = 2 * time.Second
|
||||||
disconnectGracePeriod = 2 * time.Second
|
disconnectGracePeriod = 2 * time.Second
|
||||||
|
|
@ -237,10 +229,11 @@ func (p *Peer) loop() (reason DiscReason, err error) {
|
||||||
|
|
||||||
// read loop
|
// read loop
|
||||||
readMsg := make(chan Msg)
|
readMsg := make(chan Msg)
|
||||||
readErr := make(chan error)
|
rwErr := make(chan error)
|
||||||
readNext := make(chan bool, 1)
|
readNext := make(chan bool, 1)
|
||||||
protoDone := make(chan struct{}, 1)
|
protoDone := make(chan struct{}, 1)
|
||||||
go readLoop(readMsg, readErr, readNext)
|
go readLoop(readMsg, rwErr, readNext)
|
||||||
|
go p.writeLoop(p.outgoingMsgC, rwErr)
|
||||||
readNext <- true
|
readNext <- true
|
||||||
|
|
||||||
close(p.cryptoReady)
|
close(p.cryptoReady)
|
||||||
|
|
@ -269,8 +262,8 @@ loop:
|
||||||
// we can continue reading from the socket.
|
// we can continue reading from the socket.
|
||||||
readNext <- true
|
readNext <- true
|
||||||
|
|
||||||
case err := <-readErr:
|
case err := <-rwErr:
|
||||||
// read failed. there is no need to run the
|
// read or write failed. there is no need to run the
|
||||||
// polite disconnect sequence because the connection
|
// polite disconnect sequence because the connection
|
||||||
// is probably dead anyway.
|
// is probably dead anyway.
|
||||||
// TODO: handle write errors as well
|
// TODO: handle write errors as well
|
||||||
|
|
@ -284,8 +277,9 @@ loop:
|
||||||
}
|
}
|
||||||
|
|
||||||
// wait for read loop to return.
|
// wait for read loop to return.
|
||||||
|
close(p.outgoingMsgC)
|
||||||
close(readNext)
|
close(readNext)
|
||||||
<-readErr
|
<-rwErr
|
||||||
// tell the remote end to disconnect
|
// tell the remote end to disconnect
|
||||||
done := make(chan struct{})
|
done := make(chan struct{})
|
||||||
go func() {
|
go func() {
|
||||||
|
|
@ -391,9 +385,9 @@ outer:
|
||||||
func (p *Peer) startProto(offset uint64, impl Protocol) *proto {
|
func (p *Peer) startProto(offset uint64, impl Protocol) *proto {
|
||||||
rw := &proto{
|
rw := &proto{
|
||||||
in: make(chan Msg),
|
in: make(chan Msg),
|
||||||
|
out: p.outgoingMsgC,
|
||||||
offset: offset,
|
offset: offset,
|
||||||
maxcode: impl.Length,
|
maxcode: impl.Length,
|
||||||
peer: p,
|
|
||||||
}
|
}
|
||||||
p.protoWG.Add(1)
|
p.protoWG.Add(1)
|
||||||
go func() {
|
go func() {
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@ func testPeer(protos []Protocol) (net.Conn, *Peer, <-chan error) {
|
||||||
peer := newPeer(conn1, protos, nil)
|
peer := newPeer(conn1, protos, nil)
|
||||||
peer.ourID = &peerId{}
|
peer.ourID = &peerId{}
|
||||||
peer.pubkeyHook = func(*peerAddr) error { return nil }
|
peer.pubkeyHook = func(*peerAddr) error { return nil }
|
||||||
|
peer.outgoingMsgC = make(chan Msg)
|
||||||
errc := make(chan error, 1)
|
errc := make(chan error, 1)
|
||||||
go func() {
|
go func() {
|
||||||
_, err := peer.loop()
|
_, err := peer.loop()
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue