// Copyright 2016 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see .
package adapters
import (
"fmt"
"net"
//"encoding/binary"
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/p2p/discover"
)
// devp2p RLPx underlay support
type RLPx struct {
id *NodeId
net *p2p.Server
addr []byte
m func(p2p.MsgReadWriter) Messenger
r Reporter
}
type RLPxMessenger struct {
rw p2p.MsgReadWriter
}
func NewRLPxMessenger(rw p2p.MsgReadWriter) Messenger {
return Messenger(&RLPxMessenger{rw: rw})
}
func NewRLPx(addr []byte, srv *p2p.Server, m func(p2p.MsgReadWriter) Messenger) *RLPx {
return &RLPx{
net: srv,
addr: addr,
m: m,
}
}
func NewReportingRLPx(addr []byte, srv *p2p.Server, m func(p2p.MsgReadWriter) Messenger, r Reporter) *RLPx {
rlpx := NewRLPx(addr, srv, m)
rlpx.r = r
srv.PeerConnHook = func(p *p2p.Peer) {
r.DidConnect(rlpx.id, &NodeId{p.ID()})
}
srv.PeerDisconnHook = func(p *p2p.Peer) {
r.DidDisconnect(rlpx.id, &NodeId{p.ID()})
}
return rlpx
}
func (self *RLPxMessenger) SendMsg(code uint64, msg interface{}) error {
return p2p.Send(self.rw, code, msg)
}
func (self *RLPxMessenger) ReadMsg() (p2p.Msg, error) {
return self.rw.ReadMsg()
}
func (self *RLPxMessenger) Close() {
}
func (self *RLPx) LocalAddr() []byte {
return self.addr
}
func (self *RLPx) Connect(enode []byte) error {
// TCP/UDP node address encoded with enode url scheme
// @:(?udp=)
node, err := discover.ParseNode(string(enode))
if err != nil {
return fmt.Errorf("invalid node URL: %v", err)
}
self.net.AddPeer(node)
return nil
}
func (self *RLPx) Messenger(rw p2p.MsgReadWriter) Messenger {
return self.m(rw)
}
//func (self *RLPx) Disconnect(p *p2p.Peer, rw p2p.MsgReadWriter) error {
func (self *RLPx) Disconnect(b []byte) error {
//p.Disconnect(p2p.DiscSubprotocolError)
//d, _ := binary.Uvarint(b)
//p.Disconnect(p2p.DiscReason(d))
return nil
}
// ParseAddr take two arguments, advertised in handshake and the one set on the peer struct
// and constructs the remote address object
func (self *RLPx) ParseAddr(s []byte, remoteAddr string) ([]byte, error) {
// returns self advertised node connection info (listening address w enodes)
// IP will get repaired on the other end if missing
// or resolved via ID by discovery at dialout
n, err := discover.ParseNode(string(s))
if err != nil {
return nil, err
}
// repair reported address if IP missing
if n.IP.IsUnspecified() {
host, _, err := net.SplitHostPort(remoteAddr)
if err != nil {
return nil, err
}
n.IP = net.ParseIP(host)
}
return []byte(n.String()), nil
}