From 1ad785cc023fc33f8a4fd0fdc3f0177992afde84 Mon Sep 17 00:00:00 2001 From: vyzo Date: Sat, 5 May 2018 16:45:58 +0300 Subject: [PATCH] basic client --- p2p/host/autonat/client.go | 83 ++++++++++++++++++++++++++++++++++++++ p2p/host/autonat/proto.go | 23 +++++++++++ 2 files changed, 106 insertions(+) create mode 100644 p2p/host/autonat/client.go create mode 100644 p2p/host/autonat/proto.go diff --git a/p2p/host/autonat/client.go b/p2p/host/autonat/client.go new file mode 100644 index 00000000..6709abcd --- /dev/null +++ b/p2p/host/autonat/client.go @@ -0,0 +1,83 @@ +package autonat + +import ( + "context" + "fmt" + + pb "github.com/libp2p/go-libp2p-autonat/pb" + + ggio "github.com/gogo/protobuf/io" + host "github.com/libp2p/go-libp2p-host" + inet "github.com/libp2p/go-libp2p-net" + peer "github.com/libp2p/go-libp2p-peer" + pstore "github.com/libp2p/go-libp2p-peerstore" + ma "github.com/multiformats/go-multiaddr" +) + +type AutoNATClient interface { + Dial(ctx context.Context) (ma.Multiaddr, error) +} + +type AutoNATError struct { + Status pb.Message_ResponseStatus + Text string +} + +func NewAutoNATClient(h host.Host, p peer.ID) AutoNATClient { + return &client{h: h, p: p} +} + +type client struct { + h host.Host + p peer.ID +} + +func (c *client) Dial(ctx context.Context) (ma.Multiaddr, error) { + s, err := c.h.NewStream(ctx, c.p, AutoNATProto) + if err != nil { + return nil, err + } + defer s.Close() + + r := ggio.NewDelimitedReader(s, inet.MessageSizeMax) + w := ggio.NewDelimitedWriter(s) + + req := newDialMessage(pstore.PeerInfo{ID: c.h.ID(), Addrs: c.h.Addrs()}) + err = w.WriteMsg(req) + if err != nil { + return nil, err + } + + var res pb.Message + err = r.ReadMsg(&res) + if err != nil { + return nil, err + } + + if res.GetType() != pb.Message_DIAL_RESPONSE { + return nil, fmt.Errorf("Unexpected response: %s", res.GetType().String()) + } + + status := res.GetDialResponse().GetStatus() + switch status { + case pb.Message_OK: + addr := res.GetDialResponse().GetAddr() + return ma.NewMultiaddrBytes(addr) + + default: + return nil, AutoNATError{Status: status, Text: res.GetDialResponse().GetStatusText()} + } +} + +func (e AutoNATError) Error() string { + return fmt.Sprintf("AutoNAT error: %s (%s)", e.Text, e.Status.String()) +} + +func (e AutoNATError) IsDialError() bool { + return e.Status == pb.Message_E_DIAL_ERROR +} + +func IsDialError(e error) bool { + ae, ok := e.(AutoNATError) + return ok && ae.IsDialError() +} diff --git a/p2p/host/autonat/proto.go b/p2p/host/autonat/proto.go new file mode 100644 index 00000000..142469ce --- /dev/null +++ b/p2p/host/autonat/proto.go @@ -0,0 +1,23 @@ +package autonat + +import ( + pb "github.com/libp2p/go-libp2p-autonat/pb" + + pstore "github.com/libp2p/go-libp2p-peerstore" +) + +const AutoNATProto = "/autonat/1.0.0" + +func newDialMessage(pi pstore.PeerInfo) *pb.Message { + msg := new(pb.Message) + msg.Type = pb.Message_DIAL.Enum() + msg.Dial = new(pb.Message_Dial) + msg.Dial.Peer = new(pb.Message_PeerInfo) + msg.Dial.Peer.Id = []byte(pi.ID) + msg.Dial.Peer.Addrs = make([][]byte, len(pi.Addrs)) + for i, addr := range pi.Addrs { + msg.Dial.Peer.Addrs[i] = addr.Bytes() + } + + return msg +}