lnwire: add ping and pong messages
This commit adds Ping and Pong messages to the suite of lnwire messages. The usage of these messages within the daemon are similar to the usage of Bitcoin’s ping/pong messages. Pings are to be sent periodically with a random nonce to check connection activity and also to gauge latency. Pong’s are to be sent in reply to ping messages, echo’ing the same nonce used.
This commit is contained in:
parent
f12b9b4bd7
commit
3f39f5413e
@ -54,6 +54,10 @@ const (
|
||||
|
||||
// Commands for reporting protocol errors.
|
||||
CmdErrorGeneric = uint32(4000)
|
||||
|
||||
// Commands for connection keep-alive.
|
||||
CmdPing = uint32(5000)
|
||||
CmdPong = uint32(5010)
|
||||
)
|
||||
|
||||
// Message is an interface that defines a lightning wire protocol message. The
|
||||
@ -65,7 +69,6 @@ type Message interface {
|
||||
Command() uint32
|
||||
MaxPayloadLength(uint32) uint32
|
||||
Validate() error
|
||||
String() string
|
||||
}
|
||||
|
||||
// makeEmptyMessage creates a new empty message of the proper concrete type
|
||||
@ -114,6 +117,10 @@ func makeEmptyMessage(command uint32) (Message, error) {
|
||||
msg = &RoutingTableRequestMessage{}
|
||||
case CmdRoutingTableTransferMessage:
|
||||
msg = &RoutingTableTransferMessage{}
|
||||
case CmdPing:
|
||||
msg = &Ping{}
|
||||
case CmdPong:
|
||||
msg = &Pong{}
|
||||
default:
|
||||
return nil, fmt.Errorf("unhandled command [%d]", command)
|
||||
}
|
||||
|
77
lnwire/ping.go
Normal file
77
lnwire/ping.go
Normal file
@ -0,0 +1,77 @@
|
||||
package lnwire
|
||||
|
||||
import "io"
|
||||
|
||||
// Pong defines a message which is the direct response to a received Ping
|
||||
// message. A Pong reply indicates that a connection is still active. The Pong
|
||||
// reply to a Ping message should contain the nonce carried in the original
|
||||
// Pong message.
|
||||
type Pong struct {
|
||||
// Nonce is the unique nonce that was associated with the Ping message
|
||||
// that this Pong is replying to.
|
||||
Nonce uint64
|
||||
}
|
||||
|
||||
// NewPong returns a new Pong message binded to the specified nonce.
|
||||
func NewPong(nonce uint64) *Pong {
|
||||
return &Pong{
|
||||
Nonce: nonce,
|
||||
}
|
||||
}
|
||||
|
||||
// A compile time check to ensure Pong implements the lnwire.Message interface.
|
||||
var _ Message = (*Pong)(nil)
|
||||
|
||||
// Decode deserializes a serialized Pong message stored in the passed io.Reader
|
||||
// observing the specified protocol version.
|
||||
//
|
||||
// This is part of the lnwire.Message interface.
|
||||
func (p *Pong) Decode(r io.Reader, pver uint32) error {
|
||||
err := readElements(r,
|
||||
&p.Nonce,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Encode serializes the target Pong into the passed io.Writer observing the
|
||||
// protocol version specified.
|
||||
//
|
||||
// This is part of the lnwire.Message interface.
|
||||
func (p *Pong) Encode(w io.Writer, pver uint32) error {
|
||||
err := writeElements(w,
|
||||
p.Nonce,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Command returns the integer uniquely identifying this message type on the
|
||||
// wire.
|
||||
//
|
||||
// This is part of the lnwire.Message interface.
|
||||
func (p *Pong) Command() uint32 {
|
||||
return CmdPong
|
||||
}
|
||||
|
||||
// MaxPayloadLength returns the maximum allowed payload size for a Pong
|
||||
// complete message observing the specified protocol version.
|
||||
//
|
||||
// This is part of the lnwire.Message interface.
|
||||
func (p *Pong) MaxPayloadLength(uint32) uint32 {
|
||||
return 8
|
||||
}
|
||||
|
||||
// Validate performs any necessary sanity checks to ensure all fields present
|
||||
// on the Pong are valid.
|
||||
//
|
||||
// This is part of the lnwire.Message interface.
|
||||
func (p *Pong) Validate() error {
|
||||
return nil
|
||||
}
|
31
lnwire/ping_test.go
Normal file
31
lnwire/ping_test.go
Normal file
@ -0,0 +1,31 @@
|
||||
package lnwire
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestPongEncodeDecode(t *testing.T) {
|
||||
pong := &Pong{
|
||||
Nonce: 9,
|
||||
}
|
||||
|
||||
// Next encode the pong message into an empty bytes buffer.
|
||||
var b bytes.Buffer
|
||||
if err := pong.Encode(&b, 0); err != nil {
|
||||
t.Fatalf("unable to encode pong: %v", err)
|
||||
}
|
||||
|
||||
// Deserialize the encoded pong message into a new empty struct.
|
||||
pong2 := &Pong{}
|
||||
if err := pong2.Decode(&b, 0); err != nil {
|
||||
t.Fatalf("unable to decode ping: %v", err)
|
||||
}
|
||||
|
||||
// Assert equality of the two instances.
|
||||
if !reflect.DeepEqual(pong, pong2) {
|
||||
t.Fatalf("encode/decode pong messages don't match %#v vs %#v",
|
||||
pong, pong2)
|
||||
}
|
||||
}
|
76
lnwire/pong.go
Normal file
76
lnwire/pong.go
Normal file
@ -0,0 +1,76 @@
|
||||
package lnwire
|
||||
|
||||
import "io"
|
||||
|
||||
// Ping defines a message which is sent by peers periodically to determine if
|
||||
// the connection is still valid. Each ping message should carry a unique nonce
|
||||
// which is to be echoed back within the Pong response.
|
||||
type Ping struct {
|
||||
// Nonce is a unique value associated with this ping message. The pong
|
||||
// message that responds to this ping should reference the same value.
|
||||
Nonce uint64
|
||||
}
|
||||
|
||||
// NewPing returns a new Ping message binded to the specified nonce.
|
||||
func NewPing(nonce uint64) *Ping {
|
||||
return &Ping{
|
||||
Nonce: nonce,
|
||||
}
|
||||
}
|
||||
|
||||
// A compile time check to ensure Ping implements the lnwire.Message interface.
|
||||
var _ Message = (*Ping)(nil)
|
||||
|
||||
// Decode deserializes a serialized Ping message stored in the passed io.Reader
|
||||
// observing the specified protocol version.
|
||||
//
|
||||
// This is part of the lnwire.Message interface.
|
||||
func (p *Ping) Decode(r io.Reader, pver uint32) error {
|
||||
err := readElements(r,
|
||||
&p.Nonce,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Encode serializes the target Ping into the passed io.Writer observing the
|
||||
// protocol version specified.
|
||||
//
|
||||
// This is part of the lnwire.Message interface.
|
||||
func (p *Ping) Encode(w io.Writer, pver uint32) error {
|
||||
err := writeElements(w,
|
||||
p.Nonce,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Command returns the integer uniquely identifying this message type on the
|
||||
// wire.
|
||||
//
|
||||
// This is part of the lnwire.Message interface.
|
||||
func (p *Ping) Command() uint32 {
|
||||
return CmdPing
|
||||
}
|
||||
|
||||
// MaxPayloadLength returns the maximum allowed payload size for a Ping
|
||||
// complete message observing the specified protocol version.
|
||||
//
|
||||
// This is part of the lnwire.Message interface.
|
||||
func (p Ping) MaxPayloadLength(uint32) uint32 {
|
||||
return 8
|
||||
}
|
||||
|
||||
// Validate performs any necessary sanity checks to ensure all fields present
|
||||
// on the Ping are valid.
|
||||
//
|
||||
// This is part of the lnwire.Message interface.
|
||||
func (p *Ping) Validate() error {
|
||||
return nil
|
||||
}
|
31
lnwire/pong_test.go
Normal file
31
lnwire/pong_test.go
Normal file
@ -0,0 +1,31 @@
|
||||
package lnwire
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestPingEncodeDecode(t *testing.T) {
|
||||
ping := &Ping{
|
||||
Nonce: 9,
|
||||
}
|
||||
|
||||
// Next encode the ping message into an empty bytes buffer.
|
||||
var b bytes.Buffer
|
||||
if err := ping.Encode(&b, 0); err != nil {
|
||||
t.Fatalf("unable to encode ping: %v", err)
|
||||
}
|
||||
|
||||
// Deserialize the encoded ping message into a new empty struct.
|
||||
ping2 := &Ping{}
|
||||
if err := ping2.Decode(&b, 0); err != nil {
|
||||
t.Fatalf("unable to decode ping: %v", err)
|
||||
}
|
||||
|
||||
// Assert equality of the two instances.
|
||||
if !reflect.DeepEqual(ping, ping2) {
|
||||
t.Fatalf("encode/decode ping messages don't match %#v vs %#v",
|
||||
ping, ping2)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user