cmd/monero: p2p-handshake --> p2p-peer-list
Signed-off-by: Ciro S. Costa <utxobr@protonmail.com>
This commit is contained in:
parent
9113a20dcc
commit
07252dc77e
|
@ -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{},
|
||||
)
|
||||
}
|
44
cmd/monero/p2p_peer_list.go
Normal file
44
cmd/monero/p2p_peer_list.go
Normal 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.
|
@ -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)
|
||||
|
|
|
@ -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)...)...)
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
96
pkg/levin/local_peer_list.go
Normal file
96
pkg/levin/local_peer_list.go
Normal 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()
|
||||
}
|
|
@ -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
|
||||
}
|
||||
|
|
Reference in a new issue