cmd/monero: p2p-handshake --> p2p-peer-list

Signed-off-by: Ciro S. Costa <utxobr@protonmail.com>
This commit is contained in:
Ciro S. Costa 2021-04-21 08:36:06 -04:00
parent 9113a20dcc
commit 07252dc77e
8 changed files with 195 additions and 142 deletions

View file

@ -1,41 +0,0 @@
package main
import (
"context"
"fmt"
"time"
"github.com/cirocosta/go-monero/pkg/levin"
)
type P2PHandshakeCommand struct {
NodeAddress string `long:"node-address" required:"true" description:"address of the node to ping"`
}
func (c *P2PHandshakeCommand) Execute(_ []string) error {
client, err := levin.NewClient(c.NodeAddress)
if err != nil {
return fmt.Errorf("new client: %w", err)
}
defer client.Close()
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
if err := client.Handshake(ctx); err != nil {
return fmt.Errorf("handshake: %w", err)
}
_, _ = client, ctx
return nil
}
func init() {
parser.AddCommand("p2p-handshake",
"Handshake another node in the p2p network",
"Handshake another node in the p2p network",
&P2PHandshakeCommand{},
)
}

View file

@ -0,0 +1,44 @@
package main
import (
"context"
"fmt"
"time"
"github.com/cirocosta/go-monero/pkg/levin"
)
type P2PPeerList struct {
NodeAddress string `long:"node-address" default:"xps.utxo.com.br:18080" description:"address of the node to find the peer list of"`
}
func (c *P2PPeerList) Execute(_ []string) error {
client, err := levin.NewClient(c.NodeAddress)
if err != nil {
return fmt.Errorf("new client: %w", err)
}
defer client.Close()
ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
defer cancel()
pl, err := client.Handshake(ctx)
if err != nil {
return fmt.Errorf("handshake: %w", err)
}
for addr := range pl.Peers {
fmt.Println(addr)
}
return nil
}
func init() {
parser.AddCommand("p2p-peer-list",
"Find out the list of local peers known by a node",
"Find out the list of local peers known by a node",
&P2PPeerList{},
)
}

Binary file not shown.

View file

@ -4,7 +4,6 @@ import (
"flag"
"fmt"
"io/ioutil"
"net"
"os"
"github.com/cirocosta/go-monero/pkg/levin"
@ -34,82 +33,15 @@ func run() error {
return fmt.Errorf("portable storage from bytes: %w", err)
}
// if err := json.NewEncoder(os.Stdout).Encode(ps); err != nil {
// return fmt.Errorf("encode: %w", err)
// }
pl := levin.NewLocalPeerListFromEntries(ps.Entries)
for _, entry := range ps.Entries {
if entry.Name != "local_peerlist_new" {
continue
}
peerList, ok := entry.Value.(levin.Entries)
if !ok {
panic(fmt.Errorf("unexpected peerlist value type"))
}
for _, peer := range peerList {
peerListAdr, ok := peer.Value.(levin.Entries)
if !ok {
panic(fmt.Errorf("unexpected value peerlist adr type"))
}
for _, adr := range peerListAdr {
if adr.Name != "adr" {
continue
}
addr, ok := adr.Value.(levin.Entries)
if !ok {
panic(fmt.Errorf("unexpected value type"))
}
for _, addrField := range addr {
if addrField.Name != "addr" {
continue
}
fields, ok := addrField.Value.(levin.Entries)
if !ok {
panic(fmt.Errorf("unexpected value type"))
}
var ip uint32
var port uint16
for _, field := range fields {
if field.Name == "m_ip" {
ip = field.Value.(uint32)
}
if field.Name == "m_port" {
port = field.Value.(uint16)
}
}
if ip != 0 && port != 0 {
fmt.Printf("%s:%d\n", ipzify(ip), port)
}
}
}
}
for addr := range pl.Peers {
fmt.Println(addr)
}
return nil
}
func ipzify(ip uint32) string {
result := make(net.IP, 4)
result[0] = byte(ip)
result[1] = byte(ip >> 8)
result[2] = byte(ip >> 16)
result[3] = byte(ip >> 24)
return result.String()
}
func main() {
if err := run(); err != nil {
panic(err)

View file

@ -65,13 +65,10 @@ type BoostString string
func (v BoostString) Bytes() []byte {
b := []byte{BoostSerializeTypeString}
fmt.Println("VAR_IN: ", v)
varInB, err := VarIn(len(v))
if err != nil {
panic(fmt.Errorf("varin '%d': %w", len(v), err))
}
fmt.Println("VAR_RES: ", varInB)
return append(b, append(varInB, []byte(v)...)...)
}

View file

@ -1,11 +1,11 @@
package levin
import (
"bytes"
"context"
"fmt"
"io"
"net"
"os"
"time"
)
@ -41,7 +41,7 @@ func (c *Client) Close() error {
return nil
}
func (c *Client) Handshake(ctx context.Context) error {
func (c *Client) Handshake(ctx context.Context) (*LocalPeerList, error) {
payload := (&PortableStorage{
Entries: []Entry{
{
@ -58,58 +58,47 @@ func (c *Client) Handshake(ctx context.Context) error {
},
}).Bytes()
for _, b := range payload {
fmt.Printf("%x ", b)
}
fmt.Println()
reqHeaderB := NewRequestHeader(CommandHandshake, uint64(len(payload))).Bytes()
if _, err := c.conn.Write(reqHeaderB); err != nil {
return fmt.Errorf("write header: %w", err)
return nil, fmt.Errorf("write header: %w", err)
}
if _, err := c.conn.Write(payload); err != nil {
return fmt.Errorf("write payload: %w", err)
return nil, fmt.Errorf("write payload: %w", err)
}
again:
responseHeaderB := make([]byte, LevinHeaderSizeBytes)
if _, err := io.ReadFull(c.conn, responseHeaderB); err != nil {
return fmt.Errorf("read full header: %w", err)
return nil, fmt.Errorf("read full header: %w", err)
}
respHeader, err := NewHeaderFromBytesBytes(responseHeaderB)
if err != nil {
return fmt.Errorf("new header from resp bytes: %w", err)
return nil, fmt.Errorf("new header from resp bytes: %w", err)
}
fmt.Printf("%+v\n", respHeader)
dest := new(bytes.Buffer)
if respHeader.Length != 0 {
var dest io.Writer = os.Stderr
if respHeader.Command == CommandHandshake {
f, err := os.Create("resp.bin")
if err != nil {
panic(err)
}
defer f.Close()
dest = f
}
if _, err := io.CopyN(dest, c.conn, int64(respHeader.Length)); err != nil {
return fmt.Errorf("copy payload to stdout: %w", err)
return nil, fmt.Errorf("copy payload to stdout: %w", err)
}
}
if respHeader.Command != CommandHandshake {
dest.Reset()
goto again
}
return nil
ps, err := NewPortableStorageFromBytes(dest.Bytes())
if err != nil {
return nil, fmt.Errorf("new portable storage from bytes: %w", err)
}
peerList := NewLocalPeerListFromEntries(ps.Entries)
return &peerList, nil
}
func (c *Client) Ping(ctx context.Context) error {

View file

@ -0,0 +1,96 @@
package levin
import (
"fmt"
"net"
)
type LocalPeerList struct {
Peers map[string]Peer
}
type Peer struct {
Ip string
Port uint16
}
func (p Peer) Addr() string {
return fmt.Sprintf("%s:%d", p.Ip, p.Port)
}
// TODO less panic'ing
func NewLocalPeerListFromEntries(entries Entries) LocalPeerList {
peers := map[string]Peer{}
for _, entry := range entries {
if entry.Name != "local_peerlist_new" {
continue
}
peerList := entry.Entries()
for _, peer := range peerList {
peerListAdr := peer.Entries()
for _, adr := range peerListAdr {
if adr.Name != "adr" {
continue
}
addr := adr.Entries()
for _, addrField := range addr {
if addrField.Name != "addr" {
continue
}
fields := addrField.Entries()
var ip string
var port uint16
for _, field := range fields {
if field.Name == "m_ip" {
ip = ipzify(field.Uint32())
}
if field.Name == "m_port" {
port = field.Uint16()
}
if field.Name == "addr" {
ip = net.IP([]byte(field.String())).String()
}
}
if ip != "" && port != 0 {
peer := Peer{
Ip: ip,
Port: port,
}
peers[peer.Addr()] = peer
}
}
}
}
}
return LocalPeerList{
Peers: peers,
}
}
func ipzify(ip uint32) string {
result := make(net.IP, 4)
result[0] = byte(ip)
result[1] = byte(ip >> 8)
result[2] = byte(ip >> 16)
result[3] = byte(ip >> 24)
return result.String()
}

View file

@ -23,6 +23,42 @@ type Entry struct {
Value interface{}
}
func (e Entry) String() string {
v, ok := e.Value.(string)
if !ok {
panic(fmt.Errorf("interface couldnt be casted to string"))
}
return v
}
func (e Entry) Uint16() uint16 {
v, ok := e.Value.(uint16)
if !ok {
panic(fmt.Errorf("interface couldnt be casted to uint16"))
}
return v
}
func (e Entry) Uint32() uint32 {
v, ok := e.Value.(uint32)
if !ok {
panic(fmt.Errorf("interface couldnt be casted to uint32"))
}
return v
}
func (e Entry) Entries() Entries {
v, ok := e.Value.(Entries)
if !ok {
panic(fmt.Errorf("interface couldnt be casted to levin.Entries"))
}
return v
}
func (e Entry) Bytes() []byte {
return nil
}