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:
17
vendor/github.com/libp2p/go-libp2p/p2p/protocol/circuitv2/relay/acl.go
generated
vendored
Normal file
17
vendor/github.com/libp2p/go-libp2p/p2p/protocol/circuitv2/relay/acl.go
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
package relay
|
||||
|
||||
import (
|
||||
"github.com/libp2p/go-libp2p/core/peer"
|
||||
|
||||
ma "github.com/multiformats/go-multiaddr"
|
||||
)
|
||||
|
||||
// ACLFilter is an Access Control mechanism for relayed connect.
|
||||
type ACLFilter interface {
|
||||
// AllowReserve returns true if a reservation from a peer with the given peer ID and multiaddr
|
||||
// is allowed.
|
||||
AllowReserve(p peer.ID, a ma.Multiaddr) bool
|
||||
// AllowConnect returns true if a source peer, with a given multiaddr is allowed to connect
|
||||
// to a destination peer.
|
||||
AllowConnect(src peer.ID, srcAddr ma.Multiaddr, dest peer.ID) bool
|
||||
}
|
||||
128
vendor/github.com/libp2p/go-libp2p/p2p/protocol/circuitv2/relay/constraints.go
generated
vendored
Normal file
128
vendor/github.com/libp2p/go-libp2p/p2p/protocol/circuitv2/relay/constraints.go
generated
vendored
Normal file
@@ -0,0 +1,128 @@
|
||||
package relay
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
asnutil "github.com/libp2p/go-libp2p-asn-util"
|
||||
"github.com/libp2p/go-libp2p/core/peer"
|
||||
|
||||
ma "github.com/multiformats/go-multiaddr"
|
||||
manet "github.com/multiformats/go-multiaddr/net"
|
||||
)
|
||||
|
||||
var validity = 30 * time.Minute
|
||||
|
||||
var (
|
||||
errTooManyReservations = errors.New("too many reservations")
|
||||
errTooManyReservationsForPeer = errors.New("too many reservations for peer")
|
||||
errTooManyReservationsForIP = errors.New("too many peers for IP address")
|
||||
errTooManyReservationsForASN = errors.New("too many peers for ASN")
|
||||
)
|
||||
|
||||
// constraints implements various reservation constraints
|
||||
type constraints struct {
|
||||
rc *Resources
|
||||
|
||||
mutex sync.Mutex
|
||||
total []time.Time
|
||||
peers map[peer.ID][]time.Time
|
||||
ips map[string][]time.Time
|
||||
asns map[string][]time.Time
|
||||
}
|
||||
|
||||
// newConstraints creates a new constraints object.
|
||||
// The methods are *not* thread-safe; an external lock must be held if synchronization
|
||||
// is required.
|
||||
func newConstraints(rc *Resources) *constraints {
|
||||
return &constraints{
|
||||
rc: rc,
|
||||
peers: make(map[peer.ID][]time.Time),
|
||||
ips: make(map[string][]time.Time),
|
||||
asns: make(map[string][]time.Time),
|
||||
}
|
||||
}
|
||||
|
||||
// AddReservation adds a reservation for a given peer with a given multiaddr.
|
||||
// If adding this reservation violates IP constraints, an error is returned.
|
||||
func (c *constraints) AddReservation(p peer.ID, a ma.Multiaddr) error {
|
||||
c.mutex.Lock()
|
||||
defer c.mutex.Unlock()
|
||||
|
||||
now := time.Now()
|
||||
c.cleanup(now)
|
||||
|
||||
if len(c.total) >= c.rc.MaxReservations {
|
||||
return errTooManyReservations
|
||||
}
|
||||
|
||||
ip, err := manet.ToIP(a)
|
||||
if err != nil {
|
||||
return errors.New("no IP address associated with peer")
|
||||
}
|
||||
|
||||
peerReservations := c.peers[p]
|
||||
if len(peerReservations) >= c.rc.MaxReservationsPerPeer {
|
||||
return errTooManyReservationsForPeer
|
||||
}
|
||||
|
||||
ipReservations := c.ips[ip.String()]
|
||||
if len(ipReservations) >= c.rc.MaxReservationsPerIP {
|
||||
return errTooManyReservationsForIP
|
||||
}
|
||||
|
||||
var asnReservations []time.Time
|
||||
var asn string
|
||||
// Only public addresses have an ASN. Skip checking ASN for private addresses as
|
||||
// initialising the ASN store is a costly operation. Skipping this check reduces a lot of
|
||||
// flakiness in tests
|
||||
if ip.To4() == nil && manet.IsPublicAddr(a) {
|
||||
asn, _ = asnutil.Store.AsnForIPv6(ip)
|
||||
if asn != "" {
|
||||
asnReservations = c.asns[asn]
|
||||
if len(asnReservations) >= c.rc.MaxReservationsPerASN {
|
||||
return errTooManyReservationsForASN
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
expiry := now.Add(validity)
|
||||
c.total = append(c.total, expiry)
|
||||
|
||||
peerReservations = append(peerReservations, expiry)
|
||||
c.peers[p] = peerReservations
|
||||
|
||||
ipReservations = append(ipReservations, expiry)
|
||||
c.ips[ip.String()] = ipReservations
|
||||
|
||||
if asn != "" {
|
||||
asnReservations = append(asnReservations, expiry)
|
||||
c.asns[asn] = asnReservations
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *constraints) cleanupList(l []time.Time, now time.Time) []time.Time {
|
||||
var index int
|
||||
for i, t := range l {
|
||||
if t.After(now) {
|
||||
break
|
||||
}
|
||||
index = i + 1
|
||||
}
|
||||
return l[index:]
|
||||
}
|
||||
|
||||
func (c *constraints) cleanup(now time.Time) {
|
||||
c.total = c.cleanupList(c.total, now)
|
||||
for k, peerReservations := range c.peers {
|
||||
c.peers[k] = c.cleanupList(peerReservations, now)
|
||||
}
|
||||
for k, ipReservations := range c.ips {
|
||||
c.ips[k] = c.cleanupList(ipReservations, now)
|
||||
}
|
||||
for k, asnReservations := range c.asns {
|
||||
c.asns[k] = c.cleanupList(asnReservations, now)
|
||||
}
|
||||
}
|
||||
268
vendor/github.com/libp2p/go-libp2p/p2p/protocol/circuitv2/relay/metrics.go
generated
vendored
Normal file
268
vendor/github.com/libp2p/go-libp2p/p2p/protocol/circuitv2/relay/metrics.go
generated
vendored
Normal file
@@ -0,0 +1,268 @@
|
||||
package relay
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/libp2p/go-libp2p/p2p/metricshelper"
|
||||
pbv2 "github.com/libp2p/go-libp2p/p2p/protocol/circuitv2/pb"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
)
|
||||
|
||||
const metricNamespace = "libp2p_relaysvc"
|
||||
|
||||
var (
|
||||
status = prometheus.NewGauge(
|
||||
prometheus.GaugeOpts{
|
||||
Namespace: metricNamespace,
|
||||
Name: "status",
|
||||
Help: "Relay Status",
|
||||
},
|
||||
)
|
||||
|
||||
reservationsTotal = prometheus.NewCounterVec(
|
||||
prometheus.CounterOpts{
|
||||
Namespace: metricNamespace,
|
||||
Name: "reservations_total",
|
||||
Help: "Relay Reservation Request",
|
||||
},
|
||||
[]string{"type"},
|
||||
)
|
||||
reservationRequestResponseStatusTotal = prometheus.NewCounterVec(
|
||||
prometheus.CounterOpts{
|
||||
Namespace: metricNamespace,
|
||||
Name: "reservation_request_response_status_total",
|
||||
Help: "Relay Reservation Request Response Status",
|
||||
},
|
||||
[]string{"status"},
|
||||
)
|
||||
reservationRejectionsTotal = prometheus.NewCounterVec(
|
||||
prometheus.CounterOpts{
|
||||
Namespace: metricNamespace,
|
||||
Name: "reservation_rejections_total",
|
||||
Help: "Relay Reservation Rejected Reason",
|
||||
},
|
||||
[]string{"reason"},
|
||||
)
|
||||
|
||||
connectionsTotal = prometheus.NewCounterVec(
|
||||
prometheus.CounterOpts{
|
||||
Namespace: metricNamespace,
|
||||
Name: "connections_total",
|
||||
Help: "Relay Connection Total",
|
||||
},
|
||||
[]string{"type"},
|
||||
)
|
||||
connectionRequestResponseStatusTotal = prometheus.NewCounterVec(
|
||||
prometheus.CounterOpts{
|
||||
Namespace: metricNamespace,
|
||||
Name: "connection_request_response_status_total",
|
||||
Help: "Relay Connection Request Status",
|
||||
},
|
||||
[]string{"status"},
|
||||
)
|
||||
connectionRejectionsTotal = prometheus.NewCounterVec(
|
||||
prometheus.CounterOpts{
|
||||
Namespace: metricNamespace,
|
||||
Name: "connection_rejections_total",
|
||||
Help: "Relay Connection Rejected Reason",
|
||||
},
|
||||
[]string{"reason"},
|
||||
)
|
||||
connectionDurationSeconds = prometheus.NewHistogram(
|
||||
prometheus.HistogramOpts{
|
||||
Namespace: metricNamespace,
|
||||
Name: "connection_duration_seconds",
|
||||
Help: "Relay Connection Duration",
|
||||
},
|
||||
)
|
||||
|
||||
dataTransferredBytesTotal = prometheus.NewCounter(
|
||||
prometheus.CounterOpts{
|
||||
Namespace: metricNamespace,
|
||||
Name: "data_transferred_bytes_total",
|
||||
Help: "Bytes Transferred Total",
|
||||
},
|
||||
)
|
||||
|
||||
collectors = []prometheus.Collector{
|
||||
status,
|
||||
reservationsTotal,
|
||||
reservationRequestResponseStatusTotal,
|
||||
reservationRejectionsTotal,
|
||||
connectionsTotal,
|
||||
connectionRequestResponseStatusTotal,
|
||||
connectionRejectionsTotal,
|
||||
connectionDurationSeconds,
|
||||
dataTransferredBytesTotal,
|
||||
}
|
||||
)
|
||||
|
||||
const (
|
||||
requestStatusOK = "ok"
|
||||
requestStatusRejected = "rejected"
|
||||
requestStatusError = "error"
|
||||
)
|
||||
|
||||
// MetricsTracer is the interface for tracking metrics for relay service
|
||||
type MetricsTracer interface {
|
||||
// RelayStatus tracks whether the service is currently active
|
||||
RelayStatus(enabled bool)
|
||||
|
||||
// ConnectionOpened tracks metrics on opening a relay connection
|
||||
ConnectionOpened()
|
||||
// ConnectionClosed tracks metrics on closing a relay connection
|
||||
ConnectionClosed(d time.Duration)
|
||||
// ConnectionRequestHandled tracks metrics on handling a relay connection request
|
||||
ConnectionRequestHandled(status pbv2.Status)
|
||||
|
||||
// ReservationAllowed tracks metrics on opening or renewing a relay reservation
|
||||
ReservationAllowed(isRenewal bool)
|
||||
// ReservationRequestClosed tracks metrics on closing a relay reservation
|
||||
ReservationClosed(cnt int)
|
||||
// ReservationRequestHandled tracks metrics on handling a relay reservation request
|
||||
ReservationRequestHandled(status pbv2.Status)
|
||||
|
||||
// BytesTransferred tracks the total bytes transferred by the relay service
|
||||
BytesTransferred(cnt int)
|
||||
}
|
||||
|
||||
type metricsTracer struct{}
|
||||
|
||||
var _ MetricsTracer = &metricsTracer{}
|
||||
|
||||
type metricsTracerSetting struct {
|
||||
reg prometheus.Registerer
|
||||
}
|
||||
|
||||
type MetricsTracerOption func(*metricsTracerSetting)
|
||||
|
||||
func WithRegisterer(reg prometheus.Registerer) MetricsTracerOption {
|
||||
return func(s *metricsTracerSetting) {
|
||||
if reg != nil {
|
||||
s.reg = reg
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func NewMetricsTracer(opts ...MetricsTracerOption) MetricsTracer {
|
||||
setting := &metricsTracerSetting{reg: prometheus.DefaultRegisterer}
|
||||
for _, opt := range opts {
|
||||
opt(setting)
|
||||
}
|
||||
metricshelper.RegisterCollectors(setting.reg, collectors...)
|
||||
return &metricsTracer{}
|
||||
}
|
||||
|
||||
func (mt *metricsTracer) RelayStatus(enabled bool) {
|
||||
if enabled {
|
||||
status.Set(1)
|
||||
} else {
|
||||
status.Set(0)
|
||||
}
|
||||
}
|
||||
|
||||
func (mt *metricsTracer) ConnectionOpened() {
|
||||
tags := metricshelper.GetStringSlice()
|
||||
defer metricshelper.PutStringSlice(tags)
|
||||
*tags = append(*tags, "opened")
|
||||
|
||||
connectionsTotal.WithLabelValues(*tags...).Add(1)
|
||||
}
|
||||
|
||||
func (mt *metricsTracer) ConnectionClosed(d time.Duration) {
|
||||
tags := metricshelper.GetStringSlice()
|
||||
defer metricshelper.PutStringSlice(tags)
|
||||
*tags = append(*tags, "closed")
|
||||
|
||||
connectionsTotal.WithLabelValues(*tags...).Add(1)
|
||||
connectionDurationSeconds.Observe(d.Seconds())
|
||||
}
|
||||
|
||||
func (mt *metricsTracer) ConnectionRequestHandled(status pbv2.Status) {
|
||||
tags := metricshelper.GetStringSlice()
|
||||
defer metricshelper.PutStringSlice(tags)
|
||||
|
||||
respStatus := getResponseStatus(status)
|
||||
|
||||
*tags = append(*tags, respStatus)
|
||||
connectionRequestResponseStatusTotal.WithLabelValues(*tags...).Add(1)
|
||||
if respStatus == requestStatusRejected {
|
||||
*tags = (*tags)[:0]
|
||||
*tags = append(*tags, getRejectionReason(status))
|
||||
connectionRejectionsTotal.WithLabelValues(*tags...).Add(1)
|
||||
}
|
||||
}
|
||||
|
||||
func (mt *metricsTracer) ReservationAllowed(isRenewal bool) {
|
||||
tags := metricshelper.GetStringSlice()
|
||||
defer metricshelper.PutStringSlice(tags)
|
||||
if isRenewal {
|
||||
*tags = append(*tags, "renewed")
|
||||
} else {
|
||||
*tags = append(*tags, "opened")
|
||||
}
|
||||
|
||||
reservationsTotal.WithLabelValues(*tags...).Add(1)
|
||||
}
|
||||
|
||||
func (mt *metricsTracer) ReservationClosed(cnt int) {
|
||||
tags := metricshelper.GetStringSlice()
|
||||
defer metricshelper.PutStringSlice(tags)
|
||||
*tags = append(*tags, "closed")
|
||||
|
||||
reservationsTotal.WithLabelValues(*tags...).Add(float64(cnt))
|
||||
}
|
||||
|
||||
func (mt *metricsTracer) ReservationRequestHandled(status pbv2.Status) {
|
||||
tags := metricshelper.GetStringSlice()
|
||||
defer metricshelper.PutStringSlice(tags)
|
||||
|
||||
respStatus := getResponseStatus(status)
|
||||
|
||||
*tags = append(*tags, respStatus)
|
||||
reservationRequestResponseStatusTotal.WithLabelValues(*tags...).Add(1)
|
||||
if respStatus == requestStatusRejected {
|
||||
*tags = (*tags)[:0]
|
||||
*tags = append(*tags, getRejectionReason(status))
|
||||
reservationRejectionsTotal.WithLabelValues(*tags...).Add(1)
|
||||
}
|
||||
}
|
||||
|
||||
func (mt *metricsTracer) BytesTransferred(cnt int) {
|
||||
dataTransferredBytesTotal.Add(float64(cnt))
|
||||
}
|
||||
|
||||
func getResponseStatus(status pbv2.Status) string {
|
||||
responseStatus := "unknown"
|
||||
switch status {
|
||||
case pbv2.Status_RESERVATION_REFUSED,
|
||||
pbv2.Status_RESOURCE_LIMIT_EXCEEDED,
|
||||
pbv2.Status_PERMISSION_DENIED,
|
||||
pbv2.Status_NO_RESERVATION,
|
||||
pbv2.Status_MALFORMED_MESSAGE:
|
||||
|
||||
responseStatus = requestStatusRejected
|
||||
case pbv2.Status_UNEXPECTED_MESSAGE, pbv2.Status_CONNECTION_FAILED:
|
||||
responseStatus = requestStatusError
|
||||
case pbv2.Status_OK:
|
||||
responseStatus = requestStatusOK
|
||||
}
|
||||
return responseStatus
|
||||
}
|
||||
|
||||
func getRejectionReason(status pbv2.Status) string {
|
||||
reason := "unknown"
|
||||
switch status {
|
||||
case pbv2.Status_RESERVATION_REFUSED:
|
||||
reason = "ip constraint violation"
|
||||
case pbv2.Status_RESOURCE_LIMIT_EXCEEDED:
|
||||
reason = "resource limit exceeded"
|
||||
case pbv2.Status_PERMISSION_DENIED:
|
||||
reason = "permission denied"
|
||||
case pbv2.Status_NO_RESERVATION:
|
||||
reason = "no reservation"
|
||||
case pbv2.Status_MALFORMED_MESSAGE:
|
||||
reason = "malformed message"
|
||||
}
|
||||
return reason
|
||||
}
|
||||
43
vendor/github.com/libp2p/go-libp2p/p2p/protocol/circuitv2/relay/options.go
generated
vendored
Normal file
43
vendor/github.com/libp2p/go-libp2p/p2p/protocol/circuitv2/relay/options.go
generated
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
package relay
|
||||
|
||||
type Option func(*Relay) error
|
||||
|
||||
// WithResources is a Relay option that sets specific relay resources for the relay.
|
||||
func WithResources(rc Resources) Option {
|
||||
return func(r *Relay) error {
|
||||
r.rc = rc
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithLimit is a Relay option that sets only the relayed connection limits for the relay.
|
||||
func WithLimit(limit *RelayLimit) Option {
|
||||
return func(r *Relay) error {
|
||||
r.rc.Limit = limit
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithInfiniteLimits is a Relay option that disables limits.
|
||||
func WithInfiniteLimits() Option {
|
||||
return func(r *Relay) error {
|
||||
r.rc.Limit = nil
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithACL is a Relay option that supplies an ACLFilter for access control.
|
||||
func WithACL(acl ACLFilter) Option {
|
||||
return func(r *Relay) error {
|
||||
r.acl = acl
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithMetricsTracer is a Relay option that supplies a MetricsTracer for metrics
|
||||
func WithMetricsTracer(mt MetricsTracer) Option {
|
||||
return func(r *Relay) error {
|
||||
r.metricsTracer = mt
|
||||
return nil
|
||||
}
|
||||
}
|
||||
687
vendor/github.com/libp2p/go-libp2p/p2p/protocol/circuitv2/relay/relay.go
generated
vendored
Normal file
687
vendor/github.com/libp2p/go-libp2p/p2p/protocol/circuitv2/relay/relay.go
generated
vendored
Normal file
@@ -0,0 +1,687 @@
|
||||
package relay
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"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/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"
|
||||
|
||||
logging "github.com/ipfs/go-log/v2"
|
||||
pool "github.com/libp2p/go-buffer-pool"
|
||||
asnutil "github.com/libp2p/go-libp2p-asn-util"
|
||||
ma "github.com/multiformats/go-multiaddr"
|
||||
manet "github.com/multiformats/go-multiaddr/net"
|
||||
)
|
||||
|
||||
const (
|
||||
ServiceName = "libp2p.relay/v2"
|
||||
|
||||
ReservationTagWeight = 10
|
||||
|
||||
StreamTimeout = time.Minute
|
||||
ConnectTimeout = 30 * time.Second
|
||||
HandshakeTimeout = time.Minute
|
||||
|
||||
relayHopTag = "relay-v2-hop"
|
||||
relayHopTagValue = 2
|
||||
|
||||
maxMessageSize = 4096
|
||||
)
|
||||
|
||||
var log = logging.Logger("relay")
|
||||
|
||||
// Relay is the (limited) relay service object.
|
||||
type Relay struct {
|
||||
ctx context.Context
|
||||
cancel func()
|
||||
|
||||
host host.Host
|
||||
rc Resources
|
||||
acl ACLFilter
|
||||
constraints *constraints
|
||||
scope network.ResourceScopeSpan
|
||||
notifiee network.Notifiee
|
||||
|
||||
mx sync.Mutex
|
||||
rsvp map[peer.ID]time.Time
|
||||
conns map[peer.ID]int
|
||||
closed bool
|
||||
|
||||
selfAddr ma.Multiaddr
|
||||
|
||||
metricsTracer MetricsTracer
|
||||
}
|
||||
|
||||
// New constructs a new limited relay that can provide relay services in the given host.
|
||||
func New(h host.Host, opts ...Option) (*Relay, error) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
|
||||
r := &Relay{
|
||||
ctx: ctx,
|
||||
cancel: cancel,
|
||||
host: h,
|
||||
rc: DefaultResources(),
|
||||
acl: nil,
|
||||
rsvp: make(map[peer.ID]time.Time),
|
||||
conns: make(map[peer.ID]int),
|
||||
}
|
||||
|
||||
for _, opt := range opts {
|
||||
err := opt(r)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error applying relay option: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
// get a scope for memory reservations at service level
|
||||
err := h.Network().ResourceManager().ViewService(ServiceName,
|
||||
func(s network.ServiceScope) error {
|
||||
var err error
|
||||
r.scope, err = s.BeginSpan()
|
||||
return err
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
r.constraints = newConstraints(&r.rc)
|
||||
r.selfAddr = ma.StringCast(fmt.Sprintf("/p2p/%s", h.ID()))
|
||||
|
||||
h.SetStreamHandler(proto.ProtoIDv2Hop, r.handleStream)
|
||||
r.notifiee = &network.NotifyBundle{DisconnectedF: r.disconnected}
|
||||
h.Network().Notify(r.notifiee)
|
||||
|
||||
if r.metricsTracer != nil {
|
||||
r.metricsTracer.RelayStatus(true)
|
||||
}
|
||||
go r.background()
|
||||
|
||||
return r, nil
|
||||
}
|
||||
|
||||
func (r *Relay) Close() error {
|
||||
r.mx.Lock()
|
||||
if !r.closed {
|
||||
r.closed = true
|
||||
r.mx.Unlock()
|
||||
|
||||
r.host.RemoveStreamHandler(proto.ProtoIDv2Hop)
|
||||
r.host.Network().StopNotify(r.notifiee)
|
||||
r.scope.Done()
|
||||
r.cancel()
|
||||
r.gc()
|
||||
if r.metricsTracer != nil {
|
||||
r.metricsTracer.RelayStatus(false)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
r.mx.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Relay) handleStream(s network.Stream) {
|
||||
log.Infof("new relay stream from: %s", s.Conn().RemotePeer())
|
||||
|
||||
if err := s.Scope().SetService(ServiceName); err != nil {
|
||||
log.Debugf("error attaching stream to relay service: %s", err)
|
||||
s.Reset()
|
||||
return
|
||||
}
|
||||
|
||||
if err := s.Scope().ReserveMemory(maxMessageSize, network.ReservationPriorityAlways); err != nil {
|
||||
log.Debugf("error reserving memory for stream: %s", err)
|
||||
s.Reset()
|
||||
return
|
||||
}
|
||||
defer s.Scope().ReleaseMemory(maxMessageSize)
|
||||
|
||||
rd := util.NewDelimitedReader(s, maxMessageSize)
|
||||
defer rd.Close()
|
||||
|
||||
s.SetReadDeadline(time.Now().Add(StreamTimeout))
|
||||
|
||||
var msg pbv2.HopMessage
|
||||
|
||||
err := rd.ReadMsg(&msg)
|
||||
if err != nil {
|
||||
r.handleError(s, pbv2.Status_MALFORMED_MESSAGE)
|
||||
return
|
||||
}
|
||||
// reset stream deadline as message has been read
|
||||
s.SetReadDeadline(time.Time{})
|
||||
switch msg.GetType() {
|
||||
case pbv2.HopMessage_RESERVE:
|
||||
status := r.handleReserve(s)
|
||||
if r.metricsTracer != nil {
|
||||
r.metricsTracer.ReservationRequestHandled(status)
|
||||
}
|
||||
case pbv2.HopMessage_CONNECT:
|
||||
status := r.handleConnect(s, &msg)
|
||||
if r.metricsTracer != nil {
|
||||
r.metricsTracer.ConnectionRequestHandled(status)
|
||||
}
|
||||
default:
|
||||
r.handleError(s, pbv2.Status_MALFORMED_MESSAGE)
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Relay) handleReserve(s network.Stream) pbv2.Status {
|
||||
defer s.Close()
|
||||
p := s.Conn().RemotePeer()
|
||||
a := s.Conn().RemoteMultiaddr()
|
||||
|
||||
if isRelayAddr(a) {
|
||||
log.Debugf("refusing relay reservation for %s; reservation attempt over relay connection")
|
||||
r.handleError(s, pbv2.Status_PERMISSION_DENIED)
|
||||
return pbv2.Status_PERMISSION_DENIED
|
||||
}
|
||||
|
||||
if r.acl != nil && !r.acl.AllowReserve(p, a) {
|
||||
log.Debugf("refusing relay reservation for %s; permission denied", p)
|
||||
r.handleError(s, pbv2.Status_PERMISSION_DENIED)
|
||||
return pbv2.Status_PERMISSION_DENIED
|
||||
}
|
||||
|
||||
r.mx.Lock()
|
||||
// Check if relay is still active. Otherwise ConnManager.UnTagPeer will not be called if this block runs after
|
||||
// Close() call
|
||||
if r.closed {
|
||||
r.mx.Unlock()
|
||||
log.Debugf("refusing relay reservation for %s; relay closed", p)
|
||||
r.handleError(s, pbv2.Status_PERMISSION_DENIED)
|
||||
return pbv2.Status_PERMISSION_DENIED
|
||||
}
|
||||
now := time.Now()
|
||||
|
||||
_, exists := r.rsvp[p]
|
||||
if !exists {
|
||||
if err := r.constraints.AddReservation(p, a); err != nil {
|
||||
r.mx.Unlock()
|
||||
log.Debugf("refusing relay reservation for %s; IP constraint violation: %s", p, err)
|
||||
r.handleError(s, pbv2.Status_RESERVATION_REFUSED)
|
||||
return pbv2.Status_RESERVATION_REFUSED
|
||||
}
|
||||
}
|
||||
|
||||
expire := now.Add(r.rc.ReservationTTL)
|
||||
r.rsvp[p] = expire
|
||||
r.host.ConnManager().TagPeer(p, "relay-reservation", ReservationTagWeight)
|
||||
r.mx.Unlock()
|
||||
if r.metricsTracer != nil {
|
||||
r.metricsTracer.ReservationAllowed(exists)
|
||||
}
|
||||
|
||||
log.Debugf("reserving relay slot for %s", p)
|
||||
|
||||
// Delivery of the reservation might fail for a number of reasons.
|
||||
// For example, the stream might be reset or the connection might be closed before the reservation is received.
|
||||
// In that case, the reservation will just be garbage collected later.
|
||||
if err := r.writeResponse(s, pbv2.Status_OK, r.makeReservationMsg(p, expire), r.makeLimitMsg(p)); err != nil {
|
||||
log.Debugf("error writing reservation response; retracting reservation for %s", p)
|
||||
s.Reset()
|
||||
return pbv2.Status_CONNECTION_FAILED
|
||||
}
|
||||
return pbv2.Status_OK
|
||||
}
|
||||
|
||||
func (r *Relay) handleConnect(s network.Stream, msg *pbv2.HopMessage) pbv2.Status {
|
||||
src := s.Conn().RemotePeer()
|
||||
a := s.Conn().RemoteMultiaddr()
|
||||
|
||||
span, err := r.scope.BeginSpan()
|
||||
if err != nil {
|
||||
log.Debugf("failed to begin relay transaction: %s", err)
|
||||
r.handleError(s, pbv2.Status_RESOURCE_LIMIT_EXCEEDED)
|
||||
return pbv2.Status_RESOURCE_LIMIT_EXCEEDED
|
||||
}
|
||||
|
||||
fail := func(status pbv2.Status) {
|
||||
span.Done()
|
||||
r.handleError(s, status)
|
||||
}
|
||||
|
||||
// reserve buffers for the relay
|
||||
if err := span.ReserveMemory(2*r.rc.BufferSize, network.ReservationPriorityHigh); err != nil {
|
||||
log.Debugf("error reserving memory for relay: %s", err)
|
||||
fail(pbv2.Status_RESOURCE_LIMIT_EXCEEDED)
|
||||
return pbv2.Status_RESOURCE_LIMIT_EXCEEDED
|
||||
}
|
||||
|
||||
if isRelayAddr(a) {
|
||||
log.Debugf("refusing connection from %s; connection attempt over relay connection")
|
||||
fail(pbv2.Status_PERMISSION_DENIED)
|
||||
return pbv2.Status_PERMISSION_DENIED
|
||||
}
|
||||
|
||||
dest, err := util.PeerToPeerInfoV2(msg.GetPeer())
|
||||
if err != nil {
|
||||
fail(pbv2.Status_MALFORMED_MESSAGE)
|
||||
return pbv2.Status_MALFORMED_MESSAGE
|
||||
}
|
||||
|
||||
if r.acl != nil && !r.acl.AllowConnect(src, s.Conn().RemoteMultiaddr(), dest.ID) {
|
||||
log.Debugf("refusing connection from %s to %s; permission denied", src, dest.ID)
|
||||
fail(pbv2.Status_PERMISSION_DENIED)
|
||||
return pbv2.Status_PERMISSION_DENIED
|
||||
}
|
||||
|
||||
r.mx.Lock()
|
||||
_, rsvp := r.rsvp[dest.ID]
|
||||
if !rsvp {
|
||||
r.mx.Unlock()
|
||||
log.Debugf("refusing connection from %s to %s; no reservation", src, dest.ID)
|
||||
fail(pbv2.Status_NO_RESERVATION)
|
||||
return pbv2.Status_NO_RESERVATION
|
||||
}
|
||||
|
||||
srcConns := r.conns[src]
|
||||
if srcConns >= r.rc.MaxCircuits {
|
||||
r.mx.Unlock()
|
||||
log.Debugf("refusing connection from %s to %s; too many connections from %s", src, dest.ID, src)
|
||||
fail(pbv2.Status_RESOURCE_LIMIT_EXCEEDED)
|
||||
return pbv2.Status_RESOURCE_LIMIT_EXCEEDED
|
||||
}
|
||||
|
||||
destConns := r.conns[dest.ID]
|
||||
if destConns >= r.rc.MaxCircuits {
|
||||
r.mx.Unlock()
|
||||
log.Debugf("refusing connection from %s to %s; too many connecitons to %s", src, dest.ID, dest.ID)
|
||||
fail(pbv2.Status_RESOURCE_LIMIT_EXCEEDED)
|
||||
return pbv2.Status_RESOURCE_LIMIT_EXCEEDED
|
||||
}
|
||||
|
||||
r.addConn(src)
|
||||
r.addConn(dest.ID)
|
||||
r.mx.Unlock()
|
||||
|
||||
if r.metricsTracer != nil {
|
||||
r.metricsTracer.ConnectionOpened()
|
||||
}
|
||||
connStTime := time.Now()
|
||||
|
||||
cleanup := func() {
|
||||
span.Done()
|
||||
r.mx.Lock()
|
||||
r.rmConn(src)
|
||||
r.rmConn(dest.ID)
|
||||
r.mx.Unlock()
|
||||
if r.metricsTracer != nil {
|
||||
r.metricsTracer.ConnectionClosed(time.Since(connStTime))
|
||||
}
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(r.ctx, ConnectTimeout)
|
||||
defer cancel()
|
||||
|
||||
ctx = network.WithNoDial(ctx, "relay connect")
|
||||
|
||||
bs, err := r.host.NewStream(ctx, dest.ID, proto.ProtoIDv2Stop)
|
||||
if err != nil {
|
||||
log.Debugf("error opening relay stream to %s: %s", dest.ID, err)
|
||||
cleanup()
|
||||
r.handleError(s, pbv2.Status_CONNECTION_FAILED)
|
||||
return pbv2.Status_CONNECTION_FAILED
|
||||
}
|
||||
|
||||
fail = func(status pbv2.Status) {
|
||||
bs.Reset()
|
||||
cleanup()
|
||||
r.handleError(s, status)
|
||||
}
|
||||
|
||||
if err := bs.Scope().SetService(ServiceName); err != nil {
|
||||
log.Debugf("error attaching stream to relay service: %s", err)
|
||||
fail(pbv2.Status_RESOURCE_LIMIT_EXCEEDED)
|
||||
return pbv2.Status_RESOURCE_LIMIT_EXCEEDED
|
||||
}
|
||||
|
||||
// handshake
|
||||
if err := bs.Scope().ReserveMemory(maxMessageSize, network.ReservationPriorityAlways); err != nil {
|
||||
log.Debugf("error reserving memory for stream: %s", err)
|
||||
fail(pbv2.Status_RESOURCE_LIMIT_EXCEEDED)
|
||||
return pbv2.Status_RESOURCE_LIMIT_EXCEEDED
|
||||
}
|
||||
defer bs.Scope().ReleaseMemory(maxMessageSize)
|
||||
|
||||
rd := util.NewDelimitedReader(bs, maxMessageSize)
|
||||
wr := util.NewDelimitedWriter(bs)
|
||||
defer rd.Close()
|
||||
|
||||
var stopmsg pbv2.StopMessage
|
||||
stopmsg.Type = pbv2.StopMessage_CONNECT.Enum()
|
||||
stopmsg.Peer = util.PeerInfoToPeerV2(peer.AddrInfo{ID: src})
|
||||
stopmsg.Limit = r.makeLimitMsg(dest.ID)
|
||||
|
||||
bs.SetDeadline(time.Now().Add(HandshakeTimeout))
|
||||
|
||||
err = wr.WriteMsg(&stopmsg)
|
||||
if err != nil {
|
||||
log.Debugf("error writing stop handshake")
|
||||
fail(pbv2.Status_CONNECTION_FAILED)
|
||||
return pbv2.Status_CONNECTION_FAILED
|
||||
}
|
||||
|
||||
stopmsg.Reset()
|
||||
|
||||
err = rd.ReadMsg(&stopmsg)
|
||||
if err != nil {
|
||||
log.Debugf("error reading stop response: %s", err.Error())
|
||||
fail(pbv2.Status_CONNECTION_FAILED)
|
||||
return pbv2.Status_CONNECTION_FAILED
|
||||
}
|
||||
|
||||
if t := stopmsg.GetType(); t != pbv2.StopMessage_STATUS {
|
||||
log.Debugf("unexpected stop response; not a status message (%d)", t)
|
||||
fail(pbv2.Status_CONNECTION_FAILED)
|
||||
return pbv2.Status_CONNECTION_FAILED
|
||||
}
|
||||
|
||||
if status := stopmsg.GetStatus(); status != pbv2.Status_OK {
|
||||
log.Debugf("relay stop failure: %d", status)
|
||||
fail(pbv2.Status_CONNECTION_FAILED)
|
||||
return pbv2.Status_CONNECTION_FAILED
|
||||
}
|
||||
|
||||
var response pbv2.HopMessage
|
||||
response.Type = pbv2.HopMessage_STATUS.Enum()
|
||||
response.Status = pbv2.Status_OK.Enum()
|
||||
response.Limit = r.makeLimitMsg(dest.ID)
|
||||
|
||||
wr = util.NewDelimitedWriter(s)
|
||||
err = wr.WriteMsg(&response)
|
||||
if err != nil {
|
||||
log.Debugf("error writing relay response: %s", err)
|
||||
bs.Reset()
|
||||
s.Reset()
|
||||
cleanup()
|
||||
return pbv2.Status_CONNECTION_FAILED
|
||||
}
|
||||
|
||||
// reset deadline
|
||||
bs.SetDeadline(time.Time{})
|
||||
|
||||
log.Infof("relaying connection from %s to %s", src, dest.ID)
|
||||
|
||||
var goroutines atomic.Int32
|
||||
goroutines.Store(2)
|
||||
|
||||
done := func() {
|
||||
if goroutines.Add(-1) == 0 {
|
||||
s.Close()
|
||||
bs.Close()
|
||||
cleanup()
|
||||
}
|
||||
}
|
||||
|
||||
if r.rc.Limit != nil {
|
||||
deadline := time.Now().Add(r.rc.Limit.Duration)
|
||||
s.SetDeadline(deadline)
|
||||
bs.SetDeadline(deadline)
|
||||
go r.relayLimited(s, bs, src, dest.ID, r.rc.Limit.Data, done)
|
||||
go r.relayLimited(bs, s, dest.ID, src, r.rc.Limit.Data, done)
|
||||
} else {
|
||||
go r.relayUnlimited(s, bs, src, dest.ID, done)
|
||||
go r.relayUnlimited(bs, s, dest.ID, src, done)
|
||||
}
|
||||
|
||||
return pbv2.Status_OK
|
||||
}
|
||||
|
||||
func (r *Relay) addConn(p peer.ID) {
|
||||
conns := r.conns[p]
|
||||
conns++
|
||||
r.conns[p] = conns
|
||||
if conns == 1 {
|
||||
r.host.ConnManager().TagPeer(p, relayHopTag, relayHopTagValue)
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Relay) rmConn(p peer.ID) {
|
||||
conns := r.conns[p]
|
||||
conns--
|
||||
if conns > 0 {
|
||||
r.conns[p] = conns
|
||||
} else {
|
||||
delete(r.conns, p)
|
||||
r.host.ConnManager().UntagPeer(p, relayHopTag)
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Relay) relayLimited(src, dest network.Stream, srcID, destID peer.ID, limit int64, done func()) {
|
||||
defer done()
|
||||
|
||||
buf := pool.Get(r.rc.BufferSize)
|
||||
defer pool.Put(buf)
|
||||
|
||||
limitedSrc := io.LimitReader(src, limit)
|
||||
|
||||
count, err := r.copyWithBuffer(dest, limitedSrc, buf)
|
||||
if err != nil {
|
||||
log.Debugf("relay copy error: %s", err)
|
||||
// Reset both.
|
||||
src.Reset()
|
||||
dest.Reset()
|
||||
} else {
|
||||
// propagate the close
|
||||
dest.CloseWrite()
|
||||
if count == limit {
|
||||
// we've reached the limit, discard further input
|
||||
src.CloseRead()
|
||||
}
|
||||
}
|
||||
|
||||
log.Debugf("relayed %d bytes from %s to %s", count, srcID, destID)
|
||||
}
|
||||
|
||||
func (r *Relay) relayUnlimited(src, dest network.Stream, srcID, destID peer.ID, done func()) {
|
||||
defer done()
|
||||
|
||||
buf := pool.Get(r.rc.BufferSize)
|
||||
defer pool.Put(buf)
|
||||
|
||||
count, err := r.copyWithBuffer(dest, src, buf)
|
||||
if err != nil {
|
||||
log.Debugf("relay copy error: %s", err)
|
||||
// Reset both.
|
||||
src.Reset()
|
||||
dest.Reset()
|
||||
} else {
|
||||
// propagate the close
|
||||
dest.CloseWrite()
|
||||
}
|
||||
|
||||
log.Debugf("relayed %d bytes from %s to %s", count, srcID, destID)
|
||||
}
|
||||
|
||||
// errInvalidWrite means that a write returned an impossible count.
|
||||
// copied from io.errInvalidWrite
|
||||
var errInvalidWrite = errors.New("invalid write result")
|
||||
|
||||
// copyWithBuffer copies from src to dst using the provided buf until either EOF is reached
|
||||
// on src or an error occurs. It reports the number of bytes transferred to metricsTracer.
|
||||
// The implementation is a modified form of io.CopyBuffer to support metrics tracking.
|
||||
func (r *Relay) copyWithBuffer(dst io.Writer, src io.Reader, buf []byte) (written int64, err error) {
|
||||
for {
|
||||
nr, er := src.Read(buf)
|
||||
if nr > 0 {
|
||||
nw, ew := dst.Write(buf[0:nr])
|
||||
if nw < 0 || nr < nw {
|
||||
nw = 0
|
||||
if ew == nil {
|
||||
ew = errInvalidWrite
|
||||
}
|
||||
}
|
||||
written += int64(nw)
|
||||
if ew != nil {
|
||||
err = ew
|
||||
break
|
||||
}
|
||||
if nr != nw {
|
||||
err = io.ErrShortWrite
|
||||
break
|
||||
}
|
||||
if r.metricsTracer != nil {
|
||||
r.metricsTracer.BytesTransferred(nw)
|
||||
}
|
||||
}
|
||||
if er != nil {
|
||||
if er != io.EOF {
|
||||
err = er
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
return written, err
|
||||
}
|
||||
|
||||
func (r *Relay) handleError(s network.Stream, status pbv2.Status) {
|
||||
log.Debugf("relay error: %s (%d)", pbv2.Status_name[int32(status)], status)
|
||||
err := r.writeResponse(s, status, nil, nil)
|
||||
if err != nil {
|
||||
s.Reset()
|
||||
log.Debugf("error writing relay response: %s", err.Error())
|
||||
} else {
|
||||
s.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Relay) writeResponse(s network.Stream, status pbv2.Status, rsvp *pbv2.Reservation, limit *pbv2.Limit) error {
|
||||
wr := util.NewDelimitedWriter(s)
|
||||
|
||||
var msg pbv2.HopMessage
|
||||
msg.Type = pbv2.HopMessage_STATUS.Enum()
|
||||
msg.Status = status.Enum()
|
||||
msg.Reservation = rsvp
|
||||
msg.Limit = limit
|
||||
|
||||
return wr.WriteMsg(&msg)
|
||||
}
|
||||
|
||||
func (r *Relay) makeReservationMsg(p peer.ID, expire time.Time) *pbv2.Reservation {
|
||||
expireUnix := uint64(expire.Unix())
|
||||
|
||||
var addrBytes [][]byte
|
||||
for _, addr := range r.host.Addrs() {
|
||||
if !manet.IsPublicAddr(addr) {
|
||||
continue
|
||||
}
|
||||
|
||||
addr = addr.Encapsulate(r.selfAddr)
|
||||
addrBytes = append(addrBytes, addr.Bytes())
|
||||
}
|
||||
|
||||
rsvp := &pbv2.Reservation{
|
||||
Expire: &expireUnix,
|
||||
Addrs: addrBytes,
|
||||
}
|
||||
|
||||
voucher := &proto.ReservationVoucher{
|
||||
Relay: r.host.ID(),
|
||||
Peer: p,
|
||||
Expiration: expire,
|
||||
}
|
||||
|
||||
envelope, err := record.Seal(voucher, r.host.Peerstore().PrivKey(r.host.ID()))
|
||||
if err != nil {
|
||||
log.Errorf("error sealing voucher for %s: %s", p, err)
|
||||
return rsvp
|
||||
}
|
||||
|
||||
blob, err := envelope.Marshal()
|
||||
if err != nil {
|
||||
log.Errorf("error marshalling voucher for %s: %s", p, err)
|
||||
return rsvp
|
||||
}
|
||||
|
||||
rsvp.Voucher = blob
|
||||
|
||||
return rsvp
|
||||
}
|
||||
|
||||
func (r *Relay) makeLimitMsg(p peer.ID) *pbv2.Limit {
|
||||
if r.rc.Limit == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
duration := uint32(r.rc.Limit.Duration / time.Second)
|
||||
data := uint64(r.rc.Limit.Data)
|
||||
|
||||
return &pbv2.Limit{
|
||||
Duration: &duration,
|
||||
Data: &data,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Relay) background() {
|
||||
asnutil.Store.Init()
|
||||
|
||||
ticker := time.NewTicker(time.Minute)
|
||||
defer ticker.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ticker.C:
|
||||
r.gc()
|
||||
case <-r.ctx.Done():
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Relay) gc() {
|
||||
r.mx.Lock()
|
||||
defer r.mx.Unlock()
|
||||
|
||||
now := time.Now()
|
||||
cnt := 0
|
||||
for p, expire := range r.rsvp {
|
||||
if r.closed || expire.Before(now) {
|
||||
delete(r.rsvp, p)
|
||||
r.host.ConnManager().UntagPeer(p, "relay-reservation")
|
||||
cnt++
|
||||
}
|
||||
}
|
||||
if r.metricsTracer != nil {
|
||||
r.metricsTracer.ReservationClosed(cnt)
|
||||
}
|
||||
|
||||
for p, count := range r.conns {
|
||||
if count == 0 {
|
||||
delete(r.conns, p)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Relay) disconnected(n network.Network, c network.Conn) {
|
||||
p := c.RemotePeer()
|
||||
if n.Connectedness(p) == network.Connected {
|
||||
return
|
||||
}
|
||||
|
||||
r.mx.Lock()
|
||||
_, ok := r.rsvp[p]
|
||||
if ok {
|
||||
delete(r.rsvp, p)
|
||||
}
|
||||
r.mx.Unlock()
|
||||
|
||||
if ok && r.metricsTracer != nil {
|
||||
r.metricsTracer.ReservationClosed(1)
|
||||
}
|
||||
}
|
||||
|
||||
func isRelayAddr(a ma.Multiaddr) bool {
|
||||
_, err := a.ValueForProtocol(ma.P_CIRCUIT)
|
||||
return err == nil
|
||||
}
|
||||
66
vendor/github.com/libp2p/go-libp2p/p2p/protocol/circuitv2/relay/resources.go
generated
vendored
Normal file
66
vendor/github.com/libp2p/go-libp2p/p2p/protocol/circuitv2/relay/resources.go
generated
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
package relay
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// Resources are the resource limits associated with the relay service.
|
||||
type Resources struct {
|
||||
// Limit is the (optional) relayed connection limits.
|
||||
Limit *RelayLimit
|
||||
|
||||
// ReservationTTL is the duration of a new (or refreshed reservation).
|
||||
// Defaults to 1hr.
|
||||
ReservationTTL time.Duration
|
||||
|
||||
// MaxReservations is the maximum number of active relay slots; defaults to 128.
|
||||
MaxReservations int
|
||||
// MaxCircuits is the maximum number of open relay connections for each peer; defaults to 16.
|
||||
MaxCircuits int
|
||||
// BufferSize is the size of the relayed connection buffers; defaults to 2048.
|
||||
BufferSize int
|
||||
|
||||
// MaxReservationsPerPeer is the maximum number of reservations originating from the same
|
||||
// peer; default is 4.
|
||||
MaxReservationsPerPeer int
|
||||
// MaxReservationsPerIP is the maximum number of reservations originating from the same
|
||||
// IP address; default is 8.
|
||||
MaxReservationsPerIP int
|
||||
// MaxReservationsPerASN is the maximum number of reservations origination from the same
|
||||
// ASN; default is 32
|
||||
MaxReservationsPerASN int
|
||||
}
|
||||
|
||||
// RelayLimit are the per relayed connection resource limits.
|
||||
type RelayLimit struct {
|
||||
// Duration is the time limit before resetting a relayed connection; defaults to 2min.
|
||||
Duration time.Duration
|
||||
// Data is the limit of data relayed (on each direction) before resetting the connection.
|
||||
// Defaults to 128KB
|
||||
Data int64
|
||||
}
|
||||
|
||||
// DefaultResources returns a Resources object with the default filled in.
|
||||
func DefaultResources() Resources {
|
||||
return Resources{
|
||||
Limit: DefaultLimit(),
|
||||
|
||||
ReservationTTL: time.Hour,
|
||||
|
||||
MaxReservations: 128,
|
||||
MaxCircuits: 16,
|
||||
BufferSize: 2048,
|
||||
|
||||
MaxReservationsPerPeer: 4,
|
||||
MaxReservationsPerIP: 8,
|
||||
MaxReservationsPerASN: 32,
|
||||
}
|
||||
}
|
||||
|
||||
// DefaultLimit returns a RelayLimit object with the defaults filled in.
|
||||
func DefaultLimit() *RelayLimit {
|
||||
return &RelayLimit{
|
||||
Duration: 2 * time.Minute,
|
||||
Data: 1 << 17, // 128K
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user