Integrate BACKBEAT SDK and resolve KACHING license validation
Major integrations and fixes: - Added BACKBEAT SDK integration for P2P operation timing - Implemented beat-aware status tracking for distributed operations - Added Docker secrets support for secure license management - Resolved KACHING license validation via HTTPS/TLS - Updated docker-compose configuration for clean stack deployment - Disabled rollback policies to prevent deployment failures - Added license credential storage (CHORUS-DEV-MULTI-001) Technical improvements: - BACKBEAT P2P operation tracking with phase management - Enhanced configuration system with file-based secrets - Improved error handling for license validation - Clean separation of KACHING and CHORUS deployment stacks 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
76
vendor/github.com/libp2p/go-libp2p/p2p/protocol/circuitv2/client/client.go
generated
vendored
Normal file
76
vendor/github.com/libp2p/go-libp2p/p2p/protocol/circuitv2/client/client.go
generated
vendored
Normal file
@@ -0,0 +1,76 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"sync"
|
||||
|
||||
"github.com/libp2p/go-libp2p/core/host"
|
||||
"github.com/libp2p/go-libp2p/core/peer"
|
||||
"github.com/libp2p/go-libp2p/core/transport"
|
||||
"github.com/libp2p/go-libp2p/p2p/protocol/circuitv2/proto"
|
||||
|
||||
logging "github.com/ipfs/go-log/v2"
|
||||
)
|
||||
|
||||
var log = logging.Logger("p2p-circuit")
|
||||
|
||||
// Client implements the client-side of the p2p-circuit/v2 protocol:
|
||||
// - it implements dialing through v2 relays
|
||||
// - it listens for incoming connections through v2 relays.
|
||||
//
|
||||
// For backwards compatibility with v1 relays and older nodes, the client will
|
||||
// also accept relay connections through v1 relays and fallback dial peers using p2p-circuit/v1.
|
||||
// This allows us to use the v2 code as drop in replacement for v1 in a host without breaking
|
||||
// existing code and interoperability with older nodes.
|
||||
type Client struct {
|
||||
ctx context.Context
|
||||
ctxCancel context.CancelFunc
|
||||
host host.Host
|
||||
upgrader transport.Upgrader
|
||||
|
||||
incoming chan accept
|
||||
|
||||
mx sync.Mutex
|
||||
activeDials map[peer.ID]*completion
|
||||
hopCount map[peer.ID]int
|
||||
}
|
||||
|
||||
var _ io.Closer = &Client{}
|
||||
var _ transport.Transport = &Client{}
|
||||
|
||||
type accept struct {
|
||||
conn *Conn
|
||||
writeResponse func() error
|
||||
}
|
||||
|
||||
type completion struct {
|
||||
ch chan struct{}
|
||||
relay peer.ID
|
||||
err error
|
||||
}
|
||||
|
||||
// New constructs a new p2p-circuit/v2 client, attached to the given host and using the given
|
||||
// upgrader to perform connection upgrades.
|
||||
func New(h host.Host, upgrader transport.Upgrader) (*Client, error) {
|
||||
cl := &Client{
|
||||
host: h,
|
||||
upgrader: upgrader,
|
||||
incoming: make(chan accept),
|
||||
activeDials: make(map[peer.ID]*completion),
|
||||
hopCount: make(map[peer.ID]int),
|
||||
}
|
||||
cl.ctx, cl.ctxCancel = context.WithCancel(context.Background())
|
||||
return cl, nil
|
||||
}
|
||||
|
||||
// Start registers the circuit (client) protocol stream handlers
|
||||
func (c *Client) Start() {
|
||||
c.host.SetStreamHandler(proto.ProtoIDv2Stop, c.handleStreamV2)
|
||||
}
|
||||
|
||||
func (c *Client) Close() error {
|
||||
c.ctxCancel()
|
||||
c.host.RemoveStreamHandler(proto.ProtoIDv2Stop)
|
||||
return nil
|
||||
}
|
||||
163
vendor/github.com/libp2p/go-libp2p/p2p/protocol/circuitv2/client/conn.go
generated
vendored
Normal file
163
vendor/github.com/libp2p/go-libp2p/p2p/protocol/circuitv2/client/conn.go
generated
vendored
Normal file
@@ -0,0 +1,163 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"github.com/libp2p/go-libp2p/core/network"
|
||||
"github.com/libp2p/go-libp2p/core/peer"
|
||||
tpt "github.com/libp2p/go-libp2p/core/transport"
|
||||
|
||||
ma "github.com/multiformats/go-multiaddr"
|
||||
manet "github.com/multiformats/go-multiaddr/net"
|
||||
)
|
||||
|
||||
// HopTagWeight is the connection manager weight for connections carrying relay hop streams
|
||||
var HopTagWeight = 5
|
||||
|
||||
type statLimitDuration struct{}
|
||||
type statLimitData struct{}
|
||||
|
||||
var (
|
||||
StatLimitDuration = statLimitDuration{}
|
||||
StatLimitData = statLimitData{}
|
||||
)
|
||||
|
||||
type Conn struct {
|
||||
stream network.Stream
|
||||
remote peer.AddrInfo
|
||||
stat network.ConnStats
|
||||
|
||||
client *Client
|
||||
}
|
||||
|
||||
type NetAddr struct {
|
||||
Relay string
|
||||
Remote string
|
||||
}
|
||||
|
||||
var _ net.Addr = (*NetAddr)(nil)
|
||||
|
||||
func (n *NetAddr) Network() string {
|
||||
return "libp2p-circuit-relay"
|
||||
}
|
||||
|
||||
func (n *NetAddr) String() string {
|
||||
return fmt.Sprintf("relay[%s-%s]", n.Remote, n.Relay)
|
||||
}
|
||||
|
||||
// Conn interface
|
||||
var _ manet.Conn = (*Conn)(nil)
|
||||
|
||||
func (c *Conn) Close() error {
|
||||
c.untagHop()
|
||||
return c.stream.Reset()
|
||||
}
|
||||
|
||||
func (c *Conn) Read(buf []byte) (int, error) {
|
||||
return c.stream.Read(buf)
|
||||
}
|
||||
|
||||
func (c *Conn) Write(buf []byte) (int, error) {
|
||||
return c.stream.Write(buf)
|
||||
}
|
||||
|
||||
func (c *Conn) SetDeadline(t time.Time) error {
|
||||
return c.stream.SetDeadline(t)
|
||||
}
|
||||
|
||||
func (c *Conn) SetReadDeadline(t time.Time) error {
|
||||
return c.stream.SetReadDeadline(t)
|
||||
}
|
||||
|
||||
func (c *Conn) SetWriteDeadline(t time.Time) error {
|
||||
return c.stream.SetWriteDeadline(t)
|
||||
}
|
||||
|
||||
// TODO: is it okay to cast c.Conn().RemotePeer() into a multiaddr? might be "user input"
|
||||
func (c *Conn) RemoteMultiaddr() ma.Multiaddr {
|
||||
// TODO: We should be able to do this directly without converting to/from a string.
|
||||
relayAddr, err := ma.NewComponent(
|
||||
ma.ProtocolWithCode(ma.P_P2P).Name,
|
||||
c.stream.Conn().RemotePeer().String(),
|
||||
)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return ma.Join(c.stream.Conn().RemoteMultiaddr(), relayAddr, circuitAddr)
|
||||
}
|
||||
|
||||
func (c *Conn) LocalMultiaddr() ma.Multiaddr {
|
||||
return c.stream.Conn().LocalMultiaddr()
|
||||
}
|
||||
|
||||
func (c *Conn) LocalAddr() net.Addr {
|
||||
na, err := manet.ToNetAddr(c.stream.Conn().LocalMultiaddr())
|
||||
if err != nil {
|
||||
log.Error("failed to convert local multiaddr to net addr:", err)
|
||||
return nil
|
||||
}
|
||||
return na
|
||||
}
|
||||
|
||||
func (c *Conn) RemoteAddr() net.Addr {
|
||||
return &NetAddr{
|
||||
Relay: c.stream.Conn().RemotePeer().String(),
|
||||
Remote: c.remote.ID.String(),
|
||||
}
|
||||
}
|
||||
|
||||
// ConnStat interface
|
||||
var _ network.ConnStat = (*Conn)(nil)
|
||||
|
||||
func (c *Conn) Stat() network.ConnStats {
|
||||
return c.stat
|
||||
}
|
||||
|
||||
// tagHop tags the underlying relay connection so that it can be (somewhat) protected from the
|
||||
// connection manager as it is an important connection that proxies other connections.
|
||||
// This is handled here so that the user code doesnt need to bother with this and avoid
|
||||
// clown shoes situations where a high value peer connection is behind a relayed connection and it is
|
||||
// implicitly because the connection manager closed the underlying relay connection.
|
||||
func (c *Conn) tagHop() {
|
||||
c.client.mx.Lock()
|
||||
defer c.client.mx.Unlock()
|
||||
|
||||
p := c.stream.Conn().RemotePeer()
|
||||
c.client.hopCount[p]++
|
||||
if c.client.hopCount[p] == 1 {
|
||||
c.client.host.ConnManager().TagPeer(p, "relay-hop-stream", HopTagWeight)
|
||||
}
|
||||
}
|
||||
|
||||
// untagHop removes the relay-hop-stream tag if necessary; it is invoked when a relayed connection
|
||||
// is closed.
|
||||
func (c *Conn) untagHop() {
|
||||
c.client.mx.Lock()
|
||||
defer c.client.mx.Unlock()
|
||||
|
||||
p := c.stream.Conn().RemotePeer()
|
||||
c.client.hopCount[p]--
|
||||
if c.client.hopCount[p] == 0 {
|
||||
c.client.host.ConnManager().UntagPeer(p, "relay-hop-stream")
|
||||
delete(c.client.hopCount, p)
|
||||
}
|
||||
}
|
||||
|
||||
type capableConnWithStat interface {
|
||||
tpt.CapableConn
|
||||
network.ConnStat
|
||||
}
|
||||
|
||||
type capableConn struct {
|
||||
capableConnWithStat
|
||||
}
|
||||
|
||||
var transportName = ma.ProtocolWithCode(ma.P_CIRCUIT).Name
|
||||
|
||||
func (c capableConn) ConnState() network.ConnectionState {
|
||||
return network.ConnectionState{
|
||||
Transport: transportName,
|
||||
}
|
||||
}
|
||||
189
vendor/github.com/libp2p/go-libp2p/p2p/protocol/circuitv2/client/dial.go
generated
vendored
Normal file
189
vendor/github.com/libp2p/go-libp2p/p2p/protocol/circuitv2/client/dial.go
generated
vendored
Normal file
@@ -0,0 +1,189 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/libp2p/go-libp2p/core/network"
|
||||
"github.com/libp2p/go-libp2p/core/peer"
|
||||
"github.com/libp2p/go-libp2p/core/peerstore"
|
||||
pbv2 "github.com/libp2p/go-libp2p/p2p/protocol/circuitv2/pb"
|
||||
"github.com/libp2p/go-libp2p/p2p/protocol/circuitv2/proto"
|
||||
"github.com/libp2p/go-libp2p/p2p/protocol/circuitv2/util"
|
||||
|
||||
ma "github.com/multiformats/go-multiaddr"
|
||||
)
|
||||
|
||||
const maxMessageSize = 4096
|
||||
|
||||
var DialTimeout = time.Minute
|
||||
var DialRelayTimeout = 5 * time.Second
|
||||
|
||||
// relay protocol errors; used for signalling deduplication
|
||||
type relayError struct {
|
||||
err string
|
||||
}
|
||||
|
||||
func (e relayError) Error() string {
|
||||
return e.err
|
||||
}
|
||||
|
||||
func newRelayError(t string, args ...interface{}) error {
|
||||
return relayError{err: fmt.Sprintf(t, args...)}
|
||||
}
|
||||
|
||||
func isRelayError(err error) bool {
|
||||
_, ok := err.(relayError)
|
||||
return ok
|
||||
}
|
||||
|
||||
// dialer
|
||||
func (c *Client) dial(ctx context.Context, a ma.Multiaddr, p peer.ID) (*Conn, error) {
|
||||
// split /a/p2p-circuit/b into (/a, /p2p-circuit/b)
|
||||
relayaddr, destaddr := ma.SplitFunc(a, func(c ma.Component) bool {
|
||||
return c.Protocol().Code == ma.P_CIRCUIT
|
||||
})
|
||||
|
||||
// If the address contained no /p2p-circuit part, the second part is nil.
|
||||
if destaddr == nil {
|
||||
return nil, fmt.Errorf("%s is not a relay address", a)
|
||||
}
|
||||
|
||||
if relayaddr == nil {
|
||||
return nil, fmt.Errorf("can't dial a p2p-circuit without specifying a relay: %s", a)
|
||||
}
|
||||
|
||||
dinfo := peer.AddrInfo{ID: p}
|
||||
|
||||
// Strip the /p2p-circuit prefix from the destaddr so that we can pass the destination address
|
||||
// (if present) for active relays
|
||||
_, destaddr = ma.SplitFirst(destaddr)
|
||||
if destaddr != nil {
|
||||
dinfo.Addrs = append(dinfo.Addrs, destaddr)
|
||||
}
|
||||
|
||||
rinfo, err := peer.AddrInfoFromP2pAddr(relayaddr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error parsing relay multiaddr '%s': %w", relayaddr, err)
|
||||
}
|
||||
|
||||
// deduplicate active relay dials to the same peer
|
||||
retry:
|
||||
c.mx.Lock()
|
||||
dedup, active := c.activeDials[p]
|
||||
if !active {
|
||||
dedup = &completion{ch: make(chan struct{}), relay: rinfo.ID}
|
||||
c.activeDials[p] = dedup
|
||||
}
|
||||
c.mx.Unlock()
|
||||
|
||||
if active {
|
||||
select {
|
||||
case <-dedup.ch:
|
||||
if dedup.err != nil {
|
||||
if dedup.relay != rinfo.ID {
|
||||
// different relay, retry
|
||||
goto retry
|
||||
}
|
||||
|
||||
if !isRelayError(dedup.err) {
|
||||
// not a relay protocol error, retry
|
||||
goto retry
|
||||
}
|
||||
|
||||
// don't try the same relay if it failed to connect with a protocol error
|
||||
return nil, fmt.Errorf("concurrent active dial through the same relay failed with a protocol error")
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("concurrent active dial succeeded")
|
||||
|
||||
case <-ctx.Done():
|
||||
return nil, ctx.Err()
|
||||
}
|
||||
}
|
||||
|
||||
conn, err := c.dialPeer(ctx, *rinfo, dinfo)
|
||||
|
||||
c.mx.Lock()
|
||||
dedup.err = err
|
||||
close(dedup.ch)
|
||||
delete(c.activeDials, p)
|
||||
c.mx.Unlock()
|
||||
|
||||
return conn, err
|
||||
}
|
||||
|
||||
func (c *Client) dialPeer(ctx context.Context, relay, dest peer.AddrInfo) (*Conn, error) {
|
||||
log.Debugf("dialing peer %s through relay %s", dest.ID, relay.ID)
|
||||
|
||||
if len(relay.Addrs) > 0 {
|
||||
c.host.Peerstore().AddAddrs(relay.ID, relay.Addrs, peerstore.TempAddrTTL)
|
||||
}
|
||||
|
||||
dialCtx, cancel := context.WithTimeout(ctx, DialRelayTimeout)
|
||||
defer cancel()
|
||||
s, err := c.host.NewStream(dialCtx, relay.ID, proto.ProtoIDv2Hop)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error opening hop stream to relay: %w", err)
|
||||
}
|
||||
return c.connect(s, dest)
|
||||
}
|
||||
|
||||
func (c *Client) connect(s network.Stream, dest peer.AddrInfo) (*Conn, error) {
|
||||
if err := s.Scope().ReserveMemory(maxMessageSize, network.ReservationPriorityAlways); err != nil {
|
||||
s.Reset()
|
||||
return nil, err
|
||||
}
|
||||
defer s.Scope().ReleaseMemory(maxMessageSize)
|
||||
|
||||
rd := util.NewDelimitedReader(s, maxMessageSize)
|
||||
wr := util.NewDelimitedWriter(s)
|
||||
defer rd.Close()
|
||||
|
||||
var msg pbv2.HopMessage
|
||||
|
||||
msg.Type = pbv2.HopMessage_CONNECT.Enum()
|
||||
msg.Peer = util.PeerInfoToPeerV2(dest)
|
||||
|
||||
s.SetDeadline(time.Now().Add(DialTimeout))
|
||||
|
||||
err := wr.WriteMsg(&msg)
|
||||
if err != nil {
|
||||
s.Reset()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
msg.Reset()
|
||||
|
||||
err = rd.ReadMsg(&msg)
|
||||
if err != nil {
|
||||
s.Reset()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
s.SetDeadline(time.Time{})
|
||||
|
||||
if msg.GetType() != pbv2.HopMessage_STATUS {
|
||||
s.Reset()
|
||||
return nil, newRelayError("unexpected relay response; not a status message (%d)", msg.GetType())
|
||||
}
|
||||
|
||||
status := msg.GetStatus()
|
||||
if status != pbv2.Status_OK {
|
||||
s.Reset()
|
||||
return nil, newRelayError("error opening relay circuit: %s (%d)", pbv2.Status_name[int32(status)], status)
|
||||
}
|
||||
|
||||
// check for a limit provided by the relay; if the limit is not nil, then this is a limited
|
||||
// relay connection and we mark the connection as transient.
|
||||
var stat network.ConnStats
|
||||
if limit := msg.GetLimit(); limit != nil {
|
||||
stat.Transient = true
|
||||
stat.Extra = make(map[interface{}]interface{})
|
||||
stat.Extra[StatLimitDuration] = time.Duration(limit.GetDuration()) * time.Second
|
||||
stat.Extra[StatLimitData] = limit.GetData()
|
||||
}
|
||||
|
||||
return &Conn{stream: s, remote: dest, stat: stat, client: c}, nil
|
||||
}
|
||||
88
vendor/github.com/libp2p/go-libp2p/p2p/protocol/circuitv2/client/handlers.go
generated
vendored
Normal file
88
vendor/github.com/libp2p/go-libp2p/p2p/protocol/circuitv2/client/handlers.go
generated
vendored
Normal file
@@ -0,0 +1,88 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/libp2p/go-libp2p/core/network"
|
||||
pbv2 "github.com/libp2p/go-libp2p/p2p/protocol/circuitv2/pb"
|
||||
"github.com/libp2p/go-libp2p/p2p/protocol/circuitv2/util"
|
||||
)
|
||||
|
||||
var (
|
||||
StreamTimeout = 1 * time.Minute
|
||||
AcceptTimeout = 10 * time.Second
|
||||
)
|
||||
|
||||
func (c *Client) handleStreamV2(s network.Stream) {
|
||||
log.Debugf("new relay/v2 stream from: %s", s.Conn().RemotePeer())
|
||||
|
||||
s.SetReadDeadline(time.Now().Add(StreamTimeout))
|
||||
|
||||
rd := util.NewDelimitedReader(s, maxMessageSize)
|
||||
defer rd.Close()
|
||||
|
||||
writeResponse := func(status pbv2.Status) error {
|
||||
wr := util.NewDelimitedWriter(s)
|
||||
|
||||
var msg pbv2.StopMessage
|
||||
msg.Type = pbv2.StopMessage_STATUS.Enum()
|
||||
msg.Status = status.Enum()
|
||||
|
||||
return wr.WriteMsg(&msg)
|
||||
}
|
||||
|
||||
handleError := func(status pbv2.Status) {
|
||||
log.Debugf("protocol error: %s (%d)", pbv2.Status_name[int32(status)], status)
|
||||
err := writeResponse(status)
|
||||
if err != nil {
|
||||
s.Reset()
|
||||
log.Debugf("error writing circuit response: %s", err.Error())
|
||||
} else {
|
||||
s.Close()
|
||||
}
|
||||
}
|
||||
|
||||
var msg pbv2.StopMessage
|
||||
|
||||
err := rd.ReadMsg(&msg)
|
||||
if err != nil {
|
||||
handleError(pbv2.Status_MALFORMED_MESSAGE)
|
||||
return
|
||||
}
|
||||
// reset stream deadline as message has been read
|
||||
s.SetReadDeadline(time.Time{})
|
||||
|
||||
if msg.GetType() != pbv2.StopMessage_CONNECT {
|
||||
handleError(pbv2.Status_UNEXPECTED_MESSAGE)
|
||||
return
|
||||
}
|
||||
|
||||
src, err := util.PeerToPeerInfoV2(msg.GetPeer())
|
||||
if err != nil {
|
||||
handleError(pbv2.Status_MALFORMED_MESSAGE)
|
||||
return
|
||||
}
|
||||
|
||||
// check for a limit provided by the relay; if the limit is not nil, then this is a limited
|
||||
// relay connection and we mark the connection as transient.
|
||||
var stat network.ConnStats
|
||||
if limit := msg.GetLimit(); limit != nil {
|
||||
stat.Transient = true
|
||||
stat.Extra = make(map[interface{}]interface{})
|
||||
stat.Extra[StatLimitDuration] = time.Duration(limit.GetDuration()) * time.Second
|
||||
stat.Extra[StatLimitData] = limit.GetData()
|
||||
}
|
||||
|
||||
log.Debugf("incoming relay connection from: %s", src.ID)
|
||||
|
||||
select {
|
||||
case c.incoming <- accept{
|
||||
conn: &Conn{stream: s, remote: src, stat: stat, client: c},
|
||||
writeResponse: func() error {
|
||||
return writeResponse(pbv2.Status_OK)
|
||||
},
|
||||
}:
|
||||
case <-time.After(AcceptTimeout):
|
||||
handleError(pbv2.Status_CONNECTION_FAILED)
|
||||
}
|
||||
}
|
||||
54
vendor/github.com/libp2p/go-libp2p/p2p/protocol/circuitv2/client/listen.go
generated
vendored
Normal file
54
vendor/github.com/libp2p/go-libp2p/p2p/protocol/circuitv2/client/listen.go
generated
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"net"
|
||||
|
||||
"github.com/libp2p/go-libp2p/core/transport"
|
||||
ma "github.com/multiformats/go-multiaddr"
|
||||
manet "github.com/multiformats/go-multiaddr/net"
|
||||
)
|
||||
|
||||
var _ manet.Listener = (*Listener)(nil)
|
||||
|
||||
type Listener Client
|
||||
|
||||
func (c *Client) Listener() *Listener {
|
||||
return (*Listener)(c)
|
||||
}
|
||||
|
||||
func (l *Listener) Accept() (manet.Conn, error) {
|
||||
for {
|
||||
select {
|
||||
case evt := <-l.incoming:
|
||||
err := evt.writeResponse()
|
||||
if err != nil {
|
||||
log.Debugf("error writing relay response: %s", err.Error())
|
||||
evt.conn.stream.Reset()
|
||||
continue
|
||||
}
|
||||
|
||||
log.Debugf("accepted relay connection from %s through %s", evt.conn.remote.ID, evt.conn.RemoteMultiaddr())
|
||||
|
||||
evt.conn.tagHop()
|
||||
return evt.conn, nil
|
||||
|
||||
case <-l.ctx.Done():
|
||||
return nil, transport.ErrListenerClosed
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (l *Listener) Addr() net.Addr {
|
||||
return &NetAddr{
|
||||
Relay: "any",
|
||||
Remote: "any",
|
||||
}
|
||||
}
|
||||
|
||||
func (l *Listener) Multiaddr() ma.Multiaddr {
|
||||
return circuitAddr
|
||||
}
|
||||
|
||||
func (l *Listener) Close() error {
|
||||
return (*Client)(l).Close()
|
||||
}
|
||||
159
vendor/github.com/libp2p/go-libp2p/p2p/protocol/circuitv2/client/reservation.go
generated
vendored
Normal file
159
vendor/github.com/libp2p/go-libp2p/p2p/protocol/circuitv2/client/reservation.go
generated
vendored
Normal file
@@ -0,0 +1,159 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/libp2p/go-libp2p/core/host"
|
||||
"github.com/libp2p/go-libp2p/core/peer"
|
||||
"github.com/libp2p/go-libp2p/core/peerstore"
|
||||
"github.com/libp2p/go-libp2p/core/record"
|
||||
pbv2 "github.com/libp2p/go-libp2p/p2p/protocol/circuitv2/pb"
|
||||
"github.com/libp2p/go-libp2p/p2p/protocol/circuitv2/proto"
|
||||
"github.com/libp2p/go-libp2p/p2p/protocol/circuitv2/util"
|
||||
|
||||
ma "github.com/multiformats/go-multiaddr"
|
||||
)
|
||||
|
||||
var ReserveTimeout = time.Minute
|
||||
|
||||
// Reservation is a struct carrying information about a relay/v2 slot reservation.
|
||||
type Reservation struct {
|
||||
// Expiration is the expiration time of the reservation
|
||||
Expiration time.Time
|
||||
// Addrs contains the vouched public addresses of the reserving peer, which can be
|
||||
// announced to the network
|
||||
Addrs []ma.Multiaddr
|
||||
|
||||
// LimitDuration is the time limit for which the relay will keep a relayed connection
|
||||
// open. If 0, there is no limit.
|
||||
LimitDuration time.Duration
|
||||
// LimitData is the number of bytes that the relay will relay in each direction before
|
||||
// resetting a relayed connection.
|
||||
LimitData uint64
|
||||
|
||||
// Voucher is a signed reservation voucher provided by the relay
|
||||
Voucher *proto.ReservationVoucher
|
||||
}
|
||||
|
||||
// ReservationError is the error returned on failure to reserve a slot in the relay
|
||||
type ReservationError struct {
|
||||
|
||||
// Status is the status returned by the relay for rejecting the reservation
|
||||
// request. It is set to pbv2.Status_CONNECTION_FAILED on other failures
|
||||
Status pbv2.Status
|
||||
|
||||
// Reason is the reason for reservation failure
|
||||
Reason string
|
||||
|
||||
err error
|
||||
}
|
||||
|
||||
func (re ReservationError) Error() string {
|
||||
return fmt.Sprintf("reservation error: status: %s reason: %s err: %s", pbv2.Status_name[int32(re.Status)], re.Reason, re.err)
|
||||
}
|
||||
|
||||
func (re ReservationError) Unwrap() error {
|
||||
return re.err
|
||||
}
|
||||
|
||||
// Reserve reserves a slot in a relay and returns the reservation information.
|
||||
// Clients must reserve slots in order for the relay to relay connections to them.
|
||||
func Reserve(ctx context.Context, h host.Host, ai peer.AddrInfo) (*Reservation, error) {
|
||||
if len(ai.Addrs) > 0 {
|
||||
h.Peerstore().AddAddrs(ai.ID, ai.Addrs, peerstore.TempAddrTTL)
|
||||
}
|
||||
|
||||
s, err := h.NewStream(ctx, ai.ID, proto.ProtoIDv2Hop)
|
||||
if err != nil {
|
||||
return nil, ReservationError{Status: pbv2.Status_CONNECTION_FAILED, Reason: "failed to open stream", err: err}
|
||||
}
|
||||
defer s.Close()
|
||||
|
||||
rd := util.NewDelimitedReader(s, maxMessageSize)
|
||||
wr := util.NewDelimitedWriter(s)
|
||||
defer rd.Close()
|
||||
|
||||
var msg pbv2.HopMessage
|
||||
msg.Type = pbv2.HopMessage_RESERVE.Enum()
|
||||
|
||||
s.SetDeadline(time.Now().Add(ReserveTimeout))
|
||||
|
||||
if err := wr.WriteMsg(&msg); err != nil {
|
||||
s.Reset()
|
||||
return nil, ReservationError{Status: pbv2.Status_CONNECTION_FAILED, Reason: "error writing reservation message", err: err}
|
||||
}
|
||||
|
||||
msg.Reset()
|
||||
|
||||
if err := rd.ReadMsg(&msg); err != nil {
|
||||
s.Reset()
|
||||
return nil, ReservationError{Status: pbv2.Status_CONNECTION_FAILED, Reason: "error reading reservation response message: %w", err: err}
|
||||
}
|
||||
|
||||
if msg.GetType() != pbv2.HopMessage_STATUS {
|
||||
return nil, ReservationError{
|
||||
Status: pbv2.Status_MALFORMED_MESSAGE,
|
||||
Reason: fmt.Sprintf("unexpected relay response: not a status message (%d)", msg.GetType()),
|
||||
err: err}
|
||||
}
|
||||
|
||||
if status := msg.GetStatus(); status != pbv2.Status_OK {
|
||||
return nil, ReservationError{Status: msg.GetStatus(), Reason: "reservation failed"}
|
||||
}
|
||||
|
||||
rsvp := msg.GetReservation()
|
||||
if rsvp == nil {
|
||||
return nil, ReservationError{Status: pbv2.Status_MALFORMED_MESSAGE, Reason: "missing reservation info"}
|
||||
}
|
||||
|
||||
result := &Reservation{}
|
||||
result.Expiration = time.Unix(int64(rsvp.GetExpire()), 0)
|
||||
if result.Expiration.Before(time.Now()) {
|
||||
return nil, ReservationError{
|
||||
Status: pbv2.Status_MALFORMED_MESSAGE,
|
||||
Reason: fmt.Sprintf("received reservation with expiration date in the past: %s", result.Expiration),
|
||||
}
|
||||
}
|
||||
|
||||
addrs := rsvp.GetAddrs()
|
||||
result.Addrs = make([]ma.Multiaddr, 0, len(addrs))
|
||||
for _, ab := range addrs {
|
||||
a, err := ma.NewMultiaddrBytes(ab)
|
||||
if err != nil {
|
||||
log.Warnf("ignoring unparsable relay address: %s", err)
|
||||
continue
|
||||
}
|
||||
result.Addrs = append(result.Addrs, a)
|
||||
}
|
||||
|
||||
voucherBytes := rsvp.GetVoucher()
|
||||
if voucherBytes != nil {
|
||||
_, rec, err := record.ConsumeEnvelope(voucherBytes, proto.RecordDomain)
|
||||
if err != nil {
|
||||
return nil, ReservationError{
|
||||
Status: pbv2.Status_MALFORMED_MESSAGE,
|
||||
Reason: fmt.Sprintf("error consuming voucher envelope: %s", err),
|
||||
err: err,
|
||||
}
|
||||
}
|
||||
|
||||
voucher, ok := rec.(*proto.ReservationVoucher)
|
||||
if !ok {
|
||||
return nil, ReservationError{
|
||||
Status: pbv2.Status_MALFORMED_MESSAGE,
|
||||
Reason: fmt.Sprintf("unexpected voucher record type: %+T", rec),
|
||||
}
|
||||
}
|
||||
result.Voucher = voucher
|
||||
}
|
||||
|
||||
limit := msg.GetLimit()
|
||||
if limit != nil {
|
||||
result.LimitDuration = time.Duration(limit.GetDuration()) * time.Second
|
||||
result.LimitData = limit.GetData()
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
100
vendor/github.com/libp2p/go-libp2p/p2p/protocol/circuitv2/client/transport.go
generated
vendored
Normal file
100
vendor/github.com/libp2p/go-libp2p/p2p/protocol/circuitv2/client/transport.go
generated
vendored
Normal file
@@ -0,0 +1,100 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"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/core/transport"
|
||||
|
||||
ma "github.com/multiformats/go-multiaddr"
|
||||
)
|
||||
|
||||
var circuitProtocol = ma.ProtocolWithCode(ma.P_CIRCUIT)
|
||||
var circuitAddr = ma.Cast(circuitProtocol.VCode)
|
||||
|
||||
// AddTransport constructs a new p2p-circuit/v2 client and adds it as a transport to the
|
||||
// host network
|
||||
func AddTransport(h host.Host, upgrader transport.Upgrader) error {
|
||||
n, ok := h.Network().(transport.TransportNetwork)
|
||||
if !ok {
|
||||
return fmt.Errorf("%v is not a transport network", h.Network())
|
||||
}
|
||||
|
||||
c, err := New(h, upgrader)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error constructing circuit client: %w", err)
|
||||
}
|
||||
|
||||
err = n.AddTransport(c)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error adding circuit transport: %w", err)
|
||||
}
|
||||
|
||||
err = n.Listen(circuitAddr)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error listening to circuit addr: %w", err)
|
||||
}
|
||||
|
||||
c.Start()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Transport interface
|
||||
var _ transport.Transport = (*Client)(nil)
|
||||
var _ io.Closer = (*Client)(nil)
|
||||
|
||||
func (c *Client) Dial(ctx context.Context, a ma.Multiaddr, p peer.ID) (transport.CapableConn, error) {
|
||||
connScope, err := c.host.Network().ResourceManager().OpenConnection(network.DirOutbound, false, a)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
conn, err := c.dialAndUpgrade(ctx, a, p, connScope)
|
||||
if err != nil {
|
||||
connScope.Done()
|
||||
return nil, err
|
||||
}
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
func (c *Client) dialAndUpgrade(ctx context.Context, a ma.Multiaddr, p peer.ID, connScope network.ConnManagementScope) (transport.CapableConn, error) {
|
||||
if err := connScope.SetPeer(p); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
conn, err := c.dial(ctx, a, p)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
conn.tagHop()
|
||||
cc, err := c.upgrader.Upgrade(ctx, c, conn, network.DirOutbound, p, connScope)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return capableConn{cc.(capableConnWithStat)}, nil
|
||||
}
|
||||
|
||||
func (c *Client) CanDial(addr ma.Multiaddr) bool {
|
||||
_, err := addr.ValueForProtocol(ma.P_CIRCUIT)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
func (c *Client) Listen(addr ma.Multiaddr) (transport.Listener, error) {
|
||||
// TODO connect to the relay and reserve slot if specified
|
||||
if _, err := addr.ValueForProtocol(ma.P_CIRCUIT); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return c.upgrader.UpgradeListener(c, c.Listener()), nil
|
||||
}
|
||||
|
||||
func (c *Client) Protocols() []int {
|
||||
return []int{ma.P_CIRCUIT}
|
||||
}
|
||||
|
||||
func (c *Client) Proxy() bool {
|
||||
return true
|
||||
}
|
||||
Reference in New Issue
Block a user