package autonat
import (
"context"
"fmt"
"time"
"github.com/libp2p/go-libp2p/core/host"
"github.com/libp2p/go-libp2p/core/network"
"github.com/libp2p/go-libp2p/core/peer"
"github.com/libp2p/go-libp2p/p2p/host/autonat/pb"
"github.com/libp2p/go-msgio/pbio"
)
func NewAutoNATClient (h host .Host , addrFunc AddrFunc , mt MetricsTracer ) Client {
if addrFunc == nil {
addrFunc = h .Addrs
}
return &client {h : h , addrFunc : addrFunc , mt : mt }
}
type client struct {
h host .Host
addrFunc AddrFunc
mt MetricsTracer
}
func (c *client ) DialBack (ctx context .Context , p peer .ID ) error {
s , err := c .h .NewStream (ctx , p , AutoNATProto )
if err != nil {
return err
}
if err := s .Scope ().SetService (ServiceName ); err != nil {
log .Debugf ("error attaching stream to autonat service: %s" , err )
s .Reset ()
return err
}
if err := s .Scope ().ReserveMemory (maxMsgSize , network .ReservationPriorityAlways ); err != nil {
log .Debugf ("error reserving memory for autonat stream: %s" , err )
s .Reset ()
return err
}
defer s .Scope ().ReleaseMemory (maxMsgSize )
deadline := time .Now ().Add (streamTimeout )
if ctxDeadline , ok := ctx .Deadline (); ok {
if ctxDeadline .Before (deadline ) {
deadline = ctxDeadline
}
}
s .SetDeadline (deadline )
defer s .Close ()
r := pbio .NewDelimitedReader (s , maxMsgSize )
w := pbio .NewDelimitedWriter (s )
req := newDialMessage (peer .AddrInfo {ID : c .h .ID (), Addrs : c .addrFunc ()})
if err := w .WriteMsg (req ); err != nil {
s .Reset ()
return err
}
var res pb .Message
if err := r .ReadMsg (&res ); err != nil {
s .Reset ()
return err
}
if res .GetType () != pb .Message_DIAL_RESPONSE {
s .Reset ()
return fmt .Errorf ("unexpected response: %s" , res .GetType ().String ())
}
status := res .GetDialResponse ().GetStatus ()
if c .mt != nil {
c .mt .ReceivedDialResponse (status )
}
switch status {
case pb .Message_OK :
return nil
default :
return Error {Status : status , Text : res .GetDialResponse ().GetStatusText ()}
}
}
type Error struct {
Status pb .Message_ResponseStatus
Text string
}
func (e Error ) Error () string {
return fmt .Sprintf ("AutoNAT error: %s (%s)" , e .Text , e .Status .String ())
}
func (e Error ) IsDialError () bool {
return e .Status == pb .Message_E_DIAL_ERROR
}
func (e Error ) IsDialRefused () bool {
return e .Status == pb .Message_E_DIAL_REFUSED
}
func IsDialError (e error ) bool {
ae , ok := e .(Error )
return ok && ae .IsDialError ()
}
func IsDialRefused (e error ) bool {
ae , ok := e .(Error )
return ok && ae .IsDialRefused ()
}
The pages are generated with Golds v0.8.2 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .