chore: upgrade libp2p
This commit is contained in:
parent
3e4fe1e12f
commit
b1a6607dbb
62
go.mod
62
go.mod
|
@ -22,21 +22,21 @@ require (
|
|||
github.com/ethereum/go-ethereum v1.10.26
|
||||
github.com/forPelevin/gomoji v1.1.2
|
||||
github.com/golang/mock v1.6.0
|
||||
github.com/golang/protobuf v1.5.2
|
||||
github.com/golang/protobuf v1.5.3
|
||||
github.com/google/uuid v1.3.0
|
||||
github.com/hashicorp/go-version v1.2.0
|
||||
github.com/imdario/mergo v0.3.12
|
||||
github.com/ipfs/go-cid v0.3.2
|
||||
github.com/ipfs/go-cid v0.4.1
|
||||
github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a
|
||||
github.com/keighl/metabolize v0.0.0-20150915210303-97ab655d4034
|
||||
github.com/kilic/bls12-381 v0.0.0-20200607163746-32e1441c8a9f
|
||||
github.com/lib/pq v1.10.4
|
||||
github.com/libp2p/go-libp2p v0.26.4
|
||||
github.com/libp2p/go-libp2p v0.27.3
|
||||
github.com/libp2p/go-libp2p-pubsub v0.9.3
|
||||
github.com/lucasb-eyer/go-colorful v1.0.3
|
||||
github.com/mat/besticon v0.0.0-20210314201728-1579f269edb7
|
||||
github.com/multiformats/go-multiaddr v0.8.0
|
||||
github.com/multiformats/go-multibase v0.1.1
|
||||
github.com/multiformats/go-multiaddr v0.9.0
|
||||
github.com/multiformats/go-multibase v0.2.0
|
||||
github.com/multiformats/go-multihash v0.2.1
|
||||
github.com/multiformats/go-varint v0.0.7
|
||||
github.com/mutecomm/go-sqlcipher v0.0.0-20190227152316-55dbde17881f
|
||||
|
@ -54,7 +54,7 @@ require (
|
|||
github.com/status-im/status-go/extkeys v1.1.2
|
||||
github.com/status-im/tcp-shaker v0.0.0-20191114194237-215893130501
|
||||
github.com/status-im/zxcvbn-go v0.0.0-20220311183720-5e8676676857
|
||||
github.com/stretchr/testify v1.8.1
|
||||
github.com/stretchr/testify v1.8.2
|
||||
github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a
|
||||
github.com/tsenart/tb v0.0.0-20181025101425-0d2499c8b6e9
|
||||
github.com/vacp2p/mvds v0.0.24-0.20201124060106-26d8e94130d8
|
||||
|
@ -63,7 +63,7 @@ require (
|
|||
github.com/xeipuuv/gojsonschema v1.2.0
|
||||
github.com/zenthangplus/goccm v0.0.0-20211005163543-2f2e522aca15
|
||||
go.uber.org/zap v1.24.0
|
||||
golang.org/x/crypto v0.4.0
|
||||
golang.org/x/crypto v0.7.0
|
||||
golang.org/x/image v0.0.0-20210220032944-ac19c3e999fb
|
||||
google.golang.org/protobuf v1.30.1-0.20230508203708-b8fc77060104
|
||||
gopkg.in/go-playground/assert.v1 v1.2.1 // indirect
|
||||
|
@ -82,11 +82,11 @@ require (
|
|||
github.com/meirf/gopart v0.0.0-20180520194036-37e9492a85a8
|
||||
github.com/schollz/peerdiscovery v1.7.0
|
||||
github.com/siphiuel/lc-proxy-wrapper v0.0.0-20230516150924-246507cee8c7
|
||||
github.com/waku-org/go-waku v0.6.1-0.20230518201054-a5abfa87107c
|
||||
github.com/waku-org/go-waku v0.6.1-0.20230526151800-10c2e20910bf
|
||||
github.com/yeqown/go-qrcode/v2 v2.2.1
|
||||
github.com/yeqown/go-qrcode/writer/standard v1.2.1
|
||||
go.uber.org/multierr v1.8.0
|
||||
golang.org/x/exp v0.0.0-20230206171751-46f607a40771
|
||||
go.uber.org/multierr v1.11.0
|
||||
golang.org/x/exp v0.0.0-20230321023759-10a507213a29
|
||||
golang.org/x/net v0.8.0
|
||||
)
|
||||
|
||||
|
@ -123,7 +123,7 @@ require (
|
|||
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 // indirect
|
||||
github.com/cenkalti/backoff/v4 v4.1.2 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||
github.com/containerd/cgroups v1.0.4 // indirect
|
||||
github.com/containerd/cgroups v1.1.0 // indirect
|
||||
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
|
||||
github.com/cruxic/go-hmac-drbg v0.0.0-20170206035330-84c46983886d // indirect
|
||||
|
@ -141,7 +141,7 @@ require (
|
|||
github.com/go-playground/locales v0.14.0 // indirect
|
||||
github.com/go-playground/universal-translator v0.18.0 // indirect
|
||||
github.com/go-stack/stack v1.8.1 // indirect
|
||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
|
||||
github.com/godbus/dbus/v5 v5.1.0 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang-jwt/jwt/v4 v4.3.0 // indirect
|
||||
|
@ -151,28 +151,28 @@ require (
|
|||
github.com/golang/snappy v0.0.4 // indirect
|
||||
github.com/google/btree v1.0.1 // indirect
|
||||
github.com/google/gopacket v1.1.19 // indirect
|
||||
github.com/google/pprof v0.0.0-20221203041831-ce31453925ec // indirect
|
||||
github.com/google/pprof v0.0.0-20230405160723-4a4c7d95572b // indirect
|
||||
github.com/gorilla/securecookie v1.1.1 // indirect
|
||||
github.com/gorilla/websocket v1.5.0 // indirect
|
||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||
github.com/hashicorp/go-bexpr v0.1.10 // indirect
|
||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||
github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d // indirect
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.1 // indirect
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.2 // indirect
|
||||
github.com/holiman/bloomfilter/v2 v2.0.3 // indirect
|
||||
github.com/holiman/uint256 v1.2.0 // indirect
|
||||
github.com/huandu/xstrings v1.3.2 // indirect
|
||||
github.com/huin/goupnp v1.0.3 // indirect
|
||||
github.com/huin/goupnp v1.1.0 // indirect
|
||||
github.com/jackpal/go-nat-pmp v1.0.2 // indirect
|
||||
github.com/jbenet/go-temp-err-catcher v0.1.0 // indirect
|
||||
github.com/klauspost/compress v1.15.15 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.1 // indirect
|
||||
github.com/koron/go-ssdp v0.0.3 // indirect
|
||||
github.com/klauspost/compress v1.16.4 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.4 // indirect
|
||||
github.com/koron/go-ssdp v0.0.4 // indirect
|
||||
github.com/leodido/go-urn v1.2.1 // indirect
|
||||
github.com/libp2p/go-buffer-pool v0.1.0 // indirect
|
||||
github.com/libp2p/go-cidranger v1.1.0 // indirect
|
||||
github.com/libp2p/go-flow-metrics v0.1.0 // indirect
|
||||
github.com/libp2p/go-libp2p-asn-util v0.2.0 // indirect
|
||||
github.com/libp2p/go-libp2p-asn-util v0.3.0 // indirect
|
||||
github.com/libp2p/go-mplex v0.7.0 // indirect
|
||||
github.com/libp2p/go-msgio v0.3.0 // indirect
|
||||
github.com/libp2p/go-nat v0.1.0 // indirect
|
||||
|
@ -181,10 +181,10 @@ require (
|
|||
github.com/libp2p/go-yamux/v4 v4.0.0 // indirect
|
||||
github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd // indirect
|
||||
github.com/mattn/go-colorable v0.1.8 // indirect
|
||||
github.com/mattn/go-isatty v0.0.16 // indirect
|
||||
github.com/mattn/go-isatty v0.0.18 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.13 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
|
||||
github.com/miekg/dns v1.1.50 // indirect
|
||||
github.com/miekg/dns v1.1.53 // indirect
|
||||
github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b // indirect
|
||||
github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc // indirect
|
||||
github.com/minio/sha256-simd v1.0.0 // indirect
|
||||
|
@ -196,10 +196,10 @@ require (
|
|||
github.com/multiformats/go-base36 v0.2.0 // indirect
|
||||
github.com/multiformats/go-multiaddr-dns v0.3.1 // indirect
|
||||
github.com/multiformats/go-multiaddr-fmt v0.1.0 // indirect
|
||||
github.com/multiformats/go-multicodec v0.7.0 // indirect
|
||||
github.com/multiformats/go-multicodec v0.8.1 // indirect
|
||||
github.com/multiformats/go-multistream v0.4.1 // indirect
|
||||
github.com/olekukonko/tablewriter v0.0.5 // indirect
|
||||
github.com/onsi/ginkgo/v2 v2.5.1 // indirect
|
||||
github.com/onsi/ginkgo/v2 v2.9.2 // indirect
|
||||
github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417 // indirect
|
||||
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect
|
||||
github.com/pion/datachannel v1.5.2 // indirect
|
||||
|
@ -221,12 +221,12 @@ require (
|
|||
github.com/pion/webrtc/v3 v3.1.24-0.20220208053747-94262c1b2b38 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/prometheus/client_model v0.3.0 // indirect
|
||||
github.com/prometheus/common v0.39.0 // indirect
|
||||
github.com/prometheus/common v0.42.0 // indirect
|
||||
github.com/prometheus/procfs v0.9.0 // indirect
|
||||
github.com/prometheus/tsdb v0.10.0 // indirect
|
||||
github.com/quic-go/qpack v0.4.0 // indirect
|
||||
github.com/quic-go/qtls-go1-19 v0.2.1 // indirect
|
||||
github.com/quic-go/qtls-go1-20 v0.1.1 // indirect
|
||||
github.com/quic-go/qtls-go1-19 v0.3.2 // indirect
|
||||
github.com/quic-go/qtls-go1-20 v0.2.2 // indirect
|
||||
github.com/quic-go/quic-go v0.33.0 // indirect
|
||||
github.com/quic-go/webtransport-go v0.5.2 // indirect
|
||||
github.com/raulk/go-watchdog v1.3.0 // indirect
|
||||
|
@ -260,15 +260,15 @@ require (
|
|||
go.etcd.io/bbolt v1.3.6 // indirect
|
||||
go.opencensus.io v0.24.0 // indirect
|
||||
go.uber.org/atomic v1.10.0 // indirect
|
||||
go.uber.org/dig v1.15.0 // indirect
|
||||
go.uber.org/fx v1.18.2 // indirect
|
||||
golang.org/x/mod v0.8.0 // indirect
|
||||
go.uber.org/dig v1.16.1 // indirect
|
||||
go.uber.org/fx v1.19.2 // indirect
|
||||
golang.org/x/mod v0.10.0 // indirect
|
||||
golang.org/x/sync v0.1.0 // indirect
|
||||
golang.org/x/sys v0.6.0 // indirect
|
||||
golang.org/x/sys v0.7.0 // indirect
|
||||
golang.org/x/term v0.6.0 // indirect
|
||||
golang.org/x/text v0.8.0 // indirect
|
||||
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af // indirect
|
||||
golang.org/x/tools v0.6.0 // indirect
|
||||
golang.org/x/tools v0.7.0 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f // indirect
|
||||
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
|
|
125
go.sum
125
go.sum
|
@ -517,8 +517,8 @@ github.com/containerd/cgroups v0.0.0-20201119153540-4cbc285b3327/go.mod h1:ZJeTF
|
|||
github.com/containerd/cgroups v0.0.0-20210114181951-8a68de567b68/go.mod h1:ZJeTFisyysqgcCdecO57Dj79RfL0LNeGiFUqLYQRYLE=
|
||||
github.com/containerd/cgroups v1.0.1/go.mod h1:0SJrPIenamHDcZhEcJMNBB85rHcUsw4f25ZfBiPYRkU=
|
||||
github.com/containerd/cgroups v1.0.3/go.mod h1:/ofk34relqNjSGyqPrmEULrO4Sc8LJhvJmWbUCUKqj8=
|
||||
github.com/containerd/cgroups v1.0.4 h1:jN/mbWBEaz+T1pi5OFtnkQ+8qnmEbAr1Oo1FRm5B0dA=
|
||||
github.com/containerd/cgroups v1.0.4/go.mod h1:nLNQtsF7Sl2HxNebu77i1R0oDlhiTG+kO4JTrUzo6IA=
|
||||
github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM=
|
||||
github.com/containerd/cgroups v1.1.0/go.mod h1:6ppBcbh/NOOUU+dMKrykgaBnK9lCIBxHqJDGwsa1mIw=
|
||||
github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw=
|
||||
github.com/containerd/console v0.0.0-20181022165439-0650fd9eeb50/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw=
|
||||
github.com/containerd/console v0.0.0-20191206165004-02ecf6a7291e/go.mod h1:8Pf4gM6VEbTNRIT26AyyU7hxdQU3MvAvxVI0sc00XBE=
|
||||
|
@ -860,8 +860,9 @@ github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LB
|
|||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw=
|
||||
github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4=
|
||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I=
|
||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
|
||||
github.com/gobuffalo/attrs v0.0.0-20190224210810-a9411de4debd/go.mod h1:4duuawTqi2wkkpB4ePgWMaai6/Kc6WEz83bhFwpHzj0=
|
||||
github.com/gobuffalo/depgen v0.0.0-20190329151759-d478694a28d3/go.mod h1:3STtPUQYuzV0gBVOY3vy6CfMm/ljR4pABfrTeHNLHUY=
|
||||
github.com/gobuffalo/depgen v0.1.0/go.mod h1:+ifsuy7fhi15RWncXQQKjWS9JPkdah5sZvtHc2RXGlg=
|
||||
|
@ -965,8 +966,9 @@ github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw
|
|||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM=
|
||||
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
|
||||
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
|
@ -1026,8 +1028,8 @@ github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLe
|
|||
github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20221203041831-ce31453925ec h1:fR20TYVVwhK4O7r7y+McjRYyaTH6/vjwJOajE+XhlzM=
|
||||
github.com/google/pprof v0.0.0-20221203041831-ce31453925ec/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo=
|
||||
github.com/google/pprof v0.0.0-20230405160723-4a4c7d95572b h1:Qcx5LM0fSiks9uCyFZwDBUasd3lxd1RM0GYpL+Li5o4=
|
||||
github.com/google/pprof v0.0.0-20230405160723-4a4c7d95572b/go.mod h1:79YE0hCXdHag9sBkw2o+N/YnZtTkXi0UT9Nnixa5eYk=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
|
@ -1116,8 +1118,8 @@ github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ
|
|||
github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
|
||||
github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d h1:dg1dEPuWpEqDnvIw251EVy4zlP8gWbsGj4BsUKCRpYs=
|
||||
github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.1 h1:5pv5N1lT1fjLg2VQ5KWc7kmucp2x/kvFOnxuVTqZ6x4=
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.1/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.2 h1:Dwmkdr5Nc/oBiXgJS3CDHNhJtIHkuZ3DZF5twqnfBdU=
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.2/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
|
||||
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
|
||||
|
@ -1140,8 +1142,8 @@ github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmK
|
|||
github.com/huin/goupnp v1.0.0/go.mod h1:n9v9KO1tAxYH82qOn+UTIFQDmx5n1Zxd/ClZDMX7Bnc=
|
||||
github.com/huin/goupnp v1.0.1-0.20210310174557-0ca763054c88/go.mod h1:nNs7wvRfN1eKaMknBydLNQU6146XQim8t4h+q90biWo=
|
||||
github.com/huin/goupnp v1.0.2/go.mod h1:0dxJBVBHqTMjIUMkESDTNgOOx/Mw5wYIfyFmdzSamkM=
|
||||
github.com/huin/goupnp v1.0.3 h1:N8No57ls+MnjlB+JPiCVSOyy/ot7MJTqlo7rn+NYSqQ=
|
||||
github.com/huin/goupnp v1.0.3/go.mod h1:ZxNlw5WqJj6wSsRK5+YfflQGXYfccj5VgQsMNixHM7Y=
|
||||
github.com/huin/goupnp v1.1.0 h1:gEe0Dp/lZmPZiDFzJJaOfUpOvv2MKUkoBX8lDrn9vKU=
|
||||
github.com/huin/goupnp v1.1.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8=
|
||||
github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o=
|
||||
github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
|
@ -1167,8 +1169,8 @@ github.com/influxdata/tdigest v0.0.0-20181121200506-bf2b5ad3c0a9/go.mod h1:Js0mq
|
|||
github.com/influxdata/usage-client v0.0.0-20160829180054-6d3895376368/go.mod h1:Wbbw6tYNvwa5dlB6304Sd+82Z3f7PmVZHVKU637d4po=
|
||||
github.com/intel/goresctrl v0.2.0/go.mod h1:+CZdzouYFn5EsxgqAQTEzMfwKwuc0fVdMrT9FCCAVRQ=
|
||||
github.com/ipfs/go-cid v0.0.7/go.mod h1:6Ux9z5e+HpkQdckYoX1PG/6xqKspzlEIR5SDmgqgC/I=
|
||||
github.com/ipfs/go-cid v0.3.2 h1:OGgOd+JCFM+y1DjWPmVH+2/4POtpDzwcr7VgnB7mZXc=
|
||||
github.com/ipfs/go-cid v0.3.2/go.mod h1:gQ8pKqT/sUxGY+tIwy1RPpAojYu7jAyCp5Tz1svoupw=
|
||||
github.com/ipfs/go-cid v0.4.1 h1:A/T3qGvxi4kpKWWcPC/PgbvDA2bjVLO7n4UeVwnbs/s=
|
||||
github.com/ipfs/go-cid v0.4.1/go.mod h1:uQHwDeX4c6CtyrFwdqyhpNcxVewur1M7l7fNU7LKwZk=
|
||||
github.com/ipfs/go-detect-race v0.0.1 h1:qX/xay2W3E4Q1U7d9lNs1sU9nvguX0a7319XbyQ6cOk=
|
||||
github.com/ipfs/go-detect-race v0.0.1/go.mod h1:8BNT7shDZPo99Q74BpGMK+4D8Mn4j46UU0LZ723meps=
|
||||
github.com/ipfs/go-log/v2 v2.5.1 h1:1XdUzF7048prq4aBjDQQ4SL5RxftpRGdXhNRwKSAlcY=
|
||||
|
@ -1293,22 +1295,22 @@ github.com/klauspost/compress v1.11.13/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdY
|
|||
github.com/klauspost/compress v1.13.1/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
|
||||
github.com/klauspost/compress v1.13.4/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
|
||||
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
|
||||
github.com/klauspost/compress v1.15.15 h1:EF27CXIuDsYJ6mmvtBRlEuB2UVOqHG1tAXgZ7yIO+lw=
|
||||
github.com/klauspost/compress v1.15.15/go.mod h1:ZcK2JAFqKOpnBlxcLsJzYfrS9X1akm9fHZNnD9+Vo/4=
|
||||
github.com/klauspost/compress v1.16.4 h1:91KN02FnsOYhuunwU4ssRe8lc2JosWmizWa91B5v1PU=
|
||||
github.com/klauspost/compress v1.16.4/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
|
||||
github.com/klauspost/cpuid v0.0.0-20170728055534-ae7887de9fa5/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
||||
github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||
github.com/klauspost/cpuid/v2 v2.0.6/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||
github.com/klauspost/cpuid/v2 v2.2.1 h1:U33DW0aiEj633gHYw3LoDNfkDiYnE5Q8M/TKJn2f2jI=
|
||||
github.com/klauspost/cpuid/v2 v2.2.1/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
|
||||
github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk=
|
||||
github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
|
||||
github.com/klauspost/crc32 v0.0.0-20161016154125-cb6bfca970f6/go.mod h1:+ZoRqAPRLkC4NPOvfYeR5KNOrY6TD+/sAC3HXPZgDYg=
|
||||
github.com/klauspost/pgzip v1.0.2-0.20170402124221-0bf5dcad4ada/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/koron/go-ssdp v0.0.0-20191105050749-2e1c40ed0b5d/go.mod h1:5Ky9EC2xfoUKUor0Hjgi2BJhCSXJfMOFlmyYrVKGQMk=
|
||||
github.com/koron/go-ssdp v0.0.3 h1:JivLMY45N76b4p/vsWGOKewBQu6uf39y8l+AQ7sDKx8=
|
||||
github.com/koron/go-ssdp v0.0.3/go.mod h1:b2MxI6yh02pKrsyNoQUsk4+YNikaGhe4894J+Q5lDvA=
|
||||
github.com/koron/go-ssdp v0.0.4 h1:1IDwrghSKYM7yLf7XCzbByg2sJ/JcNOZRXS2jczTwz0=
|
||||
github.com/koron/go-ssdp v0.0.4/go.mod h1:oDXq+E5IL5q0U8uSBcoAXzTzInwy5lEgC91HoKtbmZk=
|
||||
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
|
@ -1348,10 +1350,10 @@ github.com/libp2p/go-cidranger v1.1.0 h1:ewPN8EZ0dd1LSnrtuwd4709PXVcITVeuwbag38y
|
|||
github.com/libp2p/go-cidranger v1.1.0/go.mod h1:KWZTfSr+r9qEo9OkI9/SIEeAtw+NNoU0dXIXt15Okic=
|
||||
github.com/libp2p/go-flow-metrics v0.1.0 h1:0iPhMI8PskQwzh57jB9WxIuIOQ0r+15PChFGkx3Q3WM=
|
||||
github.com/libp2p/go-flow-metrics v0.1.0/go.mod h1:4Xi8MX8wj5aWNDAZttg6UPmc0ZrnFNsMtpsYUClFtro=
|
||||
github.com/libp2p/go-libp2p v0.26.4 h1:VA9ChjN0n1BwwfU/dqx4Zj9ezXtIxGk8FyJPwFONqxs=
|
||||
github.com/libp2p/go-libp2p v0.26.4/go.mod h1:x75BN32YbwuY0Awm2Uix4d4KOz+/4piInkp4Wr3yOo8=
|
||||
github.com/libp2p/go-libp2p-asn-util v0.2.0 h1:rg3+Os8jbnO5DxkC7K/Utdi+DkY3q/d1/1q+8WeNAsw=
|
||||
github.com/libp2p/go-libp2p-asn-util v0.2.0/go.mod h1:WoaWxbHKBymSN41hWSq/lGKJEca7TNm58+gGJi2WsLI=
|
||||
github.com/libp2p/go-libp2p v0.27.3 h1:tkV/zm3KCZ4R5er9Xcs2pt0YNB4JH0iBfGAtHJdLHRs=
|
||||
github.com/libp2p/go-libp2p v0.27.3/go.mod h1:FAvvfQa/YOShUYdiSS03IR9OXzkcJXwcNA2FUCh9ImE=
|
||||
github.com/libp2p/go-libp2p-asn-util v0.3.0 h1:gMDcMyYiZKkocGXDQ5nsUQyquC9+H+iLEQHwOCZ7s8s=
|
||||
github.com/libp2p/go-libp2p-asn-util v0.3.0/go.mod h1:B1mcOrKUE35Xq/ASTmQ4tN3LNzVVaMNmq2NACuqyB9w=
|
||||
github.com/libp2p/go-libp2p-pubsub v0.9.3 h1:ihcz9oIBMaCK9kcx+yHWm3mLAFBMAUsM4ux42aikDxo=
|
||||
github.com/libp2p/go-libp2p-pubsub v0.9.3/go.mod h1:RYA7aM9jIic5VV47WXu4GkcRxRhrdElWf8xtyli+Dzc=
|
||||
github.com/libp2p/go-libp2p-testing v0.12.0 h1:EPvBb4kKMWO29qP4mZGyhVzUyR25dvfUIK5WDu6iPUA=
|
||||
|
@ -1426,8 +1428,8 @@ github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2y
|
|||
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||
github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ=
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-isatty v0.0.18 h1:DOKFKCQ7FNG2L1rbrmstDN4QVRdS89Nkh85u68Uwp98=
|
||||
github.com/mattn/go-isatty v0.0.18/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||
github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
|
@ -1458,8 +1460,8 @@ github.com/meirf/gopart v0.0.0-20180520194036-37e9492a85a8/go.mod h1:Uz8uoD6o+eQ
|
|||
github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4=
|
||||
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||
github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI=
|
||||
github.com/miekg/dns v1.1.50 h1:DQUfb9uc6smULcREF09Uc+/Gd46YWqJd5DbpPE9xkcA=
|
||||
github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME=
|
||||
github.com/miekg/dns v1.1.53 h1:ZBkuHr5dxHtB1caEOlZTLPo7D3L3TWckgUUs/RHfDxw=
|
||||
github.com/miekg/dns v1.1.53/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY=
|
||||
github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs=
|
||||
github.com/mikioh/tcp v0.0.0-20190314235350-803a9b46060c h1:bzE/A84HN25pxAuk9Eej1Kz9OUelF97nAc82bDquQI8=
|
||||
github.com/mikioh/tcp v0.0.0-20190314235350-803a9b46060c/go.mod h1:0SQS9kMwD2VsyFEB++InYyBJroV/FRmBgcydeSUcJms=
|
||||
|
@ -1527,17 +1529,17 @@ github.com/multiformats/go-multiaddr v0.1.1/go.mod h1:aMKBKNEYmzmDmxfX88/vz+J5IU
|
|||
github.com/multiformats/go-multiaddr v0.2.0/go.mod h1:0nO36NvPpyV4QzvTLi/lafl2y95ncPj0vFwVF6k6wJ4=
|
||||
github.com/multiformats/go-multiaddr v0.2.2/go.mod h1:NtfXiOtHvghW9KojvtySjH5y0u0xW5UouOmQQrn6a3Y=
|
||||
github.com/multiformats/go-multiaddr v0.3.2/go.mod h1:lCKNGP1EQ1eZ35Za2wlqnabm9xQkib3fyB+nZXHLag0=
|
||||
github.com/multiformats/go-multiaddr v0.8.0 h1:aqjksEcqK+iD/Foe1RRFsGZh8+XFiGo7FgUCZlpv3LU=
|
||||
github.com/multiformats/go-multiaddr v0.8.0/go.mod h1:Fs50eBDWvZu+l3/9S6xAE7ZYj6yhxlvaVZjakWN7xRs=
|
||||
github.com/multiformats/go-multiaddr v0.9.0 h1:3h4V1LHIk5w4hJHekMKWALPXErDfz/sggzwC/NcqbDQ=
|
||||
github.com/multiformats/go-multiaddr v0.9.0/go.mod h1:mI67Lb1EeTOYb8GQfL/7wpIZwc46ElrvzhYnoJOmTT0=
|
||||
github.com/multiformats/go-multiaddr-dns v0.3.1 h1:QgQgR+LQVt3NPTjbrLLpsaT2ufAA2y0Mkk+QRVJbW3A=
|
||||
github.com/multiformats/go-multiaddr-dns v0.3.1/go.mod h1:G/245BRQ6FJGmryJCrOuTdB37AMA5AMOVuO6NY3JwTk=
|
||||
github.com/multiformats/go-multiaddr-fmt v0.1.0 h1:WLEFClPycPkp4fnIzoFoV9FVd49/eQsuaL3/CWe167E=
|
||||
github.com/multiformats/go-multiaddr-fmt v0.1.0/go.mod h1:hGtDIW4PU4BqJ50gW2quDuPVjyWNZxToGUh/HwTZYJo=
|
||||
github.com/multiformats/go-multibase v0.0.3/go.mod h1:5+1R4eQrT3PkYZ24C3W2Ue2tPwIdYQD509ZjSb5y9Oc=
|
||||
github.com/multiformats/go-multibase v0.1.1 h1:3ASCDsuLX8+j4kx58qnJ4YFq/JWTJpCyDW27ztsVTOI=
|
||||
github.com/multiformats/go-multibase v0.1.1/go.mod h1:ZEjHE+IsUrgp5mhlEAYjMtZwK1k4haNkcaPg9aoe1a8=
|
||||
github.com/multiformats/go-multicodec v0.7.0 h1:rTUjGOwjlhGHbEMbPoSUJowG1spZTVsITRANCjKTUAQ=
|
||||
github.com/multiformats/go-multicodec v0.7.0/go.mod h1:GUC8upxSBE4oG+q3kWZRw/+6yC1BqO550bjhWsJbZlw=
|
||||
github.com/multiformats/go-multibase v0.2.0 h1:isdYCVLvksgWlMW9OZRYJEa9pZETFivncJHmHnnd87g=
|
||||
github.com/multiformats/go-multibase v0.2.0/go.mod h1:bFBZX4lKCA/2lyOFSAoKH5SS6oPyjtnzK/XTFDPkNuk=
|
||||
github.com/multiformats/go-multicodec v0.8.1 h1:ycepHwavHafh3grIbR1jIXnKCsFm0fqsfEOsJ8NtKE8=
|
||||
github.com/multiformats/go-multicodec v0.8.1/go.mod h1:L3QTQvMIaVBkXOXXtVmYE+LI16i14xuaojr/H7Ai54k=
|
||||
github.com/multiformats/go-multihash v0.0.8/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew=
|
||||
github.com/multiformats/go-multihash v0.0.13/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc=
|
||||
github.com/multiformats/go-multihash v0.0.14/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc=
|
||||
|
@ -1603,8 +1605,8 @@ github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vv
|
|||
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
|
||||
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
|
||||
github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
|
||||
github.com/onsi/ginkgo/v2 v2.5.1 h1:auzK7OI497k6x4OvWq+TKAcpcSAlod0doAH72oIN0Jw=
|
||||
github.com/onsi/ginkgo/v2 v2.5.1/go.mod h1:63DOGlLAH8+REH8jUGdL3YpCpu7JODesutUjdENfUAc=
|
||||
github.com/onsi/ginkgo/v2 v2.9.2 h1:BA2GMJOtfGAfagzYtrAlufIP0lq6QERkFmHLMLPwFSU=
|
||||
github.com/onsi/ginkgo/v2 v2.9.2/go.mod h1:WHcJJG2dIlcCqVfBAwUCrJxSPFb6v4azBwgxeMeDuts=
|
||||
github.com/onsi/gomega v0.0.0-20151007035656-2152b45fa28a/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
|
||||
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
|
||||
github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
|
||||
|
@ -1619,7 +1621,7 @@ github.com/onsi/gomega v1.11.0/go.mod h1:azGKhqFUon9Vuj0YmTfLSmx0FUwqXYSTl5re8lQ
|
|||
github.com/onsi/gomega v1.15.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+tEHG0=
|
||||
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
|
||||
github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro=
|
||||
github.com/onsi/gomega v1.24.0 h1:+0glovB9Jd6z3VR+ScSwQqXVTIfJcGA9UBM8yzQxhqg=
|
||||
github.com/onsi/gomega v1.27.4 h1:Z2AnStgsdSayCMDiCU42qIz+HLqEPcgiOCXjAU/w+8E=
|
||||
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
|
||||
github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
|
||||
github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
|
||||
|
@ -1822,8 +1824,8 @@ github.com/prometheus/common v0.15.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16
|
|||
github.com/prometheus/common v0.18.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s=
|
||||
github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
|
||||
github.com/prometheus/common v0.30.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
|
||||
github.com/prometheus/common v0.39.0 h1:oOyhkDq05hPZKItWVBkJ6g6AtGxi+fy7F4JvUV8uhsI=
|
||||
github.com/prometheus/common v0.39.0/go.mod h1:6XBZ7lYdLCbkAVhwRsWTZn+IN5AB9F/NXd5w0BbEX0Y=
|
||||
github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM=
|
||||
github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc=
|
||||
github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
|
@ -1848,10 +1850,10 @@ github.com/prometheus/tsdb v0.10.0 h1:If5rVCMTp6W2SiRAQFlbpJNgVlgMEd+U2GZckwK38i
|
|||
github.com/prometheus/tsdb v0.10.0/go.mod h1:oi49uRhEe9dPUTlS3JRZOwJuVi6tmh10QSgwXEyGCt4=
|
||||
github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo=
|
||||
github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A=
|
||||
github.com/quic-go/qtls-go1-19 v0.2.1 h1:aJcKNMkH5ASEJB9FXNeZCyTEIHU1J7MmHyz1Q1TSG1A=
|
||||
github.com/quic-go/qtls-go1-19 v0.2.1/go.mod h1:ySOI96ew8lnoKPtSqx2BlI5wCpUVPT05RMAlajtnyOI=
|
||||
github.com/quic-go/qtls-go1-20 v0.1.1 h1:KbChDlg82d3IHqaj2bn6GfKRj84Per2VGf5XV3wSwQk=
|
||||
github.com/quic-go/qtls-go1-20 v0.1.1/go.mod h1:JKtK6mjbAVcUTN/9jZpvLbGxvdWIKS8uT7EiStoU1SM=
|
||||
github.com/quic-go/qtls-go1-19 v0.3.2 h1:tFxjCFcTQzK+oMxG6Zcvp4Dq8dx4yD3dDiIiyc86Z5U=
|
||||
github.com/quic-go/qtls-go1-19 v0.3.2/go.mod h1:ySOI96ew8lnoKPtSqx2BlI5wCpUVPT05RMAlajtnyOI=
|
||||
github.com/quic-go/qtls-go1-20 v0.2.2 h1:WLOPx6OY/hxtTxKV1Zrq20FtXtDEkeY00CGQm8GEa3E=
|
||||
github.com/quic-go/qtls-go1-20 v0.2.2/go.mod h1:JKtK6mjbAVcUTN/9jZpvLbGxvdWIKS8uT7EiStoU1SM=
|
||||
github.com/quic-go/quic-go v0.33.0 h1:ItNoTDN/Fm/zBlq769lLJc8ECe9gYaW40veHCCco7y0=
|
||||
github.com/quic-go/quic-go v0.33.0/go.mod h1:YMuhaAV9/jIu0XclDXwZPAsP/2Kgr5yMYhe9oxhhOFA=
|
||||
github.com/quic-go/webtransport-go v0.5.2 h1:GA6Bl6oZY+g/flt00Pnu0XtivSD8vukOu3lYhJjnGEk=
|
||||
|
@ -2042,8 +2044,9 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
|
|||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
|
||||
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
||||
github.com/syncthing/syncthing v0.14.48-rc.4/go.mod h1:nw3siZwHPA6M8iSfjDCWQ402eqvEIasMQOE8nFOxy7M=
|
||||
github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
|
||||
|
@ -2106,8 +2109,8 @@ github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1
|
|||
github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
|
||||
github.com/waku-org/go-discover v0.0.0-20221209174356-61c833f34d98 h1:xwY0kW5XZFimdqfZb9cZwT1S3VJP9j3AE6bdNd9boXM=
|
||||
github.com/waku-org/go-discover v0.0.0-20221209174356-61c833f34d98/go.mod h1:eBHgM6T4EG0RZzxpxKy+rGz/6Dw2Nd8DWxS0lm9ESDw=
|
||||
github.com/waku-org/go-waku v0.6.1-0.20230518201054-a5abfa87107c h1:aMukfU7qJJCTxMGvSftYlhu3oFSSFLOhX1v3dCeckTg=
|
||||
github.com/waku-org/go-waku v0.6.1-0.20230518201054-a5abfa87107c/go.mod h1:UTfwpa9QodcWIUpBRto1QsoBPL4Jfby0Alr9j85veP4=
|
||||
github.com/waku-org/go-waku v0.6.1-0.20230526151800-10c2e20910bf h1:9+3yMLVo/O7QX7s98gZ+nqLwl7UX/XGKBZ9PHVufkkY=
|
||||
github.com/waku-org/go-waku v0.6.1-0.20230526151800-10c2e20910bf/go.mod h1:dcGbxOa6+J+RxFP43QDJaiVrsXKGbK8v3suUabWbvOs=
|
||||
github.com/waku-org/go-zerokit-rln v0.1.12 h1:66+tU6sTlmUpuUlEv7kCFOGZ37MwZYFJBXHcm8QquwU=
|
||||
github.com/waku-org/go-zerokit-rln v0.1.12/go.mod h1:MUW+wB6Yj7UBMdZrhko7oHfUZeY2wchggXYjpUiMoac=
|
||||
github.com/waku-org/go-zerokit-rln-apple v0.0.0-20230331231302-258cacb91327 h1:Q5XQqo+PEmvrybT8D7BEsKCwIYDi80s+00Q49cfm9Gs=
|
||||
|
@ -2227,10 +2230,10 @@ go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
|||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ=
|
||||
go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
|
||||
go.uber.org/dig v1.15.0 h1:vq3YWr8zRj1eFGC7Gvf907hE0eRjPTZ1d3xHadD6liE=
|
||||
go.uber.org/dig v1.15.0/go.mod h1:pKHs0wMynzL6brANhB2hLMro+zalv1osARTviTcqHLM=
|
||||
go.uber.org/fx v1.18.2 h1:bUNI6oShr+OVFQeU8cDNbnN7VFsu+SsjHzUF51V/GAU=
|
||||
go.uber.org/fx v1.18.2/go.mod h1:g0V1KMQ66zIRk8bLu3Ea5Jt2w/cHlOIp4wdRsgh0JaY=
|
||||
go.uber.org/dig v1.16.1 h1:+alNIBsl0qfY0j6epRubp/9obgtrObRAc5aD+6jbWY8=
|
||||
go.uber.org/dig v1.16.1/go.mod h1:557JTAUZT5bUK0SvCwikmLPPtdQhfvLYtO5tJgQSbnk=
|
||||
go.uber.org/fx v1.19.2 h1:SyFgYQFr1Wl0AYstE8vyYIzP4bFz2URrScjwC4cwUvY=
|
||||
go.uber.org/fx v1.19.2/go.mod h1:43G1VcqSzbIv77y00p1DRAsyZS8WdzuYdhZXmEUkMyQ=
|
||||
go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
|
||||
go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
|
||||
go.uber.org/goleak v1.1.12 h1:gZAh5/EyT/HQwlpkCy6wTpqfH9H8Lz8zbm3dZh+OyzA=
|
||||
|
@ -2239,8 +2242,8 @@ go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/
|
|||
go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
|
||||
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
|
||||
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
|
||||
go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8=
|
||||
go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak=
|
||||
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
|
||||
go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
|
@ -2296,8 +2299,8 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y
|
|||
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20220131195533-30dcbda58838/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20220331220935-ae2d96664a29/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.4.0 h1:UVQgzMY87xqpKNgb+kDsll2Igd33HszWHFLmpaRMq/8=
|
||||
golang.org/x/crypto v0.4.0/go.mod h1:3quD/ATkf6oY+rnes5c3ExXTbLc8mueNue5/DoinL80=
|
||||
golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A=
|
||||
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
|
||||
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
|
@ -2312,8 +2315,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0
|
|||
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
|
||||
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
|
||||
golang.org/x/exp v0.0.0-20230206171751-46f607a40771 h1:xP7rWLUr1e1n2xkK5YB4LI0hPEy3LJC6Wk+D4pGlOJg=
|
||||
golang.org/x/exp v0.0.0-20230206171751-46f607a40771/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
|
||||
golang.org/x/exp v0.0.0-20230321023759-10a507213a29 h1:ooxPy7fPvB4kwsA2h+iBNHkAbp/4JxTSwCmvdjEYmug=
|
||||
golang.org/x/exp v0.0.0-20230321023759-10a507213a29/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
|
||||
golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
|
@ -2351,8 +2354,8 @@ golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
|||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk=
|
||||
golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180524181706-dfa909b99c79/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
|
@ -2430,7 +2433,6 @@ golang.org/x/net v0.0.0-20210505024714-0287a6fb4125/go.mod h1:9nx3DQGgdP8bBQD5qx
|
|||
golang.org/x/net v0.0.0-20210520170846-37e1c6afe023/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210825183410-e898025ed96a/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
|
@ -2640,10 +2642,10 @@ golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU=
|
||||
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
|
@ -2762,10 +2764,9 @@ golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
|||
golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM=
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4=
|
||||
golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s=
|
||||
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
|
|
|
@ -9,7 +9,7 @@ Go package for creating, managing, inspecting, and destroying cgroups.
|
|||
The resources format for settings on the cgroup uses the OCI runtime-spec found
|
||||
[here](https://github.com/opencontainers/runtime-spec).
|
||||
|
||||
## Examples
|
||||
## Examples (v1)
|
||||
|
||||
### Create a new cgroup
|
||||
|
||||
|
@ -58,7 +58,7 @@ if err := control.Add(cgroups.Process{Pid:1234}); err != nil {
|
|||
}
|
||||
```
|
||||
|
||||
### Update the cgroup
|
||||
### Update the cgroup
|
||||
|
||||
To update the resources applied in the cgroup
|
||||
|
||||
|
@ -133,6 +133,61 @@ event := cgroups.OOMEvent()
|
|||
efd, err := control.RegisterMemoryEvent(event)
|
||||
```
|
||||
|
||||
## Examples (v2/unified)
|
||||
|
||||
### Check that the current system is running cgroups v2
|
||||
|
||||
```go
|
||||
var cgroupV2 bool
|
||||
if cgroups.Mode() == cgroups.Unified {
|
||||
cgroupV2 = true
|
||||
}
|
||||
```
|
||||
|
||||
### Create a new cgroup
|
||||
|
||||
This creates a new systemd v2 cgroup slice. Systemd slices consider ["-" a special character](https://www.freedesktop.org/software/systemd/man/systemd.slice.html),
|
||||
so the resulting slice would be located here on disk:
|
||||
|
||||
* /sys/fs/cgroup/my.slice/my-cgroup.slice/my-cgroup-abc.slice
|
||||
|
||||
```go
|
||||
import (
|
||||
cgroupsv2 "github.com/containerd/cgroups/v2"
|
||||
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||
)
|
||||
|
||||
res := cgroupsv2.Resources{}
|
||||
// dummy PID of -1 is used for creating a "general slice" to be used as a parent cgroup.
|
||||
// see https://github.com/containerd/cgroups/blob/1df78138f1e1e6ee593db155c6b369466f577651/v2/manager.go#L732-L735
|
||||
m, err := cgroupsv2.NewSystemd("/", "my-cgroup-abc.slice", -1, &res)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
```
|
||||
|
||||
### Load an existing cgroup
|
||||
|
||||
```go
|
||||
m, err := cgroupsv2.LoadSystemd("/", "my-cgroup-abc.slice")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
```
|
||||
|
||||
### Delete a cgroup
|
||||
|
||||
```go
|
||||
m, err := cgroupsv2.LoadSystemd("/", "my-cgroup-abc.slice")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = m.DeleteSystemd()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
```
|
||||
|
||||
### Attention
|
||||
|
||||
All static path should not include `/sys/fs/cgroup/` prefix, it should start with your own cgroups name
|
||||
|
|
|
@ -1,46 +0,0 @@
|
|||
# -*- mode: ruby -*-
|
||||
# vi: set ft=ruby :
|
||||
|
||||
Vagrant.configure("2") do |config|
|
||||
# Fedora box is used for testing cgroup v2 support
|
||||
config.vm.box = "fedora/35-cloud-base"
|
||||
config.vm.provider :virtualbox do |v|
|
||||
v.memory = 4096
|
||||
v.cpus = 2
|
||||
end
|
||||
config.vm.provider :libvirt do |v|
|
||||
v.memory = 4096
|
||||
v.cpus = 2
|
||||
end
|
||||
config.vm.provision "shell", inline: <<-SHELL
|
||||
set -eux -o pipefail
|
||||
# configuration
|
||||
GO_VERSION="1.17.7"
|
||||
|
||||
# install gcc and Golang
|
||||
dnf -y install gcc
|
||||
curl -fsSL "https://dl.google.com/go/go${GO_VERSION}.linux-amd64.tar.gz" | tar Cxz /usr/local
|
||||
|
||||
# setup env vars
|
||||
cat >> /etc/profile.d/sh.local <<EOF
|
||||
PATH=/usr/local/go/bin:$PATH
|
||||
GO111MODULE=on
|
||||
export PATH GO111MODULE
|
||||
EOF
|
||||
source /etc/profile.d/sh.local
|
||||
|
||||
# enter /root/go/src/github.com/containerd/cgroups
|
||||
mkdir -p /root/go/src/github.com/containerd
|
||||
ln -s /vagrant /root/go/src/github.com/containerd/cgroups
|
||||
cd /root/go/src/github.com/containerd/cgroups
|
||||
|
||||
# create /test.sh
|
||||
cat > /test.sh <<EOF
|
||||
#!/bin/bash
|
||||
set -eux -o pipefail
|
||||
cd /root/go/src/github.com/containerd/cgroups
|
||||
go test -v ./...
|
||||
EOF
|
||||
chmod +x /test.sh
|
||||
SHELL
|
||||
end
|
|
@ -84,7 +84,7 @@ func Load(hierarchy Hierarchy, path Path, opts ...InitOpts) (Cgroup, error) {
|
|||
for _, s := range pathers(subsystems) {
|
||||
p, err := path(s.Name())
|
||||
if err != nil {
|
||||
if errors.Is(err, os.ErrNotExist) {
|
||||
if errors.Is(err, os.ErrNotExist) {
|
||||
return nil, ErrCgroupDeleted
|
||||
}
|
||||
if err == ErrControllerNotActive {
|
||||
|
@ -228,6 +228,15 @@ func (c *cgroup) Delete() error {
|
|||
}
|
||||
var errs []string
|
||||
for _, s := range c.subsystems {
|
||||
// kernel prevents cgroups with running process from being removed, check the tree is empty
|
||||
procs, err := c.processes(s.Name(), true, cgroupProcs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(procs) > 0 {
|
||||
errs = append(errs, fmt.Sprintf("%s (contains running processes)", string(s.Name())))
|
||||
continue
|
||||
}
|
||||
if d, ok := s.(deleter); ok {
|
||||
sp, err := c.path(s.Name())
|
||||
if err != nil {
|
||||
|
@ -247,6 +256,7 @@ func (c *cgroup) Delete() error {
|
|||
if err := remove(path); err != nil {
|
||||
errs = append(errs, path)
|
||||
}
|
||||
continue
|
||||
}
|
||||
}
|
||||
if len(errs) > 0 {
|
||||
|
|
|
@ -17,8 +17,9 @@
|
|||
package cgroups
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
@ -70,7 +71,7 @@ func (c *cpuacctController) Stat(path string, stats *v1.Metrics) error {
|
|||
|
||||
func (c *cpuacctController) percpuUsage(path string) ([]uint64, error) {
|
||||
var usage []uint64
|
||||
data, err := ioutil.ReadFile(filepath.Join(c.Path(path), "cpuacct.usage_percpu"))
|
||||
data, err := os.ReadFile(filepath.Join(c.Path(path), "cpuacct.usage_percpu"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -86,36 +87,41 @@ func (c *cpuacctController) percpuUsage(path string) ([]uint64, error) {
|
|||
|
||||
func (c *cpuacctController) getUsage(path string) (user uint64, kernel uint64, err error) {
|
||||
statPath := filepath.Join(c.Path(path), "cpuacct.stat")
|
||||
data, err := ioutil.ReadFile(statPath)
|
||||
f, err := os.Open(statPath)
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
fields := strings.Fields(string(data))
|
||||
if len(fields) != 4 {
|
||||
return 0, 0, fmt.Errorf("%q is expected to have 4 fields", statPath)
|
||||
defer f.Close()
|
||||
var (
|
||||
raw = make(map[string]uint64)
|
||||
sc = bufio.NewScanner(f)
|
||||
)
|
||||
for sc.Scan() {
|
||||
key, v, err := parseKV(sc.Text())
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
raw[key] = v
|
||||
}
|
||||
if err := sc.Err(); err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
for _, t := range []struct {
|
||||
index int
|
||||
name string
|
||||
value *uint64
|
||||
}{
|
||||
{
|
||||
index: 0,
|
||||
name: "user",
|
||||
value: &user,
|
||||
},
|
||||
{
|
||||
index: 2,
|
||||
name: "system",
|
||||
value: &kernel,
|
||||
},
|
||||
} {
|
||||
if fields[t.index] != t.name {
|
||||
return 0, 0, fmt.Errorf("expected field %q but found %q in %q", t.name, fields[t.index], statPath)
|
||||
}
|
||||
v, err := strconv.ParseUint(fields[t.index+1], 10, 64)
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
v, ok := raw[t.name]
|
||||
if !ok {
|
||||
return 0, 0, fmt.Errorf("expected field %q but not found in %q", t.name, statPath)
|
||||
}
|
||||
*t.value = v
|
||||
}
|
||||
|
|
|
@ -19,7 +19,6 @@ package cgroups
|
|||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
|
@ -87,10 +86,10 @@ func (c *cpusetController) Update(path string, resources *specs.LinuxResources)
|
|||
}
|
||||
|
||||
func (c *cpusetController) getValues(path string) (cpus []byte, mems []byte, err error) {
|
||||
if cpus, err = ioutil.ReadFile(filepath.Join(path, "cpuset.cpus")); err != nil && !os.IsNotExist(err) {
|
||||
if cpus, err = os.ReadFile(filepath.Join(path, "cpuset.cpus")); err != nil && !os.IsNotExist(err) {
|
||||
return
|
||||
}
|
||||
if mems, err = ioutil.ReadFile(filepath.Join(path, "cpuset.mems")); err != nil && !os.IsNotExist(err) {
|
||||
if mems, err = os.ReadFile(filepath.Join(path, "cpuset.mems")); err != nil && !os.IsNotExist(err) {
|
||||
return
|
||||
}
|
||||
return cpus, mems, nil
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
package cgroups
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
@ -58,7 +58,7 @@ func (f *freezerController) changeState(path string, state State) error {
|
|||
}
|
||||
|
||||
func (f *freezerController) state(path string) (State, error) {
|
||||
current, err := ioutil.ReadFile(filepath.Join(f.root, path, "freezer.state"))
|
||||
current, err := os.ReadFile(filepath.Join(f.root, path, "freezer.state"))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
package cgroups
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
|
@ -69,7 +68,7 @@ func (p *pidsController) Stat(path string, stats *v1.Metrics) error {
|
|||
return err
|
||||
}
|
||||
var max uint64
|
||||
maxData, err := ioutil.ReadFile(filepath.Join(p.Path(path), "pids.max"))
|
||||
maxData, err := os.ReadFile(filepath.Join(p.Path(path), "pids.max"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
package cgroups
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"math"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
@ -126,13 +125,13 @@ func toRdmaEntry(strEntries []string) []*v1.RdmaEntry {
|
|||
|
||||
func (p *rdmaController) Stat(path string, stats *v1.Metrics) error {
|
||||
|
||||
currentData, err := ioutil.ReadFile(filepath.Join(p.Path(path), "rdma.current"))
|
||||
currentData, err := os.ReadFile(filepath.Join(p.Path(path), "rdma.current"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
currentPerDevices := strings.Split(string(currentData), "\n")
|
||||
|
||||
maxData, err := ioutil.ReadFile(filepath.Join(p.Path(path), "rdma.max"))
|
||||
maxData, err := os.ReadFile(filepath.Join(p.Path(path), "rdma.max"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -21,7 +21,6 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
|
@ -200,7 +199,7 @@ func hugePageSizes() ([]string, error) {
|
|||
pageSizes []string
|
||||
sizeList = []string{"B", "KB", "MB", "GB", "TB", "PB"}
|
||||
)
|
||||
files, err := ioutil.ReadDir("/sys/kernel/mm/hugepages")
|
||||
files, err := os.ReadDir("/sys/kernel/mm/hugepages")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -216,7 +215,7 @@ func hugePageSizes() ([]string, error) {
|
|||
}
|
||||
|
||||
func readUint(path string) (uint64, error) {
|
||||
v, err := ioutil.ReadFile(path)
|
||||
v, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
@ -382,7 +381,7 @@ func retryingWriteFile(path string, data []byte, mode os.FileMode) error {
|
|||
// Retry writes on EINTR; see:
|
||||
// https://github.com/golang/go/issues/38033
|
||||
for {
|
||||
err := ioutil.WriteFile(path, data, mode)
|
||||
err := os.WriteFile(path, data, mode)
|
||||
if err == nil {
|
||||
return nil
|
||||
} else if !errors.Is(err, syscall.EINTR) {
|
||||
|
|
|
@ -72,9 +72,23 @@ type ValueType struct {
|
|||
type Sample struct {
|
||||
Location []*Location
|
||||
Value []int64
|
||||
Label map[string][]string
|
||||
// Label is a per-label-key map to values for string labels.
|
||||
//
|
||||
// In general, having multiple values for the given label key is strongly
|
||||
// discouraged - see docs for the sample label field in profile.proto. The
|
||||
// main reason this unlikely state is tracked here is to make the
|
||||
// decoding->encoding roundtrip not lossy. But we expect that the value
|
||||
// slices present in this map are always of length 1.
|
||||
Label map[string][]string
|
||||
// NumLabel is a per-label-key map to values for numeric labels. See a note
|
||||
// above on handling multiple values for a label.
|
||||
NumLabel map[string][]int64
|
||||
NumUnit map[string][]string
|
||||
// NumUnit is a per-label-key map to the unit names of corresponding numeric
|
||||
// label values. The unit info may be missing even if the label is in
|
||||
// NumLabel, see the docs in profile.proto for details. When the value is
|
||||
// slice is present and not nil, its length must be equal to the length of
|
||||
// the corresponding value slice in NumLabel.
|
||||
NumUnit map[string][]string
|
||||
|
||||
locationIDX []uint64
|
||||
labelX []label
|
||||
|
@ -715,6 +729,35 @@ func (s *Sample) HasLabel(key, value string) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
// SetNumLabel sets the specified key to the specified value for all samples in the
|
||||
// profile. "unit" is a slice that describes the units that each corresponding member
|
||||
// of "values" is measured in (e.g. bytes or seconds). If there is no relevant
|
||||
// unit for a given value, that member of "unit" should be the empty string.
|
||||
// "unit" must either have the same length as "value", or be nil.
|
||||
func (p *Profile) SetNumLabel(key string, value []int64, unit []string) {
|
||||
for _, sample := range p.Sample {
|
||||
if sample.NumLabel == nil {
|
||||
sample.NumLabel = map[string][]int64{key: value}
|
||||
} else {
|
||||
sample.NumLabel[key] = value
|
||||
}
|
||||
if sample.NumUnit == nil {
|
||||
sample.NumUnit = map[string][]string{key: unit}
|
||||
} else {
|
||||
sample.NumUnit[key] = unit
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// RemoveNumLabel removes all numerical labels associated with the specified key for all
|
||||
// samples in the profile.
|
||||
func (p *Profile) RemoveNumLabel(key string) {
|
||||
for _, sample := range p.Sample {
|
||||
delete(sample.NumLabel, key)
|
||||
delete(sample.NumUnit, key)
|
||||
}
|
||||
}
|
||||
|
||||
// DiffBaseSample returns true if a sample belongs to the diff base and false
|
||||
// otherwise.
|
||||
func (s *Sample) DiffBaseSample() bool {
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
# Copyright (c) HashiCorp, Inc.
|
||||
# SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
linters:
|
||||
enable:
|
||||
- megacheck
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package lru
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"errors"
|
||||
"sync"
|
||||
|
||||
"github.com/hashicorp/golang-lru/v2/simplelru"
|
||||
|
@ -32,7 +35,7 @@ type TwoQueueCache[K comparable, V any] struct {
|
|||
|
||||
recent simplelru.LRUCache[K, V]
|
||||
frequent simplelru.LRUCache[K, V]
|
||||
recentEvict simplelru.LRUCache[K, V]
|
||||
recentEvict simplelru.LRUCache[K, struct{}]
|
||||
lock sync.RWMutex
|
||||
}
|
||||
|
||||
|
@ -46,13 +49,13 @@ func New2Q[K comparable, V any](size int) (*TwoQueueCache[K, V], error) {
|
|||
// parameter values.
|
||||
func New2QParams[K comparable, V any](size int, recentRatio, ghostRatio float64) (*TwoQueueCache[K, V], error) {
|
||||
if size <= 0 {
|
||||
return nil, fmt.Errorf("invalid size")
|
||||
return nil, errors.New("invalid size")
|
||||
}
|
||||
if recentRatio < 0.0 || recentRatio > 1.0 {
|
||||
return nil, fmt.Errorf("invalid recent ratio")
|
||||
return nil, errors.New("invalid recent ratio")
|
||||
}
|
||||
if ghostRatio < 0.0 || ghostRatio > 1.0 {
|
||||
return nil, fmt.Errorf("invalid ghost ratio")
|
||||
return nil, errors.New("invalid ghost ratio")
|
||||
}
|
||||
|
||||
// Determine the sub-sizes
|
||||
|
@ -68,7 +71,7 @@ func New2QParams[K comparable, V any](size int, recentRatio, ghostRatio float64)
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
recentEvict, err := simplelru.NewLRU[K, V](evictSize, nil)
|
||||
recentEvict, err := simplelru.NewLRU[K, struct{}](evictSize, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -153,8 +156,7 @@ func (c *TwoQueueCache[K, V]) ensureSpace(recentEvict bool) {
|
|||
// the target, evict from there
|
||||
if recentLen > 0 && (recentLen > c.recentSize || (recentLen == c.recentSize && !recentEvict)) {
|
||||
k, _, _ := c.recent.RemoveOldest()
|
||||
var empty V
|
||||
c.recentEvict.Add(k, empty)
|
||||
c.recentEvict.Add(k, struct{}{})
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ Example
|
|||
Using the LRU is very simple:
|
||||
|
||||
```go
|
||||
l, _ := New(128)
|
||||
l, _ := New[int, interface{}](128)
|
||||
for i := 0; i < 256; i++ {
|
||||
l.Add(i, nil)
|
||||
}
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package lru
|
||||
|
||||
import (
|
||||
|
@ -18,11 +21,11 @@ type ARCCache[K comparable, V any] struct {
|
|||
size int // Size is the total capacity of the cache
|
||||
p int // P is the dynamic preference towards T1 or T2
|
||||
|
||||
t1 simplelru.LRUCache[K, V] // T1 is the LRU for recently accessed items
|
||||
b1 simplelru.LRUCache[K, V] // B1 is the LRU for evictions from t1
|
||||
t1 simplelru.LRUCache[K, V] // T1 is the LRU for recently accessed items
|
||||
b1 simplelru.LRUCache[K, struct{}] // B1 is the LRU for evictions from t1
|
||||
|
||||
t2 simplelru.LRUCache[K, V] // T2 is the LRU for frequently accessed items
|
||||
b2 simplelru.LRUCache[K, V] // B2 is the LRU for evictions from t2
|
||||
t2 simplelru.LRUCache[K, V] // T2 is the LRU for frequently accessed items
|
||||
b2 simplelru.LRUCache[K, struct{}] // B2 is the LRU for evictions from t2
|
||||
|
||||
lock sync.RWMutex
|
||||
}
|
||||
|
@ -30,11 +33,11 @@ type ARCCache[K comparable, V any] struct {
|
|||
// NewARC creates an ARC of the given size
|
||||
func NewARC[K comparable, V any](size int) (*ARCCache[K, V], error) {
|
||||
// Create the sub LRUs
|
||||
b1, err := simplelru.NewLRU[K, V](size, nil)
|
||||
b1, err := simplelru.NewLRU[K, struct{}](size, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b2, err := simplelru.NewLRU[K, V](size, nil)
|
||||
b2, err := simplelru.NewLRU[K, struct{}](size, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -182,14 +185,12 @@ func (c *ARCCache[K, V]) replace(b2ContainsKey bool) {
|
|||
if t1Len > 0 && (t1Len > c.p || (t1Len == c.p && b2ContainsKey)) {
|
||||
k, _, ok := c.t1.RemoveOldest()
|
||||
if ok {
|
||||
var empty V
|
||||
c.b1.Add(k, empty)
|
||||
c.b1.Add(k, struct{}{})
|
||||
}
|
||||
} else {
|
||||
k, _, ok := c.t2.RemoveOldest()
|
||||
if ok {
|
||||
var empty V
|
||||
c.b2.Add(k, empty)
|
||||
c.b2.Add(k, struct{}{})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
// Package lru provides three different LRU caches of varying sophistication.
|
||||
//
|
||||
// Cache is a simple LRU cache. It is based on the
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package lru
|
||||
|
||||
import (
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package simplelru
|
||||
|
||||
import (
|
||||
|
@ -100,8 +103,7 @@ func (c *LRU[K, V]) Remove(key K) (present bool) {
|
|||
|
||||
// RemoveOldest removes the oldest item from the cache.
|
||||
func (c *LRU[K, V]) RemoveOldest() (key K, value V, ok bool) {
|
||||
ent := c.evictList.back()
|
||||
if ent != nil {
|
||||
if ent := c.evictList.back(); ent != nil {
|
||||
c.removeElement(ent)
|
||||
return ent.key, ent.value, true
|
||||
}
|
||||
|
@ -110,8 +112,7 @@ func (c *LRU[K, V]) RemoveOldest() (key K, value V, ok bool) {
|
|||
|
||||
// GetOldest returns the oldest entry
|
||||
func (c *LRU[K, V]) GetOldest() (key K, value V, ok bool) {
|
||||
ent := c.evictList.back()
|
||||
if ent != nil {
|
||||
if ent := c.evictList.back(); ent != nil {
|
||||
return ent.key, ent.value, true
|
||||
}
|
||||
return
|
||||
|
@ -148,8 +149,7 @@ func (c *LRU[K, V]) Resize(size int) (evicted int) {
|
|||
|
||||
// removeOldest removes the oldest item from the cache.
|
||||
func (c *LRU[K, V]) removeOldest() {
|
||||
ent := c.evictList.back()
|
||||
if ent != nil {
|
||||
if ent := c.evictList.back(); ent != nil {
|
||||
c.removeElement(ent)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
// Package simplelru provides simple LRU implementation based on build-in container/list.
|
||||
package simplelru
|
||||
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package lru
|
||||
|
||||
import (
|
||||
|
|
|
@ -63,3 +63,14 @@ func init() {
|
|||
goupnp.CharsetReaderFault = charset.NewReaderLabel
|
||||
}
|
||||
```
|
||||
|
||||
## `v2alpha`
|
||||
|
||||
The `v2alpha` subdirectory contains experimental work on a version 2 API. The plan is to eventually
|
||||
create a `v2` subdirectory with a stable version of the version 2 API. The v1 API will stay where
|
||||
it currently is.
|
||||
|
||||
> NOTE:
|
||||
>
|
||||
> * `v2alpha` will be deleted one day, so don't rely on it always existing.
|
||||
> * `v2alpha` will have API breaking changes, even with itself.
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
//go:generate goupnpdcpgen -dcp_name internetgateway1
|
||||
//go:generate goupnpdcpgen -dcp_name internetgateway1 -code_tmpl_file ../dcps.gotemplate
|
||||
package internetgateway1
|
||||
|
|
|
@ -49,35 +49,47 @@ type LANHostConfigManagement1 struct {
|
|||
goupnp.ServiceClient
|
||||
}
|
||||
|
||||
// NewLANHostConfigManagement1Clients discovers instances of the service on the network,
|
||||
// NewLANHostConfigManagement1ClientsCtx discovers instances of the service on the network,
|
||||
// and returns clients to any that are found. errors will contain an error for
|
||||
// any devices that replied but which could not be queried, and err will be set
|
||||
// if the discovery process failed outright.
|
||||
//
|
||||
// This is a typical entry calling point into this package.
|
||||
func NewLANHostConfigManagement1Clients() (clients []*LANHostConfigManagement1, errors []error, err error) {
|
||||
func NewLANHostConfigManagement1ClientsCtx(ctx context.Context) (clients []*LANHostConfigManagement1, errors []error, err error) {
|
||||
var genericClients []goupnp.ServiceClient
|
||||
if genericClients, errors, err = goupnp.NewServiceClients(URN_LANHostConfigManagement_1); err != nil {
|
||||
if genericClients, errors, err = goupnp.NewServiceClientsCtx(ctx, URN_LANHostConfigManagement_1); err != nil {
|
||||
return
|
||||
}
|
||||
clients = newLANHostConfigManagement1ClientsFromGenericClients(genericClients)
|
||||
return
|
||||
}
|
||||
|
||||
// NewLANHostConfigManagement1ClientsByURL discovers instances of the service at the given
|
||||
// NewLANHostConfigManagement1Clients is the legacy version of NewLANHostConfigManagement1ClientsCtx, but uses
|
||||
// context.Background() as the context.
|
||||
func NewLANHostConfigManagement1Clients() (clients []*LANHostConfigManagement1, errors []error, err error) {
|
||||
return NewLANHostConfigManagement1ClientsCtx(context.Background())
|
||||
}
|
||||
|
||||
// NewLANHostConfigManagement1ClientsByURLCtx discovers instances of the service at the given
|
||||
// URL, and returns clients to any that are found. An error is returned if
|
||||
// there was an error probing the service.
|
||||
//
|
||||
// This is a typical entry calling point into this package when reusing an
|
||||
// previously discovered service URL.
|
||||
func NewLANHostConfigManagement1ClientsByURL(loc *url.URL) ([]*LANHostConfigManagement1, error) {
|
||||
genericClients, err := goupnp.NewServiceClientsByURL(loc, URN_LANHostConfigManagement_1)
|
||||
func NewLANHostConfigManagement1ClientsByURLCtx(ctx context.Context, loc *url.URL) ([]*LANHostConfigManagement1, error) {
|
||||
genericClients, err := goupnp.NewServiceClientsByURLCtx(ctx, loc, URN_LANHostConfigManagement_1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return newLANHostConfigManagement1ClientsFromGenericClients(genericClients), nil
|
||||
}
|
||||
|
||||
// NewLANHostConfigManagement1ClientsByURL is the legacy version of NewLANHostConfigManagement1ClientsByURLCtx, but uses
|
||||
// context.Background() as the context.
|
||||
func NewLANHostConfigManagement1ClientsByURL(loc *url.URL) ([]*LANHostConfigManagement1, error) {
|
||||
return NewLANHostConfigManagement1ClientsByURLCtx(context.Background(), loc)
|
||||
}
|
||||
|
||||
// NewLANHostConfigManagement1ClientsFromRootDevice discovers instances of the service in
|
||||
// a given root device, and returns clients to any that are found. An error is
|
||||
// returned if there was not at least one instance of the service within the
|
||||
|
@ -798,35 +810,47 @@ type Layer3Forwarding1 struct {
|
|||
goupnp.ServiceClient
|
||||
}
|
||||
|
||||
// NewLayer3Forwarding1Clients discovers instances of the service on the network,
|
||||
// NewLayer3Forwarding1ClientsCtx discovers instances of the service on the network,
|
||||
// and returns clients to any that are found. errors will contain an error for
|
||||
// any devices that replied but which could not be queried, and err will be set
|
||||
// if the discovery process failed outright.
|
||||
//
|
||||
// This is a typical entry calling point into this package.
|
||||
func NewLayer3Forwarding1Clients() (clients []*Layer3Forwarding1, errors []error, err error) {
|
||||
func NewLayer3Forwarding1ClientsCtx(ctx context.Context) (clients []*Layer3Forwarding1, errors []error, err error) {
|
||||
var genericClients []goupnp.ServiceClient
|
||||
if genericClients, errors, err = goupnp.NewServiceClients(URN_Layer3Forwarding_1); err != nil {
|
||||
if genericClients, errors, err = goupnp.NewServiceClientsCtx(ctx, URN_Layer3Forwarding_1); err != nil {
|
||||
return
|
||||
}
|
||||
clients = newLayer3Forwarding1ClientsFromGenericClients(genericClients)
|
||||
return
|
||||
}
|
||||
|
||||
// NewLayer3Forwarding1ClientsByURL discovers instances of the service at the given
|
||||
// NewLayer3Forwarding1Clients is the legacy version of NewLayer3Forwarding1ClientsCtx, but uses
|
||||
// context.Background() as the context.
|
||||
func NewLayer3Forwarding1Clients() (clients []*Layer3Forwarding1, errors []error, err error) {
|
||||
return NewLayer3Forwarding1ClientsCtx(context.Background())
|
||||
}
|
||||
|
||||
// NewLayer3Forwarding1ClientsByURLCtx discovers instances of the service at the given
|
||||
// URL, and returns clients to any that are found. An error is returned if
|
||||
// there was an error probing the service.
|
||||
//
|
||||
// This is a typical entry calling point into this package when reusing an
|
||||
// previously discovered service URL.
|
||||
func NewLayer3Forwarding1ClientsByURL(loc *url.URL) ([]*Layer3Forwarding1, error) {
|
||||
genericClients, err := goupnp.NewServiceClientsByURL(loc, URN_Layer3Forwarding_1)
|
||||
func NewLayer3Forwarding1ClientsByURLCtx(ctx context.Context, loc *url.URL) ([]*Layer3Forwarding1, error) {
|
||||
genericClients, err := goupnp.NewServiceClientsByURLCtx(ctx, loc, URN_Layer3Forwarding_1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return newLayer3Forwarding1ClientsFromGenericClients(genericClients), nil
|
||||
}
|
||||
|
||||
// NewLayer3Forwarding1ClientsByURL is the legacy version of NewLayer3Forwarding1ClientsByURLCtx, but uses
|
||||
// context.Background() as the context.
|
||||
func NewLayer3Forwarding1ClientsByURL(loc *url.URL) ([]*Layer3Forwarding1, error) {
|
||||
return NewLayer3Forwarding1ClientsByURLCtx(context.Background(), loc)
|
||||
}
|
||||
|
||||
// NewLayer3Forwarding1ClientsFromRootDevice discovers instances of the service in
|
||||
// a given root device, and returns clients to any that are found. An error is
|
||||
// returned if there was not at least one instance of the service within the
|
||||
|
@ -929,35 +953,47 @@ type WANCableLinkConfig1 struct {
|
|||
goupnp.ServiceClient
|
||||
}
|
||||
|
||||
// NewWANCableLinkConfig1Clients discovers instances of the service on the network,
|
||||
// NewWANCableLinkConfig1ClientsCtx discovers instances of the service on the network,
|
||||
// and returns clients to any that are found. errors will contain an error for
|
||||
// any devices that replied but which could not be queried, and err will be set
|
||||
// if the discovery process failed outright.
|
||||
//
|
||||
// This is a typical entry calling point into this package.
|
||||
func NewWANCableLinkConfig1Clients() (clients []*WANCableLinkConfig1, errors []error, err error) {
|
||||
func NewWANCableLinkConfig1ClientsCtx(ctx context.Context) (clients []*WANCableLinkConfig1, errors []error, err error) {
|
||||
var genericClients []goupnp.ServiceClient
|
||||
if genericClients, errors, err = goupnp.NewServiceClients(URN_WANCableLinkConfig_1); err != nil {
|
||||
if genericClients, errors, err = goupnp.NewServiceClientsCtx(ctx, URN_WANCableLinkConfig_1); err != nil {
|
||||
return
|
||||
}
|
||||
clients = newWANCableLinkConfig1ClientsFromGenericClients(genericClients)
|
||||
return
|
||||
}
|
||||
|
||||
// NewWANCableLinkConfig1ClientsByURL discovers instances of the service at the given
|
||||
// NewWANCableLinkConfig1Clients is the legacy version of NewWANCableLinkConfig1ClientsCtx, but uses
|
||||
// context.Background() as the context.
|
||||
func NewWANCableLinkConfig1Clients() (clients []*WANCableLinkConfig1, errors []error, err error) {
|
||||
return NewWANCableLinkConfig1ClientsCtx(context.Background())
|
||||
}
|
||||
|
||||
// NewWANCableLinkConfig1ClientsByURLCtx discovers instances of the service at the given
|
||||
// URL, and returns clients to any that are found. An error is returned if
|
||||
// there was an error probing the service.
|
||||
//
|
||||
// This is a typical entry calling point into this package when reusing an
|
||||
// previously discovered service URL.
|
||||
func NewWANCableLinkConfig1ClientsByURL(loc *url.URL) ([]*WANCableLinkConfig1, error) {
|
||||
genericClients, err := goupnp.NewServiceClientsByURL(loc, URN_WANCableLinkConfig_1)
|
||||
func NewWANCableLinkConfig1ClientsByURLCtx(ctx context.Context, loc *url.URL) ([]*WANCableLinkConfig1, error) {
|
||||
genericClients, err := goupnp.NewServiceClientsByURLCtx(ctx, loc, URN_WANCableLinkConfig_1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return newWANCableLinkConfig1ClientsFromGenericClients(genericClients), nil
|
||||
}
|
||||
|
||||
// NewWANCableLinkConfig1ClientsByURL is the legacy version of NewWANCableLinkConfig1ClientsByURLCtx, but uses
|
||||
// context.Background() as the context.
|
||||
func NewWANCableLinkConfig1ClientsByURL(loc *url.URL) ([]*WANCableLinkConfig1, error) {
|
||||
return NewWANCableLinkConfig1ClientsByURLCtx(context.Background(), loc)
|
||||
}
|
||||
|
||||
// NewWANCableLinkConfig1ClientsFromRootDevice discovers instances of the service in
|
||||
// a given root device, and returns clients to any that are found. An error is
|
||||
// returned if there was not at least one instance of the service within the
|
||||
|
@ -1347,35 +1383,47 @@ type WANCommonInterfaceConfig1 struct {
|
|||
goupnp.ServiceClient
|
||||
}
|
||||
|
||||
// NewWANCommonInterfaceConfig1Clients discovers instances of the service on the network,
|
||||
// NewWANCommonInterfaceConfig1ClientsCtx discovers instances of the service on the network,
|
||||
// and returns clients to any that are found. errors will contain an error for
|
||||
// any devices that replied but which could not be queried, and err will be set
|
||||
// if the discovery process failed outright.
|
||||
//
|
||||
// This is a typical entry calling point into this package.
|
||||
func NewWANCommonInterfaceConfig1Clients() (clients []*WANCommonInterfaceConfig1, errors []error, err error) {
|
||||
func NewWANCommonInterfaceConfig1ClientsCtx(ctx context.Context) (clients []*WANCommonInterfaceConfig1, errors []error, err error) {
|
||||
var genericClients []goupnp.ServiceClient
|
||||
if genericClients, errors, err = goupnp.NewServiceClients(URN_WANCommonInterfaceConfig_1); err != nil {
|
||||
if genericClients, errors, err = goupnp.NewServiceClientsCtx(ctx, URN_WANCommonInterfaceConfig_1); err != nil {
|
||||
return
|
||||
}
|
||||
clients = newWANCommonInterfaceConfig1ClientsFromGenericClients(genericClients)
|
||||
return
|
||||
}
|
||||
|
||||
// NewWANCommonInterfaceConfig1ClientsByURL discovers instances of the service at the given
|
||||
// NewWANCommonInterfaceConfig1Clients is the legacy version of NewWANCommonInterfaceConfig1ClientsCtx, but uses
|
||||
// context.Background() as the context.
|
||||
func NewWANCommonInterfaceConfig1Clients() (clients []*WANCommonInterfaceConfig1, errors []error, err error) {
|
||||
return NewWANCommonInterfaceConfig1ClientsCtx(context.Background())
|
||||
}
|
||||
|
||||
// NewWANCommonInterfaceConfig1ClientsByURLCtx discovers instances of the service at the given
|
||||
// URL, and returns clients to any that are found. An error is returned if
|
||||
// there was an error probing the service.
|
||||
//
|
||||
// This is a typical entry calling point into this package when reusing an
|
||||
// previously discovered service URL.
|
||||
func NewWANCommonInterfaceConfig1ClientsByURL(loc *url.URL) ([]*WANCommonInterfaceConfig1, error) {
|
||||
genericClients, err := goupnp.NewServiceClientsByURL(loc, URN_WANCommonInterfaceConfig_1)
|
||||
func NewWANCommonInterfaceConfig1ClientsByURLCtx(ctx context.Context, loc *url.URL) ([]*WANCommonInterfaceConfig1, error) {
|
||||
genericClients, err := goupnp.NewServiceClientsByURLCtx(ctx, loc, URN_WANCommonInterfaceConfig_1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return newWANCommonInterfaceConfig1ClientsFromGenericClients(genericClients), nil
|
||||
}
|
||||
|
||||
// NewWANCommonInterfaceConfig1ClientsByURL is the legacy version of NewWANCommonInterfaceConfig1ClientsByURLCtx, but uses
|
||||
// context.Background() as the context.
|
||||
func NewWANCommonInterfaceConfig1ClientsByURL(loc *url.URL) ([]*WANCommonInterfaceConfig1, error) {
|
||||
return NewWANCommonInterfaceConfig1ClientsByURLCtx(context.Background(), loc)
|
||||
}
|
||||
|
||||
// NewWANCommonInterfaceConfig1ClientsFromRootDevice discovers instances of the service in
|
||||
// a given root device, and returns clients to any that are found. An error is
|
||||
// returned if there was not at least one instance of the service within the
|
||||
|
@ -1784,35 +1832,47 @@ type WANDSLLinkConfig1 struct {
|
|||
goupnp.ServiceClient
|
||||
}
|
||||
|
||||
// NewWANDSLLinkConfig1Clients discovers instances of the service on the network,
|
||||
// NewWANDSLLinkConfig1ClientsCtx discovers instances of the service on the network,
|
||||
// and returns clients to any that are found. errors will contain an error for
|
||||
// any devices that replied but which could not be queried, and err will be set
|
||||
// if the discovery process failed outright.
|
||||
//
|
||||
// This is a typical entry calling point into this package.
|
||||
func NewWANDSLLinkConfig1Clients() (clients []*WANDSLLinkConfig1, errors []error, err error) {
|
||||
func NewWANDSLLinkConfig1ClientsCtx(ctx context.Context) (clients []*WANDSLLinkConfig1, errors []error, err error) {
|
||||
var genericClients []goupnp.ServiceClient
|
||||
if genericClients, errors, err = goupnp.NewServiceClients(URN_WANDSLLinkConfig_1); err != nil {
|
||||
if genericClients, errors, err = goupnp.NewServiceClientsCtx(ctx, URN_WANDSLLinkConfig_1); err != nil {
|
||||
return
|
||||
}
|
||||
clients = newWANDSLLinkConfig1ClientsFromGenericClients(genericClients)
|
||||
return
|
||||
}
|
||||
|
||||
// NewWANDSLLinkConfig1ClientsByURL discovers instances of the service at the given
|
||||
// NewWANDSLLinkConfig1Clients is the legacy version of NewWANDSLLinkConfig1ClientsCtx, but uses
|
||||
// context.Background() as the context.
|
||||
func NewWANDSLLinkConfig1Clients() (clients []*WANDSLLinkConfig1, errors []error, err error) {
|
||||
return NewWANDSLLinkConfig1ClientsCtx(context.Background())
|
||||
}
|
||||
|
||||
// NewWANDSLLinkConfig1ClientsByURLCtx discovers instances of the service at the given
|
||||
// URL, and returns clients to any that are found. An error is returned if
|
||||
// there was an error probing the service.
|
||||
//
|
||||
// This is a typical entry calling point into this package when reusing an
|
||||
// previously discovered service URL.
|
||||
func NewWANDSLLinkConfig1ClientsByURL(loc *url.URL) ([]*WANDSLLinkConfig1, error) {
|
||||
genericClients, err := goupnp.NewServiceClientsByURL(loc, URN_WANDSLLinkConfig_1)
|
||||
func NewWANDSLLinkConfig1ClientsByURLCtx(ctx context.Context, loc *url.URL) ([]*WANDSLLinkConfig1, error) {
|
||||
genericClients, err := goupnp.NewServiceClientsByURLCtx(ctx, loc, URN_WANDSLLinkConfig_1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return newWANDSLLinkConfig1ClientsFromGenericClients(genericClients), nil
|
||||
}
|
||||
|
||||
// NewWANDSLLinkConfig1ClientsByURL is the legacy version of NewWANDSLLinkConfig1ClientsByURLCtx, but uses
|
||||
// context.Background() as the context.
|
||||
func NewWANDSLLinkConfig1ClientsByURL(loc *url.URL) ([]*WANDSLLinkConfig1, error) {
|
||||
return NewWANDSLLinkConfig1ClientsByURLCtx(context.Background(), loc)
|
||||
}
|
||||
|
||||
// NewWANDSLLinkConfig1ClientsFromRootDevice discovers instances of the service in
|
||||
// a given root device, and returns clients to any that are found. An error is
|
||||
// returned if there was not at least one instance of the service within the
|
||||
|
@ -2204,35 +2264,47 @@ type WANEthernetLinkConfig1 struct {
|
|||
goupnp.ServiceClient
|
||||
}
|
||||
|
||||
// NewWANEthernetLinkConfig1Clients discovers instances of the service on the network,
|
||||
// NewWANEthernetLinkConfig1ClientsCtx discovers instances of the service on the network,
|
||||
// and returns clients to any that are found. errors will contain an error for
|
||||
// any devices that replied but which could not be queried, and err will be set
|
||||
// if the discovery process failed outright.
|
||||
//
|
||||
// This is a typical entry calling point into this package.
|
||||
func NewWANEthernetLinkConfig1Clients() (clients []*WANEthernetLinkConfig1, errors []error, err error) {
|
||||
func NewWANEthernetLinkConfig1ClientsCtx(ctx context.Context) (clients []*WANEthernetLinkConfig1, errors []error, err error) {
|
||||
var genericClients []goupnp.ServiceClient
|
||||
if genericClients, errors, err = goupnp.NewServiceClients(URN_WANEthernetLinkConfig_1); err != nil {
|
||||
if genericClients, errors, err = goupnp.NewServiceClientsCtx(ctx, URN_WANEthernetLinkConfig_1); err != nil {
|
||||
return
|
||||
}
|
||||
clients = newWANEthernetLinkConfig1ClientsFromGenericClients(genericClients)
|
||||
return
|
||||
}
|
||||
|
||||
// NewWANEthernetLinkConfig1ClientsByURL discovers instances of the service at the given
|
||||
// NewWANEthernetLinkConfig1Clients is the legacy version of NewWANEthernetLinkConfig1ClientsCtx, but uses
|
||||
// context.Background() as the context.
|
||||
func NewWANEthernetLinkConfig1Clients() (clients []*WANEthernetLinkConfig1, errors []error, err error) {
|
||||
return NewWANEthernetLinkConfig1ClientsCtx(context.Background())
|
||||
}
|
||||
|
||||
// NewWANEthernetLinkConfig1ClientsByURLCtx discovers instances of the service at the given
|
||||
// URL, and returns clients to any that are found. An error is returned if
|
||||
// there was an error probing the service.
|
||||
//
|
||||
// This is a typical entry calling point into this package when reusing an
|
||||
// previously discovered service URL.
|
||||
func NewWANEthernetLinkConfig1ClientsByURL(loc *url.URL) ([]*WANEthernetLinkConfig1, error) {
|
||||
genericClients, err := goupnp.NewServiceClientsByURL(loc, URN_WANEthernetLinkConfig_1)
|
||||
func NewWANEthernetLinkConfig1ClientsByURLCtx(ctx context.Context, loc *url.URL) ([]*WANEthernetLinkConfig1, error) {
|
||||
genericClients, err := goupnp.NewServiceClientsByURLCtx(ctx, loc, URN_WANEthernetLinkConfig_1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return newWANEthernetLinkConfig1ClientsFromGenericClients(genericClients), nil
|
||||
}
|
||||
|
||||
// NewWANEthernetLinkConfig1ClientsByURL is the legacy version of NewWANEthernetLinkConfig1ClientsByURLCtx, but uses
|
||||
// context.Background() as the context.
|
||||
func NewWANEthernetLinkConfig1ClientsByURL(loc *url.URL) ([]*WANEthernetLinkConfig1, error) {
|
||||
return NewWANEthernetLinkConfig1ClientsByURLCtx(context.Background(), loc)
|
||||
}
|
||||
|
||||
// NewWANEthernetLinkConfig1ClientsFromRootDevice discovers instances of the service in
|
||||
// a given root device, and returns clients to any that are found. An error is
|
||||
// returned if there was not at least one instance of the service within the
|
||||
|
@ -2302,35 +2374,47 @@ type WANIPConnection1 struct {
|
|||
goupnp.ServiceClient
|
||||
}
|
||||
|
||||
// NewWANIPConnection1Clients discovers instances of the service on the network,
|
||||
// NewWANIPConnection1ClientsCtx discovers instances of the service on the network,
|
||||
// and returns clients to any that are found. errors will contain an error for
|
||||
// any devices that replied but which could not be queried, and err will be set
|
||||
// if the discovery process failed outright.
|
||||
//
|
||||
// This is a typical entry calling point into this package.
|
||||
func NewWANIPConnection1Clients() (clients []*WANIPConnection1, errors []error, err error) {
|
||||
func NewWANIPConnection1ClientsCtx(ctx context.Context) (clients []*WANIPConnection1, errors []error, err error) {
|
||||
var genericClients []goupnp.ServiceClient
|
||||
if genericClients, errors, err = goupnp.NewServiceClients(URN_WANIPConnection_1); err != nil {
|
||||
if genericClients, errors, err = goupnp.NewServiceClientsCtx(ctx, URN_WANIPConnection_1); err != nil {
|
||||
return
|
||||
}
|
||||
clients = newWANIPConnection1ClientsFromGenericClients(genericClients)
|
||||
return
|
||||
}
|
||||
|
||||
// NewWANIPConnection1ClientsByURL discovers instances of the service at the given
|
||||
// NewWANIPConnection1Clients is the legacy version of NewWANIPConnection1ClientsCtx, but uses
|
||||
// context.Background() as the context.
|
||||
func NewWANIPConnection1Clients() (clients []*WANIPConnection1, errors []error, err error) {
|
||||
return NewWANIPConnection1ClientsCtx(context.Background())
|
||||
}
|
||||
|
||||
// NewWANIPConnection1ClientsByURLCtx discovers instances of the service at the given
|
||||
// URL, and returns clients to any that are found. An error is returned if
|
||||
// there was an error probing the service.
|
||||
//
|
||||
// This is a typical entry calling point into this package when reusing an
|
||||
// previously discovered service URL.
|
||||
func NewWANIPConnection1ClientsByURL(loc *url.URL) ([]*WANIPConnection1, error) {
|
||||
genericClients, err := goupnp.NewServiceClientsByURL(loc, URN_WANIPConnection_1)
|
||||
func NewWANIPConnection1ClientsByURLCtx(ctx context.Context, loc *url.URL) ([]*WANIPConnection1, error) {
|
||||
genericClients, err := goupnp.NewServiceClientsByURLCtx(ctx, loc, URN_WANIPConnection_1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return newWANIPConnection1ClientsFromGenericClients(genericClients), nil
|
||||
}
|
||||
|
||||
// NewWANIPConnection1ClientsByURL is the legacy version of NewWANIPConnection1ClientsByURLCtx, but uses
|
||||
// context.Background() as the context.
|
||||
func NewWANIPConnection1ClientsByURL(loc *url.URL) ([]*WANIPConnection1, error) {
|
||||
return NewWANIPConnection1ClientsByURLCtx(context.Background(), loc)
|
||||
}
|
||||
|
||||
// NewWANIPConnection1ClientsFromRootDevice discovers instances of the service in
|
||||
// a given root device, and returns clients to any that are found. An error is
|
||||
// returned if there was not at least one instance of the service within the
|
||||
|
@ -3148,35 +3232,47 @@ type WANPOTSLinkConfig1 struct {
|
|||
goupnp.ServiceClient
|
||||
}
|
||||
|
||||
// NewWANPOTSLinkConfig1Clients discovers instances of the service on the network,
|
||||
// NewWANPOTSLinkConfig1ClientsCtx discovers instances of the service on the network,
|
||||
// and returns clients to any that are found. errors will contain an error for
|
||||
// any devices that replied but which could not be queried, and err will be set
|
||||
// if the discovery process failed outright.
|
||||
//
|
||||
// This is a typical entry calling point into this package.
|
||||
func NewWANPOTSLinkConfig1Clients() (clients []*WANPOTSLinkConfig1, errors []error, err error) {
|
||||
func NewWANPOTSLinkConfig1ClientsCtx(ctx context.Context) (clients []*WANPOTSLinkConfig1, errors []error, err error) {
|
||||
var genericClients []goupnp.ServiceClient
|
||||
if genericClients, errors, err = goupnp.NewServiceClients(URN_WANPOTSLinkConfig_1); err != nil {
|
||||
if genericClients, errors, err = goupnp.NewServiceClientsCtx(ctx, URN_WANPOTSLinkConfig_1); err != nil {
|
||||
return
|
||||
}
|
||||
clients = newWANPOTSLinkConfig1ClientsFromGenericClients(genericClients)
|
||||
return
|
||||
}
|
||||
|
||||
// NewWANPOTSLinkConfig1ClientsByURL discovers instances of the service at the given
|
||||
// NewWANPOTSLinkConfig1Clients is the legacy version of NewWANPOTSLinkConfig1ClientsCtx, but uses
|
||||
// context.Background() as the context.
|
||||
func NewWANPOTSLinkConfig1Clients() (clients []*WANPOTSLinkConfig1, errors []error, err error) {
|
||||
return NewWANPOTSLinkConfig1ClientsCtx(context.Background())
|
||||
}
|
||||
|
||||
// NewWANPOTSLinkConfig1ClientsByURLCtx discovers instances of the service at the given
|
||||
// URL, and returns clients to any that are found. An error is returned if
|
||||
// there was an error probing the service.
|
||||
//
|
||||
// This is a typical entry calling point into this package when reusing an
|
||||
// previously discovered service URL.
|
||||
func NewWANPOTSLinkConfig1ClientsByURL(loc *url.URL) ([]*WANPOTSLinkConfig1, error) {
|
||||
genericClients, err := goupnp.NewServiceClientsByURL(loc, URN_WANPOTSLinkConfig_1)
|
||||
func NewWANPOTSLinkConfig1ClientsByURLCtx(ctx context.Context, loc *url.URL) ([]*WANPOTSLinkConfig1, error) {
|
||||
genericClients, err := goupnp.NewServiceClientsByURLCtx(ctx, loc, URN_WANPOTSLinkConfig_1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return newWANPOTSLinkConfig1ClientsFromGenericClients(genericClients), nil
|
||||
}
|
||||
|
||||
// NewWANPOTSLinkConfig1ClientsByURL is the legacy version of NewWANPOTSLinkConfig1ClientsByURLCtx, but uses
|
||||
// context.Background() as the context.
|
||||
func NewWANPOTSLinkConfig1ClientsByURL(loc *url.URL) ([]*WANPOTSLinkConfig1, error) {
|
||||
return NewWANPOTSLinkConfig1ClientsByURLCtx(context.Background(), loc)
|
||||
}
|
||||
|
||||
// NewWANPOTSLinkConfig1ClientsFromRootDevice discovers instances of the service in
|
||||
// a given root device, and returns clients to any that are found. An error is
|
||||
// returned if there was not at least one instance of the service within the
|
||||
|
@ -3559,35 +3655,47 @@ type WANPPPConnection1 struct {
|
|||
goupnp.ServiceClient
|
||||
}
|
||||
|
||||
// NewWANPPPConnection1Clients discovers instances of the service on the network,
|
||||
// NewWANPPPConnection1ClientsCtx discovers instances of the service on the network,
|
||||
// and returns clients to any that are found. errors will contain an error for
|
||||
// any devices that replied but which could not be queried, and err will be set
|
||||
// if the discovery process failed outright.
|
||||
//
|
||||
// This is a typical entry calling point into this package.
|
||||
func NewWANPPPConnection1Clients() (clients []*WANPPPConnection1, errors []error, err error) {
|
||||
func NewWANPPPConnection1ClientsCtx(ctx context.Context) (clients []*WANPPPConnection1, errors []error, err error) {
|
||||
var genericClients []goupnp.ServiceClient
|
||||
if genericClients, errors, err = goupnp.NewServiceClients(URN_WANPPPConnection_1); err != nil {
|
||||
if genericClients, errors, err = goupnp.NewServiceClientsCtx(ctx, URN_WANPPPConnection_1); err != nil {
|
||||
return
|
||||
}
|
||||
clients = newWANPPPConnection1ClientsFromGenericClients(genericClients)
|
||||
return
|
||||
}
|
||||
|
||||
// NewWANPPPConnection1ClientsByURL discovers instances of the service at the given
|
||||
// NewWANPPPConnection1Clients is the legacy version of NewWANPPPConnection1ClientsCtx, but uses
|
||||
// context.Background() as the context.
|
||||
func NewWANPPPConnection1Clients() (clients []*WANPPPConnection1, errors []error, err error) {
|
||||
return NewWANPPPConnection1ClientsCtx(context.Background())
|
||||
}
|
||||
|
||||
// NewWANPPPConnection1ClientsByURLCtx discovers instances of the service at the given
|
||||
// URL, and returns clients to any that are found. An error is returned if
|
||||
// there was an error probing the service.
|
||||
//
|
||||
// This is a typical entry calling point into this package when reusing an
|
||||
// previously discovered service URL.
|
||||
func NewWANPPPConnection1ClientsByURL(loc *url.URL) ([]*WANPPPConnection1, error) {
|
||||
genericClients, err := goupnp.NewServiceClientsByURL(loc, URN_WANPPPConnection_1)
|
||||
func NewWANPPPConnection1ClientsByURLCtx(ctx context.Context, loc *url.URL) ([]*WANPPPConnection1, error) {
|
||||
genericClients, err := goupnp.NewServiceClientsByURLCtx(ctx, loc, URN_WANPPPConnection_1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return newWANPPPConnection1ClientsFromGenericClients(genericClients), nil
|
||||
}
|
||||
|
||||
// NewWANPPPConnection1ClientsByURL is the legacy version of NewWANPPPConnection1ClientsByURLCtx, but uses
|
||||
// context.Background() as the context.
|
||||
func NewWANPPPConnection1ClientsByURL(loc *url.URL) ([]*WANPPPConnection1, error) {
|
||||
return NewWANPPPConnection1ClientsByURLCtx(context.Background(), loc)
|
||||
}
|
||||
|
||||
// NewWANPPPConnection1ClientsFromRootDevice discovers instances of the service in
|
||||
// a given root device, and returns clients to any that are found. An error is
|
||||
// returned if there was not at least one instance of the service within the
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
//go:generate goupnpdcpgen -dcp_name internetgateway2
|
||||
//go:generate goupnpdcpgen -dcp_name internetgateway2 -code_tmpl_file ../dcps.gotemplate
|
||||
package internetgateway2
|
||||
|
|
|
@ -54,35 +54,47 @@ type DeviceProtection1 struct {
|
|||
goupnp.ServiceClient
|
||||
}
|
||||
|
||||
// NewDeviceProtection1Clients discovers instances of the service on the network,
|
||||
// NewDeviceProtection1ClientsCtx discovers instances of the service on the network,
|
||||
// and returns clients to any that are found. errors will contain an error for
|
||||
// any devices that replied but which could not be queried, and err will be set
|
||||
// if the discovery process failed outright.
|
||||
//
|
||||
// This is a typical entry calling point into this package.
|
||||
func NewDeviceProtection1Clients() (clients []*DeviceProtection1, errors []error, err error) {
|
||||
func NewDeviceProtection1ClientsCtx(ctx context.Context) (clients []*DeviceProtection1, errors []error, err error) {
|
||||
var genericClients []goupnp.ServiceClient
|
||||
if genericClients, errors, err = goupnp.NewServiceClients(URN_DeviceProtection_1); err != nil {
|
||||
if genericClients, errors, err = goupnp.NewServiceClientsCtx(ctx, URN_DeviceProtection_1); err != nil {
|
||||
return
|
||||
}
|
||||
clients = newDeviceProtection1ClientsFromGenericClients(genericClients)
|
||||
return
|
||||
}
|
||||
|
||||
// NewDeviceProtection1ClientsByURL discovers instances of the service at the given
|
||||
// NewDeviceProtection1Clients is the legacy version of NewDeviceProtection1ClientsCtx, but uses
|
||||
// context.Background() as the context.
|
||||
func NewDeviceProtection1Clients() (clients []*DeviceProtection1, errors []error, err error) {
|
||||
return NewDeviceProtection1ClientsCtx(context.Background())
|
||||
}
|
||||
|
||||
// NewDeviceProtection1ClientsByURLCtx discovers instances of the service at the given
|
||||
// URL, and returns clients to any that are found. An error is returned if
|
||||
// there was an error probing the service.
|
||||
//
|
||||
// This is a typical entry calling point into this package when reusing an
|
||||
// previously discovered service URL.
|
||||
func NewDeviceProtection1ClientsByURL(loc *url.URL) ([]*DeviceProtection1, error) {
|
||||
genericClients, err := goupnp.NewServiceClientsByURL(loc, URN_DeviceProtection_1)
|
||||
func NewDeviceProtection1ClientsByURLCtx(ctx context.Context, loc *url.URL) ([]*DeviceProtection1, error) {
|
||||
genericClients, err := goupnp.NewServiceClientsByURLCtx(ctx, loc, URN_DeviceProtection_1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return newDeviceProtection1ClientsFromGenericClients(genericClients), nil
|
||||
}
|
||||
|
||||
// NewDeviceProtection1ClientsByURL is the legacy version of NewDeviceProtection1ClientsByURLCtx, but uses
|
||||
// context.Background() as the context.
|
||||
func NewDeviceProtection1ClientsByURL(loc *url.URL) ([]*DeviceProtection1, error) {
|
||||
return NewDeviceProtection1ClientsByURLCtx(context.Background(), loc)
|
||||
}
|
||||
|
||||
// NewDeviceProtection1ClientsFromRootDevice discovers instances of the service in
|
||||
// a given root device, and returns clients to any that are found. An error is
|
||||
// returned if there was not at least one instance of the service within the
|
||||
|
@ -672,35 +684,47 @@ type LANHostConfigManagement1 struct {
|
|||
goupnp.ServiceClient
|
||||
}
|
||||
|
||||
// NewLANHostConfigManagement1Clients discovers instances of the service on the network,
|
||||
// NewLANHostConfigManagement1ClientsCtx discovers instances of the service on the network,
|
||||
// and returns clients to any that are found. errors will contain an error for
|
||||
// any devices that replied but which could not be queried, and err will be set
|
||||
// if the discovery process failed outright.
|
||||
//
|
||||
// This is a typical entry calling point into this package.
|
||||
func NewLANHostConfigManagement1Clients() (clients []*LANHostConfigManagement1, errors []error, err error) {
|
||||
func NewLANHostConfigManagement1ClientsCtx(ctx context.Context) (clients []*LANHostConfigManagement1, errors []error, err error) {
|
||||
var genericClients []goupnp.ServiceClient
|
||||
if genericClients, errors, err = goupnp.NewServiceClients(URN_LANHostConfigManagement_1); err != nil {
|
||||
if genericClients, errors, err = goupnp.NewServiceClientsCtx(ctx, URN_LANHostConfigManagement_1); err != nil {
|
||||
return
|
||||
}
|
||||
clients = newLANHostConfigManagement1ClientsFromGenericClients(genericClients)
|
||||
return
|
||||
}
|
||||
|
||||
// NewLANHostConfigManagement1ClientsByURL discovers instances of the service at the given
|
||||
// NewLANHostConfigManagement1Clients is the legacy version of NewLANHostConfigManagement1ClientsCtx, but uses
|
||||
// context.Background() as the context.
|
||||
func NewLANHostConfigManagement1Clients() (clients []*LANHostConfigManagement1, errors []error, err error) {
|
||||
return NewLANHostConfigManagement1ClientsCtx(context.Background())
|
||||
}
|
||||
|
||||
// NewLANHostConfigManagement1ClientsByURLCtx discovers instances of the service at the given
|
||||
// URL, and returns clients to any that are found. An error is returned if
|
||||
// there was an error probing the service.
|
||||
//
|
||||
// This is a typical entry calling point into this package when reusing an
|
||||
// previously discovered service URL.
|
||||
func NewLANHostConfigManagement1ClientsByURL(loc *url.URL) ([]*LANHostConfigManagement1, error) {
|
||||
genericClients, err := goupnp.NewServiceClientsByURL(loc, URN_LANHostConfigManagement_1)
|
||||
func NewLANHostConfigManagement1ClientsByURLCtx(ctx context.Context, loc *url.URL) ([]*LANHostConfigManagement1, error) {
|
||||
genericClients, err := goupnp.NewServiceClientsByURLCtx(ctx, loc, URN_LANHostConfigManagement_1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return newLANHostConfigManagement1ClientsFromGenericClients(genericClients), nil
|
||||
}
|
||||
|
||||
// NewLANHostConfigManagement1ClientsByURL is the legacy version of NewLANHostConfigManagement1ClientsByURLCtx, but uses
|
||||
// context.Background() as the context.
|
||||
func NewLANHostConfigManagement1ClientsByURL(loc *url.URL) ([]*LANHostConfigManagement1, error) {
|
||||
return NewLANHostConfigManagement1ClientsByURLCtx(context.Background(), loc)
|
||||
}
|
||||
|
||||
// NewLANHostConfigManagement1ClientsFromRootDevice discovers instances of the service in
|
||||
// a given root device, and returns clients to any that are found. An error is
|
||||
// returned if there was not at least one instance of the service within the
|
||||
|
@ -1421,35 +1445,47 @@ type Layer3Forwarding1 struct {
|
|||
goupnp.ServiceClient
|
||||
}
|
||||
|
||||
// NewLayer3Forwarding1Clients discovers instances of the service on the network,
|
||||
// NewLayer3Forwarding1ClientsCtx discovers instances of the service on the network,
|
||||
// and returns clients to any that are found. errors will contain an error for
|
||||
// any devices that replied but which could not be queried, and err will be set
|
||||
// if the discovery process failed outright.
|
||||
//
|
||||
// This is a typical entry calling point into this package.
|
||||
func NewLayer3Forwarding1Clients() (clients []*Layer3Forwarding1, errors []error, err error) {
|
||||
func NewLayer3Forwarding1ClientsCtx(ctx context.Context) (clients []*Layer3Forwarding1, errors []error, err error) {
|
||||
var genericClients []goupnp.ServiceClient
|
||||
if genericClients, errors, err = goupnp.NewServiceClients(URN_Layer3Forwarding_1); err != nil {
|
||||
if genericClients, errors, err = goupnp.NewServiceClientsCtx(ctx, URN_Layer3Forwarding_1); err != nil {
|
||||
return
|
||||
}
|
||||
clients = newLayer3Forwarding1ClientsFromGenericClients(genericClients)
|
||||
return
|
||||
}
|
||||
|
||||
// NewLayer3Forwarding1ClientsByURL discovers instances of the service at the given
|
||||
// NewLayer3Forwarding1Clients is the legacy version of NewLayer3Forwarding1ClientsCtx, but uses
|
||||
// context.Background() as the context.
|
||||
func NewLayer3Forwarding1Clients() (clients []*Layer3Forwarding1, errors []error, err error) {
|
||||
return NewLayer3Forwarding1ClientsCtx(context.Background())
|
||||
}
|
||||
|
||||
// NewLayer3Forwarding1ClientsByURLCtx discovers instances of the service at the given
|
||||
// URL, and returns clients to any that are found. An error is returned if
|
||||
// there was an error probing the service.
|
||||
//
|
||||
// This is a typical entry calling point into this package when reusing an
|
||||
// previously discovered service URL.
|
||||
func NewLayer3Forwarding1ClientsByURL(loc *url.URL) ([]*Layer3Forwarding1, error) {
|
||||
genericClients, err := goupnp.NewServiceClientsByURL(loc, URN_Layer3Forwarding_1)
|
||||
func NewLayer3Forwarding1ClientsByURLCtx(ctx context.Context, loc *url.URL) ([]*Layer3Forwarding1, error) {
|
||||
genericClients, err := goupnp.NewServiceClientsByURLCtx(ctx, loc, URN_Layer3Forwarding_1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return newLayer3Forwarding1ClientsFromGenericClients(genericClients), nil
|
||||
}
|
||||
|
||||
// NewLayer3Forwarding1ClientsByURL is the legacy version of NewLayer3Forwarding1ClientsByURLCtx, but uses
|
||||
// context.Background() as the context.
|
||||
func NewLayer3Forwarding1ClientsByURL(loc *url.URL) ([]*Layer3Forwarding1, error) {
|
||||
return NewLayer3Forwarding1ClientsByURLCtx(context.Background(), loc)
|
||||
}
|
||||
|
||||
// NewLayer3Forwarding1ClientsFromRootDevice discovers instances of the service in
|
||||
// a given root device, and returns clients to any that are found. An error is
|
||||
// returned if there was not at least one instance of the service within the
|
||||
|
@ -1552,35 +1588,47 @@ type WANCableLinkConfig1 struct {
|
|||
goupnp.ServiceClient
|
||||
}
|
||||
|
||||
// NewWANCableLinkConfig1Clients discovers instances of the service on the network,
|
||||
// NewWANCableLinkConfig1ClientsCtx discovers instances of the service on the network,
|
||||
// and returns clients to any that are found. errors will contain an error for
|
||||
// any devices that replied but which could not be queried, and err will be set
|
||||
// if the discovery process failed outright.
|
||||
//
|
||||
// This is a typical entry calling point into this package.
|
||||
func NewWANCableLinkConfig1Clients() (clients []*WANCableLinkConfig1, errors []error, err error) {
|
||||
func NewWANCableLinkConfig1ClientsCtx(ctx context.Context) (clients []*WANCableLinkConfig1, errors []error, err error) {
|
||||
var genericClients []goupnp.ServiceClient
|
||||
if genericClients, errors, err = goupnp.NewServiceClients(URN_WANCableLinkConfig_1); err != nil {
|
||||
if genericClients, errors, err = goupnp.NewServiceClientsCtx(ctx, URN_WANCableLinkConfig_1); err != nil {
|
||||
return
|
||||
}
|
||||
clients = newWANCableLinkConfig1ClientsFromGenericClients(genericClients)
|
||||
return
|
||||
}
|
||||
|
||||
// NewWANCableLinkConfig1ClientsByURL discovers instances of the service at the given
|
||||
// NewWANCableLinkConfig1Clients is the legacy version of NewWANCableLinkConfig1ClientsCtx, but uses
|
||||
// context.Background() as the context.
|
||||
func NewWANCableLinkConfig1Clients() (clients []*WANCableLinkConfig1, errors []error, err error) {
|
||||
return NewWANCableLinkConfig1ClientsCtx(context.Background())
|
||||
}
|
||||
|
||||
// NewWANCableLinkConfig1ClientsByURLCtx discovers instances of the service at the given
|
||||
// URL, and returns clients to any that are found. An error is returned if
|
||||
// there was an error probing the service.
|
||||
//
|
||||
// This is a typical entry calling point into this package when reusing an
|
||||
// previously discovered service URL.
|
||||
func NewWANCableLinkConfig1ClientsByURL(loc *url.URL) ([]*WANCableLinkConfig1, error) {
|
||||
genericClients, err := goupnp.NewServiceClientsByURL(loc, URN_WANCableLinkConfig_1)
|
||||
func NewWANCableLinkConfig1ClientsByURLCtx(ctx context.Context, loc *url.URL) ([]*WANCableLinkConfig1, error) {
|
||||
genericClients, err := goupnp.NewServiceClientsByURLCtx(ctx, loc, URN_WANCableLinkConfig_1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return newWANCableLinkConfig1ClientsFromGenericClients(genericClients), nil
|
||||
}
|
||||
|
||||
// NewWANCableLinkConfig1ClientsByURL is the legacy version of NewWANCableLinkConfig1ClientsByURLCtx, but uses
|
||||
// context.Background() as the context.
|
||||
func NewWANCableLinkConfig1ClientsByURL(loc *url.URL) ([]*WANCableLinkConfig1, error) {
|
||||
return NewWANCableLinkConfig1ClientsByURLCtx(context.Background(), loc)
|
||||
}
|
||||
|
||||
// NewWANCableLinkConfig1ClientsFromRootDevice discovers instances of the service in
|
||||
// a given root device, and returns clients to any that are found. An error is
|
||||
// returned if there was not at least one instance of the service within the
|
||||
|
@ -1970,35 +2018,47 @@ type WANCommonInterfaceConfig1 struct {
|
|||
goupnp.ServiceClient
|
||||
}
|
||||
|
||||
// NewWANCommonInterfaceConfig1Clients discovers instances of the service on the network,
|
||||
// NewWANCommonInterfaceConfig1ClientsCtx discovers instances of the service on the network,
|
||||
// and returns clients to any that are found. errors will contain an error for
|
||||
// any devices that replied but which could not be queried, and err will be set
|
||||
// if the discovery process failed outright.
|
||||
//
|
||||
// This is a typical entry calling point into this package.
|
||||
func NewWANCommonInterfaceConfig1Clients() (clients []*WANCommonInterfaceConfig1, errors []error, err error) {
|
||||
func NewWANCommonInterfaceConfig1ClientsCtx(ctx context.Context) (clients []*WANCommonInterfaceConfig1, errors []error, err error) {
|
||||
var genericClients []goupnp.ServiceClient
|
||||
if genericClients, errors, err = goupnp.NewServiceClients(URN_WANCommonInterfaceConfig_1); err != nil {
|
||||
if genericClients, errors, err = goupnp.NewServiceClientsCtx(ctx, URN_WANCommonInterfaceConfig_1); err != nil {
|
||||
return
|
||||
}
|
||||
clients = newWANCommonInterfaceConfig1ClientsFromGenericClients(genericClients)
|
||||
return
|
||||
}
|
||||
|
||||
// NewWANCommonInterfaceConfig1ClientsByURL discovers instances of the service at the given
|
||||
// NewWANCommonInterfaceConfig1Clients is the legacy version of NewWANCommonInterfaceConfig1ClientsCtx, but uses
|
||||
// context.Background() as the context.
|
||||
func NewWANCommonInterfaceConfig1Clients() (clients []*WANCommonInterfaceConfig1, errors []error, err error) {
|
||||
return NewWANCommonInterfaceConfig1ClientsCtx(context.Background())
|
||||
}
|
||||
|
||||
// NewWANCommonInterfaceConfig1ClientsByURLCtx discovers instances of the service at the given
|
||||
// URL, and returns clients to any that are found. An error is returned if
|
||||
// there was an error probing the service.
|
||||
//
|
||||
// This is a typical entry calling point into this package when reusing an
|
||||
// previously discovered service URL.
|
||||
func NewWANCommonInterfaceConfig1ClientsByURL(loc *url.URL) ([]*WANCommonInterfaceConfig1, error) {
|
||||
genericClients, err := goupnp.NewServiceClientsByURL(loc, URN_WANCommonInterfaceConfig_1)
|
||||
func NewWANCommonInterfaceConfig1ClientsByURLCtx(ctx context.Context, loc *url.URL) ([]*WANCommonInterfaceConfig1, error) {
|
||||
genericClients, err := goupnp.NewServiceClientsByURLCtx(ctx, loc, URN_WANCommonInterfaceConfig_1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return newWANCommonInterfaceConfig1ClientsFromGenericClients(genericClients), nil
|
||||
}
|
||||
|
||||
// NewWANCommonInterfaceConfig1ClientsByURL is the legacy version of NewWANCommonInterfaceConfig1ClientsByURLCtx, but uses
|
||||
// context.Background() as the context.
|
||||
func NewWANCommonInterfaceConfig1ClientsByURL(loc *url.URL) ([]*WANCommonInterfaceConfig1, error) {
|
||||
return NewWANCommonInterfaceConfig1ClientsByURLCtx(context.Background(), loc)
|
||||
}
|
||||
|
||||
// NewWANCommonInterfaceConfig1ClientsFromRootDevice discovers instances of the service in
|
||||
// a given root device, and returns clients to any that are found. An error is
|
||||
// returned if there was not at least one instance of the service within the
|
||||
|
@ -2407,35 +2467,47 @@ type WANDSLLinkConfig1 struct {
|
|||
goupnp.ServiceClient
|
||||
}
|
||||
|
||||
// NewWANDSLLinkConfig1Clients discovers instances of the service on the network,
|
||||
// NewWANDSLLinkConfig1ClientsCtx discovers instances of the service on the network,
|
||||
// and returns clients to any that are found. errors will contain an error for
|
||||
// any devices that replied but which could not be queried, and err will be set
|
||||
// if the discovery process failed outright.
|
||||
//
|
||||
// This is a typical entry calling point into this package.
|
||||
func NewWANDSLLinkConfig1Clients() (clients []*WANDSLLinkConfig1, errors []error, err error) {
|
||||
func NewWANDSLLinkConfig1ClientsCtx(ctx context.Context) (clients []*WANDSLLinkConfig1, errors []error, err error) {
|
||||
var genericClients []goupnp.ServiceClient
|
||||
if genericClients, errors, err = goupnp.NewServiceClients(URN_WANDSLLinkConfig_1); err != nil {
|
||||
if genericClients, errors, err = goupnp.NewServiceClientsCtx(ctx, URN_WANDSLLinkConfig_1); err != nil {
|
||||
return
|
||||
}
|
||||
clients = newWANDSLLinkConfig1ClientsFromGenericClients(genericClients)
|
||||
return
|
||||
}
|
||||
|
||||
// NewWANDSLLinkConfig1ClientsByURL discovers instances of the service at the given
|
||||
// NewWANDSLLinkConfig1Clients is the legacy version of NewWANDSLLinkConfig1ClientsCtx, but uses
|
||||
// context.Background() as the context.
|
||||
func NewWANDSLLinkConfig1Clients() (clients []*WANDSLLinkConfig1, errors []error, err error) {
|
||||
return NewWANDSLLinkConfig1ClientsCtx(context.Background())
|
||||
}
|
||||
|
||||
// NewWANDSLLinkConfig1ClientsByURLCtx discovers instances of the service at the given
|
||||
// URL, and returns clients to any that are found. An error is returned if
|
||||
// there was an error probing the service.
|
||||
//
|
||||
// This is a typical entry calling point into this package when reusing an
|
||||
// previously discovered service URL.
|
||||
func NewWANDSLLinkConfig1ClientsByURL(loc *url.URL) ([]*WANDSLLinkConfig1, error) {
|
||||
genericClients, err := goupnp.NewServiceClientsByURL(loc, URN_WANDSLLinkConfig_1)
|
||||
func NewWANDSLLinkConfig1ClientsByURLCtx(ctx context.Context, loc *url.URL) ([]*WANDSLLinkConfig1, error) {
|
||||
genericClients, err := goupnp.NewServiceClientsByURLCtx(ctx, loc, URN_WANDSLLinkConfig_1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return newWANDSLLinkConfig1ClientsFromGenericClients(genericClients), nil
|
||||
}
|
||||
|
||||
// NewWANDSLLinkConfig1ClientsByURL is the legacy version of NewWANDSLLinkConfig1ClientsByURLCtx, but uses
|
||||
// context.Background() as the context.
|
||||
func NewWANDSLLinkConfig1ClientsByURL(loc *url.URL) ([]*WANDSLLinkConfig1, error) {
|
||||
return NewWANDSLLinkConfig1ClientsByURLCtx(context.Background(), loc)
|
||||
}
|
||||
|
||||
// NewWANDSLLinkConfig1ClientsFromRootDevice discovers instances of the service in
|
||||
// a given root device, and returns clients to any that are found. An error is
|
||||
// returned if there was not at least one instance of the service within the
|
||||
|
@ -2827,35 +2899,47 @@ type WANEthernetLinkConfig1 struct {
|
|||
goupnp.ServiceClient
|
||||
}
|
||||
|
||||
// NewWANEthernetLinkConfig1Clients discovers instances of the service on the network,
|
||||
// NewWANEthernetLinkConfig1ClientsCtx discovers instances of the service on the network,
|
||||
// and returns clients to any that are found. errors will contain an error for
|
||||
// any devices that replied but which could not be queried, and err will be set
|
||||
// if the discovery process failed outright.
|
||||
//
|
||||
// This is a typical entry calling point into this package.
|
||||
func NewWANEthernetLinkConfig1Clients() (clients []*WANEthernetLinkConfig1, errors []error, err error) {
|
||||
func NewWANEthernetLinkConfig1ClientsCtx(ctx context.Context) (clients []*WANEthernetLinkConfig1, errors []error, err error) {
|
||||
var genericClients []goupnp.ServiceClient
|
||||
if genericClients, errors, err = goupnp.NewServiceClients(URN_WANEthernetLinkConfig_1); err != nil {
|
||||
if genericClients, errors, err = goupnp.NewServiceClientsCtx(ctx, URN_WANEthernetLinkConfig_1); err != nil {
|
||||
return
|
||||
}
|
||||
clients = newWANEthernetLinkConfig1ClientsFromGenericClients(genericClients)
|
||||
return
|
||||
}
|
||||
|
||||
// NewWANEthernetLinkConfig1ClientsByURL discovers instances of the service at the given
|
||||
// NewWANEthernetLinkConfig1Clients is the legacy version of NewWANEthernetLinkConfig1ClientsCtx, but uses
|
||||
// context.Background() as the context.
|
||||
func NewWANEthernetLinkConfig1Clients() (clients []*WANEthernetLinkConfig1, errors []error, err error) {
|
||||
return NewWANEthernetLinkConfig1ClientsCtx(context.Background())
|
||||
}
|
||||
|
||||
// NewWANEthernetLinkConfig1ClientsByURLCtx discovers instances of the service at the given
|
||||
// URL, and returns clients to any that are found. An error is returned if
|
||||
// there was an error probing the service.
|
||||
//
|
||||
// This is a typical entry calling point into this package when reusing an
|
||||
// previously discovered service URL.
|
||||
func NewWANEthernetLinkConfig1ClientsByURL(loc *url.URL) ([]*WANEthernetLinkConfig1, error) {
|
||||
genericClients, err := goupnp.NewServiceClientsByURL(loc, URN_WANEthernetLinkConfig_1)
|
||||
func NewWANEthernetLinkConfig1ClientsByURLCtx(ctx context.Context, loc *url.URL) ([]*WANEthernetLinkConfig1, error) {
|
||||
genericClients, err := goupnp.NewServiceClientsByURLCtx(ctx, loc, URN_WANEthernetLinkConfig_1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return newWANEthernetLinkConfig1ClientsFromGenericClients(genericClients), nil
|
||||
}
|
||||
|
||||
// NewWANEthernetLinkConfig1ClientsByURL is the legacy version of NewWANEthernetLinkConfig1ClientsByURLCtx, but uses
|
||||
// context.Background() as the context.
|
||||
func NewWANEthernetLinkConfig1ClientsByURL(loc *url.URL) ([]*WANEthernetLinkConfig1, error) {
|
||||
return NewWANEthernetLinkConfig1ClientsByURLCtx(context.Background(), loc)
|
||||
}
|
||||
|
||||
// NewWANEthernetLinkConfig1ClientsFromRootDevice discovers instances of the service in
|
||||
// a given root device, and returns clients to any that are found. An error is
|
||||
// returned if there was not at least one instance of the service within the
|
||||
|
@ -2925,35 +3009,47 @@ type WANIPConnection1 struct {
|
|||
goupnp.ServiceClient
|
||||
}
|
||||
|
||||
// NewWANIPConnection1Clients discovers instances of the service on the network,
|
||||
// NewWANIPConnection1ClientsCtx discovers instances of the service on the network,
|
||||
// and returns clients to any that are found. errors will contain an error for
|
||||
// any devices that replied but which could not be queried, and err will be set
|
||||
// if the discovery process failed outright.
|
||||
//
|
||||
// This is a typical entry calling point into this package.
|
||||
func NewWANIPConnection1Clients() (clients []*WANIPConnection1, errors []error, err error) {
|
||||
func NewWANIPConnection1ClientsCtx(ctx context.Context) (clients []*WANIPConnection1, errors []error, err error) {
|
||||
var genericClients []goupnp.ServiceClient
|
||||
if genericClients, errors, err = goupnp.NewServiceClients(URN_WANIPConnection_1); err != nil {
|
||||
if genericClients, errors, err = goupnp.NewServiceClientsCtx(ctx, URN_WANIPConnection_1); err != nil {
|
||||
return
|
||||
}
|
||||
clients = newWANIPConnection1ClientsFromGenericClients(genericClients)
|
||||
return
|
||||
}
|
||||
|
||||
// NewWANIPConnection1ClientsByURL discovers instances of the service at the given
|
||||
// NewWANIPConnection1Clients is the legacy version of NewWANIPConnection1ClientsCtx, but uses
|
||||
// context.Background() as the context.
|
||||
func NewWANIPConnection1Clients() (clients []*WANIPConnection1, errors []error, err error) {
|
||||
return NewWANIPConnection1ClientsCtx(context.Background())
|
||||
}
|
||||
|
||||
// NewWANIPConnection1ClientsByURLCtx discovers instances of the service at the given
|
||||
// URL, and returns clients to any that are found. An error is returned if
|
||||
// there was an error probing the service.
|
||||
//
|
||||
// This is a typical entry calling point into this package when reusing an
|
||||
// previously discovered service URL.
|
||||
func NewWANIPConnection1ClientsByURL(loc *url.URL) ([]*WANIPConnection1, error) {
|
||||
genericClients, err := goupnp.NewServiceClientsByURL(loc, URN_WANIPConnection_1)
|
||||
func NewWANIPConnection1ClientsByURLCtx(ctx context.Context, loc *url.URL) ([]*WANIPConnection1, error) {
|
||||
genericClients, err := goupnp.NewServiceClientsByURLCtx(ctx, loc, URN_WANIPConnection_1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return newWANIPConnection1ClientsFromGenericClients(genericClients), nil
|
||||
}
|
||||
|
||||
// NewWANIPConnection1ClientsByURL is the legacy version of NewWANIPConnection1ClientsByURLCtx, but uses
|
||||
// context.Background() as the context.
|
||||
func NewWANIPConnection1ClientsByURL(loc *url.URL) ([]*WANIPConnection1, error) {
|
||||
return NewWANIPConnection1ClientsByURLCtx(context.Background(), loc)
|
||||
}
|
||||
|
||||
// NewWANIPConnection1ClientsFromRootDevice discovers instances of the service in
|
||||
// a given root device, and returns clients to any that are found. An error is
|
||||
// returned if there was not at least one instance of the service within the
|
||||
|
@ -3771,35 +3867,47 @@ type WANIPConnection2 struct {
|
|||
goupnp.ServiceClient
|
||||
}
|
||||
|
||||
// NewWANIPConnection2Clients discovers instances of the service on the network,
|
||||
// NewWANIPConnection2ClientsCtx discovers instances of the service on the network,
|
||||
// and returns clients to any that are found. errors will contain an error for
|
||||
// any devices that replied but which could not be queried, and err will be set
|
||||
// if the discovery process failed outright.
|
||||
//
|
||||
// This is a typical entry calling point into this package.
|
||||
func NewWANIPConnection2Clients() (clients []*WANIPConnection2, errors []error, err error) {
|
||||
func NewWANIPConnection2ClientsCtx(ctx context.Context) (clients []*WANIPConnection2, errors []error, err error) {
|
||||
var genericClients []goupnp.ServiceClient
|
||||
if genericClients, errors, err = goupnp.NewServiceClients(URN_WANIPConnection_2); err != nil {
|
||||
if genericClients, errors, err = goupnp.NewServiceClientsCtx(ctx, URN_WANIPConnection_2); err != nil {
|
||||
return
|
||||
}
|
||||
clients = newWANIPConnection2ClientsFromGenericClients(genericClients)
|
||||
return
|
||||
}
|
||||
|
||||
// NewWANIPConnection2ClientsByURL discovers instances of the service at the given
|
||||
// NewWANIPConnection2Clients is the legacy version of NewWANIPConnection2ClientsCtx, but uses
|
||||
// context.Background() as the context.
|
||||
func NewWANIPConnection2Clients() (clients []*WANIPConnection2, errors []error, err error) {
|
||||
return NewWANIPConnection2ClientsCtx(context.Background())
|
||||
}
|
||||
|
||||
// NewWANIPConnection2ClientsByURLCtx discovers instances of the service at the given
|
||||
// URL, and returns clients to any that are found. An error is returned if
|
||||
// there was an error probing the service.
|
||||
//
|
||||
// This is a typical entry calling point into this package when reusing an
|
||||
// previously discovered service URL.
|
||||
func NewWANIPConnection2ClientsByURL(loc *url.URL) ([]*WANIPConnection2, error) {
|
||||
genericClients, err := goupnp.NewServiceClientsByURL(loc, URN_WANIPConnection_2)
|
||||
func NewWANIPConnection2ClientsByURLCtx(ctx context.Context, loc *url.URL) ([]*WANIPConnection2, error) {
|
||||
genericClients, err := goupnp.NewServiceClientsByURLCtx(ctx, loc, URN_WANIPConnection_2)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return newWANIPConnection2ClientsFromGenericClients(genericClients), nil
|
||||
}
|
||||
|
||||
// NewWANIPConnection2ClientsByURL is the legacy version of NewWANIPConnection2ClientsByURLCtx, but uses
|
||||
// context.Background() as the context.
|
||||
func NewWANIPConnection2ClientsByURL(loc *url.URL) ([]*WANIPConnection2, error) {
|
||||
return NewWANIPConnection2ClientsByURLCtx(context.Background(), loc)
|
||||
}
|
||||
|
||||
// NewWANIPConnection2ClientsFromRootDevice discovers instances of the service in
|
||||
// a given root device, and returns clients to any that are found. An error is
|
||||
// returned if there was not at least one instance of the service within the
|
||||
|
@ -4833,35 +4941,47 @@ type WANIPv6FirewallControl1 struct {
|
|||
goupnp.ServiceClient
|
||||
}
|
||||
|
||||
// NewWANIPv6FirewallControl1Clients discovers instances of the service on the network,
|
||||
// NewWANIPv6FirewallControl1ClientsCtx discovers instances of the service on the network,
|
||||
// and returns clients to any that are found. errors will contain an error for
|
||||
// any devices that replied but which could not be queried, and err will be set
|
||||
// if the discovery process failed outright.
|
||||
//
|
||||
// This is a typical entry calling point into this package.
|
||||
func NewWANIPv6FirewallControl1Clients() (clients []*WANIPv6FirewallControl1, errors []error, err error) {
|
||||
func NewWANIPv6FirewallControl1ClientsCtx(ctx context.Context) (clients []*WANIPv6FirewallControl1, errors []error, err error) {
|
||||
var genericClients []goupnp.ServiceClient
|
||||
if genericClients, errors, err = goupnp.NewServiceClients(URN_WANIPv6FirewallControl_1); err != nil {
|
||||
if genericClients, errors, err = goupnp.NewServiceClientsCtx(ctx, URN_WANIPv6FirewallControl_1); err != nil {
|
||||
return
|
||||
}
|
||||
clients = newWANIPv6FirewallControl1ClientsFromGenericClients(genericClients)
|
||||
return
|
||||
}
|
||||
|
||||
// NewWANIPv6FirewallControl1ClientsByURL discovers instances of the service at the given
|
||||
// NewWANIPv6FirewallControl1Clients is the legacy version of NewWANIPv6FirewallControl1ClientsCtx, but uses
|
||||
// context.Background() as the context.
|
||||
func NewWANIPv6FirewallControl1Clients() (clients []*WANIPv6FirewallControl1, errors []error, err error) {
|
||||
return NewWANIPv6FirewallControl1ClientsCtx(context.Background())
|
||||
}
|
||||
|
||||
// NewWANIPv6FirewallControl1ClientsByURLCtx discovers instances of the service at the given
|
||||
// URL, and returns clients to any that are found. An error is returned if
|
||||
// there was an error probing the service.
|
||||
//
|
||||
// This is a typical entry calling point into this package when reusing an
|
||||
// previously discovered service URL.
|
||||
func NewWANIPv6FirewallControl1ClientsByURL(loc *url.URL) ([]*WANIPv6FirewallControl1, error) {
|
||||
genericClients, err := goupnp.NewServiceClientsByURL(loc, URN_WANIPv6FirewallControl_1)
|
||||
func NewWANIPv6FirewallControl1ClientsByURLCtx(ctx context.Context, loc *url.URL) ([]*WANIPv6FirewallControl1, error) {
|
||||
genericClients, err := goupnp.NewServiceClientsByURLCtx(ctx, loc, URN_WANIPv6FirewallControl_1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return newWANIPv6FirewallControl1ClientsFromGenericClients(genericClients), nil
|
||||
}
|
||||
|
||||
// NewWANIPv6FirewallControl1ClientsByURL is the legacy version of NewWANIPv6FirewallControl1ClientsByURLCtx, but uses
|
||||
// context.Background() as the context.
|
||||
func NewWANIPv6FirewallControl1ClientsByURL(loc *url.URL) ([]*WANIPv6FirewallControl1, error) {
|
||||
return NewWANIPv6FirewallControl1ClientsByURLCtx(context.Background(), loc)
|
||||
}
|
||||
|
||||
// NewWANIPv6FirewallControl1ClientsFromRootDevice discovers instances of the service in
|
||||
// a given root device, and returns clients to any that are found. An error is
|
||||
// returned if there was not at least one instance of the service within the
|
||||
|
@ -5243,35 +5363,47 @@ type WANPOTSLinkConfig1 struct {
|
|||
goupnp.ServiceClient
|
||||
}
|
||||
|
||||
// NewWANPOTSLinkConfig1Clients discovers instances of the service on the network,
|
||||
// NewWANPOTSLinkConfig1ClientsCtx discovers instances of the service on the network,
|
||||
// and returns clients to any that are found. errors will contain an error for
|
||||
// any devices that replied but which could not be queried, and err will be set
|
||||
// if the discovery process failed outright.
|
||||
//
|
||||
// This is a typical entry calling point into this package.
|
||||
func NewWANPOTSLinkConfig1Clients() (clients []*WANPOTSLinkConfig1, errors []error, err error) {
|
||||
func NewWANPOTSLinkConfig1ClientsCtx(ctx context.Context) (clients []*WANPOTSLinkConfig1, errors []error, err error) {
|
||||
var genericClients []goupnp.ServiceClient
|
||||
if genericClients, errors, err = goupnp.NewServiceClients(URN_WANPOTSLinkConfig_1); err != nil {
|
||||
if genericClients, errors, err = goupnp.NewServiceClientsCtx(ctx, URN_WANPOTSLinkConfig_1); err != nil {
|
||||
return
|
||||
}
|
||||
clients = newWANPOTSLinkConfig1ClientsFromGenericClients(genericClients)
|
||||
return
|
||||
}
|
||||
|
||||
// NewWANPOTSLinkConfig1ClientsByURL discovers instances of the service at the given
|
||||
// NewWANPOTSLinkConfig1Clients is the legacy version of NewWANPOTSLinkConfig1ClientsCtx, but uses
|
||||
// context.Background() as the context.
|
||||
func NewWANPOTSLinkConfig1Clients() (clients []*WANPOTSLinkConfig1, errors []error, err error) {
|
||||
return NewWANPOTSLinkConfig1ClientsCtx(context.Background())
|
||||
}
|
||||
|
||||
// NewWANPOTSLinkConfig1ClientsByURLCtx discovers instances of the service at the given
|
||||
// URL, and returns clients to any that are found. An error is returned if
|
||||
// there was an error probing the service.
|
||||
//
|
||||
// This is a typical entry calling point into this package when reusing an
|
||||
// previously discovered service URL.
|
||||
func NewWANPOTSLinkConfig1ClientsByURL(loc *url.URL) ([]*WANPOTSLinkConfig1, error) {
|
||||
genericClients, err := goupnp.NewServiceClientsByURL(loc, URN_WANPOTSLinkConfig_1)
|
||||
func NewWANPOTSLinkConfig1ClientsByURLCtx(ctx context.Context, loc *url.URL) ([]*WANPOTSLinkConfig1, error) {
|
||||
genericClients, err := goupnp.NewServiceClientsByURLCtx(ctx, loc, URN_WANPOTSLinkConfig_1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return newWANPOTSLinkConfig1ClientsFromGenericClients(genericClients), nil
|
||||
}
|
||||
|
||||
// NewWANPOTSLinkConfig1ClientsByURL is the legacy version of NewWANPOTSLinkConfig1ClientsByURLCtx, but uses
|
||||
// context.Background() as the context.
|
||||
func NewWANPOTSLinkConfig1ClientsByURL(loc *url.URL) ([]*WANPOTSLinkConfig1, error) {
|
||||
return NewWANPOTSLinkConfig1ClientsByURLCtx(context.Background(), loc)
|
||||
}
|
||||
|
||||
// NewWANPOTSLinkConfig1ClientsFromRootDevice discovers instances of the service in
|
||||
// a given root device, and returns clients to any that are found. An error is
|
||||
// returned if there was not at least one instance of the service within the
|
||||
|
@ -5654,35 +5786,47 @@ type WANPPPConnection1 struct {
|
|||
goupnp.ServiceClient
|
||||
}
|
||||
|
||||
// NewWANPPPConnection1Clients discovers instances of the service on the network,
|
||||
// NewWANPPPConnection1ClientsCtx discovers instances of the service on the network,
|
||||
// and returns clients to any that are found. errors will contain an error for
|
||||
// any devices that replied but which could not be queried, and err will be set
|
||||
// if the discovery process failed outright.
|
||||
//
|
||||
// This is a typical entry calling point into this package.
|
||||
func NewWANPPPConnection1Clients() (clients []*WANPPPConnection1, errors []error, err error) {
|
||||
func NewWANPPPConnection1ClientsCtx(ctx context.Context) (clients []*WANPPPConnection1, errors []error, err error) {
|
||||
var genericClients []goupnp.ServiceClient
|
||||
if genericClients, errors, err = goupnp.NewServiceClients(URN_WANPPPConnection_1); err != nil {
|
||||
if genericClients, errors, err = goupnp.NewServiceClientsCtx(ctx, URN_WANPPPConnection_1); err != nil {
|
||||
return
|
||||
}
|
||||
clients = newWANPPPConnection1ClientsFromGenericClients(genericClients)
|
||||
return
|
||||
}
|
||||
|
||||
// NewWANPPPConnection1ClientsByURL discovers instances of the service at the given
|
||||
// NewWANPPPConnection1Clients is the legacy version of NewWANPPPConnection1ClientsCtx, but uses
|
||||
// context.Background() as the context.
|
||||
func NewWANPPPConnection1Clients() (clients []*WANPPPConnection1, errors []error, err error) {
|
||||
return NewWANPPPConnection1ClientsCtx(context.Background())
|
||||
}
|
||||
|
||||
// NewWANPPPConnection1ClientsByURLCtx discovers instances of the service at the given
|
||||
// URL, and returns clients to any that are found. An error is returned if
|
||||
// there was an error probing the service.
|
||||
//
|
||||
// This is a typical entry calling point into this package when reusing an
|
||||
// previously discovered service URL.
|
||||
func NewWANPPPConnection1ClientsByURL(loc *url.URL) ([]*WANPPPConnection1, error) {
|
||||
genericClients, err := goupnp.NewServiceClientsByURL(loc, URN_WANPPPConnection_1)
|
||||
func NewWANPPPConnection1ClientsByURLCtx(ctx context.Context, loc *url.URL) ([]*WANPPPConnection1, error) {
|
||||
genericClients, err := goupnp.NewServiceClientsByURLCtx(ctx, loc, URN_WANPPPConnection_1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return newWANPPPConnection1ClientsFromGenericClients(genericClients), nil
|
||||
}
|
||||
|
||||
// NewWANPPPConnection1ClientsByURL is the legacy version of NewWANPPPConnection1ClientsByURLCtx, but uses
|
||||
// context.Background() as the context.
|
||||
func NewWANPPPConnection1ClientsByURL(loc *url.URL) ([]*WANPPPConnection1, error) {
|
||||
return NewWANPPPConnection1ClientsByURLCtx(context.Background(), loc)
|
||||
}
|
||||
|
||||
// NewWANPPPConnection1ClientsFromRootDevice discovers instances of the service in
|
||||
// a given root device, and returns clients to any that are found. An error is
|
||||
// returned if there was not at least one instance of the service within the
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
package goupnp
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/xml"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
@ -51,6 +52,7 @@ type Device struct {
|
|||
ModelDescription string `xml:"modelDescription"`
|
||||
ModelName string `xml:"modelName"`
|
||||
ModelNumber string `xml:"modelNumber"`
|
||||
ModelType string `xml:"modelType"`
|
||||
ModelURL URLField `xml:"modelURL"`
|
||||
SerialNumber string `xml:"serialNumber"`
|
||||
UDN string `xml:"UDN"`
|
||||
|
@ -148,19 +150,25 @@ func (srv *Service) String() string {
|
|||
return fmt.Sprintf("Service ID %s : %s", srv.ServiceId, srv.ServiceType)
|
||||
}
|
||||
|
||||
// RequestSCPD requests the SCPD (soap actions and state variables description)
|
||||
// RequestSCPDCtx requests the SCPD (soap actions and state variables description)
|
||||
// for the service.
|
||||
func (srv *Service) RequestSCPD() (*scpd.SCPD, error) {
|
||||
func (srv *Service) RequestSCPDCtx(ctx context.Context) (*scpd.SCPD, error) {
|
||||
if !srv.SCPDURL.Ok {
|
||||
return nil, errors.New("bad/missing SCPD URL, or no URLBase has been set")
|
||||
}
|
||||
s := new(scpd.SCPD)
|
||||
if err := requestXml(srv.SCPDURL.URL.String(), scpd.SCPDXMLNamespace, s); err != nil {
|
||||
if err := requestXml(ctx, srv.SCPDURL.URL.String(), scpd.SCPDXMLNamespace, s); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// RequestSCPD is the legacy version of RequestSCPDCtx, but uses
|
||||
// context.Background() as the context.
|
||||
func (srv *Service) RequestSCPD() (*scpd.SCPD, error) {
|
||||
return srv.RequestSCPDCtx(context.Background())
|
||||
}
|
||||
|
||||
// RequestSCDP is for compatibility only, prefer RequestSCPD. This was a
|
||||
// misspelling of RequestSCDP.
|
||||
func (srv *Service) RequestSCDP() (*scpd.SCPD, error) {
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
go 1.18
|
||||
|
||||
use (
|
||||
.
|
||||
./v2alpha
|
||||
)
|
|
@ -15,6 +15,7 @@
|
|||
package goupnp
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"io"
|
||||
|
@ -72,19 +73,19 @@ type MaybeRootDevice struct {
|
|||
Err error
|
||||
}
|
||||
|
||||
// DiscoverDevices attempts to find targets of the given type. This is
|
||||
// DiscoverDevicesCtx attempts to find targets of the given type. This is
|
||||
// typically the entry-point for this package. searchTarget is typically a URN
|
||||
// in the form "urn:schemas-upnp-org:device:..." or
|
||||
// "urn:schemas-upnp-org:service:...". A single error is returned for errors
|
||||
// while attempting to send the query. An error or RootDevice is returned for
|
||||
// each discovered RootDevice.
|
||||
func DiscoverDevices(searchTarget string) ([]MaybeRootDevice, error) {
|
||||
func DiscoverDevicesCtx(ctx context.Context, searchTarget string) ([]MaybeRootDevice, error) {
|
||||
hc, hcCleanup, err := httpuClient()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer hcCleanup()
|
||||
responses, err := ssdp.SSDPRawSearch(hc, string(searchTarget), 2, 3)
|
||||
responses, err := ssdp.SSDPRawSearchCtx(ctx, hc, string(searchTarget), 2, 3)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -99,7 +100,7 @@ func DiscoverDevices(searchTarget string) ([]MaybeRootDevice, error) {
|
|||
continue
|
||||
}
|
||||
maybe.Location = loc
|
||||
if root, err := DeviceByURL(loc); err != nil {
|
||||
if root, err := DeviceByURLCtx(ctx, loc); err != nil {
|
||||
maybe.Err = err
|
||||
} else {
|
||||
maybe.Root = root
|
||||
|
@ -112,10 +113,16 @@ func DiscoverDevices(searchTarget string) ([]MaybeRootDevice, error) {
|
|||
return results, nil
|
||||
}
|
||||
|
||||
func DeviceByURL(loc *url.URL) (*RootDevice, error) {
|
||||
// DiscoverDevices is the legacy version of DiscoverDevicesCtx, but uses
|
||||
// context.Background() as the context.
|
||||
func DiscoverDevices(searchTarget string) ([]MaybeRootDevice, error) {
|
||||
return DiscoverDevicesCtx(context.Background(), searchTarget)
|
||||
}
|
||||
|
||||
func DeviceByURLCtx(ctx context.Context, loc *url.URL) (*RootDevice, error) {
|
||||
locStr := loc.String()
|
||||
root := new(RootDevice)
|
||||
if err := requestXml(locStr, DeviceXMLNamespace, root); err != nil {
|
||||
if err := requestXml(ctx, locStr, DeviceXMLNamespace, root); err != nil {
|
||||
return nil, ContextError{fmt.Sprintf("error requesting root device details from %q", locStr), err}
|
||||
}
|
||||
var urlBaseStr string
|
||||
|
@ -132,17 +139,29 @@ func DeviceByURL(loc *url.URL) (*RootDevice, error) {
|
|||
return root, nil
|
||||
}
|
||||
|
||||
func DeviceByURL(loc *url.URL) (*RootDevice, error) {
|
||||
return DeviceByURLCtx(context.Background(), loc)
|
||||
}
|
||||
|
||||
// CharsetReaderDefault specifies the charset reader used while decoding the output
|
||||
// from a UPnP server. It can be modified in an init function to allow for non-utf8 encodings,
|
||||
// but should not be changed after requesting clients.
|
||||
var CharsetReaderDefault func(charset string, input io.Reader) (io.Reader, error)
|
||||
|
||||
func requestXml(url string, defaultSpace string, doc interface{}) error {
|
||||
timeout := time.Duration(3 * time.Second)
|
||||
client := http.Client{
|
||||
Timeout: timeout,
|
||||
// HTTPClient specifies the http.Client object used when fetching the XML from the UPnP server.
|
||||
// HTTPClient defaults the http.DefaultClient. This may be overridden by the importing application.
|
||||
var HTTPClientDefault = http.DefaultClient
|
||||
|
||||
func requestXml(ctx context.Context, url string, defaultSpace string, doc interface{}) error {
|
||||
ctx, cancel := context.WithTimeout(ctx, 3*time.Second)
|
||||
defer cancel()
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
resp, err := client.Get(url)
|
||||
|
||||
resp, err := HTTPClientDefault.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
"net"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"sync"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -73,20 +74,25 @@ func (srv *Server) Serve(l net.PacketConn) error {
|
|||
if srv.MaxMessageBytes != 0 {
|
||||
maxMessageBytes = srv.MaxMessageBytes
|
||||
}
|
||||
|
||||
bufPool := &sync.Pool{
|
||||
New: func() interface{} {
|
||||
return make([]byte, maxMessageBytes)
|
||||
},
|
||||
}
|
||||
for {
|
||||
buf := make([]byte, maxMessageBytes)
|
||||
buf := bufPool.Get().([]byte)
|
||||
n, peerAddr, err := l.ReadFrom(buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
buf = buf[:n]
|
||||
|
||||
go func(buf []byte, peerAddr net.Addr) {
|
||||
go func() {
|
||||
defer bufPool.Put(buf)
|
||||
// At least one router's UPnP implementation has added a trailing space
|
||||
// after "HTTP/1.1" - trim it.
|
||||
buf = trailingWhitespaceRx.ReplaceAllLiteral(buf, crlf)
|
||||
reqBuf := trailingWhitespaceRx.ReplaceAllLiteral(buf[:n], crlf)
|
||||
|
||||
req, err := http.ReadRequest(bufio.NewReader(bytes.NewBuffer(buf)))
|
||||
req, err := http.ReadRequest(bufio.NewReader(bytes.NewBuffer(reqBuf)))
|
||||
if err != nil {
|
||||
log.Printf("httpu: Failed to parse request: %v", err)
|
||||
return
|
||||
|
@ -94,7 +100,7 @@ func (srv *Server) Serve(l net.PacketConn) error {
|
|||
req.RemoteAddr = peerAddr.String()
|
||||
srv.Handler.ServeMessage(req)
|
||||
// No need to call req.Body.Close - underlying reader is bytes.Buffer.
|
||||
}(buf, peerAddr)
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package goupnp
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/url"
|
||||
|
@ -21,12 +22,12 @@ type ServiceClient struct {
|
|||
localAddr net.IP
|
||||
}
|
||||
|
||||
// NewServiceClients discovers services, and returns clients for them. err will
|
||||
// NewServiceClientsCtx discovers services, and returns clients for them. err will
|
||||
// report any error with the discovery process (blocking any device/service
|
||||
// discovery), errors reports errors on a per-root-device basis.
|
||||
func NewServiceClients(searchTarget string) (clients []ServiceClient, errors []error, err error) {
|
||||
func NewServiceClientsCtx(ctx context.Context, searchTarget string) (clients []ServiceClient, errors []error, err error) {
|
||||
var maybeRootDevices []MaybeRootDevice
|
||||
if maybeRootDevices, err = DiscoverDevices(searchTarget); err != nil {
|
||||
if maybeRootDevices, err = DiscoverDevicesCtx(ctx, searchTarget); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -49,16 +50,28 @@ func NewServiceClients(searchTarget string) (clients []ServiceClient, errors []e
|
|||
return
|
||||
}
|
||||
|
||||
// NewServiceClientsByURL creates client(s) for the given service URN, for a
|
||||
// NewServiceClients is the legacy version of NewServiceClientsCtx, but uses
|
||||
// context.Background() as the context.
|
||||
func NewServiceClients(searchTarget string) (clients []ServiceClient, errors []error, err error) {
|
||||
return NewServiceClientsCtx(context.Background(), searchTarget)
|
||||
}
|
||||
|
||||
// NewServiceClientsByURLCtx creates client(s) for the given service URN, for a
|
||||
// root device at the given URL.
|
||||
func NewServiceClientsByURL(loc *url.URL, searchTarget string) ([]ServiceClient, error) {
|
||||
rootDevice, err := DeviceByURL(loc)
|
||||
func NewServiceClientsByURLCtx(ctx context.Context, loc *url.URL, searchTarget string) ([]ServiceClient, error) {
|
||||
rootDevice, err := DeviceByURLCtx(ctx, loc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return NewServiceClientsFromRootDevice(rootDevice, loc, searchTarget)
|
||||
}
|
||||
|
||||
// NewServiceClientsByURL is the legacy version of NewServiceClientsByURLCtx, but uses
|
||||
// context.Background() as the context.
|
||||
func NewServiceClientsByURL(loc *url.URL, searchTarget string) ([]ServiceClient, error) {
|
||||
return NewServiceClientsByURLCtx(context.Background(), loc, searchTarget)
|
||||
}
|
||||
|
||||
// NewServiceClientsFromDevice creates client(s) for the given service URN, in
|
||||
// a given root device. The loc parameter is simply assigned to the
|
||||
// Location attribute of the returned ServiceClient(s).
|
||||
|
|
|
@ -526,3 +526,53 @@ func MarshalURI(v *url.URL) (string, error) {
|
|||
func UnmarshalURI(s string) (*url.URL, error) {
|
||||
return url.Parse(s)
|
||||
}
|
||||
|
||||
// TypeData provides metadata about for marshalling and unmarshalling a SOAP
|
||||
// type.
|
||||
type TypeData struct {
|
||||
funcSuffix string
|
||||
goType string
|
||||
}
|
||||
|
||||
// GoTypeName returns the name of the Go type.
|
||||
func (td TypeData) GoTypeName() string {
|
||||
return td.goType
|
||||
}
|
||||
|
||||
// MarshalFunc returns the name of the function that marshals the type.
|
||||
func (td TypeData) MarshalFunc() string {
|
||||
return fmt.Sprintf("Marshal%s", td.funcSuffix)
|
||||
}
|
||||
|
||||
// UnmarshalFunc returns the name of the function that unmarshals the type.
|
||||
func (td TypeData) UnmarshalFunc() string {
|
||||
return fmt.Sprintf("Unmarshal%s", td.funcSuffix)
|
||||
}
|
||||
|
||||
// TypeDataMap maps from a SOAP type (e.g "fixed.14.4") to its type data.
|
||||
var TypeDataMap = map[string]TypeData{
|
||||
"ui1": {"Ui1", "uint8"},
|
||||
"ui2": {"Ui2", "uint16"},
|
||||
"ui4": {"Ui4", "uint32"},
|
||||
"ui8": {"Ui8", "uint64"},
|
||||
"i1": {"I1", "int8"},
|
||||
"i2": {"I2", "int16"},
|
||||
"i4": {"I4", "int32"},
|
||||
"int": {"Int", "int64"},
|
||||
"r4": {"R4", "float32"},
|
||||
"r8": {"R8", "float64"},
|
||||
"number": {"R8", "float64"}, // Alias for r8.
|
||||
"fixed.14.4": {"Fixed14_4", "float64"},
|
||||
"float": {"R8", "float64"},
|
||||
"char": {"Char", "rune"},
|
||||
"string": {"String", "string"},
|
||||
"date": {"Date", "time.Time"},
|
||||
"dateTime": {"DateTime", "time.Time"},
|
||||
"dateTime.tz": {"DateTimeTz", "time.Time"},
|
||||
"time": {"TimeOfDay", "soap.TimeOfDay"},
|
||||
"time.tz": {"TimeOfDayTz", "soap.TimeOfDay"},
|
||||
"boolean": {"Boolean", "bool"},
|
||||
"bin.base64": {"BinBase64", "[]byte"},
|
||||
"bin.hex": {"BinHex", "[]byte"},
|
||||
"uri": {"URI", "*url.URL"},
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package ssdp
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"log"
|
||||
"net/http"
|
||||
|
@ -34,14 +35,15 @@ type HTTPUClient interface {
|
|||
) ([]*http.Response, error)
|
||||
}
|
||||
|
||||
// SSDPRawSearch performs a fairly raw SSDP search request, and returns the
|
||||
// SSDPRawSearchCtx performs a fairly raw SSDP search request, and returns the
|
||||
// unique response(s) that it receives. Each response has the requested
|
||||
// searchTarget, a USN, and a valid location. maxWaitSeconds states how long to
|
||||
// wait for responses in seconds, and must be a minimum of 1 (the
|
||||
// implementation waits an additional 100ms for responses to arrive), 2 is a
|
||||
// reasonable value for this. numSends is the number of requests to send - 3 is
|
||||
// a reasonable value for this.
|
||||
func SSDPRawSearch(
|
||||
func SSDPRawSearchCtx(
|
||||
ctx context.Context,
|
||||
httpu HTTPUClient,
|
||||
searchTarget string,
|
||||
maxWaitSeconds int,
|
||||
|
@ -51,7 +53,7 @@ func SSDPRawSearch(
|
|||
return nil, errors.New("ssdp: maxWaitSeconds must be >= 1")
|
||||
}
|
||||
|
||||
req := http.Request{
|
||||
req := (&http.Request{
|
||||
Method: methodSearch,
|
||||
// TODO: Support both IPv4 and IPv6.
|
||||
Host: ssdpUDP4Addr,
|
||||
|
@ -64,8 +66,8 @@ func SSDPRawSearch(
|
|||
"MAN": []string{ssdpDiscover},
|
||||
"ST": []string{searchTarget},
|
||||
},
|
||||
}
|
||||
allResponses, err := httpu.Do(&req, time.Duration(maxWaitSeconds)*time.Second+100*time.Millisecond, numSends)
|
||||
}).WithContext(ctx)
|
||||
allResponses, err := httpu.Do(req, time.Duration(maxWaitSeconds)*time.Second+100*time.Millisecond, numSends)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -97,3 +99,9 @@ func SSDPRawSearch(
|
|||
|
||||
return responses, nil
|
||||
}
|
||||
|
||||
// SSDPRawSearch is the legacy version of SSDPRawSearchCtx, but uses
|
||||
// context.Background() as the context.
|
||||
func SSDPRawSearch(httpu HTTPUClient, searchTarget string, maxWaitSeconds int, numSends int) ([]*http.Response, error) {
|
||||
return SSDPRawSearchCtx(context.Background(), httpu, searchTarget, maxWaitSeconds, numSends)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"folders": [
|
||||
{
|
||||
"path": "."
|
||||
},
|
||||
{
|
||||
"path": "v2alpha"
|
||||
}
|
||||
],
|
||||
"settings": {}
|
||||
}
|
|
@ -69,7 +69,7 @@ import (
|
|||
// Create a cid manually by specifying the 'prefix' parameters
|
||||
pref := cid.Prefix{
|
||||
Version: 1,
|
||||
Codec: mc.Raw,
|
||||
Codec: uint64(mc.Raw),
|
||||
MhType: mh.SHA2_256,
|
||||
MhLength: -1, // default length
|
||||
}
|
||||
|
|
|
@ -37,10 +37,32 @@ import (
|
|||
// UnsupportedVersionString just holds an error message
|
||||
const UnsupportedVersionString = "<unsupported cid version>"
|
||||
|
||||
// ErrInvalidCid is an error that indicates that a CID is invalid.
|
||||
type ErrInvalidCid struct {
|
||||
Err error
|
||||
}
|
||||
|
||||
func (e ErrInvalidCid) Error() string {
|
||||
return fmt.Sprintf("invalid cid: %s", e.Err)
|
||||
}
|
||||
|
||||
func (e ErrInvalidCid) Unwrap() error {
|
||||
return e.Err
|
||||
}
|
||||
|
||||
func (e ErrInvalidCid) Is(err error) bool {
|
||||
switch err.(type) {
|
||||
case ErrInvalidCid, *ErrInvalidCid:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
// ErrCidTooShort means that the cid passed to decode was not long
|
||||
// enough to be a valid Cid
|
||||
ErrCidTooShort = errors.New("cid too short")
|
||||
ErrCidTooShort = ErrInvalidCid{errors.New("cid too short")}
|
||||
|
||||
// ErrInvalidEncoding means that selected encoding is not supported
|
||||
// by this Cid version
|
||||
|
@ -90,10 +112,10 @@ func tryNewCidV0(mhash mh.Multihash) (Cid, error) {
|
|||
// incorrectly detect it as CidV1 in the Version() method
|
||||
dec, err := mh.Decode(mhash)
|
||||
if err != nil {
|
||||
return Undef, err
|
||||
return Undef, ErrInvalidCid{err}
|
||||
}
|
||||
if dec.Code != mh.SHA2_256 || dec.Length != 32 {
|
||||
return Undef, fmt.Errorf("invalid hash for cidv0 %d-%d", dec.Code, dec.Length)
|
||||
return Undef, ErrInvalidCid{fmt.Errorf("invalid hash for cidv0 %d-%d", dec.Code, dec.Length)}
|
||||
}
|
||||
return Cid{string(mhash)}, nil
|
||||
}
|
||||
|
@ -177,7 +199,7 @@ func Parse(v interface{}) (Cid, error) {
|
|||
case Cid:
|
||||
return v2, nil
|
||||
default:
|
||||
return Undef, fmt.Errorf("can't parse %+v as Cid", v2)
|
||||
return Undef, ErrInvalidCid{fmt.Errorf("can't parse %+v as Cid", v2)}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -210,7 +232,7 @@ func Decode(v string) (Cid, error) {
|
|||
if len(v) == 46 && v[:2] == "Qm" {
|
||||
hash, err := mh.FromB58String(v)
|
||||
if err != nil {
|
||||
return Undef, err
|
||||
return Undef, ErrInvalidCid{err}
|
||||
}
|
||||
|
||||
return tryNewCidV0(hash)
|
||||
|
@ -218,7 +240,7 @@ func Decode(v string) (Cid, error) {
|
|||
|
||||
_, data, err := mbase.Decode(v)
|
||||
if err != nil {
|
||||
return Undef, err
|
||||
return Undef, ErrInvalidCid{err}
|
||||
}
|
||||
|
||||
return Cast(data)
|
||||
|
@ -240,7 +262,7 @@ func ExtractEncoding(v string) (mbase.Encoding, error) {
|
|||
// check encoding is valid
|
||||
_, err := mbase.NewEncoder(encoding)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
return -1, ErrInvalidCid{err}
|
||||
}
|
||||
|
||||
return encoding, nil
|
||||
|
@ -260,11 +282,11 @@ func ExtractEncoding(v string) (mbase.Encoding, error) {
|
|||
func Cast(data []byte) (Cid, error) {
|
||||
nr, c, err := CidFromBytes(data)
|
||||
if err != nil {
|
||||
return Undef, err
|
||||
return Undef, ErrInvalidCid{err}
|
||||
}
|
||||
|
||||
if nr != len(data) {
|
||||
return Undef, fmt.Errorf("trailing bytes in data buffer passed to cid Cast")
|
||||
return Undef, ErrInvalidCid{fmt.Errorf("trailing bytes in data buffer passed to cid Cast")}
|
||||
}
|
||||
|
||||
return c, nil
|
||||
|
@ -434,7 +456,7 @@ func (c Cid) Equals(o Cid) bool {
|
|||
// UnmarshalJSON parses the JSON representation of a Cid.
|
||||
func (c *Cid) UnmarshalJSON(b []byte) error {
|
||||
if len(b) < 2 {
|
||||
return fmt.Errorf("invalid cid json blob")
|
||||
return ErrInvalidCid{fmt.Errorf("invalid cid json blob")}
|
||||
}
|
||||
obj := struct {
|
||||
CidTarget string `json:"/"`
|
||||
|
@ -442,7 +464,7 @@ func (c *Cid) UnmarshalJSON(b []byte) error {
|
|||
objptr := &obj
|
||||
err := json.Unmarshal(b, &objptr)
|
||||
if err != nil {
|
||||
return err
|
||||
return ErrInvalidCid{err}
|
||||
}
|
||||
if objptr == nil {
|
||||
*c = Cid{}
|
||||
|
@ -450,12 +472,12 @@ func (c *Cid) UnmarshalJSON(b []byte) error {
|
|||
}
|
||||
|
||||
if obj.CidTarget == "" {
|
||||
return fmt.Errorf("cid was incorrectly formatted")
|
||||
return ErrInvalidCid{fmt.Errorf("cid was incorrectly formatted")}
|
||||
}
|
||||
|
||||
out, err := Decode(obj.CidTarget)
|
||||
if err != nil {
|
||||
return err
|
||||
return ErrInvalidCid{err}
|
||||
}
|
||||
|
||||
*c = out
|
||||
|
@ -542,12 +564,12 @@ func (p Prefix) Sum(data []byte) (Cid, error) {
|
|||
if p.Version == 0 && (p.MhType != mh.SHA2_256 ||
|
||||
(p.MhLength != 32 && p.MhLength != -1)) {
|
||||
|
||||
return Undef, fmt.Errorf("invalid v0 prefix")
|
||||
return Undef, ErrInvalidCid{fmt.Errorf("invalid v0 prefix")}
|
||||
}
|
||||
|
||||
hash, err := mh.Sum(data, p.MhType, length)
|
||||
if err != nil {
|
||||
return Undef, err
|
||||
return Undef, ErrInvalidCid{err}
|
||||
}
|
||||
|
||||
switch p.Version {
|
||||
|
@ -556,7 +578,7 @@ func (p Prefix) Sum(data []byte) (Cid, error) {
|
|||
case 1:
|
||||
return NewCidV1(p.Codec, hash), nil
|
||||
default:
|
||||
return Undef, fmt.Errorf("invalid cid version")
|
||||
return Undef, ErrInvalidCid{fmt.Errorf("invalid cid version")}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -586,22 +608,22 @@ func PrefixFromBytes(buf []byte) (Prefix, error) {
|
|||
r := bytes.NewReader(buf)
|
||||
vers, err := varint.ReadUvarint(r)
|
||||
if err != nil {
|
||||
return Prefix{}, err
|
||||
return Prefix{}, ErrInvalidCid{err}
|
||||
}
|
||||
|
||||
codec, err := varint.ReadUvarint(r)
|
||||
if err != nil {
|
||||
return Prefix{}, err
|
||||
return Prefix{}, ErrInvalidCid{err}
|
||||
}
|
||||
|
||||
mhtype, err := varint.ReadUvarint(r)
|
||||
if err != nil {
|
||||
return Prefix{}, err
|
||||
return Prefix{}, ErrInvalidCid{err}
|
||||
}
|
||||
|
||||
mhlen, err := varint.ReadUvarint(r)
|
||||
if err != nil {
|
||||
return Prefix{}, err
|
||||
return Prefix{}, ErrInvalidCid{err}
|
||||
}
|
||||
|
||||
return Prefix{
|
||||
|
@ -615,12 +637,12 @@ func PrefixFromBytes(buf []byte) (Prefix, error) {
|
|||
func CidFromBytes(data []byte) (int, Cid, error) {
|
||||
if len(data) > 2 && data[0] == mh.SHA2_256 && data[1] == 32 {
|
||||
if len(data) < 34 {
|
||||
return 0, Undef, fmt.Errorf("not enough bytes for cid v0")
|
||||
return 0, Undef, ErrInvalidCid{fmt.Errorf("not enough bytes for cid v0")}
|
||||
}
|
||||
|
||||
h, err := mh.Cast(data[:34])
|
||||
if err != nil {
|
||||
return 0, Undef, err
|
||||
return 0, Undef, ErrInvalidCid{err}
|
||||
}
|
||||
|
||||
return 34, Cid{string(h)}, nil
|
||||
|
@ -628,21 +650,21 @@ func CidFromBytes(data []byte) (int, Cid, error) {
|
|||
|
||||
vers, n, err := varint.FromUvarint(data)
|
||||
if err != nil {
|
||||
return 0, Undef, err
|
||||
return 0, Undef, ErrInvalidCid{err}
|
||||
}
|
||||
|
||||
if vers != 1 {
|
||||
return 0, Undef, fmt.Errorf("expected 1 as the cid version number, got: %d", vers)
|
||||
return 0, Undef, ErrInvalidCid{fmt.Errorf("expected 1 as the cid version number, got: %d", vers)}
|
||||
}
|
||||
|
||||
_, cn, err := varint.FromUvarint(data[n:])
|
||||
if err != nil {
|
||||
return 0, Undef, err
|
||||
return 0, Undef, ErrInvalidCid{err}
|
||||
}
|
||||
|
||||
mhnr, _, err := mh.MHFromBytes(data[n+cn:])
|
||||
if err != nil {
|
||||
return 0, Undef, err
|
||||
return 0, Undef, ErrInvalidCid{err}
|
||||
}
|
||||
|
||||
l := n + cn + mhnr
|
||||
|
@ -695,6 +717,9 @@ func (r *bufByteReader) ReadByte() (byte, error) {
|
|||
// It's recommended to supply a reader that buffers and implements io.ByteReader,
|
||||
// as CidFromReader has to do many single-byte reads to decode varints.
|
||||
// If the argument only implements io.Reader, single-byte Read calls are used instead.
|
||||
//
|
||||
// If the Reader is found to yield zero bytes, an io.EOF error is returned directly, in all
|
||||
// other error cases, an ErrInvalidCid, wrapping the original error, is returned.
|
||||
func CidFromReader(r io.Reader) (int, Cid, error) {
|
||||
// 64 bytes is enough for any CIDv0,
|
||||
// and it's enough for most CIDv1s in practice.
|
||||
|
@ -705,32 +730,37 @@ func CidFromReader(r io.Reader) (int, Cid, error) {
|
|||
// The varint package wants a io.ByteReader, so we must wrap our io.Reader.
|
||||
vers, err := varint.ReadUvarint(br)
|
||||
if err != nil {
|
||||
return len(br.dst), Undef, err
|
||||
if err == io.EOF {
|
||||
// First-byte read in ReadUvarint errors with io.EOF, so reader has no data.
|
||||
// Subsequent reads with an EOF will return io.ErrUnexpectedEOF and be wrapped here.
|
||||
return 0, Undef, err
|
||||
}
|
||||
return len(br.dst), Undef, ErrInvalidCid{err}
|
||||
}
|
||||
|
||||
// If we have a CIDv0, read the rest of the bytes and cast the buffer.
|
||||
if vers == mh.SHA2_256 {
|
||||
if n, err := io.ReadFull(r, br.dst[1:34]); err != nil {
|
||||
return len(br.dst) + n, Undef, err
|
||||
return len(br.dst) + n, Undef, ErrInvalidCid{err}
|
||||
}
|
||||
|
||||
br.dst = br.dst[:34]
|
||||
h, err := mh.Cast(br.dst)
|
||||
if err != nil {
|
||||
return len(br.dst), Undef, err
|
||||
return len(br.dst), Undef, ErrInvalidCid{err}
|
||||
}
|
||||
|
||||
return len(br.dst), Cid{string(h)}, nil
|
||||
}
|
||||
|
||||
if vers != 1 {
|
||||
return len(br.dst), Undef, fmt.Errorf("expected 1 as the cid version number, got: %d", vers)
|
||||
return len(br.dst), Undef, ErrInvalidCid{fmt.Errorf("expected 1 as the cid version number, got: %d", vers)}
|
||||
}
|
||||
|
||||
// CID block encoding multicodec.
|
||||
_, err = varint.ReadUvarint(br)
|
||||
if err != nil {
|
||||
return len(br.dst), Undef, err
|
||||
return len(br.dst), Undef, ErrInvalidCid{err}
|
||||
}
|
||||
|
||||
// We could replace most of the code below with go-multihash's ReadMultihash.
|
||||
|
@ -741,19 +771,19 @@ func CidFromReader(r io.Reader) (int, Cid, error) {
|
|||
// Multihash hash function code.
|
||||
_, err = varint.ReadUvarint(br)
|
||||
if err != nil {
|
||||
return len(br.dst), Undef, err
|
||||
return len(br.dst), Undef, ErrInvalidCid{err}
|
||||
}
|
||||
|
||||
// Multihash digest length.
|
||||
mhl, err := varint.ReadUvarint(br)
|
||||
if err != nil {
|
||||
return len(br.dst), Undef, err
|
||||
return len(br.dst), Undef, ErrInvalidCid{err}
|
||||
}
|
||||
|
||||
// Refuse to make large allocations to prevent OOMs due to bugs.
|
||||
const maxDigestAlloc = 32 << 20 // 32MiB
|
||||
if mhl > maxDigestAlloc {
|
||||
return len(br.dst), Undef, fmt.Errorf("refusing to allocate %d bytes for a digest", mhl)
|
||||
return len(br.dst), Undef, ErrInvalidCid{fmt.Errorf("refusing to allocate %d bytes for a digest", mhl)}
|
||||
}
|
||||
|
||||
// Fine to convert mhl to int, given maxDigestAlloc.
|
||||
|
@ -772,7 +802,7 @@ func CidFromReader(r io.Reader) (int, Cid, error) {
|
|||
if n, err := io.ReadFull(r, br.dst[prefixLength:cidLength]); err != nil {
|
||||
// We can't use len(br.dst) here,
|
||||
// as we've only read n bytes past prefixLength.
|
||||
return prefixLength + n, Undef, err
|
||||
return prefixLength + n, Undef, ErrInvalidCid{err}
|
||||
}
|
||||
|
||||
// This simply ensures the multihash is valid.
|
||||
|
@ -780,7 +810,7 @@ func CidFromReader(r io.Reader) (int, Cid, error) {
|
|||
// for now, it helps ensure consistency with CidFromBytes.
|
||||
_, _, err = mh.MHFromBytes(br.dst[mhStart:])
|
||||
if err != nil {
|
||||
return len(br.dst), Undef, err
|
||||
return len(br.dst), Undef, ErrInvalidCid{err}
|
||||
}
|
||||
|
||||
return len(br.dst), Cid{string(br.dst)}, nil
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
{
|
||||
"version": "v0.3.2"
|
||||
"version": "v0.4.1"
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
before:
|
||||
hooks:
|
||||
- ./gen.sh
|
||||
- go install mvdan.cc/garble@v0.7.2
|
||||
- go install mvdan.cc/garble@v0.9.3
|
||||
|
||||
builds:
|
||||
-
|
||||
|
|
|
@ -16,6 +16,27 @@ This package provides various compression algorithms.
|
|||
|
||||
# changelog
|
||||
|
||||
* Mar 13, 2023 - [v1.16.1](https://github.com/klauspost/compress/releases/tag/v1.16.1)
|
||||
* zstd: Speed up + improve best encoder by @greatroar in https://github.com/klauspost/compress/pull/776
|
||||
* gzhttp: Add optional [BREACH mitigation](https://github.com/klauspost/compress/tree/master/gzhttp#breach-mitigation). https://github.com/klauspost/compress/pull/762 https://github.com/klauspost/compress/pull/768 https://github.com/klauspost/compress/pull/769 https://github.com/klauspost/compress/pull/770 https://github.com/klauspost/compress/pull/767
|
||||
* s2: Add Intel LZ4s converter https://github.com/klauspost/compress/pull/766
|
||||
* zstd: Minor bug fixes https://github.com/klauspost/compress/pull/771 https://github.com/klauspost/compress/pull/772 https://github.com/klauspost/compress/pull/773
|
||||
* huff0: Speed up compress1xDo by @greatroar in https://github.com/klauspost/compress/pull/774
|
||||
|
||||
* Feb 26, 2023 - [v1.16.0](https://github.com/klauspost/compress/releases/tag/v1.16.0)
|
||||
* s2: Add [Dictionary](https://github.com/klauspost/compress/tree/master/s2#dictionaries) support. https://github.com/klauspost/compress/pull/685
|
||||
* s2: Add Compression Size Estimate. https://github.com/klauspost/compress/pull/752
|
||||
* s2: Add support for custom stream encoder. https://github.com/klauspost/compress/pull/755
|
||||
* s2: Add LZ4 block converter. https://github.com/klauspost/compress/pull/748
|
||||
* s2: Support io.ReaderAt in ReadSeeker. https://github.com/klauspost/compress/pull/747
|
||||
* s2c/s2sx: Use concurrent decoding. https://github.com/klauspost/compress/pull/746
|
||||
|
||||
* Jan 21st, 2023 (v1.15.15)
|
||||
* deflate: Improve level 7-9 by @klauspost in https://github.com/klauspost/compress/pull/739
|
||||
* zstd: Add delta encoding support by @greatroar in https://github.com/klauspost/compress/pull/728
|
||||
* zstd: Various speed improvements by @greatroar https://github.com/klauspost/compress/pull/741 https://github.com/klauspost/compress/pull/734 https://github.com/klauspost/compress/pull/736 https://github.com/klauspost/compress/pull/744 https://github.com/klauspost/compress/pull/743 https://github.com/klauspost/compress/pull/745
|
||||
* gzhttp: Add SuffixETag() and DropETag() options to prevent ETag collisions on compressed responses by @willbicks in https://github.com/klauspost/compress/pull/740
|
||||
|
||||
* Jan 3rd, 2023 (v1.15.14)
|
||||
|
||||
* flate: Improve speed in big stateless blocks https://github.com/klauspost/compress/pull/718
|
||||
|
@ -594,6 +615,8 @@ Here are other packages of good quality and pure Go (no cgo wrappers or autoconv
|
|||
* [github.com/pierrec/lz4](https://github.com/pierrec/lz4) - strong multithreaded LZ4 compression.
|
||||
* [github.com/cosnicolaou/pbzip2](https://github.com/cosnicolaou/pbzip2) - multithreaded bzip2 decompression.
|
||||
* [github.com/dsnet/compress](https://github.com/dsnet/compress) - brotli decompression, bzip2 writer.
|
||||
* [github.com/ronanh/intcomp](https://github.com/ronanh/intcomp) - Integer compression.
|
||||
* [github.com/spenczar/fpc](https://github.com/spenczar/fpc) - Float compression.
|
||||
|
||||
# license
|
||||
|
||||
|
|
|
@ -260,7 +260,9 @@ func (s *Scratch) buildDtable() error {
|
|||
// If the buffer is over-read an error is returned.
|
||||
func (s *Scratch) decompress() error {
|
||||
br := &s.bits
|
||||
br.init(s.br.unread())
|
||||
if err := br.init(s.br.unread()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var s1, s2 decoder
|
||||
// Initialize and decode first state and symbol.
|
||||
|
|
|
@ -60,6 +60,22 @@ func (b *bitWriter) encTwoSymbols(ct cTable, av, bv byte) {
|
|||
b.nBits += encA.nBits + encB.nBits
|
||||
}
|
||||
|
||||
// encFourSymbols adds up to 32 bits from four symbols.
|
||||
// It will not check if there is space for them,
|
||||
// so the caller must ensure that b has been flushed recently.
|
||||
func (b *bitWriter) encFourSymbols(encA, encB, encC, encD cTableEntry) {
|
||||
bitsA := encA.nBits
|
||||
bitsB := bitsA + encB.nBits
|
||||
bitsC := bitsB + encC.nBits
|
||||
bitsD := bitsC + encD.nBits
|
||||
combined := uint64(encA.val) |
|
||||
(uint64(encB.val) << (bitsA & 63)) |
|
||||
(uint64(encC.val) << (bitsB & 63)) |
|
||||
(uint64(encD.val) << (bitsC & 63))
|
||||
b.bitContainer |= combined << (b.nBits & 63)
|
||||
b.nBits += bitsD
|
||||
}
|
||||
|
||||
// flush32 will flush out, so there are at least 32 bits available for writing.
|
||||
func (b *bitWriter) flush32() {
|
||||
if b.nBits < 32 {
|
||||
|
|
|
@ -248,8 +248,7 @@ func (s *Scratch) compress1xDo(dst, src []byte) ([]byte, error) {
|
|||
tmp := src[n : n+4]
|
||||
// tmp should be len 4
|
||||
bw.flush32()
|
||||
bw.encTwoSymbols(cTable, tmp[3], tmp[2])
|
||||
bw.encTwoSymbols(cTable, tmp[1], tmp[0])
|
||||
bw.encFourSymbols(cTable[tmp[3]], cTable[tmp[2]], cTable[tmp[1]], cTable[tmp[0]])
|
||||
}
|
||||
} else {
|
||||
for ; n >= 0; n -= 4 {
|
||||
|
|
|
@ -61,7 +61,7 @@ func ReadTable(in []byte, s *Scratch) (s2 *Scratch, remain []byte, err error) {
|
|||
b, err := fse.Decompress(in[:iSize], s.fse)
|
||||
s.fse.Out = nil
|
||||
if err != nil {
|
||||
return s, nil, err
|
||||
return s, nil, fmt.Errorf("fse decompress returned: %w", err)
|
||||
}
|
||||
if len(b) > 255 {
|
||||
return s, nil, errors.New("corrupt input: output table too large")
|
||||
|
|
|
@ -103,6 +103,28 @@ func hash(u, shift uint32) uint32 {
|
|||
return (u * 0x1e35a7bd) >> shift
|
||||
}
|
||||
|
||||
// EncodeBlockInto exposes encodeBlock but checks dst size.
|
||||
func EncodeBlockInto(dst, src []byte) (d int) {
|
||||
if MaxEncodedLen(len(src)) > len(dst) {
|
||||
return 0
|
||||
}
|
||||
|
||||
// encodeBlock breaks on too big blocks, so split.
|
||||
for len(src) > 0 {
|
||||
p := src
|
||||
src = nil
|
||||
if len(p) > maxBlockSize {
|
||||
p, src = p[:maxBlockSize], p[maxBlockSize:]
|
||||
}
|
||||
if len(p) < minNonLiteralBlockSize {
|
||||
d += emitLiteral(dst[d:], p)
|
||||
} else {
|
||||
d += encodeBlock(dst[d:], p)
|
||||
}
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
// encodeBlock encodes a non-empty src to a guaranteed-large-enough dst. It
|
||||
// assumes that the varint-encoded length of the decompressed bytes has already
|
||||
// been written.
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"hash/crc32"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
@ -442,6 +443,9 @@ func (b *blockDec) decodeLiterals(in []byte, hist *history) (remain []byte, err
|
|||
}
|
||||
}
|
||||
var err error
|
||||
if debugDecoder {
|
||||
println("huff table input:", len(literals), "CRC:", crc32.ChecksumIEEE(literals))
|
||||
}
|
||||
huff, literals, err = huff0.ReadTable(literals, huff)
|
||||
if err != nil {
|
||||
println("reading huffman table:", err)
|
||||
|
|
|
@ -473,7 +473,7 @@ func (b *blockEnc) encode(org []byte, raw, rawAllLits bool) error {
|
|||
return b.encodeLits(b.literals, rawAllLits)
|
||||
}
|
||||
// We want some difference to at least account for the headers.
|
||||
saved := b.size - len(b.literals) - (b.size >> 5)
|
||||
saved := b.size - len(b.literals) - (b.size >> 6)
|
||||
if saved < 16 {
|
||||
if org == nil {
|
||||
return errIncompressible
|
||||
|
@ -779,10 +779,13 @@ func (b *blockEnc) encode(org []byte, raw, rawAllLits bool) error {
|
|||
}
|
||||
b.output = wr.out
|
||||
|
||||
// Maybe even add a bigger margin.
|
||||
if len(b.output)-3-bhOffset >= b.size {
|
||||
// Maybe even add a bigger margin.
|
||||
// Discard and encode as raw block.
|
||||
b.output = b.encodeRawTo(b.output[:bhOffset], org)
|
||||
b.popOffsets()
|
||||
b.litEnc.Reuse = huff0.ReusePolicyNone
|
||||
return errIncompressible
|
||||
return nil
|
||||
}
|
||||
|
||||
// Size is output minus block header.
|
||||
|
|
|
@ -54,7 +54,7 @@ func (b *byteBuf) readBig(n int, dst []byte) ([]byte, error) {
|
|||
func (b *byteBuf) readByte() (byte, error) {
|
||||
bb := *b
|
||||
if len(bb) < 1 {
|
||||
return 0, nil
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
r := bb[0]
|
||||
*b = bb[1:]
|
||||
|
|
|
@ -455,12 +455,7 @@ func (d *Decoder) nextBlock(blocking bool) (ok bool) {
|
|||
}
|
||||
|
||||
if len(next.b) > 0 {
|
||||
n, err := d.current.crc.Write(next.b)
|
||||
if err == nil {
|
||||
if n != len(next.b) {
|
||||
d.current.err = io.ErrShortWrite
|
||||
}
|
||||
}
|
||||
d.current.crc.Write(next.b)
|
||||
}
|
||||
if next.err == nil && next.d != nil && next.d.hasCRC {
|
||||
got := uint32(d.current.crc.Sum64())
|
||||
|
|
|
@ -32,14 +32,38 @@ func (d *dict) ID() uint32 {
|
|||
return d.id
|
||||
}
|
||||
|
||||
// DictContentSize returns the dictionary content size or 0 if d is nil.
|
||||
func (d *dict) DictContentSize() int {
|
||||
// ContentSize returns the dictionary content size or 0 if d is nil.
|
||||
func (d *dict) ContentSize() int {
|
||||
if d == nil {
|
||||
return 0
|
||||
}
|
||||
return len(d.content)
|
||||
}
|
||||
|
||||
// Content returns the dictionary content.
|
||||
func (d *dict) Content() []byte {
|
||||
if d == nil {
|
||||
return nil
|
||||
}
|
||||
return d.content
|
||||
}
|
||||
|
||||
// Offsets returns the initial offsets.
|
||||
func (d *dict) Offsets() [3]int {
|
||||
if d == nil {
|
||||
return [3]int{}
|
||||
}
|
||||
return d.offsets
|
||||
}
|
||||
|
||||
// LitEncoder returns the literal encoder.
|
||||
func (d *dict) LitEncoder() *huff0.Scratch {
|
||||
if d == nil {
|
||||
return nil
|
||||
}
|
||||
return d.litEnc
|
||||
}
|
||||
|
||||
// Load a dictionary as described in
|
||||
// https://github.com/facebook/zstd/blob/master/doc/zstd_compression_format.md#dictionary-format
|
||||
func loadDict(b []byte) (*dict, error) {
|
||||
|
@ -64,7 +88,7 @@ func loadDict(b []byte) (*dict, error) {
|
|||
var err error
|
||||
d.litEnc, b, err = huff0.ReadTable(b[8:], nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("loading literal table: %w", err)
|
||||
}
|
||||
d.litEnc.Reuse = huff0.ReusePolicyMust
|
||||
|
||||
|
@ -122,3 +146,16 @@ func loadDict(b []byte) (*dict, error) {
|
|||
|
||||
return &d, nil
|
||||
}
|
||||
|
||||
// InspectDictionary loads a zstd dictionary and provides functions to inspect the content.
|
||||
func InspectDictionary(b []byte) (interface {
|
||||
ID() uint32
|
||||
ContentSize() int
|
||||
Content() []byte
|
||||
Offsets() [3]int
|
||||
LitEncoder() *huff0.Scratch
|
||||
}, error) {
|
||||
initPredefined()
|
||||
d, err := loadDict(b)
|
||||
return d, err
|
||||
}
|
||||
|
|
|
@ -149,7 +149,7 @@ func (e *fastBase) resetBase(d *dict, singleBlock bool) {
|
|||
if singleBlock {
|
||||
e.lowMem = true
|
||||
}
|
||||
e.ensureHist(d.DictContentSize() + maxCompressedBlockSize)
|
||||
e.ensureHist(d.ContentSize() + maxCompressedBlockSize)
|
||||
e.lowMem = low
|
||||
}
|
||||
|
||||
|
|
|
@ -32,10 +32,9 @@ type match struct {
|
|||
length int32
|
||||
rep int32
|
||||
est int32
|
||||
_ [12]byte // Aligned size to cache line: 4+4+4+4+4 bytes + 12 bytes padding = 32 bytes
|
||||
}
|
||||
|
||||
const highScore = 25000
|
||||
const highScore = maxMatchLen * 8
|
||||
|
||||
// estBits will estimate output bits from predefined tables.
|
||||
func (m *match) estBits(bitsPerByte int32) {
|
||||
|
@ -160,7 +159,6 @@ func (e *bestFastEncoder) Encode(blk *blockEnc, src []byte) {
|
|||
|
||||
// nextEmit is where in src the next emitLiteral should start from.
|
||||
nextEmit := s
|
||||
cv := load6432(src, s)
|
||||
|
||||
// Relative offsets
|
||||
offset1 := int32(blk.recentOffsets[0])
|
||||
|
@ -174,7 +172,6 @@ func (e *bestFastEncoder) Encode(blk *blockEnc, src []byte) {
|
|||
blk.literals = append(blk.literals, src[nextEmit:until]...)
|
||||
s.litLen = uint32(until - nextEmit)
|
||||
}
|
||||
_ = addLiterals
|
||||
|
||||
if debugEncoder {
|
||||
println("recent offsets:", blk.recentOffsets)
|
||||
|
@ -189,53 +186,96 @@ encodeLoop:
|
|||
panic("offset0 was 0")
|
||||
}
|
||||
|
||||
bestOf := func(a, b *match) *match {
|
||||
if a.est-b.est+(a.s-b.s)*bitsPerByte>>10 < 0 {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
||||
const goodEnough = 100
|
||||
const goodEnough = 250
|
||||
|
||||
cv := load6432(src, s)
|
||||
|
||||
nextHashL := hashLen(cv, bestLongTableBits, bestLongLen)
|
||||
nextHashS := hashLen(cv, bestShortTableBits, bestShortLen)
|
||||
candidateL := e.longTable[nextHashL]
|
||||
candidateS := e.table[nextHashS]
|
||||
|
||||
matchAt := func(offset int32, s int32, first uint32, rep int32) match {
|
||||
// Set m to a match at offset if it looks like that will improve compression.
|
||||
improve := func(m *match, offset int32, s int32, first uint32, rep int32) {
|
||||
if s-offset >= e.maxMatchOff || load3232(src, offset) != first {
|
||||
return match{s: s, est: highScore}
|
||||
return
|
||||
}
|
||||
if debugAsserts {
|
||||
if offset <= 0 {
|
||||
panic(offset)
|
||||
}
|
||||
if !bytes.Equal(src[s:s+4], src[offset:offset+4]) {
|
||||
panic(fmt.Sprintf("first match mismatch: %v != %v, first: %08x", src[s:s+4], src[offset:offset+4], first))
|
||||
}
|
||||
}
|
||||
m := match{offset: offset, s: s, length: 4 + e.matchlen(s+4, offset+4, src), rep: rep}
|
||||
m.estBits(bitsPerByte)
|
||||
return m
|
||||
// Try to quick reject if we already have a long match.
|
||||
if m.length > 16 {
|
||||
left := len(src) - int(m.s+m.length)
|
||||
// If we are too close to the end, keep as is.
|
||||
if left <= 0 {
|
||||
return
|
||||
}
|
||||
checkLen := m.length - (s - m.s) - 8
|
||||
if left > 2 && checkLen > 4 {
|
||||
// Check 4 bytes, 4 bytes from the end of the current match.
|
||||
a := load3232(src, offset+checkLen)
|
||||
b := load3232(src, s+checkLen)
|
||||
if a != b {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
l := 4 + e.matchlen(s+4, offset+4, src)
|
||||
if rep < 0 {
|
||||
// Extend candidate match backwards as far as possible.
|
||||
tMin := s - e.maxMatchOff
|
||||
if tMin < 0 {
|
||||
tMin = 0
|
||||
}
|
||||
for offset > tMin && s > nextEmit && src[offset-1] == src[s-1] && l < maxMatchLength {
|
||||
s--
|
||||
offset--
|
||||
l++
|
||||
}
|
||||
}
|
||||
|
||||
cand := match{offset: offset, s: s, length: l, rep: rep}
|
||||
cand.estBits(bitsPerByte)
|
||||
if m.est >= highScore || cand.est-m.est+(cand.s-m.s)*bitsPerByte>>10 < 0 {
|
||||
*m = cand
|
||||
}
|
||||
}
|
||||
|
||||
m1 := matchAt(candidateL.offset-e.cur, s, uint32(cv), -1)
|
||||
m2 := matchAt(candidateL.prev-e.cur, s, uint32(cv), -1)
|
||||
m3 := matchAt(candidateS.offset-e.cur, s, uint32(cv), -1)
|
||||
m4 := matchAt(candidateS.prev-e.cur, s, uint32(cv), -1)
|
||||
best := bestOf(bestOf(&m1, &m2), bestOf(&m3, &m4))
|
||||
best := match{s: s, est: highScore}
|
||||
improve(&best, candidateL.offset-e.cur, s, uint32(cv), -1)
|
||||
improve(&best, candidateL.prev-e.cur, s, uint32(cv), -1)
|
||||
improve(&best, candidateS.offset-e.cur, s, uint32(cv), -1)
|
||||
improve(&best, candidateS.prev-e.cur, s, uint32(cv), -1)
|
||||
|
||||
if canRepeat && best.length < goodEnough {
|
||||
cv32 := uint32(cv >> 8)
|
||||
spp := s + 1
|
||||
m1 := matchAt(spp-offset1, spp, cv32, 1)
|
||||
m2 := matchAt(spp-offset2, spp, cv32, 2)
|
||||
m3 := matchAt(spp-offset3, spp, cv32, 3)
|
||||
best = bestOf(bestOf(best, &m1), bestOf(&m2, &m3))
|
||||
if best.length > 0 {
|
||||
cv32 = uint32(cv >> 24)
|
||||
spp += 2
|
||||
m1 := matchAt(spp-offset1, spp, cv32, 1)
|
||||
m2 := matchAt(spp-offset2, spp, cv32, 2)
|
||||
m3 := matchAt(spp-offset3, spp, cv32, 3)
|
||||
best = bestOf(bestOf(best, &m1), bestOf(&m2, &m3))
|
||||
if s == nextEmit {
|
||||
// Check repeats straight after a match.
|
||||
improve(&best, s-offset2, s, uint32(cv), 1|4)
|
||||
improve(&best, s-offset3, s, uint32(cv), 2|4)
|
||||
if offset1 > 1 {
|
||||
improve(&best, s-(offset1-1), s, uint32(cv), 3|4)
|
||||
}
|
||||
}
|
||||
|
||||
// If either no match or a non-repeat match, check at + 1
|
||||
if best.rep <= 0 {
|
||||
cv32 := uint32(cv >> 8)
|
||||
spp := s + 1
|
||||
improve(&best, spp-offset1, spp, cv32, 1)
|
||||
improve(&best, spp-offset2, spp, cv32, 2)
|
||||
improve(&best, spp-offset3, spp, cv32, 3)
|
||||
if best.rep < 0 {
|
||||
cv32 = uint32(cv >> 24)
|
||||
spp += 2
|
||||
improve(&best, spp-offset1, spp, cv32, 1)
|
||||
improve(&best, spp-offset2, spp, cv32, 2)
|
||||
improve(&best, spp-offset3, spp, cv32, 3)
|
||||
}
|
||||
}
|
||||
}
|
||||
// Load next and check...
|
||||
|
@ -250,47 +290,45 @@ encodeLoop:
|
|||
if s >= sLimit {
|
||||
break encodeLoop
|
||||
}
|
||||
cv = load6432(src, s)
|
||||
continue
|
||||
}
|
||||
|
||||
s++
|
||||
candidateS = e.table[hashLen(cv>>8, bestShortTableBits, bestShortLen)]
|
||||
cv = load6432(src, s)
|
||||
cv2 := load6432(src, s+1)
|
||||
cv = load6432(src, s+1)
|
||||
cv2 := load6432(src, s+2)
|
||||
candidateL = e.longTable[hashLen(cv, bestLongTableBits, bestLongLen)]
|
||||
candidateL2 := e.longTable[hashLen(cv2, bestLongTableBits, bestLongLen)]
|
||||
|
||||
// Short at s+1
|
||||
m1 := matchAt(candidateS.offset-e.cur, s, uint32(cv), -1)
|
||||
improve(&best, candidateS.offset-e.cur, s+1, uint32(cv), -1)
|
||||
// Long at s+1, s+2
|
||||
m2 := matchAt(candidateL.offset-e.cur, s, uint32(cv), -1)
|
||||
m3 := matchAt(candidateL.prev-e.cur, s, uint32(cv), -1)
|
||||
m4 := matchAt(candidateL2.offset-e.cur, s+1, uint32(cv2), -1)
|
||||
m5 := matchAt(candidateL2.prev-e.cur, s+1, uint32(cv2), -1)
|
||||
best = bestOf(bestOf(bestOf(best, &m1), &m2), bestOf(bestOf(&m3, &m4), &m5))
|
||||
improve(&best, candidateL.offset-e.cur, s+1, uint32(cv), -1)
|
||||
improve(&best, candidateL.prev-e.cur, s+1, uint32(cv), -1)
|
||||
improve(&best, candidateL2.offset-e.cur, s+2, uint32(cv2), -1)
|
||||
improve(&best, candidateL2.prev-e.cur, s+2, uint32(cv2), -1)
|
||||
if false {
|
||||
// Short at s+3.
|
||||
// Too often worse...
|
||||
m := matchAt(e.table[hashLen(cv2>>8, bestShortTableBits, bestShortLen)].offset-e.cur, s+2, uint32(cv2>>8), -1)
|
||||
best = bestOf(best, &m)
|
||||
improve(&best, e.table[hashLen(cv2>>8, bestShortTableBits, bestShortLen)].offset-e.cur, s+3, uint32(cv2>>8), -1)
|
||||
}
|
||||
// See if we can find a better match by checking where the current best ends.
|
||||
// Use that offset to see if we can find a better full match.
|
||||
if sAt := best.s + best.length; sAt < sLimit {
|
||||
nextHashL := hashLen(load6432(src, sAt), bestLongTableBits, bestLongLen)
|
||||
candidateEnd := e.longTable[nextHashL]
|
||||
// Start check at a fixed offset to allow for a few mismatches.
|
||||
// For this compression level 2 yields the best results.
|
||||
const skipBeginning = 2
|
||||
if pos := candidateEnd.offset - e.cur - best.length + skipBeginning; pos >= 0 {
|
||||
m := matchAt(pos, best.s+skipBeginning, load3232(src, best.s+skipBeginning), -1)
|
||||
bestEnd := bestOf(best, &m)
|
||||
if pos := candidateEnd.prev - e.cur - best.length + skipBeginning; pos >= 0 {
|
||||
m := matchAt(pos, best.s+skipBeginning, load3232(src, best.s+skipBeginning), -1)
|
||||
bestEnd = bestOf(bestEnd, &m)
|
||||
|
||||
// Start check at a fixed offset to allow for a few mismatches.
|
||||
// For this compression level 2 yields the best results.
|
||||
// We cannot do this if we have already indexed this position.
|
||||
const skipBeginning = 2
|
||||
if best.s > s-skipBeginning {
|
||||
// See if we can find a better match by checking where the current best ends.
|
||||
// Use that offset to see if we can find a better full match.
|
||||
if sAt := best.s + best.length; sAt < sLimit {
|
||||
nextHashL := hashLen(load6432(src, sAt), bestLongTableBits, bestLongLen)
|
||||
candidateEnd := e.longTable[nextHashL]
|
||||
|
||||
if off := candidateEnd.offset - e.cur - best.length + skipBeginning; off >= 0 {
|
||||
improve(&best, off, best.s+skipBeginning, load3232(src, best.s+skipBeginning), -1)
|
||||
if off := candidateEnd.prev - e.cur - best.length + skipBeginning; off >= 0 {
|
||||
improve(&best, off, best.s+skipBeginning, load3232(src, best.s+skipBeginning), -1)
|
||||
}
|
||||
}
|
||||
best = bestEnd
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -303,51 +341,34 @@ encodeLoop:
|
|||
|
||||
// We have a match, we can store the forward value
|
||||
if best.rep > 0 {
|
||||
s = best.s
|
||||
var seq seq
|
||||
seq.matchLen = uint32(best.length - zstdMinMatch)
|
||||
|
||||
// We might be able to match backwards.
|
||||
// Extend as long as we can.
|
||||
start := best.s
|
||||
// We end the search early, so we don't risk 0 literals
|
||||
// and have to do special offset treatment.
|
||||
startLimit := nextEmit + 1
|
||||
|
||||
tMin := s - e.maxMatchOff
|
||||
if tMin < 0 {
|
||||
tMin = 0
|
||||
if debugAsserts && s <= nextEmit {
|
||||
panic("s <= nextEmit")
|
||||
}
|
||||
repIndex := best.offset
|
||||
for repIndex > tMin && start > startLimit && src[repIndex-1] == src[start-1] && seq.matchLen < maxMatchLength-zstdMinMatch-1 {
|
||||
repIndex--
|
||||
start--
|
||||
seq.matchLen++
|
||||
}
|
||||
addLiterals(&seq, start)
|
||||
addLiterals(&seq, best.s)
|
||||
|
||||
// rep 0
|
||||
seq.offset = uint32(best.rep)
|
||||
// Repeat. If bit 4 is set, this is a non-lit repeat.
|
||||
seq.offset = uint32(best.rep & 3)
|
||||
if debugSequences {
|
||||
println("repeat sequence", seq, "next s:", s)
|
||||
}
|
||||
blk.sequences = append(blk.sequences, seq)
|
||||
|
||||
// Index match start+1 (long) -> s - 1
|
||||
index0 := s
|
||||
// Index old s + 1 -> s - 1
|
||||
index0 := s + 1
|
||||
s = best.s + best.length
|
||||
|
||||
nextEmit = s
|
||||
if s >= sLimit {
|
||||
if debugEncoder {
|
||||
println("repeat ended", s, best.length)
|
||||
|
||||
}
|
||||
break encodeLoop
|
||||
}
|
||||
// Index skipped...
|
||||
off := index0 + e.cur
|
||||
for index0 < s-1 {
|
||||
for index0 < s {
|
||||
cv0 := load6432(src, index0)
|
||||
h0 := hashLen(cv0, bestLongTableBits, bestLongLen)
|
||||
h1 := hashLen(cv0, bestShortTableBits, bestShortLen)
|
||||
|
@ -357,17 +378,19 @@ encodeLoop:
|
|||
index0++
|
||||
}
|
||||
switch best.rep {
|
||||
case 2:
|
||||
case 2, 4 | 1:
|
||||
offset1, offset2 = offset2, offset1
|
||||
case 3:
|
||||
case 3, 4 | 2:
|
||||
offset1, offset2, offset3 = offset3, offset1, offset2
|
||||
case 4 | 3:
|
||||
offset1, offset2, offset3 = offset1-1, offset1, offset2
|
||||
}
|
||||
cv = load6432(src, s)
|
||||
continue
|
||||
}
|
||||
|
||||
// A 4-byte match has been found. Update recent offsets.
|
||||
// We'll later see if more than 4 bytes.
|
||||
index0 := s + 1
|
||||
s = best.s
|
||||
t := best.offset
|
||||
offset1, offset2, offset3 = s-t, offset1, offset2
|
||||
|
@ -380,22 +403,9 @@ encodeLoop:
|
|||
panic("invalid offset")
|
||||
}
|
||||
|
||||
// Extend the n-byte match as long as possible.
|
||||
l := best.length
|
||||
|
||||
// Extend backwards
|
||||
tMin := s - e.maxMatchOff
|
||||
if tMin < 0 {
|
||||
tMin = 0
|
||||
}
|
||||
for t > tMin && s > nextEmit && src[t-1] == src[s-1] && l < maxMatchLength {
|
||||
s--
|
||||
t--
|
||||
l++
|
||||
}
|
||||
|
||||
// Write our sequence
|
||||
var seq seq
|
||||
l := best.length
|
||||
seq.litLen = uint32(s - nextEmit)
|
||||
seq.matchLen = uint32(l - zstdMinMatch)
|
||||
if seq.litLen > 0 {
|
||||
|
@ -412,10 +422,8 @@ encodeLoop:
|
|||
break encodeLoop
|
||||
}
|
||||
|
||||
// Index match start+1 (long) -> s - 1
|
||||
index0 := s - l + 1
|
||||
// every entry
|
||||
for index0 < s-1 {
|
||||
// Index old s + 1 -> s - 1
|
||||
for index0 < s {
|
||||
cv0 := load6432(src, index0)
|
||||
h0 := hashLen(cv0, bestLongTableBits, bestLongLen)
|
||||
h1 := hashLen(cv0, bestShortTableBits, bestShortLen)
|
||||
|
@ -424,50 +432,6 @@ encodeLoop:
|
|||
e.table[h1] = prevEntry{offset: off, prev: e.table[h1].offset}
|
||||
index0++
|
||||
}
|
||||
|
||||
cv = load6432(src, s)
|
||||
if !canRepeat {
|
||||
continue
|
||||
}
|
||||
|
||||
// Check offset 2
|
||||
for {
|
||||
o2 := s - offset2
|
||||
if load3232(src, o2) != uint32(cv) {
|
||||
// Do regular search
|
||||
break
|
||||
}
|
||||
|
||||
// Store this, since we have it.
|
||||
nextHashS := hashLen(cv, bestShortTableBits, bestShortLen)
|
||||
nextHashL := hashLen(cv, bestLongTableBits, bestLongLen)
|
||||
|
||||
// We have at least 4 byte match.
|
||||
// No need to check backwards. We come straight from a match
|
||||
l := 4 + e.matchlen(s+4, o2+4, src)
|
||||
|
||||
e.longTable[nextHashL] = prevEntry{offset: s + e.cur, prev: e.longTable[nextHashL].offset}
|
||||
e.table[nextHashS] = prevEntry{offset: s + e.cur, prev: e.table[nextHashS].offset}
|
||||
seq.matchLen = uint32(l) - zstdMinMatch
|
||||
seq.litLen = 0
|
||||
|
||||
// Since litlen is always 0, this is offset 1.
|
||||
seq.offset = 1
|
||||
s += l
|
||||
nextEmit = s
|
||||
if debugSequences {
|
||||
println("sequence", seq, "next s:", s)
|
||||
}
|
||||
blk.sequences = append(blk.sequences, seq)
|
||||
|
||||
// Swap offset 1 and 2.
|
||||
offset1, offset2 = offset2, offset1
|
||||
if s >= sLimit {
|
||||
// Finished
|
||||
break encodeLoop
|
||||
}
|
||||
cv = load6432(src, s)
|
||||
}
|
||||
}
|
||||
|
||||
if int(nextEmit) < len(src) {
|
||||
|
|
|
@ -277,23 +277,9 @@ func (e *Encoder) nextBlock(final bool) error {
|
|||
s.eofWritten = true
|
||||
}
|
||||
|
||||
err := errIncompressible
|
||||
// If we got the exact same number of literals as input,
|
||||
// assume the literals cannot be compressed.
|
||||
if len(src) != len(blk.literals) || len(src) != e.o.blockSize {
|
||||
err = blk.encode(src, e.o.noEntropy, !e.o.allLitEntropy)
|
||||
}
|
||||
switch err {
|
||||
case errIncompressible:
|
||||
if debugEncoder {
|
||||
println("Storing incompressible block as raw")
|
||||
}
|
||||
blk.encodeRaw(src)
|
||||
// In fast mode, we do not transfer offsets, so we don't have to deal with changing the.
|
||||
case nil:
|
||||
default:
|
||||
s.err = err
|
||||
return err
|
||||
s.err = blk.encode(src, e.o.noEntropy, !e.o.allLitEntropy)
|
||||
if s.err != nil {
|
||||
return s.err
|
||||
}
|
||||
_, s.err = s.w.Write(blk.output)
|
||||
s.nWritten += int64(len(blk.output))
|
||||
|
@ -343,22 +329,8 @@ func (e *Encoder) nextBlock(final bool) error {
|
|||
}
|
||||
s.wWg.Done()
|
||||
}()
|
||||
err := errIncompressible
|
||||
// If we got the exact same number of literals as input,
|
||||
// assume the literals cannot be compressed.
|
||||
if len(src) != len(blk.literals) || len(src) != e.o.blockSize {
|
||||
err = blk.encode(src, e.o.noEntropy, !e.o.allLitEntropy)
|
||||
}
|
||||
switch err {
|
||||
case errIncompressible:
|
||||
if debugEncoder {
|
||||
println("Storing incompressible block as raw")
|
||||
}
|
||||
blk.encodeRaw(src)
|
||||
// In fast mode, we do not transfer offsets, so we don't have to deal with changing the.
|
||||
case nil:
|
||||
default:
|
||||
s.writeErr = err
|
||||
s.writeErr = blk.encode(src, e.o.noEntropy, !e.o.allLitEntropy)
|
||||
if s.writeErr != nil {
|
||||
return
|
||||
}
|
||||
_, s.writeErr = s.w.Write(blk.output)
|
||||
|
@ -568,25 +540,15 @@ func (e *Encoder) EncodeAll(src, dst []byte) []byte {
|
|||
|
||||
// If we got the exact same number of literals as input,
|
||||
// assume the literals cannot be compressed.
|
||||
err := errIncompressible
|
||||
oldout := blk.output
|
||||
if len(blk.literals) != len(src) || len(src) != e.o.blockSize {
|
||||
// Output directly to dst
|
||||
blk.output = dst
|
||||
err = blk.encode(src, e.o.noEntropy, !e.o.allLitEntropy)
|
||||
}
|
||||
// Output directly to dst
|
||||
blk.output = dst
|
||||
|
||||
switch err {
|
||||
case errIncompressible:
|
||||
if debugEncoder {
|
||||
println("Storing incompressible block as raw")
|
||||
}
|
||||
dst = blk.encodeRawTo(dst, src)
|
||||
case nil:
|
||||
dst = blk.output
|
||||
default:
|
||||
err := blk.encode(src, e.o.noEntropy, !e.o.allLitEntropy)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
dst = blk.output
|
||||
blk.output = oldout
|
||||
} else {
|
||||
enc.Reset(e.o.dict, false)
|
||||
|
@ -605,25 +567,11 @@ func (e *Encoder) EncodeAll(src, dst []byte) []byte {
|
|||
if len(src) == 0 {
|
||||
blk.last = true
|
||||
}
|
||||
err := errIncompressible
|
||||
// If we got the exact same number of literals as input,
|
||||
// assume the literals cannot be compressed.
|
||||
if len(blk.literals) != len(todo) || len(todo) != e.o.blockSize {
|
||||
err = blk.encode(todo, e.o.noEntropy, !e.o.allLitEntropy)
|
||||
}
|
||||
|
||||
switch err {
|
||||
case errIncompressible:
|
||||
if debugEncoder {
|
||||
println("Storing incompressible block as raw")
|
||||
}
|
||||
dst = blk.encodeRawTo(dst, todo)
|
||||
blk.popOffsets()
|
||||
case nil:
|
||||
dst = append(dst, blk.output...)
|
||||
default:
|
||||
err := blk.encode(todo, e.o.noEntropy, !e.o.allLitEntropy)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
dst = append(dst, blk.output...)
|
||||
blk.reset(nil)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ func (o *encoderOptions) setDefault() {
|
|||
blockSize: maxCompressedBlockSize,
|
||||
windowSize: 8 << 20,
|
||||
level: SpeedDefault,
|
||||
allLitEntropy: true,
|
||||
allLitEntropy: false,
|
||||
lowMem: false,
|
||||
}
|
||||
}
|
||||
|
@ -238,7 +238,7 @@ func WithEncoderLevel(l EncoderLevel) EOption {
|
|||
}
|
||||
}
|
||||
if !o.customALEntropy {
|
||||
o.allLitEntropy = l > SpeedFastest
|
||||
o.allLitEntropy = l > SpeedDefault
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
|
@ -293,13 +293,9 @@ func (d *frameDec) next(block *blockDec) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// checkCRC will check the checksum if the frame has one.
|
||||
// checkCRC will check the checksum, assuming the frame has one.
|
||||
// Will return ErrCRCMismatch if crc check failed, otherwise nil.
|
||||
func (d *frameDec) checkCRC() error {
|
||||
if !d.HasCheckSum {
|
||||
return nil
|
||||
}
|
||||
|
||||
// We can overwrite upper tmp now
|
||||
buf, err := d.rawInput.readSmall(4)
|
||||
if err != nil {
|
||||
|
@ -307,10 +303,6 @@ func (d *frameDec) checkCRC() error {
|
|||
return err
|
||||
}
|
||||
|
||||
if d.o.ignoreChecksum {
|
||||
return nil
|
||||
}
|
||||
|
||||
want := binary.LittleEndian.Uint32(buf[:4])
|
||||
got := uint32(d.crc.Sum64())
|
||||
|
||||
|
@ -326,17 +318,13 @@ func (d *frameDec) checkCRC() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// consumeCRC reads the checksum data if the frame has one.
|
||||
// consumeCRC skips over the checksum, assuming the frame has one.
|
||||
func (d *frameDec) consumeCRC() error {
|
||||
if d.HasCheckSum {
|
||||
_, err := d.rawInput.readSmall(4)
|
||||
if err != nil {
|
||||
println("CRC missing?", err)
|
||||
return err
|
||||
}
|
||||
_, err := d.rawInput.readSmall(4)
|
||||
if err != nil {
|
||||
println("CRC missing?", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
return err
|
||||
}
|
||||
|
||||
// runDecoder will run the decoder for the remainder of the frame.
|
||||
|
@ -415,15 +403,8 @@ func (d *frameDec) runDecoder(dst []byte, dec *blockDec) ([]byte, error) {
|
|||
if d.o.ignoreChecksum {
|
||||
err = d.consumeCRC()
|
||||
} else {
|
||||
var n int
|
||||
n, err = d.crc.Write(dst[crcStart:])
|
||||
if err == nil {
|
||||
if n != len(dst)-crcStart {
|
||||
err = io.ErrShortWrite
|
||||
} else {
|
||||
err = d.checkCRC()
|
||||
}
|
||||
}
|
||||
d.crc.Write(dst[crcStart:])
|
||||
err = d.checkCRC()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -236,9 +236,12 @@ func (s *sequenceDecs) decodeSync(hist []byte) error {
|
|||
maxBlockSize = s.windowSize
|
||||
}
|
||||
|
||||
if debugDecoder {
|
||||
println("decodeSync: decoding", seqs, "sequences", br.remain(), "bits remain on stream")
|
||||
}
|
||||
for i := seqs - 1; i >= 0; i-- {
|
||||
if br.overread() {
|
||||
printf("reading sequence %d, exceeded available data\n", seqs-i)
|
||||
printf("reading sequence %d, exceeded available data. Overread by %d\n", seqs-i, -br.remain())
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
var ll, mo, ml int
|
||||
|
@ -314,9 +317,6 @@ func (s *sequenceDecs) decodeSync(hist []byte) error {
|
|||
}
|
||||
size := ll + ml + len(out)
|
||||
if size-startSize > maxBlockSize {
|
||||
if size-startSize == 424242 {
|
||||
panic("here")
|
||||
}
|
||||
return fmt.Errorf("output bigger than max block size (%d)", maxBlockSize)
|
||||
}
|
||||
if size > cap(out) {
|
||||
|
@ -427,8 +427,7 @@ func (s *sequenceDecs) decodeSync(hist []byte) error {
|
|||
}
|
||||
}
|
||||
|
||||
// Check if space for literals
|
||||
if size := len(s.literals) + len(s.out) - startSize; size > maxBlockSize {
|
||||
if size := len(s.literals) + len(out) - startSize; size > maxBlockSize {
|
||||
return fmt.Errorf("output bigger than max block size (%d)", maxBlockSize)
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ package zstd
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/klauspost/compress/internal/cpuinfo"
|
||||
)
|
||||
|
@ -134,6 +135,9 @@ func (s *sequenceDecs) decodeSyncSimple(hist []byte) (bool, error) {
|
|||
return true, fmt.Errorf("unexpected literal count, want %d bytes, but only %d is available",
|
||||
ctx.ll, ctx.litRemain+ctx.ll)
|
||||
|
||||
case errorOverread:
|
||||
return true, io.ErrUnexpectedEOF
|
||||
|
||||
case errorNotEnoughSpace:
|
||||
size := ctx.outPosition + ctx.ll + ctx.ml
|
||||
if debugDecoder {
|
||||
|
@ -148,7 +152,6 @@ func (s *sequenceDecs) decodeSyncSimple(hist []byte) (bool, error) {
|
|||
s.seqSize += ctx.litRemain
|
||||
if s.seqSize > maxBlockSize {
|
||||
return true, fmt.Errorf("output bigger than max block size (%d)", maxBlockSize)
|
||||
|
||||
}
|
||||
err := br.close()
|
||||
if err != nil {
|
||||
|
@ -203,6 +206,9 @@ const errorNotEnoughLiterals = 4
|
|||
// error reported when capacity of `out` is too small
|
||||
const errorNotEnoughSpace = 5
|
||||
|
||||
// error reported when bits are overread.
|
||||
const errorOverread = 6
|
||||
|
||||
// sequenceDecs_decode implements the main loop of sequenceDecs in x86 asm.
|
||||
//
|
||||
// Please refer to seqdec_generic.go for the reference implementation.
|
||||
|
@ -248,6 +254,10 @@ func (s *sequenceDecs) decode(seqs []seqVals) error {
|
|||
litRemain: len(s.literals),
|
||||
}
|
||||
|
||||
if debugDecoder {
|
||||
println("decode: decoding", len(seqs), "sequences", br.remain(), "bits remain on stream")
|
||||
}
|
||||
|
||||
s.seqSize = 0
|
||||
lte56bits := s.maxBits+s.offsets.fse.actualTableLog+s.matchLengths.fse.actualTableLog+s.litLengths.fse.actualTableLog <= 56
|
||||
var errCode int
|
||||
|
@ -278,6 +288,8 @@ func (s *sequenceDecs) decode(seqs []seqVals) error {
|
|||
case errorNotEnoughLiterals:
|
||||
ll := ctx.seqs[i].ll
|
||||
return fmt.Errorf("unexpected literal count, want %d bytes, but only %d is available", ll, ctx.litRemain+ll)
|
||||
case errorOverread:
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
|
||||
return fmt.Errorf("sequenceDecs_decode_amd64 returned erronous code %d", errCode)
|
||||
|
@ -292,6 +304,9 @@ func (s *sequenceDecs) decode(seqs []seqVals) error {
|
|||
if s.seqSize > maxBlockSize {
|
||||
return fmt.Errorf("output bigger than max block size (%d)", maxBlockSize)
|
||||
}
|
||||
if debugDecoder {
|
||||
println("decode: ", br.remain(), "bits remain on stream. code:", errCode)
|
||||
}
|
||||
err := br.close()
|
||||
if err != nil {
|
||||
printf("Closing sequences: %v, %+v\n", err, *br)
|
||||
|
|
|
@ -38,7 +38,7 @@ sequenceDecs_decode_amd64_main_loop:
|
|||
|
||||
sequenceDecs_decode_amd64_fill_byte_by_byte:
|
||||
CMPQ SI, $0x00
|
||||
JLE sequenceDecs_decode_amd64_fill_end
|
||||
JLE sequenceDecs_decode_amd64_fill_check_overread
|
||||
CMPQ BX, $0x07
|
||||
JLE sequenceDecs_decode_amd64_fill_end
|
||||
SHLQ $0x08, DX
|
||||
|
@ -49,6 +49,10 @@ sequenceDecs_decode_amd64_fill_byte_by_byte:
|
|||
ORQ AX, DX
|
||||
JMP sequenceDecs_decode_amd64_fill_byte_by_byte
|
||||
|
||||
sequenceDecs_decode_amd64_fill_check_overread:
|
||||
CMPQ BX, $0x40
|
||||
JA error_overread
|
||||
|
||||
sequenceDecs_decode_amd64_fill_end:
|
||||
// Update offset
|
||||
MOVQ R9, AX
|
||||
|
@ -105,7 +109,7 @@ sequenceDecs_decode_amd64_ml_update_zero:
|
|||
|
||||
sequenceDecs_decode_amd64_fill_2_byte_by_byte:
|
||||
CMPQ SI, $0x00
|
||||
JLE sequenceDecs_decode_amd64_fill_2_end
|
||||
JLE sequenceDecs_decode_amd64_fill_2_check_overread
|
||||
CMPQ BX, $0x07
|
||||
JLE sequenceDecs_decode_amd64_fill_2_end
|
||||
SHLQ $0x08, DX
|
||||
|
@ -116,6 +120,10 @@ sequenceDecs_decode_amd64_fill_2_byte_by_byte:
|
|||
ORQ AX, DX
|
||||
JMP sequenceDecs_decode_amd64_fill_2_byte_by_byte
|
||||
|
||||
sequenceDecs_decode_amd64_fill_2_check_overread:
|
||||
CMPQ BX, $0x40
|
||||
JA error_overread
|
||||
|
||||
sequenceDecs_decode_amd64_fill_2_end:
|
||||
// Update literal length
|
||||
MOVQ DI, AX
|
||||
|
@ -320,6 +328,11 @@ error_not_enough_literals:
|
|||
MOVQ $0x00000004, ret+24(FP)
|
||||
RET
|
||||
|
||||
// Return with overread error
|
||||
error_overread:
|
||||
MOVQ $0x00000006, ret+24(FP)
|
||||
RET
|
||||
|
||||
// func sequenceDecs_decode_56_amd64(s *sequenceDecs, br *bitReader, ctx *decodeAsmContext) int
|
||||
// Requires: CMOV
|
||||
TEXT ·sequenceDecs_decode_56_amd64(SB), $8-32
|
||||
|
@ -356,7 +369,7 @@ sequenceDecs_decode_56_amd64_main_loop:
|
|||
|
||||
sequenceDecs_decode_56_amd64_fill_byte_by_byte:
|
||||
CMPQ SI, $0x00
|
||||
JLE sequenceDecs_decode_56_amd64_fill_end
|
||||
JLE sequenceDecs_decode_56_amd64_fill_check_overread
|
||||
CMPQ BX, $0x07
|
||||
JLE sequenceDecs_decode_56_amd64_fill_end
|
||||
SHLQ $0x08, DX
|
||||
|
@ -367,6 +380,10 @@ sequenceDecs_decode_56_amd64_fill_byte_by_byte:
|
|||
ORQ AX, DX
|
||||
JMP sequenceDecs_decode_56_amd64_fill_byte_by_byte
|
||||
|
||||
sequenceDecs_decode_56_amd64_fill_check_overread:
|
||||
CMPQ BX, $0x40
|
||||
JA error_overread
|
||||
|
||||
sequenceDecs_decode_56_amd64_fill_end:
|
||||
// Update offset
|
||||
MOVQ R9, AX
|
||||
|
@ -613,6 +630,11 @@ error_not_enough_literals:
|
|||
MOVQ $0x00000004, ret+24(FP)
|
||||
RET
|
||||
|
||||
// Return with overread error
|
||||
error_overread:
|
||||
MOVQ $0x00000006, ret+24(FP)
|
||||
RET
|
||||
|
||||
// func sequenceDecs_decode_bmi2(s *sequenceDecs, br *bitReader, ctx *decodeAsmContext) int
|
||||
// Requires: BMI, BMI2, CMOV
|
||||
TEXT ·sequenceDecs_decode_bmi2(SB), $8-32
|
||||
|
@ -649,7 +671,7 @@ sequenceDecs_decode_bmi2_main_loop:
|
|||
|
||||
sequenceDecs_decode_bmi2_fill_byte_by_byte:
|
||||
CMPQ BX, $0x00
|
||||
JLE sequenceDecs_decode_bmi2_fill_end
|
||||
JLE sequenceDecs_decode_bmi2_fill_check_overread
|
||||
CMPQ DX, $0x07
|
||||
JLE sequenceDecs_decode_bmi2_fill_end
|
||||
SHLQ $0x08, AX
|
||||
|
@ -660,6 +682,10 @@ sequenceDecs_decode_bmi2_fill_byte_by_byte:
|
|||
ORQ CX, AX
|
||||
JMP sequenceDecs_decode_bmi2_fill_byte_by_byte
|
||||
|
||||
sequenceDecs_decode_bmi2_fill_check_overread:
|
||||
CMPQ DX, $0x40
|
||||
JA error_overread
|
||||
|
||||
sequenceDecs_decode_bmi2_fill_end:
|
||||
// Update offset
|
||||
MOVQ $0x00000808, CX
|
||||
|
@ -700,7 +726,7 @@ sequenceDecs_decode_bmi2_fill_end:
|
|||
|
||||
sequenceDecs_decode_bmi2_fill_2_byte_by_byte:
|
||||
CMPQ BX, $0x00
|
||||
JLE sequenceDecs_decode_bmi2_fill_2_end
|
||||
JLE sequenceDecs_decode_bmi2_fill_2_check_overread
|
||||
CMPQ DX, $0x07
|
||||
JLE sequenceDecs_decode_bmi2_fill_2_end
|
||||
SHLQ $0x08, AX
|
||||
|
@ -711,6 +737,10 @@ sequenceDecs_decode_bmi2_fill_2_byte_by_byte:
|
|||
ORQ CX, AX
|
||||
JMP sequenceDecs_decode_bmi2_fill_2_byte_by_byte
|
||||
|
||||
sequenceDecs_decode_bmi2_fill_2_check_overread:
|
||||
CMPQ DX, $0x40
|
||||
JA error_overread
|
||||
|
||||
sequenceDecs_decode_bmi2_fill_2_end:
|
||||
// Update literal length
|
||||
MOVQ $0x00000808, CX
|
||||
|
@ -889,6 +919,11 @@ error_not_enough_literals:
|
|||
MOVQ $0x00000004, ret+24(FP)
|
||||
RET
|
||||
|
||||
// Return with overread error
|
||||
error_overread:
|
||||
MOVQ $0x00000006, ret+24(FP)
|
||||
RET
|
||||
|
||||
// func sequenceDecs_decode_56_bmi2(s *sequenceDecs, br *bitReader, ctx *decodeAsmContext) int
|
||||
// Requires: BMI, BMI2, CMOV
|
||||
TEXT ·sequenceDecs_decode_56_bmi2(SB), $8-32
|
||||
|
@ -925,7 +960,7 @@ sequenceDecs_decode_56_bmi2_main_loop:
|
|||
|
||||
sequenceDecs_decode_56_bmi2_fill_byte_by_byte:
|
||||
CMPQ BX, $0x00
|
||||
JLE sequenceDecs_decode_56_bmi2_fill_end
|
||||
JLE sequenceDecs_decode_56_bmi2_fill_check_overread
|
||||
CMPQ DX, $0x07
|
||||
JLE sequenceDecs_decode_56_bmi2_fill_end
|
||||
SHLQ $0x08, AX
|
||||
|
@ -936,6 +971,10 @@ sequenceDecs_decode_56_bmi2_fill_byte_by_byte:
|
|||
ORQ CX, AX
|
||||
JMP sequenceDecs_decode_56_bmi2_fill_byte_by_byte
|
||||
|
||||
sequenceDecs_decode_56_bmi2_fill_check_overread:
|
||||
CMPQ DX, $0x40
|
||||
JA error_overread
|
||||
|
||||
sequenceDecs_decode_56_bmi2_fill_end:
|
||||
// Update offset
|
||||
MOVQ $0x00000808, CX
|
||||
|
@ -1140,6 +1179,11 @@ error_not_enough_literals:
|
|||
MOVQ $0x00000004, ret+24(FP)
|
||||
RET
|
||||
|
||||
// Return with overread error
|
||||
error_overread:
|
||||
MOVQ $0x00000006, ret+24(FP)
|
||||
RET
|
||||
|
||||
// func sequenceDecs_executeSimple_amd64(ctx *executeAsmContext) bool
|
||||
// Requires: SSE
|
||||
TEXT ·sequenceDecs_executeSimple_amd64(SB), $8-9
|
||||
|
@ -1804,7 +1848,7 @@ sequenceDecs_decodeSync_amd64_main_loop:
|
|||
|
||||
sequenceDecs_decodeSync_amd64_fill_byte_by_byte:
|
||||
CMPQ SI, $0x00
|
||||
JLE sequenceDecs_decodeSync_amd64_fill_end
|
||||
JLE sequenceDecs_decodeSync_amd64_fill_check_overread
|
||||
CMPQ BX, $0x07
|
||||
JLE sequenceDecs_decodeSync_amd64_fill_end
|
||||
SHLQ $0x08, DX
|
||||
|
@ -1815,6 +1859,10 @@ sequenceDecs_decodeSync_amd64_fill_byte_by_byte:
|
|||
ORQ AX, DX
|
||||
JMP sequenceDecs_decodeSync_amd64_fill_byte_by_byte
|
||||
|
||||
sequenceDecs_decodeSync_amd64_fill_check_overread:
|
||||
CMPQ BX, $0x40
|
||||
JA error_overread
|
||||
|
||||
sequenceDecs_decodeSync_amd64_fill_end:
|
||||
// Update offset
|
||||
MOVQ R9, AX
|
||||
|
@ -1871,7 +1919,7 @@ sequenceDecs_decodeSync_amd64_ml_update_zero:
|
|||
|
||||
sequenceDecs_decodeSync_amd64_fill_2_byte_by_byte:
|
||||
CMPQ SI, $0x00
|
||||
JLE sequenceDecs_decodeSync_amd64_fill_2_end
|
||||
JLE sequenceDecs_decodeSync_amd64_fill_2_check_overread
|
||||
CMPQ BX, $0x07
|
||||
JLE sequenceDecs_decodeSync_amd64_fill_2_end
|
||||
SHLQ $0x08, DX
|
||||
|
@ -1882,6 +1930,10 @@ sequenceDecs_decodeSync_amd64_fill_2_byte_by_byte:
|
|||
ORQ AX, DX
|
||||
JMP sequenceDecs_decodeSync_amd64_fill_2_byte_by_byte
|
||||
|
||||
sequenceDecs_decodeSync_amd64_fill_2_check_overread:
|
||||
CMPQ BX, $0x40
|
||||
JA error_overread
|
||||
|
||||
sequenceDecs_decodeSync_amd64_fill_2_end:
|
||||
// Update literal length
|
||||
MOVQ DI, AX
|
||||
|
@ -2291,6 +2343,11 @@ error_not_enough_literals:
|
|||
MOVQ $0x00000004, ret+24(FP)
|
||||
RET
|
||||
|
||||
// Return with overread error
|
||||
error_overread:
|
||||
MOVQ $0x00000006, ret+24(FP)
|
||||
RET
|
||||
|
||||
// Return with not enough output space error
|
||||
error_not_enough_space:
|
||||
MOVQ ctx+16(FP), AX
|
||||
|
@ -2356,7 +2413,7 @@ sequenceDecs_decodeSync_bmi2_main_loop:
|
|||
|
||||
sequenceDecs_decodeSync_bmi2_fill_byte_by_byte:
|
||||
CMPQ BX, $0x00
|
||||
JLE sequenceDecs_decodeSync_bmi2_fill_end
|
||||
JLE sequenceDecs_decodeSync_bmi2_fill_check_overread
|
||||
CMPQ DX, $0x07
|
||||
JLE sequenceDecs_decodeSync_bmi2_fill_end
|
||||
SHLQ $0x08, AX
|
||||
|
@ -2367,6 +2424,10 @@ sequenceDecs_decodeSync_bmi2_fill_byte_by_byte:
|
|||
ORQ CX, AX
|
||||
JMP sequenceDecs_decodeSync_bmi2_fill_byte_by_byte
|
||||
|
||||
sequenceDecs_decodeSync_bmi2_fill_check_overread:
|
||||
CMPQ DX, $0x40
|
||||
JA error_overread
|
||||
|
||||
sequenceDecs_decodeSync_bmi2_fill_end:
|
||||
// Update offset
|
||||
MOVQ $0x00000808, CX
|
||||
|
@ -2407,7 +2468,7 @@ sequenceDecs_decodeSync_bmi2_fill_end:
|
|||
|
||||
sequenceDecs_decodeSync_bmi2_fill_2_byte_by_byte:
|
||||
CMPQ BX, $0x00
|
||||
JLE sequenceDecs_decodeSync_bmi2_fill_2_end
|
||||
JLE sequenceDecs_decodeSync_bmi2_fill_2_check_overread
|
||||
CMPQ DX, $0x07
|
||||
JLE sequenceDecs_decodeSync_bmi2_fill_2_end
|
||||
SHLQ $0x08, AX
|
||||
|
@ -2418,6 +2479,10 @@ sequenceDecs_decodeSync_bmi2_fill_2_byte_by_byte:
|
|||
ORQ CX, AX
|
||||
JMP sequenceDecs_decodeSync_bmi2_fill_2_byte_by_byte
|
||||
|
||||
sequenceDecs_decodeSync_bmi2_fill_2_check_overread:
|
||||
CMPQ DX, $0x40
|
||||
JA error_overread
|
||||
|
||||
sequenceDecs_decodeSync_bmi2_fill_2_end:
|
||||
// Update literal length
|
||||
MOVQ $0x00000808, CX
|
||||
|
@ -2801,6 +2866,11 @@ error_not_enough_literals:
|
|||
MOVQ $0x00000004, ret+24(FP)
|
||||
RET
|
||||
|
||||
// Return with overread error
|
||||
error_overread:
|
||||
MOVQ $0x00000006, ret+24(FP)
|
||||
RET
|
||||
|
||||
// Return with not enough output space error
|
||||
error_not_enough_space:
|
||||
MOVQ ctx+16(FP), AX
|
||||
|
@ -2866,7 +2936,7 @@ sequenceDecs_decodeSync_safe_amd64_main_loop:
|
|||
|
||||
sequenceDecs_decodeSync_safe_amd64_fill_byte_by_byte:
|
||||
CMPQ SI, $0x00
|
||||
JLE sequenceDecs_decodeSync_safe_amd64_fill_end
|
||||
JLE sequenceDecs_decodeSync_safe_amd64_fill_check_overread
|
||||
CMPQ BX, $0x07
|
||||
JLE sequenceDecs_decodeSync_safe_amd64_fill_end
|
||||
SHLQ $0x08, DX
|
||||
|
@ -2877,6 +2947,10 @@ sequenceDecs_decodeSync_safe_amd64_fill_byte_by_byte:
|
|||
ORQ AX, DX
|
||||
JMP sequenceDecs_decodeSync_safe_amd64_fill_byte_by_byte
|
||||
|
||||
sequenceDecs_decodeSync_safe_amd64_fill_check_overread:
|
||||
CMPQ BX, $0x40
|
||||
JA error_overread
|
||||
|
||||
sequenceDecs_decodeSync_safe_amd64_fill_end:
|
||||
// Update offset
|
||||
MOVQ R9, AX
|
||||
|
@ -2933,7 +3007,7 @@ sequenceDecs_decodeSync_safe_amd64_ml_update_zero:
|
|||
|
||||
sequenceDecs_decodeSync_safe_amd64_fill_2_byte_by_byte:
|
||||
CMPQ SI, $0x00
|
||||
JLE sequenceDecs_decodeSync_safe_amd64_fill_2_end
|
||||
JLE sequenceDecs_decodeSync_safe_amd64_fill_2_check_overread
|
||||
CMPQ BX, $0x07
|
||||
JLE sequenceDecs_decodeSync_safe_amd64_fill_2_end
|
||||
SHLQ $0x08, DX
|
||||
|
@ -2944,6 +3018,10 @@ sequenceDecs_decodeSync_safe_amd64_fill_2_byte_by_byte:
|
|||
ORQ AX, DX
|
||||
JMP sequenceDecs_decodeSync_safe_amd64_fill_2_byte_by_byte
|
||||
|
||||
sequenceDecs_decodeSync_safe_amd64_fill_2_check_overread:
|
||||
CMPQ BX, $0x40
|
||||
JA error_overread
|
||||
|
||||
sequenceDecs_decodeSync_safe_amd64_fill_2_end:
|
||||
// Update literal length
|
||||
MOVQ DI, AX
|
||||
|
@ -3455,6 +3533,11 @@ error_not_enough_literals:
|
|||
MOVQ $0x00000004, ret+24(FP)
|
||||
RET
|
||||
|
||||
// Return with overread error
|
||||
error_overread:
|
||||
MOVQ $0x00000006, ret+24(FP)
|
||||
RET
|
||||
|
||||
// Return with not enough output space error
|
||||
error_not_enough_space:
|
||||
MOVQ ctx+16(FP), AX
|
||||
|
@ -3520,7 +3603,7 @@ sequenceDecs_decodeSync_safe_bmi2_main_loop:
|
|||
|
||||
sequenceDecs_decodeSync_safe_bmi2_fill_byte_by_byte:
|
||||
CMPQ BX, $0x00
|
||||
JLE sequenceDecs_decodeSync_safe_bmi2_fill_end
|
||||
JLE sequenceDecs_decodeSync_safe_bmi2_fill_check_overread
|
||||
CMPQ DX, $0x07
|
||||
JLE sequenceDecs_decodeSync_safe_bmi2_fill_end
|
||||
SHLQ $0x08, AX
|
||||
|
@ -3531,6 +3614,10 @@ sequenceDecs_decodeSync_safe_bmi2_fill_byte_by_byte:
|
|||
ORQ CX, AX
|
||||
JMP sequenceDecs_decodeSync_safe_bmi2_fill_byte_by_byte
|
||||
|
||||
sequenceDecs_decodeSync_safe_bmi2_fill_check_overread:
|
||||
CMPQ DX, $0x40
|
||||
JA error_overread
|
||||
|
||||
sequenceDecs_decodeSync_safe_bmi2_fill_end:
|
||||
// Update offset
|
||||
MOVQ $0x00000808, CX
|
||||
|
@ -3571,7 +3658,7 @@ sequenceDecs_decodeSync_safe_bmi2_fill_end:
|
|||
|
||||
sequenceDecs_decodeSync_safe_bmi2_fill_2_byte_by_byte:
|
||||
CMPQ BX, $0x00
|
||||
JLE sequenceDecs_decodeSync_safe_bmi2_fill_2_end
|
||||
JLE sequenceDecs_decodeSync_safe_bmi2_fill_2_check_overread
|
||||
CMPQ DX, $0x07
|
||||
JLE sequenceDecs_decodeSync_safe_bmi2_fill_2_end
|
||||
SHLQ $0x08, AX
|
||||
|
@ -3582,6 +3669,10 @@ sequenceDecs_decodeSync_safe_bmi2_fill_2_byte_by_byte:
|
|||
ORQ CX, AX
|
||||
JMP sequenceDecs_decodeSync_safe_bmi2_fill_2_byte_by_byte
|
||||
|
||||
sequenceDecs_decodeSync_safe_bmi2_fill_2_check_overread:
|
||||
CMPQ DX, $0x40
|
||||
JA error_overread
|
||||
|
||||
sequenceDecs_decodeSync_safe_bmi2_fill_2_end:
|
||||
// Update literal length
|
||||
MOVQ $0x00000808, CX
|
||||
|
@ -4067,6 +4158,11 @@ error_not_enough_literals:
|
|||
MOVQ $0x00000004, ret+24(FP)
|
||||
RET
|
||||
|
||||
// Return with overread error
|
||||
error_overread:
|
||||
MOVQ $0x00000006, ret+24(FP)
|
||||
RET
|
||||
|
||||
// Return with not enough output space error
|
||||
error_not_enough_space:
|
||||
MOVQ ctx+16(FP), AX
|
||||
|
|
|
@ -128,11 +128,11 @@ func matchLen(a, b []byte) (n int) {
|
|||
}
|
||||
|
||||
func load3232(b []byte, i int32) uint32 {
|
||||
return binary.LittleEndian.Uint32(b[i:])
|
||||
return binary.LittleEndian.Uint32(b[:len(b):len(b)][i:])
|
||||
}
|
||||
|
||||
func load6432(b []byte, i int32) uint64 {
|
||||
return binary.LittleEndian.Uint64(b[i:])
|
||||
return binary.LittleEndian.Uint64(b[:len(b):len(b)][i:])
|
||||
}
|
||||
|
||||
type byter interface {
|
||||
|
|
|
@ -19,6 +19,20 @@ Package home: https://github.com/klauspost/cpuid
|
|||
`go get -u github.com/klauspost/cpuid/v2` using modules.
|
||||
Drop `v2` for others.
|
||||
|
||||
Installing binary:
|
||||
|
||||
`go install github.com/klauspost/cpuid/v2/cmd/cpuid@latest`
|
||||
|
||||
Or download binaries from release page: https://github.com/klauspost/cpuid/releases
|
||||
|
||||
### Homebrew
|
||||
|
||||
For macOS/Linux users, you can install via [brew](https://brew.sh/)
|
||||
|
||||
```sh
|
||||
$ brew install cpuid
|
||||
```
|
||||
|
||||
## example
|
||||
|
||||
```Go
|
||||
|
@ -269,6 +283,7 @@ Exit Code 1
|
|||
| AMD3DNOWEXT | AMD 3DNowExt |
|
||||
| AMXBF16 | Tile computational operations on BFLOAT16 numbers |
|
||||
| AMXINT8 | Tile computational operations on 8-bit integers |
|
||||
| AMXFP16 | Tile computational operations on FP16 numbers |
|
||||
| AMXTILE | Tile architecture |
|
||||
| AVX | AVX functions |
|
||||
| AVX2 | AVX2 functions |
|
||||
|
@ -288,8 +303,12 @@ Exit Code 1
|
|||
| AVX512VNNI | AVX-512 Vector Neural Network Instructions |
|
||||
| AVX512VP2INTERSECT | AVX-512 Intersect for D/Q |
|
||||
| AVX512VPOPCNTDQ | AVX-512 Vector Population Count Doubleword and Quadword |
|
||||
| AVXIFMA | AVX-IFMA instructions |
|
||||
| AVXNECONVERT | AVX-NE-CONVERT instructions |
|
||||
| AVXSLOW | Indicates the CPU performs 2 128 bit operations instead of one |
|
||||
| AVXVNNI | AVX (VEX encoded) VNNI neural network instructions |
|
||||
| AVXVNNIINT8 | AVX-VNNI-INT8 instructions |
|
||||
| BHI_CTRL | Branch History Injection and Intra-mode Branch Target Injection / CVE-2022-0001, CVE-2022-0002 / INTEL-SA-00598 |
|
||||
| BMI1 | Bit Manipulation Instruction Set 1 |
|
||||
| BMI2 | Bit Manipulation Instruction Set 2 |
|
||||
| CETIBT | Intel CET Indirect Branch Tracking |
|
||||
|
@ -298,6 +317,7 @@ Exit Code 1
|
|||
| CLMUL | Carry-less Multiplication |
|
||||
| CLZERO | CLZERO instruction supported |
|
||||
| CMOV | i686 CMOV |
|
||||
| CMPCCXADD | CMPCCXADD instructions |
|
||||
| CMPSB_SCADBS_SHORT | Fast short CMPSB and SCASB |
|
||||
| CMPXCHG8 | CMPXCHG8 instruction |
|
||||
| CPBOOST | Core Performance Boost |
|
||||
|
@ -342,6 +362,7 @@ Exit Code 1
|
|||
| IBS_OPFUSE | AMD: Indicates support for IbsOpFuse |
|
||||
| IBS_PREVENTHOST | Disallowing IBS use by the host supported |
|
||||
| IBS_ZEN4 | Fetch and Op IBS support IBS extensions added with Zen4 |
|
||||
| IDPRED_CTRL | IPRED_DIS |
|
||||
| INT_WBINVD | WBINVD/WBNOINVD are interruptible. |
|
||||
| INVLPGB | NVLPGB and TLBSYNC instruction supported |
|
||||
| LAHF | LAHF/SAHF in long mode |
|
||||
|
@ -359,8 +380,9 @@ Exit Code 1
|
|||
| MOVDIRI | Move Doubleword as Direct Store |
|
||||
| MOVSB_ZL | Fast Zero-Length MOVSB |
|
||||
| MPX | Intel MPX (Memory Protection Extensions) |
|
||||
| MOVU | MOVU SSE instructions are more efficient and should be preferred to SSE MOVL/MOVH. MOVUPS is more efficient than MOVLPS/MOVHPS. MOVUPD is more efficient than MOVLPD/MOVHPD |
|
||||
| MOVU | MOVU SSE instructions are more efficient and should be preferred to SSE MOVL/MOVH. MOVUPS is more efficient than MOVLPS/MOVHPS. MOVUPD is more efficient than MOVLPD/MOVHPD |
|
||||
| MSRIRC | Instruction Retired Counter MSR available |
|
||||
| MSRLIST | Read/Write List of Model Specific Registers |
|
||||
| MSR_PAGEFLUSH | Page Flush MSR available |
|
||||
| NRIPS | Indicates support for NRIP save on VMEXIT |
|
||||
| NX | NX (No-Execute) bit |
|
||||
|
@ -368,11 +390,13 @@ Exit Code 1
|
|||
| PCONFIG | PCONFIG for Intel Multi-Key Total Memory Encryption |
|
||||
| POPCNT | POPCNT instruction |
|
||||
| PPIN | AMD: Protected Processor Inventory Number support. Indicates that Protected Processor Inventory Number (PPIN) capability can be enabled |
|
||||
| PSFD | AMD: Predictive Store Forward Disable |
|
||||
| PREFETCHI | PREFETCHIT0/1 instructions |
|
||||
| PSFD | Predictive Store Forward Disable |
|
||||
| RDPRU | RDPRU instruction supported |
|
||||
| RDRAND | RDRAND instruction is available |
|
||||
| RDSEED | RDSEED instruction is available |
|
||||
| RDTSCP | RDTSCP Instruction |
|
||||
| RRSBA_CTRL | Restricted RSB Alternate |
|
||||
| RTM | Restricted Transactional Memory |
|
||||
| RTM_ALWAYS_ABORT | Indicates that the loaded microcode is forcing RTM abort. |
|
||||
| SERIALIZE | Serialize Instruction Execution |
|
||||
|
@ -425,6 +449,7 @@ Exit Code 1
|
|||
| VTE | AMD Virtual Transparent Encryption supported |
|
||||
| WAITPKG | TPAUSE, UMONITOR, UMWAIT |
|
||||
| WBNOINVD | Write Back and Do Not Invalidate Cache |
|
||||
| WRMSRNS | Non-Serializing Write to Model Specific Register |
|
||||
| X87 | FPU |
|
||||
| XGETBV1 | Supports XGETBV with ECX = 1 |
|
||||
| XOP | Bulldozer XOP functions |
|
||||
|
|
|
@ -73,6 +73,7 @@ const (
|
|||
AMD3DNOW // AMD 3DNOW
|
||||
AMD3DNOWEXT // AMD 3DNowExt
|
||||
AMXBF16 // Tile computational operations on BFLOAT16 numbers
|
||||
AMXFP16 // Tile computational operations on FP16 numbers
|
||||
AMXINT8 // Tile computational operations on 8-bit integers
|
||||
AMXTILE // Tile architecture
|
||||
AVX // AVX functions
|
||||
|
@ -93,8 +94,12 @@ const (
|
|||
AVX512VNNI // AVX-512 Vector Neural Network Instructions
|
||||
AVX512VP2INTERSECT // AVX-512 Intersect for D/Q
|
||||
AVX512VPOPCNTDQ // AVX-512 Vector Population Count Doubleword and Quadword
|
||||
AVXIFMA // AVX-IFMA instructions
|
||||
AVXNECONVERT // AVX-NE-CONVERT instructions
|
||||
AVXSLOW // Indicates the CPU performs 2 128 bit operations instead of one
|
||||
AVXVNNI // AVX (VEX encoded) VNNI neural network instructions
|
||||
AVXVNNIINT8 // AVX-VNNI-INT8 instructions
|
||||
BHI_CTRL // Branch History Injection and Intra-mode Branch Target Injection / CVE-2022-0001, CVE-2022-0002 / INTEL-SA-00598
|
||||
BMI1 // Bit Manipulation Instruction Set 1
|
||||
BMI2 // Bit Manipulation Instruction Set 2
|
||||
CETIBT // Intel CET Indirect Branch Tracking
|
||||
|
@ -103,6 +108,7 @@ const (
|
|||
CLMUL // Carry-less Multiplication
|
||||
CLZERO // CLZERO instruction supported
|
||||
CMOV // i686 CMOV
|
||||
CMPCCXADD // CMPCCXADD instructions
|
||||
CMPSB_SCADBS_SHORT // Fast short CMPSB and SCASB
|
||||
CMPXCHG8 // CMPXCHG8 instruction
|
||||
CPBOOST // Core Performance Boost
|
||||
|
@ -147,6 +153,7 @@ const (
|
|||
IBS_OPFUSE // AMD: Indicates support for IbsOpFuse
|
||||
IBS_PREVENTHOST // Disallowing IBS use by the host supported
|
||||
IBS_ZEN4 // AMD: Fetch and Op IBS support IBS extensions added with Zen4
|
||||
IDPRED_CTRL // IPRED_DIS
|
||||
INT_WBINVD // WBINVD/WBNOINVD are interruptible.
|
||||
INVLPGB // NVLPGB and TLBSYNC instruction supported
|
||||
LAHF // LAHF/SAHF in long mode
|
||||
|
@ -166,6 +173,7 @@ const (
|
|||
MOVU // AMD: MOVU SSE instructions are more efficient and should be preferred to SSE MOVL/MOVH. MOVUPS is more efficient than MOVLPS/MOVHPS. MOVUPD is more efficient than MOVLPD/MOVHPD
|
||||
MPX // Intel MPX (Memory Protection Extensions)
|
||||
MSRIRC // Instruction Retired Counter MSR available
|
||||
MSRLIST // Read/Write List of Model Specific Registers
|
||||
MSR_PAGEFLUSH // Page Flush MSR available
|
||||
NRIPS // Indicates support for NRIP save on VMEXIT
|
||||
NX // NX (No-Execute) bit
|
||||
|
@ -173,11 +181,13 @@ const (
|
|||
PCONFIG // PCONFIG for Intel Multi-Key Total Memory Encryption
|
||||
POPCNT // POPCNT instruction
|
||||
PPIN // AMD: Protected Processor Inventory Number support. Indicates that Protected Processor Inventory Number (PPIN) capability can be enabled
|
||||
PSFD // AMD: Predictive Store Forward Disable
|
||||
PREFETCHI // PREFETCHIT0/1 instructions
|
||||
PSFD // Predictive Store Forward Disable
|
||||
RDPRU // RDPRU instruction supported
|
||||
RDRAND // RDRAND instruction is available
|
||||
RDSEED // RDSEED instruction is available
|
||||
RDTSCP // RDTSCP Instruction
|
||||
RRSBA_CTRL // Restricted RSB Alternate
|
||||
RTM // Restricted Transactional Memory
|
||||
RTM_ALWAYS_ABORT // Indicates that the loaded microcode is forcing RTM abort.
|
||||
SERIALIZE // Serialize Instruction Execution
|
||||
|
@ -230,6 +240,7 @@ const (
|
|||
VTE // AMD Virtual Transparent Encryption supported
|
||||
WAITPKG // TPAUSE, UMONITOR, UMWAIT
|
||||
WBNOINVD // Write Back and Do Not Invalidate Cache
|
||||
WRMSRNS // Non-Serializing Write to Model Specific Register
|
||||
X87 // FPU
|
||||
XGETBV1 // Supports XGETBV with ECX = 1
|
||||
XOP // Bulldozer XOP functions
|
||||
|
@ -1175,13 +1186,20 @@ func support() flagSet {
|
|||
fs.setIf(edx&(1<<30) != 0, IA32_CORE_CAP)
|
||||
fs.setIf(edx&(1<<31) != 0, SPEC_CTRL_SSBD)
|
||||
|
||||
// CPUID.(EAX=7, ECX=1)
|
||||
// CPUID.(EAX=7, ECX=1).EDX
|
||||
fs.setIf(edx&(1<<4) != 0, AVXVNNIINT8)
|
||||
fs.setIf(edx&(1<<5) != 0, AVXNECONVERT)
|
||||
fs.setIf(edx&(1<<14) != 0, PREFETCHI)
|
||||
|
||||
// CPUID.(EAX=7, ECX=1).EAX
|
||||
eax1, _, _, _ := cpuidex(7, 1)
|
||||
fs.setIf(fs.inSet(AVX) && eax1&(1<<4) != 0, AVXVNNI)
|
||||
fs.setIf(eax1&(1<<7) != 0, CMPCCXADD)
|
||||
fs.setIf(eax1&(1<<10) != 0, MOVSB_ZL)
|
||||
fs.setIf(eax1&(1<<11) != 0, STOSB_SHORT)
|
||||
fs.setIf(eax1&(1<<12) != 0, CMPSB_SCADBS_SHORT)
|
||||
fs.setIf(eax1&(1<<22) != 0, HRESET)
|
||||
fs.setIf(eax1&(1<<23) != 0, AVXIFMA)
|
||||
fs.setIf(eax1&(1<<26) != 0, LAM)
|
||||
|
||||
// Only detect AVX-512 features if XGETBV is supported
|
||||
|
@ -1219,12 +1237,20 @@ func support() flagSet {
|
|||
fs.setIf(edx&(1<<25) != 0, AMXINT8)
|
||||
// eax1 = CPUID.(EAX=7, ECX=1).EAX
|
||||
fs.setIf(eax1&(1<<5) != 0, AVX512BF16)
|
||||
fs.setIf(eax1&(1<<19) != 0, WRMSRNS)
|
||||
fs.setIf(eax1&(1<<21) != 0, AMXFP16)
|
||||
fs.setIf(eax1&(1<<27) != 0, MSRLIST)
|
||||
}
|
||||
}
|
||||
|
||||
// CPUID.(EAX=7, ECX=2)
|
||||
_, _, _, edx = cpuidex(7, 2)
|
||||
fs.setIf(edx&(1<<0) != 0, PSFD)
|
||||
fs.setIf(edx&(1<<1) != 0, IDPRED_CTRL)
|
||||
fs.setIf(edx&(1<<2) != 0, RRSBA_CTRL)
|
||||
fs.setIf(edx&(1<<4) != 0, BHI_CTRL)
|
||||
fs.setIf(edx&(1<<5) != 0, MCDT_NO)
|
||||
|
||||
}
|
||||
|
||||
// Processor Extended State Enumeration Sub-leaf (EAX = 0DH, ECX = 1)
|
||||
|
|
|
@ -13,201 +13,212 @@ func _() {
|
|||
_ = x[AMD3DNOW-3]
|
||||
_ = x[AMD3DNOWEXT-4]
|
||||
_ = x[AMXBF16-5]
|
||||
_ = x[AMXINT8-6]
|
||||
_ = x[AMXTILE-7]
|
||||
_ = x[AVX-8]
|
||||
_ = x[AVX2-9]
|
||||
_ = x[AVX512BF16-10]
|
||||
_ = x[AVX512BITALG-11]
|
||||
_ = x[AVX512BW-12]
|
||||
_ = x[AVX512CD-13]
|
||||
_ = x[AVX512DQ-14]
|
||||
_ = x[AVX512ER-15]
|
||||
_ = x[AVX512F-16]
|
||||
_ = x[AVX512FP16-17]
|
||||
_ = x[AVX512IFMA-18]
|
||||
_ = x[AVX512PF-19]
|
||||
_ = x[AVX512VBMI-20]
|
||||
_ = x[AVX512VBMI2-21]
|
||||
_ = x[AVX512VL-22]
|
||||
_ = x[AVX512VNNI-23]
|
||||
_ = x[AVX512VP2INTERSECT-24]
|
||||
_ = x[AVX512VPOPCNTDQ-25]
|
||||
_ = x[AVXSLOW-26]
|
||||
_ = x[AVXVNNI-27]
|
||||
_ = x[BMI1-28]
|
||||
_ = x[BMI2-29]
|
||||
_ = x[CETIBT-30]
|
||||
_ = x[CETSS-31]
|
||||
_ = x[CLDEMOTE-32]
|
||||
_ = x[CLMUL-33]
|
||||
_ = x[CLZERO-34]
|
||||
_ = x[CMOV-35]
|
||||
_ = x[CMPSB_SCADBS_SHORT-36]
|
||||
_ = x[CMPXCHG8-37]
|
||||
_ = x[CPBOOST-38]
|
||||
_ = x[CPPC-39]
|
||||
_ = x[CX16-40]
|
||||
_ = x[EFER_LMSLE_UNS-41]
|
||||
_ = x[ENQCMD-42]
|
||||
_ = x[ERMS-43]
|
||||
_ = x[F16C-44]
|
||||
_ = x[FLUSH_L1D-45]
|
||||
_ = x[FMA3-46]
|
||||
_ = x[FMA4-47]
|
||||
_ = x[FP128-48]
|
||||
_ = x[FP256-49]
|
||||
_ = x[FSRM-50]
|
||||
_ = x[FXSR-51]
|
||||
_ = x[FXSROPT-52]
|
||||
_ = x[GFNI-53]
|
||||
_ = x[HLE-54]
|
||||
_ = x[HRESET-55]
|
||||
_ = x[HTT-56]
|
||||
_ = x[HWA-57]
|
||||
_ = x[HYBRID_CPU-58]
|
||||
_ = x[HYPERVISOR-59]
|
||||
_ = x[IA32_ARCH_CAP-60]
|
||||
_ = x[IA32_CORE_CAP-61]
|
||||
_ = x[IBPB-62]
|
||||
_ = x[IBRS-63]
|
||||
_ = x[IBRS_PREFERRED-64]
|
||||
_ = x[IBRS_PROVIDES_SMP-65]
|
||||
_ = x[IBS-66]
|
||||
_ = x[IBSBRNTRGT-67]
|
||||
_ = x[IBSFETCHSAM-68]
|
||||
_ = x[IBSFFV-69]
|
||||
_ = x[IBSOPCNT-70]
|
||||
_ = x[IBSOPCNTEXT-71]
|
||||
_ = x[IBSOPSAM-72]
|
||||
_ = x[IBSRDWROPCNT-73]
|
||||
_ = x[IBSRIPINVALIDCHK-74]
|
||||
_ = x[IBS_FETCH_CTLX-75]
|
||||
_ = x[IBS_OPDATA4-76]
|
||||
_ = x[IBS_OPFUSE-77]
|
||||
_ = x[IBS_PREVENTHOST-78]
|
||||
_ = x[IBS_ZEN4-79]
|
||||
_ = x[INT_WBINVD-80]
|
||||
_ = x[INVLPGB-81]
|
||||
_ = x[LAHF-82]
|
||||
_ = x[LAM-83]
|
||||
_ = x[LBRVIRT-84]
|
||||
_ = x[LZCNT-85]
|
||||
_ = x[MCAOVERFLOW-86]
|
||||
_ = x[MCDT_NO-87]
|
||||
_ = x[MCOMMIT-88]
|
||||
_ = x[MD_CLEAR-89]
|
||||
_ = x[MMX-90]
|
||||
_ = x[MMXEXT-91]
|
||||
_ = x[MOVBE-92]
|
||||
_ = x[MOVDIR64B-93]
|
||||
_ = x[MOVDIRI-94]
|
||||
_ = x[MOVSB_ZL-95]
|
||||
_ = x[MOVU-96]
|
||||
_ = x[MPX-97]
|
||||
_ = x[MSRIRC-98]
|
||||
_ = x[MSR_PAGEFLUSH-99]
|
||||
_ = x[NRIPS-100]
|
||||
_ = x[NX-101]
|
||||
_ = x[OSXSAVE-102]
|
||||
_ = x[PCONFIG-103]
|
||||
_ = x[POPCNT-104]
|
||||
_ = x[PPIN-105]
|
||||
_ = x[PSFD-106]
|
||||
_ = x[RDPRU-107]
|
||||
_ = x[RDRAND-108]
|
||||
_ = x[RDSEED-109]
|
||||
_ = x[RDTSCP-110]
|
||||
_ = x[RTM-111]
|
||||
_ = x[RTM_ALWAYS_ABORT-112]
|
||||
_ = x[SERIALIZE-113]
|
||||
_ = x[SEV-114]
|
||||
_ = x[SEV_64BIT-115]
|
||||
_ = x[SEV_ALTERNATIVE-116]
|
||||
_ = x[SEV_DEBUGSWAP-117]
|
||||
_ = x[SEV_ES-118]
|
||||
_ = x[SEV_RESTRICTED-119]
|
||||
_ = x[SEV_SNP-120]
|
||||
_ = x[SGX-121]
|
||||
_ = x[SGXLC-122]
|
||||
_ = x[SHA-123]
|
||||
_ = x[SME-124]
|
||||
_ = x[SME_COHERENT-125]
|
||||
_ = x[SPEC_CTRL_SSBD-126]
|
||||
_ = x[SRBDS_CTRL-127]
|
||||
_ = x[SSE-128]
|
||||
_ = x[SSE2-129]
|
||||
_ = x[SSE3-130]
|
||||
_ = x[SSE4-131]
|
||||
_ = x[SSE42-132]
|
||||
_ = x[SSE4A-133]
|
||||
_ = x[SSSE3-134]
|
||||
_ = x[STIBP-135]
|
||||
_ = x[STIBP_ALWAYSON-136]
|
||||
_ = x[STOSB_SHORT-137]
|
||||
_ = x[SUCCOR-138]
|
||||
_ = x[SVM-139]
|
||||
_ = x[SVMDA-140]
|
||||
_ = x[SVMFBASID-141]
|
||||
_ = x[SVML-142]
|
||||
_ = x[SVMNP-143]
|
||||
_ = x[SVMPF-144]
|
||||
_ = x[SVMPFT-145]
|
||||
_ = x[SYSCALL-146]
|
||||
_ = x[SYSEE-147]
|
||||
_ = x[TBM-148]
|
||||
_ = x[TLB_FLUSH_NESTED-149]
|
||||
_ = x[TME-150]
|
||||
_ = x[TOPEXT-151]
|
||||
_ = x[TSCRATEMSR-152]
|
||||
_ = x[TSXLDTRK-153]
|
||||
_ = x[VAES-154]
|
||||
_ = x[VMCBCLEAN-155]
|
||||
_ = x[VMPL-156]
|
||||
_ = x[VMSA_REGPROT-157]
|
||||
_ = x[VMX-158]
|
||||
_ = x[VPCLMULQDQ-159]
|
||||
_ = x[VTE-160]
|
||||
_ = x[WAITPKG-161]
|
||||
_ = x[WBNOINVD-162]
|
||||
_ = x[X87-163]
|
||||
_ = x[XGETBV1-164]
|
||||
_ = x[XOP-165]
|
||||
_ = x[XSAVE-166]
|
||||
_ = x[XSAVEC-167]
|
||||
_ = x[XSAVEOPT-168]
|
||||
_ = x[XSAVES-169]
|
||||
_ = x[AESARM-170]
|
||||
_ = x[ARMCPUID-171]
|
||||
_ = x[ASIMD-172]
|
||||
_ = x[ASIMDDP-173]
|
||||
_ = x[ASIMDHP-174]
|
||||
_ = x[ASIMDRDM-175]
|
||||
_ = x[ATOMICS-176]
|
||||
_ = x[CRC32-177]
|
||||
_ = x[DCPOP-178]
|
||||
_ = x[EVTSTRM-179]
|
||||
_ = x[FCMA-180]
|
||||
_ = x[FP-181]
|
||||
_ = x[FPHP-182]
|
||||
_ = x[GPA-183]
|
||||
_ = x[JSCVT-184]
|
||||
_ = x[LRCPC-185]
|
||||
_ = x[PMULL-186]
|
||||
_ = x[SHA1-187]
|
||||
_ = x[SHA2-188]
|
||||
_ = x[SHA3-189]
|
||||
_ = x[SHA512-190]
|
||||
_ = x[SM3-191]
|
||||
_ = x[SM4-192]
|
||||
_ = x[SVE-193]
|
||||
_ = x[lastID-194]
|
||||
_ = x[AMXFP16-6]
|
||||
_ = x[AMXINT8-7]
|
||||
_ = x[AMXTILE-8]
|
||||
_ = x[AVX-9]
|
||||
_ = x[AVX2-10]
|
||||
_ = x[AVX512BF16-11]
|
||||
_ = x[AVX512BITALG-12]
|
||||
_ = x[AVX512BW-13]
|
||||
_ = x[AVX512CD-14]
|
||||
_ = x[AVX512DQ-15]
|
||||
_ = x[AVX512ER-16]
|
||||
_ = x[AVX512F-17]
|
||||
_ = x[AVX512FP16-18]
|
||||
_ = x[AVX512IFMA-19]
|
||||
_ = x[AVX512PF-20]
|
||||
_ = x[AVX512VBMI-21]
|
||||
_ = x[AVX512VBMI2-22]
|
||||
_ = x[AVX512VL-23]
|
||||
_ = x[AVX512VNNI-24]
|
||||
_ = x[AVX512VP2INTERSECT-25]
|
||||
_ = x[AVX512VPOPCNTDQ-26]
|
||||
_ = x[AVXIFMA-27]
|
||||
_ = x[AVXNECONVERT-28]
|
||||
_ = x[AVXSLOW-29]
|
||||
_ = x[AVXVNNI-30]
|
||||
_ = x[AVXVNNIINT8-31]
|
||||
_ = x[BHI_CTRL-32]
|
||||
_ = x[BMI1-33]
|
||||
_ = x[BMI2-34]
|
||||
_ = x[CETIBT-35]
|
||||
_ = x[CETSS-36]
|
||||
_ = x[CLDEMOTE-37]
|
||||
_ = x[CLMUL-38]
|
||||
_ = x[CLZERO-39]
|
||||
_ = x[CMOV-40]
|
||||
_ = x[CMPCCXADD-41]
|
||||
_ = x[CMPSB_SCADBS_SHORT-42]
|
||||
_ = x[CMPXCHG8-43]
|
||||
_ = x[CPBOOST-44]
|
||||
_ = x[CPPC-45]
|
||||
_ = x[CX16-46]
|
||||
_ = x[EFER_LMSLE_UNS-47]
|
||||
_ = x[ENQCMD-48]
|
||||
_ = x[ERMS-49]
|
||||
_ = x[F16C-50]
|
||||
_ = x[FLUSH_L1D-51]
|
||||
_ = x[FMA3-52]
|
||||
_ = x[FMA4-53]
|
||||
_ = x[FP128-54]
|
||||
_ = x[FP256-55]
|
||||
_ = x[FSRM-56]
|
||||
_ = x[FXSR-57]
|
||||
_ = x[FXSROPT-58]
|
||||
_ = x[GFNI-59]
|
||||
_ = x[HLE-60]
|
||||
_ = x[HRESET-61]
|
||||
_ = x[HTT-62]
|
||||
_ = x[HWA-63]
|
||||
_ = x[HYBRID_CPU-64]
|
||||
_ = x[HYPERVISOR-65]
|
||||
_ = x[IA32_ARCH_CAP-66]
|
||||
_ = x[IA32_CORE_CAP-67]
|
||||
_ = x[IBPB-68]
|
||||
_ = x[IBRS-69]
|
||||
_ = x[IBRS_PREFERRED-70]
|
||||
_ = x[IBRS_PROVIDES_SMP-71]
|
||||
_ = x[IBS-72]
|
||||
_ = x[IBSBRNTRGT-73]
|
||||
_ = x[IBSFETCHSAM-74]
|
||||
_ = x[IBSFFV-75]
|
||||
_ = x[IBSOPCNT-76]
|
||||
_ = x[IBSOPCNTEXT-77]
|
||||
_ = x[IBSOPSAM-78]
|
||||
_ = x[IBSRDWROPCNT-79]
|
||||
_ = x[IBSRIPINVALIDCHK-80]
|
||||
_ = x[IBS_FETCH_CTLX-81]
|
||||
_ = x[IBS_OPDATA4-82]
|
||||
_ = x[IBS_OPFUSE-83]
|
||||
_ = x[IBS_PREVENTHOST-84]
|
||||
_ = x[IBS_ZEN4-85]
|
||||
_ = x[IDPRED_CTRL-86]
|
||||
_ = x[INT_WBINVD-87]
|
||||
_ = x[INVLPGB-88]
|
||||
_ = x[LAHF-89]
|
||||
_ = x[LAM-90]
|
||||
_ = x[LBRVIRT-91]
|
||||
_ = x[LZCNT-92]
|
||||
_ = x[MCAOVERFLOW-93]
|
||||
_ = x[MCDT_NO-94]
|
||||
_ = x[MCOMMIT-95]
|
||||
_ = x[MD_CLEAR-96]
|
||||
_ = x[MMX-97]
|
||||
_ = x[MMXEXT-98]
|
||||
_ = x[MOVBE-99]
|
||||
_ = x[MOVDIR64B-100]
|
||||
_ = x[MOVDIRI-101]
|
||||
_ = x[MOVSB_ZL-102]
|
||||
_ = x[MOVU-103]
|
||||
_ = x[MPX-104]
|
||||
_ = x[MSRIRC-105]
|
||||
_ = x[MSRLIST-106]
|
||||
_ = x[MSR_PAGEFLUSH-107]
|
||||
_ = x[NRIPS-108]
|
||||
_ = x[NX-109]
|
||||
_ = x[OSXSAVE-110]
|
||||
_ = x[PCONFIG-111]
|
||||
_ = x[POPCNT-112]
|
||||
_ = x[PPIN-113]
|
||||
_ = x[PREFETCHI-114]
|
||||
_ = x[PSFD-115]
|
||||
_ = x[RDPRU-116]
|
||||
_ = x[RDRAND-117]
|
||||
_ = x[RDSEED-118]
|
||||
_ = x[RDTSCP-119]
|
||||
_ = x[RRSBA_CTRL-120]
|
||||
_ = x[RTM-121]
|
||||
_ = x[RTM_ALWAYS_ABORT-122]
|
||||
_ = x[SERIALIZE-123]
|
||||
_ = x[SEV-124]
|
||||
_ = x[SEV_64BIT-125]
|
||||
_ = x[SEV_ALTERNATIVE-126]
|
||||
_ = x[SEV_DEBUGSWAP-127]
|
||||
_ = x[SEV_ES-128]
|
||||
_ = x[SEV_RESTRICTED-129]
|
||||
_ = x[SEV_SNP-130]
|
||||
_ = x[SGX-131]
|
||||
_ = x[SGXLC-132]
|
||||
_ = x[SHA-133]
|
||||
_ = x[SME-134]
|
||||
_ = x[SME_COHERENT-135]
|
||||
_ = x[SPEC_CTRL_SSBD-136]
|
||||
_ = x[SRBDS_CTRL-137]
|
||||
_ = x[SSE-138]
|
||||
_ = x[SSE2-139]
|
||||
_ = x[SSE3-140]
|
||||
_ = x[SSE4-141]
|
||||
_ = x[SSE42-142]
|
||||
_ = x[SSE4A-143]
|
||||
_ = x[SSSE3-144]
|
||||
_ = x[STIBP-145]
|
||||
_ = x[STIBP_ALWAYSON-146]
|
||||
_ = x[STOSB_SHORT-147]
|
||||
_ = x[SUCCOR-148]
|
||||
_ = x[SVM-149]
|
||||
_ = x[SVMDA-150]
|
||||
_ = x[SVMFBASID-151]
|
||||
_ = x[SVML-152]
|
||||
_ = x[SVMNP-153]
|
||||
_ = x[SVMPF-154]
|
||||
_ = x[SVMPFT-155]
|
||||
_ = x[SYSCALL-156]
|
||||
_ = x[SYSEE-157]
|
||||
_ = x[TBM-158]
|
||||
_ = x[TLB_FLUSH_NESTED-159]
|
||||
_ = x[TME-160]
|
||||
_ = x[TOPEXT-161]
|
||||
_ = x[TSCRATEMSR-162]
|
||||
_ = x[TSXLDTRK-163]
|
||||
_ = x[VAES-164]
|
||||
_ = x[VMCBCLEAN-165]
|
||||
_ = x[VMPL-166]
|
||||
_ = x[VMSA_REGPROT-167]
|
||||
_ = x[VMX-168]
|
||||
_ = x[VPCLMULQDQ-169]
|
||||
_ = x[VTE-170]
|
||||
_ = x[WAITPKG-171]
|
||||
_ = x[WBNOINVD-172]
|
||||
_ = x[WRMSRNS-173]
|
||||
_ = x[X87-174]
|
||||
_ = x[XGETBV1-175]
|
||||
_ = x[XOP-176]
|
||||
_ = x[XSAVE-177]
|
||||
_ = x[XSAVEC-178]
|
||||
_ = x[XSAVEOPT-179]
|
||||
_ = x[XSAVES-180]
|
||||
_ = x[AESARM-181]
|
||||
_ = x[ARMCPUID-182]
|
||||
_ = x[ASIMD-183]
|
||||
_ = x[ASIMDDP-184]
|
||||
_ = x[ASIMDHP-185]
|
||||
_ = x[ASIMDRDM-186]
|
||||
_ = x[ATOMICS-187]
|
||||
_ = x[CRC32-188]
|
||||
_ = x[DCPOP-189]
|
||||
_ = x[EVTSTRM-190]
|
||||
_ = x[FCMA-191]
|
||||
_ = x[FP-192]
|
||||
_ = x[FPHP-193]
|
||||
_ = x[GPA-194]
|
||||
_ = x[JSCVT-195]
|
||||
_ = x[LRCPC-196]
|
||||
_ = x[PMULL-197]
|
||||
_ = x[SHA1-198]
|
||||
_ = x[SHA2-199]
|
||||
_ = x[SHA3-200]
|
||||
_ = x[SHA512-201]
|
||||
_ = x[SM3-202]
|
||||
_ = x[SM4-203]
|
||||
_ = x[SVE-204]
|
||||
_ = x[lastID-205]
|
||||
_ = x[firstID-0]
|
||||
}
|
||||
|
||||
const _FeatureID_name = "firstIDADXAESNIAMD3DNOWAMD3DNOWEXTAMXBF16AMXINT8AMXTILEAVXAVX2AVX512BF16AVX512BITALGAVX512BWAVX512CDAVX512DQAVX512ERAVX512FAVX512FP16AVX512IFMAAVX512PFAVX512VBMIAVX512VBMI2AVX512VLAVX512VNNIAVX512VP2INTERSECTAVX512VPOPCNTDQAVXSLOWAVXVNNIBMI1BMI2CETIBTCETSSCLDEMOTECLMULCLZEROCMOVCMPSB_SCADBS_SHORTCMPXCHG8CPBOOSTCPPCCX16EFER_LMSLE_UNSENQCMDERMSF16CFLUSH_L1DFMA3FMA4FP128FP256FSRMFXSRFXSROPTGFNIHLEHRESETHTTHWAHYBRID_CPUHYPERVISORIA32_ARCH_CAPIA32_CORE_CAPIBPBIBRSIBRS_PREFERREDIBRS_PROVIDES_SMPIBSIBSBRNTRGTIBSFETCHSAMIBSFFVIBSOPCNTIBSOPCNTEXTIBSOPSAMIBSRDWROPCNTIBSRIPINVALIDCHKIBS_FETCH_CTLXIBS_OPDATA4IBS_OPFUSEIBS_PREVENTHOSTIBS_ZEN4INT_WBINVDINVLPGBLAHFLAMLBRVIRTLZCNTMCAOVERFLOWMCDT_NOMCOMMITMD_CLEARMMXMMXEXTMOVBEMOVDIR64BMOVDIRIMOVSB_ZLMOVUMPXMSRIRCMSR_PAGEFLUSHNRIPSNXOSXSAVEPCONFIGPOPCNTPPINPSFDRDPRURDRANDRDSEEDRDTSCPRTMRTM_ALWAYS_ABORTSERIALIZESEVSEV_64BITSEV_ALTERNATIVESEV_DEBUGSWAPSEV_ESSEV_RESTRICTEDSEV_SNPSGXSGXLCSHASMESME_COHERENTSPEC_CTRL_SSBDSRBDS_CTRLSSESSE2SSE3SSE4SSE42SSE4ASSSE3STIBPSTIBP_ALWAYSONSTOSB_SHORTSUCCORSVMSVMDASVMFBASIDSVMLSVMNPSVMPFSVMPFTSYSCALLSYSEETBMTLB_FLUSH_NESTEDTMETOPEXTTSCRATEMSRTSXLDTRKVAESVMCBCLEANVMPLVMSA_REGPROTVMXVPCLMULQDQVTEWAITPKGWBNOINVDX87XGETBV1XOPXSAVEXSAVECXSAVEOPTXSAVESAESARMARMCPUIDASIMDASIMDDPASIMDHPASIMDRDMATOMICSCRC32DCPOPEVTSTRMFCMAFPFPHPGPAJSCVTLRCPCPMULLSHA1SHA2SHA3SHA512SM3SM4SVElastID"
|
||||
const _FeatureID_name = "firstIDADXAESNIAMD3DNOWAMD3DNOWEXTAMXBF16AMXFP16AMXINT8AMXTILEAVXAVX2AVX512BF16AVX512BITALGAVX512BWAVX512CDAVX512DQAVX512ERAVX512FAVX512FP16AVX512IFMAAVX512PFAVX512VBMIAVX512VBMI2AVX512VLAVX512VNNIAVX512VP2INTERSECTAVX512VPOPCNTDQAVXIFMAAVXNECONVERTAVXSLOWAVXVNNIAVXVNNIINT8BHI_CTRLBMI1BMI2CETIBTCETSSCLDEMOTECLMULCLZEROCMOVCMPCCXADDCMPSB_SCADBS_SHORTCMPXCHG8CPBOOSTCPPCCX16EFER_LMSLE_UNSENQCMDERMSF16CFLUSH_L1DFMA3FMA4FP128FP256FSRMFXSRFXSROPTGFNIHLEHRESETHTTHWAHYBRID_CPUHYPERVISORIA32_ARCH_CAPIA32_CORE_CAPIBPBIBRSIBRS_PREFERREDIBRS_PROVIDES_SMPIBSIBSBRNTRGTIBSFETCHSAMIBSFFVIBSOPCNTIBSOPCNTEXTIBSOPSAMIBSRDWROPCNTIBSRIPINVALIDCHKIBS_FETCH_CTLXIBS_OPDATA4IBS_OPFUSEIBS_PREVENTHOSTIBS_ZEN4IDPRED_CTRLINT_WBINVDINVLPGBLAHFLAMLBRVIRTLZCNTMCAOVERFLOWMCDT_NOMCOMMITMD_CLEARMMXMMXEXTMOVBEMOVDIR64BMOVDIRIMOVSB_ZLMOVUMPXMSRIRCMSRLISTMSR_PAGEFLUSHNRIPSNXOSXSAVEPCONFIGPOPCNTPPINPREFETCHIPSFDRDPRURDRANDRDSEEDRDTSCPRRSBA_CTRLRTMRTM_ALWAYS_ABORTSERIALIZESEVSEV_64BITSEV_ALTERNATIVESEV_DEBUGSWAPSEV_ESSEV_RESTRICTEDSEV_SNPSGXSGXLCSHASMESME_COHERENTSPEC_CTRL_SSBDSRBDS_CTRLSSESSE2SSE3SSE4SSE42SSE4ASSSE3STIBPSTIBP_ALWAYSONSTOSB_SHORTSUCCORSVMSVMDASVMFBASIDSVMLSVMNPSVMPFSVMPFTSYSCALLSYSEETBMTLB_FLUSH_NESTEDTMETOPEXTTSCRATEMSRTSXLDTRKVAESVMCBCLEANVMPLVMSA_REGPROTVMXVPCLMULQDQVTEWAITPKGWBNOINVDWRMSRNSX87XGETBV1XOPXSAVEXSAVECXSAVEOPTXSAVESAESARMARMCPUIDASIMDASIMDDPASIMDHPASIMDRDMATOMICSCRC32DCPOPEVTSTRMFCMAFPFPHPGPAJSCVTLRCPCPMULLSHA1SHA2SHA3SHA512SM3SM4SVElastID"
|
||||
|
||||
var _FeatureID_index = [...]uint16{0, 7, 10, 15, 23, 34, 41, 48, 55, 58, 62, 72, 84, 92, 100, 108, 116, 123, 133, 143, 151, 161, 172, 180, 190, 208, 223, 230, 237, 241, 245, 251, 256, 264, 269, 275, 279, 297, 305, 312, 316, 320, 334, 340, 344, 348, 357, 361, 365, 370, 375, 379, 383, 390, 394, 397, 403, 406, 409, 419, 429, 442, 455, 459, 463, 477, 494, 497, 507, 518, 524, 532, 543, 551, 563, 579, 593, 604, 614, 629, 637, 647, 654, 658, 661, 668, 673, 684, 691, 698, 706, 709, 715, 720, 729, 736, 744, 748, 751, 757, 770, 775, 777, 784, 791, 797, 801, 805, 810, 816, 822, 828, 831, 847, 856, 859, 868, 883, 896, 902, 916, 923, 926, 931, 934, 937, 949, 963, 973, 976, 980, 984, 988, 993, 998, 1003, 1008, 1022, 1033, 1039, 1042, 1047, 1056, 1060, 1065, 1070, 1076, 1083, 1088, 1091, 1107, 1110, 1116, 1126, 1134, 1138, 1147, 1151, 1163, 1166, 1176, 1179, 1186, 1194, 1197, 1204, 1207, 1212, 1218, 1226, 1232, 1238, 1246, 1251, 1258, 1265, 1273, 1280, 1285, 1290, 1297, 1301, 1303, 1307, 1310, 1315, 1320, 1325, 1329, 1333, 1337, 1343, 1346, 1349, 1352, 1358}
|
||||
var _FeatureID_index = [...]uint16{0, 7, 10, 15, 23, 34, 41, 48, 55, 62, 65, 69, 79, 91, 99, 107, 115, 123, 130, 140, 150, 158, 168, 179, 187, 197, 215, 230, 237, 249, 256, 263, 274, 282, 286, 290, 296, 301, 309, 314, 320, 324, 333, 351, 359, 366, 370, 374, 388, 394, 398, 402, 411, 415, 419, 424, 429, 433, 437, 444, 448, 451, 457, 460, 463, 473, 483, 496, 509, 513, 517, 531, 548, 551, 561, 572, 578, 586, 597, 605, 617, 633, 647, 658, 668, 683, 691, 702, 712, 719, 723, 726, 733, 738, 749, 756, 763, 771, 774, 780, 785, 794, 801, 809, 813, 816, 822, 829, 842, 847, 849, 856, 863, 869, 873, 882, 886, 891, 897, 903, 909, 919, 922, 938, 947, 950, 959, 974, 987, 993, 1007, 1014, 1017, 1022, 1025, 1028, 1040, 1054, 1064, 1067, 1071, 1075, 1079, 1084, 1089, 1094, 1099, 1113, 1124, 1130, 1133, 1138, 1147, 1151, 1156, 1161, 1167, 1174, 1179, 1182, 1198, 1201, 1207, 1217, 1225, 1229, 1238, 1242, 1254, 1257, 1267, 1270, 1277, 1285, 1292, 1295, 1302, 1305, 1310, 1316, 1324, 1330, 1336, 1344, 1349, 1356, 1363, 1371, 1378, 1383, 1388, 1395, 1399, 1401, 1405, 1408, 1413, 1418, 1423, 1427, 1431, 1435, 1441, 1444, 1447, 1450, 1456}
|
||||
|
||||
func (i FeatureID) String() string {
|
||||
if i < 0 || i >= FeatureID(len(_FeatureID_index)-1) {
|
||||
|
|
|
@ -6,11 +6,11 @@ build:
|
|||
|
||||
.PHONY: test
|
||||
test:
|
||||
go test ./...
|
||||
go test -gcflags '-e' ./...
|
||||
|
||||
.PHONY: test-race
|
||||
test-race:
|
||||
go test -race .
|
||||
.PHONY: bench
|
||||
bench:
|
||||
go test -bench ./...
|
||||
|
||||
.PHONY: tags
|
||||
tags:
|
||||
|
@ -19,20 +19,16 @@ tags:
|
|||
.PHONY: cover
|
||||
cover:
|
||||
mkdir -p tmp
|
||||
go test -coverprofile tmp/_cover.out .
|
||||
go test -coverprofile tmp/_cover.out . ./internal/...
|
||||
go tool cover -html tmp/_cover.out -o tmp/cover.html
|
||||
|
||||
.PHONY: checkall
|
||||
checkall: vet lint staticcheck
|
||||
checkall: vet staticcheck
|
||||
|
||||
.PHONY: vet
|
||||
vet:
|
||||
go vet ./...
|
||||
|
||||
.PHONY: lint
|
||||
lint:
|
||||
golint ./...
|
||||
|
||||
.PHONY: staticcheck
|
||||
staticcheck:
|
||||
staticcheck ./...
|
||||
|
@ -45,6 +41,10 @@ clean: examples-clean
|
|||
|
||||
# based on: github.com/koron-go/_skeleton/Makefile
|
||||
|
||||
.PHONY: test-race
|
||||
test-race:
|
||||
go test -race .
|
||||
|
||||
.PHONY: examples
|
||||
examples: examples-build
|
||||
|
||||
|
|
|
@ -8,42 +8,50 @@ import (
|
|||
"net"
|
||||
"net/http"
|
||||
"sync"
|
||||
|
||||
"github.com/koron/go-ssdp/internal/multicast"
|
||||
"github.com/koron/go-ssdp/internal/ssdplog"
|
||||
)
|
||||
|
||||
type message struct {
|
||||
to net.Addr
|
||||
data []byte
|
||||
data multicast.DataProvider
|
||||
}
|
||||
|
||||
// Advertiser is a server to advertise a service.
|
||||
type Advertiser struct {
|
||||
st string
|
||||
usn string
|
||||
location string
|
||||
server string
|
||||
maxAge int
|
||||
st string
|
||||
usn string
|
||||
locProv LocationProvider
|
||||
server string
|
||||
maxAge int
|
||||
|
||||
conn *multicastConn
|
||||
conn *multicast.Conn
|
||||
ch chan *message
|
||||
wg sync.WaitGroup
|
||||
wgS sync.WaitGroup
|
||||
}
|
||||
|
||||
// Advertise starts advertisement of service.
|
||||
func Advertise(st, usn, location, server string, maxAge int) (*Advertiser, error) {
|
||||
conn, err := multicastListen(recvAddrResolver)
|
||||
// location should be a string or a ssdp.LocationProvider.
|
||||
func Advertise(st, usn string, location interface{}, server string, maxAge int) (*Advertiser, error) {
|
||||
locProv, err := toLocationProvider(location)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
logf("SSDP advertise on: %s", conn.LocalAddr().String())
|
||||
conn, err := multicast.Listen(multicast.RecvAddrResolver)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ssdplog.Printf("SSDP advertise on: %s", conn.LocalAddr().String())
|
||||
a := &Advertiser{
|
||||
st: st,
|
||||
usn: usn,
|
||||
location: location,
|
||||
server: server,
|
||||
maxAge: maxAge,
|
||||
conn: conn,
|
||||
ch: make(chan *message),
|
||||
st: st,
|
||||
usn: usn,
|
||||
locProv: locProv,
|
||||
server: server,
|
||||
maxAge: maxAge,
|
||||
conn: conn,
|
||||
ch: make(chan *message),
|
||||
}
|
||||
a.wg.Add(2)
|
||||
a.wgS.Add(1)
|
||||
|
@ -60,9 +68,10 @@ func Advertise(st, usn, location, server string, maxAge int) (*Advertiser, error
|
|||
}
|
||||
|
||||
func (a *Advertiser) recvMain() error {
|
||||
err := a.conn.readPackets(0, func(addr net.Addr, data []byte) error {
|
||||
// TODO: update listening interfaces of a.conn
|
||||
err := a.conn.ReadPackets(0, func(addr net.Addr, data []byte) error {
|
||||
if err := a.handleRaw(addr, data); err != nil {
|
||||
logf("failed to handle message: %s", err)
|
||||
ssdplog.Printf("failed to handle message: %s", err)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
@ -72,16 +81,13 @@ func (a *Advertiser) recvMain() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (a *Advertiser) sendMain() error {
|
||||
func (a *Advertiser) sendMain() {
|
||||
for msg := range a.ch {
|
||||
_, err := a.conn.WriteTo(msg.data, msg.to)
|
||||
if err != nil {
|
||||
if nerr, ok := err.(net.Error); !ok || !nerr.Temporary() {
|
||||
logf("failed to send: %s", err)
|
||||
}
|
||||
ssdplog.Printf("failed to send: %s", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *Advertiser) handleRaw(from net.Addr, raw []byte) error {
|
||||
|
@ -104,19 +110,16 @@ func (a *Advertiser) handleRaw(from net.Addr, raw []byte) error {
|
|||
// skip when ST is not matched/expected.
|
||||
return nil
|
||||
}
|
||||
logf("received M-SEARCH MAN=%s ST=%s from %s", man, st, from.String())
|
||||
ssdplog.Printf("received M-SEARCH MAN=%s ST=%s from %s", man, st, from.String())
|
||||
// build and send a response.
|
||||
msg, err := buildOK(a.st, a.usn, a.location, a.server, a.maxAge)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
a.ch <- &message{to: from, data: msg}
|
||||
msg := buildOK(a.st, a.usn, a.locProv.Location(from, nil), a.server, a.maxAge)
|
||||
a.ch <- &message{to: from, data: multicast.BytesDataProvider(msg)}
|
||||
return nil
|
||||
}
|
||||
|
||||
func buildOK(st, usn, location, server string, maxAge int) ([]byte, error) {
|
||||
func buildOK(st, usn, location, server string, maxAge int) []byte {
|
||||
// bytes.Buffer#Write() is never fail, so we can omit error checks.
|
||||
b := new(bytes.Buffer)
|
||||
// FIXME: error should be checked.
|
||||
b.WriteString("HTTP/1.1 200 OK\r\n")
|
||||
fmt.Fprintf(b, "EXT: \r\n")
|
||||
fmt.Fprintf(b, "ST: %s\r\n", st)
|
||||
|
@ -129,7 +132,7 @@ func buildOK(st, usn, location, server string, maxAge int) ([]byte, error) {
|
|||
}
|
||||
fmt.Fprintf(b, "CACHE-CONTROL: max-age=%d\r\n", maxAge)
|
||||
b.WriteString("\r\n")
|
||||
return b.Bytes(), nil
|
||||
return b.Bytes()
|
||||
}
|
||||
|
||||
// Close stops advertisement.
|
||||
|
@ -149,23 +152,26 @@ func (a *Advertiser) Close() error {
|
|||
|
||||
// Alive announces ssdp:alive message.
|
||||
func (a *Advertiser) Alive() error {
|
||||
addr, err := multicastSendAddr()
|
||||
addr, err := multicast.SendAddr()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
msg, err := buildAlive(addr, a.st, a.usn, a.location, a.server,
|
||||
a.maxAge)
|
||||
if err != nil {
|
||||
return err
|
||||
msg := &aliveDataProvider{
|
||||
host: addr,
|
||||
nt: a.st,
|
||||
usn: a.usn,
|
||||
location: a.locProv,
|
||||
server: a.server,
|
||||
maxAge: a.maxAge,
|
||||
}
|
||||
a.ch <- &message{to: addr, data: msg}
|
||||
logf("sent alive")
|
||||
ssdplog.Printf("sent alive")
|
||||
return nil
|
||||
}
|
||||
|
||||
// Bye announces ssdp:byebye message.
|
||||
func (a *Advertiser) Bye() error {
|
||||
addr, err := multicastSendAddr()
|
||||
addr, err := multicast.SendAddr()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -173,7 +179,7 @@ func (a *Advertiser) Bye() error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
a.ch <- &message{to: addr, data: msg}
|
||||
logf("sent bye")
|
||||
a.ch <- &message{to: addr, data: multicast.BytesDataProvider(msg)}
|
||||
ssdplog.Printf("sent bye")
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -4,24 +4,35 @@ import (
|
|||
"bytes"
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
"github.com/koron/go-ssdp/internal/multicast"
|
||||
)
|
||||
|
||||
// AnnounceAlive sends ssdp:alive message.
|
||||
func AnnounceAlive(nt, usn, location, server string, maxAge int, localAddr string) error {
|
||||
// location should be a string or a ssdp.LocationProvider.
|
||||
func AnnounceAlive(nt, usn string, location interface{}, server string, maxAge int, localAddr string) error {
|
||||
locProv, err := toLocationProvider(location)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// dial multicast UDP packet.
|
||||
conn, err := multicastListen(&udpAddrResolver{addr: localAddr})
|
||||
conn, err := multicast.Listen(&multicast.AddrResolver{Addr: localAddr})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer conn.Close()
|
||||
// build and send message.
|
||||
addr, err := multicastSendAddr()
|
||||
addr, err := multicast.SendAddr()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
msg, err := buildAlive(addr, nt, usn, location, server, maxAge)
|
||||
if err != nil {
|
||||
return err
|
||||
msg := &aliveDataProvider{
|
||||
host: addr,
|
||||
nt: nt,
|
||||
usn: usn,
|
||||
location: locProv,
|
||||
server: server,
|
||||
maxAge: maxAge,
|
||||
}
|
||||
if _, err := conn.WriteTo(msg, addr); err != nil {
|
||||
return err
|
||||
|
@ -29,9 +40,24 @@ func AnnounceAlive(nt, usn, location, server string, maxAge int, localAddr strin
|
|||
return nil
|
||||
}
|
||||
|
||||
func buildAlive(raddr net.Addr, nt, usn, location, server string, maxAge int) ([]byte, error) {
|
||||
type aliveDataProvider struct {
|
||||
host net.Addr
|
||||
nt string
|
||||
usn string
|
||||
location LocationProvider
|
||||
server string
|
||||
maxAge int
|
||||
}
|
||||
|
||||
func (p *aliveDataProvider) Bytes(ifi *net.Interface) []byte {
|
||||
return buildAlive(p.host, p.nt, p.usn, p.location.Location(nil, ifi), p.server, p.maxAge)
|
||||
}
|
||||
|
||||
var _ multicast.DataProvider = (*aliveDataProvider)(nil)
|
||||
|
||||
func buildAlive(raddr net.Addr, nt, usn, location, server string, maxAge int) []byte {
|
||||
// bytes.Buffer#Write() is never fail, so we can omit error checks.
|
||||
b := new(bytes.Buffer)
|
||||
// FIXME: error should be checked.
|
||||
b.WriteString("NOTIFY * HTTP/1.1\r\n")
|
||||
fmt.Fprintf(b, "HOST: %s\r\n", raddr.String())
|
||||
fmt.Fprintf(b, "NT: %s\r\n", nt)
|
||||
|
@ -45,19 +71,19 @@ func buildAlive(raddr net.Addr, nt, usn, location, server string, maxAge int) ([
|
|||
}
|
||||
fmt.Fprintf(b, "CACHE-CONTROL: max-age=%d\r\n", maxAge)
|
||||
b.WriteString("\r\n")
|
||||
return b.Bytes(), nil
|
||||
return b.Bytes()
|
||||
}
|
||||
|
||||
// AnnounceBye sends ssdp:byebye message.
|
||||
func AnnounceBye(nt, usn, localAddr string) error {
|
||||
// dial multicast UDP packet.
|
||||
conn, err := multicastListen(&udpAddrResolver{addr: localAddr})
|
||||
conn, err := multicast.Listen(&multicast.AddrResolver{Addr: localAddr})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer conn.Close()
|
||||
// build and send message.
|
||||
addr, err := multicastSendAddr()
|
||||
addr, err := multicast.SendAddr()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -65,7 +91,7 @@ func AnnounceBye(nt, usn, localAddr string) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := conn.WriteTo(msg, addr); err != nil {
|
||||
if _, err := conn.WriteTo(multicast.BytesDataProvider(msg), addr); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
Package ssdp provides ...
|
||||
Package ssdp provides SSDP advertiser or so.
|
||||
*/
|
||||
package ssdp
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
/*
|
||||
Package multicast provides utilities for network multicast.
|
||||
*/
|
||||
package multicast
|
|
@ -1,33 +1,23 @@
|
|||
package ssdp
|
||||
package multicast
|
||||
|
||||
import (
|
||||
"net"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// Interfaces specify target interfaces to multicast. If no interfaces are
|
||||
// specified, all interfaces will be used.
|
||||
var Interfaces []net.Interface
|
||||
type InterfacesProviderFunc func() []net.Interface
|
||||
|
||||
var ifLock sync.Mutex
|
||||
var ifList []net.Interface
|
||||
// InterfacesProvider specify a function to list all interfaces to multicast.
|
||||
// If no provider are given, all possible interfaces will be used.
|
||||
var InterfacesProvider InterfacesProviderFunc
|
||||
|
||||
// interfaces gets list of net.Interface to multicast UDP packet.
|
||||
func interfaces() ([]net.Interface, error) {
|
||||
ifLock.Lock()
|
||||
defer ifLock.Unlock()
|
||||
if len(Interfaces) > 0 {
|
||||
return Interfaces, nil
|
||||
if p := InterfacesProvider; p != nil {
|
||||
if list := p(); len(list) > 0 {
|
||||
return list, nil
|
||||
}
|
||||
}
|
||||
if len(ifList) > 0 {
|
||||
return ifList, nil
|
||||
}
|
||||
l, err := interfacesIPv4()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ifList = l
|
||||
return ifList, nil
|
||||
return interfacesIPv4()
|
||||
}
|
||||
|
||||
// interfacesIPv4 lists net.Interface on IPv4.
|
||||
|
@ -38,7 +28,7 @@ func interfacesIPv4() ([]net.Interface, error) {
|
|||
}
|
||||
list := make([]net.Interface, 0, len(iflist))
|
||||
for _, ifi := range iflist {
|
||||
if !hasLinkUp(&ifi) || !hasIPv4Address(&ifi) {
|
||||
if !hasLinkUp(&ifi) || !hasMulticast(&ifi) || !hasIPv4Address(&ifi) {
|
||||
continue
|
||||
}
|
||||
list = append(list, ifi)
|
||||
|
@ -51,6 +41,11 @@ func hasLinkUp(ifi *net.Interface) bool {
|
|||
return ifi.Flags&net.FlagUp != 0
|
||||
}
|
||||
|
||||
// hasMulticast checks an I/F supports multicast or not.
|
||||
func hasMulticast(ifi *net.Interface) bool {
|
||||
return ifi.Flags&net.FlagMulticast != 0
|
||||
}
|
||||
|
||||
// hasIPv4Address checks an I/F have IPv4 address.
|
||||
func hasIPv4Address(ifi *net.Interface) bool {
|
||||
addrs, err := ifi.Addrs()
|
|
@ -1,4 +1,4 @@
|
|||
package ssdp
|
||||
package multicast
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
@ -7,17 +7,20 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/koron/go-ssdp/internal/ssdplog"
|
||||
"golang.org/x/net/ipv4"
|
||||
)
|
||||
|
||||
type multicastConn struct {
|
||||
// Conn is multicast connection.
|
||||
type Conn struct {
|
||||
laddr *net.UDPAddr
|
||||
conn *net.UDPConn
|
||||
pconn *ipv4.PacketConn
|
||||
iflist []net.Interface
|
||||
}
|
||||
|
||||
func multicastListen(r *udpAddrResolver) (*multicastConn, error) {
|
||||
// Listen starts to receiving multicast messages.
|
||||
func Listen(r *AddrResolver) (*Conn, error) {
|
||||
// prepare parameters.
|
||||
laddr, err := r.resolve()
|
||||
if err != nil {
|
||||
|
@ -34,7 +37,7 @@ func multicastListen(r *udpAddrResolver) (*multicastConn, error) {
|
|||
conn.Close()
|
||||
return nil, err
|
||||
}
|
||||
return &multicastConn{
|
||||
return &Conn{
|
||||
laddr: laddr,
|
||||
conn: conn,
|
||||
pconn: pconn,
|
||||
|
@ -47,7 +50,7 @@ func newIPv4MulticastConn(conn *net.UDPConn) (*ipv4.PacketConn, []net.Interface,
|
|||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
addr, err := multicastSendAddr()
|
||||
addr, err := SendAddr()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
@ -66,11 +69,11 @@ func joinGroupIPv4(conn *net.UDPConn, iflist []net.Interface, gaddr net.Addr) (*
|
|||
joined := 0
|
||||
for _, ifi := range iflist {
|
||||
if err := wrap.JoinGroup(&ifi, gaddr); err != nil {
|
||||
logf("failed to join group %s on %s: %s", gaddr.String(), ifi.Name, err)
|
||||
ssdplog.Printf("failed to join group %s on %s: %s", gaddr.String(), ifi.Name, err)
|
||||
continue
|
||||
}
|
||||
joined++
|
||||
logf("joined group %s on %s", gaddr.String(), ifi.Name)
|
||||
ssdplog.Printf("joined group %s on %s (#%d)", gaddr.String(), ifi.Name, ifi.Index)
|
||||
}
|
||||
if joined == 0 {
|
||||
return nil, errors.New("no interfaces had joined to group")
|
||||
|
@ -78,7 +81,8 @@ func joinGroupIPv4(conn *net.UDPConn, iflist []net.Interface, gaddr net.Addr) (*
|
|||
return wrap, nil
|
||||
}
|
||||
|
||||
func (mc *multicastConn) Close() error {
|
||||
// Close closes a multicast connection.
|
||||
func (mc *Conn) Close() error {
|
||||
if err := mc.pconn.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -86,26 +90,49 @@ func (mc *multicastConn) Close() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (mc *multicastConn) WriteTo(data []byte, to net.Addr) (int, error) {
|
||||
// DataProvider provides a body of multicast message to send.
|
||||
type DataProvider interface {
|
||||
Bytes(*net.Interface) []byte
|
||||
}
|
||||
|
||||
//type multicastDataProviderFunc func(*net.Interface) []byte
|
||||
//
|
||||
//func (f multicastDataProviderFunc) Bytes(ifi *net.Interface) []byte {
|
||||
// return f(ifi)
|
||||
//}
|
||||
|
||||
type BytesDataProvider []byte
|
||||
|
||||
func (b BytesDataProvider) Bytes(ifi *net.Interface) []byte {
|
||||
return []byte(b)
|
||||
}
|
||||
|
||||
// WriteTo sends a multicast message to interfaces.
|
||||
func (mc *Conn) WriteTo(dataProv DataProvider, to net.Addr) (int, error) {
|
||||
if uaddr, ok := to.(*net.UDPAddr); ok && !uaddr.IP.IsMulticast() {
|
||||
return mc.conn.WriteTo(data, to)
|
||||
return mc.conn.WriteTo(dataProv.Bytes(nil), to)
|
||||
}
|
||||
sum := 0
|
||||
for _, ifi := range mc.iflist {
|
||||
if err := mc.pconn.SetMulticastInterface(&ifi); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if _, err := mc.pconn.WriteTo(data, nil, to); err != nil {
|
||||
n, err := mc.pconn.WriteTo(dataProv.Bytes(&ifi), nil, to)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
sum += n
|
||||
}
|
||||
return len(data), nil
|
||||
return sum, nil
|
||||
}
|
||||
|
||||
func (mc *multicastConn) LocalAddr() net.Addr {
|
||||
// LocalAddr returns local address to listen multicast packets.
|
||||
func (mc *Conn) LocalAddr() net.Addr {
|
||||
return mc.laddr
|
||||
}
|
||||
|
||||
func (mc *multicastConn) readPackets(timeout time.Duration, h packetHandler) error {
|
||||
// ReadPackets reads multicast packets.
|
||||
func (mc *Conn) ReadPackets(timeout time.Duration, h PacketHandler) error {
|
||||
buf := make([]byte, 65535)
|
||||
if timeout > 0 {
|
||||
mc.pconn.SetReadDeadline(time.Now().Add(timeout))
|
|
@ -0,0 +1,65 @@
|
|||
package multicast
|
||||
|
||||
import (
|
||||
"net"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type PacketHandler func(net.Addr, []byte) error
|
||||
|
||||
type AddrResolver struct {
|
||||
Addr string
|
||||
|
||||
mu sync.RWMutex
|
||||
udp *net.UDPAddr
|
||||
err error
|
||||
}
|
||||
|
||||
func (r *AddrResolver) setAddress(addr string) {
|
||||
r.mu.Lock()
|
||||
r.Addr = addr
|
||||
r.udp = nil
|
||||
r.err = nil
|
||||
r.mu.Unlock()
|
||||
}
|
||||
|
||||
func (r *AddrResolver) resolve() (*net.UDPAddr, error) {
|
||||
r.mu.RLock()
|
||||
if err := r.err; err != nil {
|
||||
r.mu.RUnlock()
|
||||
return nil, err
|
||||
}
|
||||
if udp := r.udp; udp != nil {
|
||||
r.mu.RUnlock()
|
||||
return udp, nil
|
||||
}
|
||||
r.mu.RUnlock()
|
||||
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
r.udp, r.err = net.ResolveUDPAddr("udp4", r.Addr)
|
||||
return r.udp, r.err
|
||||
}
|
||||
|
||||
var RecvAddrResolver = &AddrResolver{Addr: "224.0.0.1:1900"}
|
||||
|
||||
// SetRecvAddrIPv4 updates multicast address where to receive packets.
|
||||
// This never fail now.
|
||||
func SetRecvAddrIPv4(addr string) error {
|
||||
RecvAddrResolver.setAddress(addr)
|
||||
return nil
|
||||
}
|
||||
|
||||
var sendAddrResolver = &AddrResolver{Addr: "239.255.255.250:1900"}
|
||||
|
||||
// SendAddr returns an address to send multicast UDP package.
|
||||
func SendAddr() (*net.UDPAddr, error) {
|
||||
return sendAddrResolver.resolve()
|
||||
}
|
||||
|
||||
// SetSendAddrIPv4 updates a UDP address to send multicast packets.
|
||||
// This never fail now.
|
||||
func SetSendAddrIPv4(addr string) error {
|
||||
sendAddrResolver.setAddress(addr)
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
/*
|
||||
Package ssdplog provides log mechanism for ssdp.
|
||||
*/
|
||||
package ssdplog
|
||||
|
||||
import "log"
|
||||
|
||||
var LoggerProvider = func() *log.Logger { return nil }
|
||||
|
||||
func Printf(s string, a ...interface{}) {
|
||||
if p := LoggerProvider; p != nil {
|
||||
if l := p(); l != nil {
|
||||
l.Printf(s, a...)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
package ssdp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
)
|
||||
|
||||
// LocationProvider provides address for Location header which can be reached from
|
||||
// "from" address network.
|
||||
type LocationProvider interface {
|
||||
// Location provides an address be reachable from the network located
|
||||
// by "from" address or "ifi" interface.
|
||||
// One of "from" or "ifi" must not be nil.
|
||||
Location(from net.Addr, ifi *net.Interface) string
|
||||
}
|
||||
|
||||
// LocationProviderFunc type is an adapter to allow the use of ordinary
|
||||
// functions are location providers.
|
||||
type LocationProviderFunc func(net.Addr, *net.Interface) string
|
||||
|
||||
func (f LocationProviderFunc) Location(from net.Addr, ifi *net.Interface) string {
|
||||
return f(from, ifi)
|
||||
}
|
||||
|
||||
type fixedLocation string
|
||||
|
||||
func (s fixedLocation) Location(net.Addr, *net.Interface) string {
|
||||
return string(s)
|
||||
}
|
||||
|
||||
func toLocationProvider(v interface{}) (LocationProvider, error) {
|
||||
switch w := v.(type) {
|
||||
case string:
|
||||
return fixedLocation(w), nil
|
||||
case LocationProvider:
|
||||
return w, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("location should be a string or a ssdp.LocationProvider but got %T", w)
|
||||
}
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
package ssdp
|
||||
|
||||
import "log"
|
||||
|
||||
// Logger is default logger for SSDP module.
|
||||
var Logger *log.Logger
|
||||
|
||||
func logf(s string, a ...interface{}) {
|
||||
if l := Logger; l != nil {
|
||||
l.Printf(s, a...)
|
||||
}
|
||||
}
|
|
@ -9,6 +9,9 @@ import (
|
|||
"net"
|
||||
"net/http"
|
||||
"sync"
|
||||
|
||||
"github.com/koron/go-ssdp/internal/multicast"
|
||||
"github.com/koron/go-ssdp/internal/ssdplog"
|
||||
)
|
||||
|
||||
// Monitor monitors SSDP's alive and byebye messages.
|
||||
|
@ -17,17 +20,17 @@ type Monitor struct {
|
|||
Bye ByeHandler
|
||||
Search SearchHandler
|
||||
|
||||
conn *multicastConn
|
||||
conn *multicast.Conn
|
||||
wg sync.WaitGroup
|
||||
}
|
||||
|
||||
// Start starts to monitor SSDP messages.
|
||||
func (m *Monitor) Start() error {
|
||||
conn, err := multicastListen(recvAddrResolver)
|
||||
conn, err := multicast.Listen(multicast.RecvAddrResolver)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
logf("monitoring on %s", conn.LocalAddr().String())
|
||||
ssdplog.Printf("monitoring on %s", conn.LocalAddr().String())
|
||||
m.conn = conn
|
||||
m.wg.Add(1)
|
||||
go func() {
|
||||
|
@ -38,7 +41,8 @@ func (m *Monitor) Start() error {
|
|||
}
|
||||
|
||||
func (m *Monitor) serve() error {
|
||||
err := m.conn.readPackets(0, func(addr net.Addr, data []byte) error {
|
||||
// TODO: update listening interfaces of m.conn
|
||||
err := m.conn.ReadPackets(0, func(addr net.Addr, data []byte) error {
|
||||
msg := make([]byte, len(data))
|
||||
copy(msg, data)
|
||||
go m.handleRaw(addr, msg)
|
||||
|
@ -62,7 +66,7 @@ func (m *Monitor) handleRaw(addr net.Addr, raw []byte) error {
|
|||
return m.handleNotify(addr, raw)
|
||||
}
|
||||
n := bytes.Index(raw, []byte("\r\n"))
|
||||
logf("unexpected method: %q", string(raw[:n]))
|
||||
ssdplog.Printf("unexpected method: %q", string(raw[:n]))
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,9 @@ import (
|
|||
"regexp"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/koron/go-ssdp/internal/multicast"
|
||||
"github.com/koron/go-ssdp/internal/ssdplog"
|
||||
)
|
||||
|
||||
// Service is discovered service.
|
||||
|
@ -68,15 +71,15 @@ const (
|
|||
// Search searches services by SSDP.
|
||||
func Search(searchType string, waitSec int, localAddr string) ([]Service, error) {
|
||||
// dial multicast UDP packet.
|
||||
conn, err := multicastListen(&udpAddrResolver{addr: localAddr})
|
||||
conn, err := multicast.Listen(&multicast.AddrResolver{Addr: localAddr})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer conn.Close()
|
||||
logf("search on %s", conn.LocalAddr().String())
|
||||
ssdplog.Printf("search on %s", conn.LocalAddr().String())
|
||||
|
||||
// send request.
|
||||
addr, err := multicastSendAddr()
|
||||
addr, err := multicast.SendAddr()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -84,7 +87,7 @@ func Search(searchType string, waitSec int, localAddr string) ([]Service, error)
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if _, err := conn.WriteTo(msg, addr); err != nil {
|
||||
if _, err := conn.WriteTo(multicast.BytesDataProvider(msg), addr); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
@ -93,15 +96,15 @@ func Search(searchType string, waitSec int, localAddr string) ([]Service, error)
|
|||
h := func(a net.Addr, d []byte) error {
|
||||
srv, err := parseService(a, d)
|
||||
if err != nil {
|
||||
logf("invalid search response from %s: %s", a.String(), err)
|
||||
ssdplog.Printf("invalid search response from %s: %s", a.String(), err)
|
||||
return nil
|
||||
}
|
||||
list = append(list, *srv)
|
||||
logf("search response from %s: %s", a.String(), srv.USN)
|
||||
ssdplog.Printf("search response from %s: %s", a.String(), srv.USN)
|
||||
return nil
|
||||
}
|
||||
d := time.Second * time.Duration(waitSec)
|
||||
if err := conn.readPackets(d, h); err != nil {
|
||||
if err := conn.ReadPackets(d, h); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
package ssdp
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net"
|
||||
|
||||
"github.com/koron/go-ssdp/internal/multicast"
|
||||
"github.com/koron/go-ssdp/internal/ssdplog"
|
||||
)
|
||||
|
||||
func init() {
|
||||
multicast.InterfacesProvider = func() []net.Interface {
|
||||
return Interfaces
|
||||
}
|
||||
ssdplog.LoggerProvider = func() *log.Logger {
|
||||
return Logger
|
||||
}
|
||||
}
|
||||
|
||||
// Interfaces specify target interfaces to multicast. If no interfaces are
|
||||
// specified, all interfaces will be used.
|
||||
var Interfaces []net.Interface
|
||||
|
||||
// Logger is default logger for SSDP module.
|
||||
var Logger *log.Logger
|
||||
|
||||
// SetMulticastRecvAddrIPv4 updates multicast address where to receive packets.
|
||||
// This never fail now.
|
||||
func SetMulticastRecvAddrIPv4(addr string) error {
|
||||
return multicast.SetRecvAddrIPv4(addr)
|
||||
}
|
||||
|
||||
// SetMulticastSendAddrIPv4 updates a UDP address to send multicast packets.
|
||||
// This never fail now.
|
||||
func SetMulticastSendAddrIPv4(addr string) error {
|
||||
return multicast.SetSendAddrIPv4(addr)
|
||||
}
|
|
@ -1,65 +0,0 @@
|
|||
package ssdp
|
||||
|
||||
import (
|
||||
"net"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type packetHandler func(net.Addr, []byte) error
|
||||
|
||||
type udpAddrResolver struct {
|
||||
addr string
|
||||
|
||||
mu sync.RWMutex
|
||||
udp *net.UDPAddr
|
||||
err error
|
||||
}
|
||||
|
||||
func (r *udpAddrResolver) setAddress(addr string) {
|
||||
r.mu.Lock()
|
||||
r.addr = addr
|
||||
r.udp = nil
|
||||
r.err = nil
|
||||
r.mu.Unlock()
|
||||
}
|
||||
|
||||
func (r *udpAddrResolver) resolve() (*net.UDPAddr, error) {
|
||||
r.mu.RLock()
|
||||
if err := r.err; err != nil {
|
||||
r.mu.RUnlock()
|
||||
return nil, err
|
||||
}
|
||||
if udp := r.udp; udp != nil {
|
||||
r.mu.RUnlock()
|
||||
return udp, nil
|
||||
}
|
||||
r.mu.RUnlock()
|
||||
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
r.udp, r.err = net.ResolveUDPAddr("udp4", r.addr)
|
||||
return r.udp, r.err
|
||||
}
|
||||
|
||||
var recvAddrResolver = &udpAddrResolver{addr: "224.0.0.0:1900"}
|
||||
|
||||
// SetMulticastRecvAddrIPv4 updates multicast address where to receive packets.
|
||||
// This never fail now.
|
||||
func SetMulticastRecvAddrIPv4(addr string) error {
|
||||
recvAddrResolver.setAddress(addr)
|
||||
return nil
|
||||
}
|
||||
|
||||
var sendAddrResolver = &udpAddrResolver{addr: "239.255.255.250:1900"}
|
||||
|
||||
// multicastSendAddr returns an address to send multicast UDP package.
|
||||
func multicastSendAddr() (*net.UDPAddr, error) {
|
||||
return sendAddrResolver.resolve()
|
||||
}
|
||||
|
||||
// SetMulticastSendAddrIPv4 updates a UDP address to send multicast packets.
|
||||
// This never fail now.
|
||||
func SetMulticastSendAddrIPv4(addr string) error {
|
||||
sendAddrResolver.setAddress(addr)
|
||||
return nil
|
||||
}
|
|
@ -4,14 +4,15 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"sync"
|
||||
|
||||
"github.com/libp2p/go-cidranger"
|
||||
)
|
||||
|
||||
var Store *indirectAsnStore
|
||||
var Store *lazyAsnStore
|
||||
|
||||
func init() {
|
||||
Store = newIndirectAsnStore()
|
||||
Store = &lazyAsnStore{}
|
||||
}
|
||||
|
||||
type networkWithAsn struct {
|
||||
|
@ -66,32 +67,29 @@ func newAsnStore() (*asnStore, error) {
|
|||
return &asnStore{cr}, nil
|
||||
}
|
||||
|
||||
type indirectAsnStore struct {
|
||||
store *asnStore
|
||||
doneLoading chan struct{}
|
||||
// lazyAsnStore builds the underlying trie on first call to AsnForIPv6.
|
||||
// Alternatively, Init can be called to manually trigger initialization.
|
||||
type lazyAsnStore struct {
|
||||
store *asnStore
|
||||
once sync.Once
|
||||
}
|
||||
|
||||
// AsnForIPv6 returns the AS number for the given IPv6 address.
|
||||
// If no mapping exists for the given IP, this function will
|
||||
// return an empty ASN and a nil error.
|
||||
func (a *indirectAsnStore) AsnForIPv6(ip net.IP) (string, error) {
|
||||
<-a.doneLoading
|
||||
func (a *lazyAsnStore) AsnForIPv6(ip net.IP) (string, error) {
|
||||
a.once.Do(a.init)
|
||||
return a.store.AsnForIPv6(ip)
|
||||
}
|
||||
|
||||
func newIndirectAsnStore() *indirectAsnStore {
|
||||
a := &indirectAsnStore{
|
||||
doneLoading: make(chan struct{}),
|
||||
}
|
||||
|
||||
go func() {
|
||||
defer close(a.doneLoading)
|
||||
store, err := newAsnStore()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
a.store = store
|
||||
}()
|
||||
|
||||
return a
|
||||
func (a *lazyAsnStore) Init() {
|
||||
a.once.Do(a.init)
|
||||
}
|
||||
|
||||
func (a *lazyAsnStore) init() {
|
||||
store, err := newAsnStore()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
a.store = store
|
||||
}
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
{
|
||||
"version": "v0.2.0"
|
||||
"version": "v0.3.0"
|
||||
}
|
||||
|
|
|
@ -1,8 +1,63 @@
|
|||
# Table Of Contents <!-- omit in toc -->
|
||||
- [v0.27.0](#v0270)
|
||||
- [v0.26.4](#v0264)
|
||||
- [v0.26.3](#v0263)
|
||||
- [v0.26.2](#v0262)
|
||||
- [v0.26.1](#v0261)
|
||||
- [v0.26.0](#v0260)
|
||||
- [v0.25.1](#v0251)
|
||||
- [v0.25.0](#v0250)
|
||||
|
||||
# [v0.27.0](https://github.com/libp2p/go-libp2p/releases/tag/v0.27.0)
|
||||
|
||||
### Breaking Changes <!-- omit in toc -->
|
||||
|
||||
* The `LocalPrivateKey` method was removed from the `network.Conn` interface. [#2144](https://github.com/libp2p/go-libp2p/pull/2144)
|
||||
|
||||
## 🔦 Highlights <!-- omit in toc -->
|
||||
|
||||
### Additional metrics <!-- omit in toc -->
|
||||
Since the last release, we've added metrics for:
|
||||
* [Relay Service](https://github.com/libp2p/go-libp2p/pull/2154): RequestStatus, RequestCounts, RejectionReasons for Reservation and Connection Requests,
|
||||
ConnectionDuration, BytesTransferred, Relay Service Status.
|
||||
* [Autorelay](https://github.com/libp2p/go-libp2p/pull/2185): relay finder status, reservation request outcomes, current reservations, candidate circuit v2 support, current candidates, relay addresses updated, num relay address, and scheduled work times
|
||||
|
||||
## 🐞 Bugfixes <!-- omit in toc -->
|
||||
|
||||
* autonat: don't change status on dial request refused [2225](https://github.com/libp2p/go-libp2p/pull/2225)
|
||||
* relaysvc: fix flaky TestReachabilityChangeEvent [2215](https://github.com/libp2p/go-libp2p/pull/2215)
|
||||
* basichost: prevent duplicate dials [2196](https://github.com/libp2p/go-libp2p/pull/2196)
|
||||
* websocket: don't set a WSS multiaddr for accepted unencrypted conns [2199](https://github.com/libp2p/go-libp2p/pull/2199)
|
||||
* identify: Fix IdentifyWait when Connected events happen out of order [2173](https://github.com/libp2p/go-libp2p/pull/2173)
|
||||
* circuitv2: cleanup relay service properly [2164](https://github.com/libp2p/go-libp2p/pull/2164)
|
||||
|
||||
**Full Changelog**: https://github.com/libp2p/go-libp2p/compare/v0.26.4...v0.27.0
|
||||
|
||||
# [v0.26.4](https://github.com/libp2p/go-libp2p/releases/tag/v0.26.4)
|
||||
|
||||
This patch release fixes a busy-looping happening inside AutoRelay on private nodes, see [2208](https://github.com/libp2p/go-libp2p/pull/2208).
|
||||
|
||||
**Full Changelog**: https://github.com/libp2p/go-libp2p/compare/v0.26.0...v0.26.4
|
||||
|
||||
# [v0.26.3](https://github.com/libp2p/go-libp2p/releases/tag/v0.26.3)
|
||||
|
||||
* rcmgr: fix JSON marshalling of ResourceManagerStat peer map [2156](https://github.com/libp2p/go-libp2p/pull/2156)
|
||||
* websocket: Don't limit message sizes in the websocket reader [2193](https://github.com/libp2p/go-libp2p/pull/2193)
|
||||
|
||||
**Full Changelog**: https://github.com/libp2p/go-libp2p/compare/v0.26.0...v0.26.3
|
||||
|
||||
# [v0.26.2](https://github.com/libp2p/go-libp2p/releases/tag/v0.26.2)
|
||||
|
||||
This patch release fixes two bugs:
|
||||
* A panic in WebTransport: https://github.com/quic-go/webtransport-go/releases/tag/v0.5.2
|
||||
* Incorrect accounting of accepted connections in the swarm metrics: [#2147](https://github.com/libp2p/go-libp2p/pull/2147)
|
||||
|
||||
**Full Changelog**: https://github.com/libp2p/go-libp2p/compare/v0.26.0...v0.26.2
|
||||
|
||||
# v0.26.1
|
||||
|
||||
This version was retracted due to errors when publishing the release.
|
||||
|
||||
# [v0.26.0](https://github.com/libp2p/go-libp2p/releases/tag/v0.26.0)
|
||||
|
||||
## 🔦 Highlights <!-- omit in toc -->
|
||||
|
|
|
@ -56,11 +56,6 @@ import "github.com/libp2p/go-libp2p"
|
|||
|
||||
Examples can be found in the [examples folder](examples).
|
||||
|
||||
## Development
|
||||
|
||||
### Tests
|
||||
|
||||
`go test ./...` will run all tests in the repo.
|
||||
|
||||
# Contribute
|
||||
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
# Security Policy
|
||||
|
||||
go-libp2p is still in development. This means that there may be problems in our protocols,
|
||||
or there may be mistakes in our implementations.
|
||||
We take security vulnerabilities very seriously. If you discover a security issue,
|
||||
please bring it to our attention right away!
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
If you find a vulnerability that may affect live deployments -- for example, by exposing
|
||||
a remote execution exploit -- please [**report privately**](https://github.com/libp2p/go-libp2p/security/advisories/new).
|
||||
Please **DO NOT file a public issue**.
|
||||
|
||||
If the issue is an implementation weakness that cannot be immediately exploited or
|
||||
something not yet deployed, just discuss it openly.
|
||||
If you need assistance, please reach out to [security@libp2p.io](mailto:security@libp2p.io).
|
||||
|
||||
## Reporting a non security bug
|
||||
|
||||
For non-security bugs, please simply file a GitHub [issue](https://github.com/libp2p/go-libp2p/issues/new).
|
|
@ -8,6 +8,7 @@ import (
|
|||
|
||||
"github.com/libp2p/go-libp2p/core/connmgr"
|
||||
"github.com/libp2p/go-libp2p/core/crypto"
|
||||
"github.com/libp2p/go-libp2p/core/event"
|
||||
"github.com/libp2p/go-libp2p/core/host"
|
||||
"github.com/libp2p/go-libp2p/core/metrics"
|
||||
"github.com/libp2p/go-libp2p/core/network"
|
||||
|
@ -23,6 +24,7 @@ import (
|
|||
"github.com/libp2p/go-libp2p/p2p/host/autorelay"
|
||||
bhost "github.com/libp2p/go-libp2p/p2p/host/basic"
|
||||
blankhost "github.com/libp2p/go-libp2p/p2p/host/blank"
|
||||
"github.com/libp2p/go-libp2p/p2p/host/eventbus"
|
||||
"github.com/libp2p/go-libp2p/p2p/host/peerstore/pstoremem"
|
||||
routed "github.com/libp2p/go-libp2p/p2p/host/routed"
|
||||
"github.com/libp2p/go-libp2p/p2p/net/swarm"
|
||||
|
@ -123,7 +125,7 @@ type Config struct {
|
|||
PrometheusRegisterer prometheus.Registerer
|
||||
}
|
||||
|
||||
func (cfg *Config) makeSwarm(enableMetrics bool) (*swarm.Swarm, error) {
|
||||
func (cfg *Config) makeSwarm(eventBus event.Bus, enableMetrics bool) (*swarm.Swarm, error) {
|
||||
if cfg.Peerstore == nil {
|
||||
return nil, fmt.Errorf("no peerstore specified")
|
||||
}
|
||||
|
@ -176,7 +178,7 @@ func (cfg *Config) makeSwarm(enableMetrics bool) (*swarm.Swarm, error) {
|
|||
swarm.WithMetricsTracer(swarm.NewMetricsTracer(swarm.WithRegisterer(cfg.PrometheusRegisterer))))
|
||||
}
|
||||
// TODO: Make the swarm implementation configurable.
|
||||
return swarm.NewSwarm(pid, cfg.Peerstore, opts...)
|
||||
return swarm.NewSwarm(pid, cfg.Peerstore, eventBus, opts...)
|
||||
}
|
||||
|
||||
func (cfg *Config) addTransports(h host.Host) error {
|
||||
|
@ -284,12 +286,14 @@ func (cfg *Config) addTransports(h host.Host) error {
|
|||
//
|
||||
// This function consumes the config. Do not reuse it (really!).
|
||||
func (cfg *Config) NewNode() (host.Host, error) {
|
||||
swrm, err := cfg.makeSwarm(!cfg.DisableMetrics)
|
||||
eventBus := eventbus.NewBus(eventbus.WithMetricsTracer(eventbus.NewMetricsTracer(eventbus.WithRegisterer(cfg.PrometheusRegisterer))))
|
||||
swrm, err := cfg.makeSwarm(eventBus, !cfg.DisableMetrics)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
h, err := bhost.NewHost(swrm, &bhost.HostOpts{
|
||||
EventBus: eventBus,
|
||||
ConnManager: cfg.ConnManager,
|
||||
AddrsFactory: cfg.AddrsFactory,
|
||||
NATManager: cfg.NATManager,
|
||||
|
@ -350,6 +354,12 @@ func (cfg *Config) NewNode() (host.Host, error) {
|
|||
h.Close()
|
||||
return nil, fmt.Errorf("cannot enable autorelay; relay is not enabled")
|
||||
}
|
||||
if !cfg.DisableMetrics {
|
||||
mt := autorelay.WithMetricsTracer(
|
||||
autorelay.NewMetricsTracer(autorelay.WithRegisterer(cfg.PrometheusRegisterer)))
|
||||
mtOpts := []autorelay.Option{mt}
|
||||
cfg.AutoRelayOpts = append(mtOpts, cfg.AutoRelayOpts...)
|
||||
}
|
||||
|
||||
ar, err = autorelay.NewAutoRelay(h, cfg.AutoRelayOpts...)
|
||||
if err != nil {
|
||||
|
@ -397,7 +407,7 @@ func (cfg *Config) NewNode() (host.Host, error) {
|
|||
Peerstore: ps,
|
||||
}
|
||||
|
||||
dialer, err := autoNatCfg.makeSwarm(false)
|
||||
dialer, err := autoNatCfg.makeSwarm(eventbus.NewBus(), false)
|
||||
if err != nil {
|
||||
h.Close()
|
||||
return nil, err
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.28.1
|
||||
// protoc-gen-go v1.30.0
|
||||
// protoc v3.21.12
|
||||
// source: pb/crypto.proto
|
||||
|
||||
|
|
|
@ -33,6 +33,10 @@ type Conn interface {
|
|||
|
||||
// GetStreams returns all open streams over this conn.
|
||||
GetStreams() []Stream
|
||||
|
||||
// IsClosed returns whether a connection is fully closed, so it can
|
||||
// be garbage collected.
|
||||
IsClosed() bool
|
||||
}
|
||||
|
||||
// ConnectionState holds information about the connection.
|
||||
|
@ -53,9 +57,6 @@ type ConnSecurity interface {
|
|||
// LocalPeer returns our peer ID
|
||||
LocalPeer() peer.ID
|
||||
|
||||
// LocalPrivateKey returns our private key
|
||||
LocalPrivateKey() ic.PrivKey
|
||||
|
||||
// RemotePeer returns the peer ID of the remote peer.
|
||||
RemotePeer() peer.ID
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.28.1
|
||||
// protoc-gen-go v1.30.0
|
||||
// protoc v3.21.12
|
||||
// source: pb/peer_record.proto
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.28.1
|
||||
// protoc-gen-go v1.30.0
|
||||
// protoc v3.21.12
|
||||
// source: pb/envelope.proto
|
||||
|
||||
|
|
|
@ -40,9 +40,7 @@ type Transport struct {
|
|||
|
||||
var _ sec.SecureTransport = &Transport{}
|
||||
|
||||
// NewWithIdentity constructs a new insecure transport. The provided private key
|
||||
// is stored and returned from LocalPrivateKey to satisfy the
|
||||
// SecureTransport interface, and the public key is sent to
|
||||
// NewWithIdentity constructs a new insecure transport. The public key is sent to
|
||||
// remote peers. No security is provided.
|
||||
func NewWithIdentity(protocolID protocol.ID, id peer.ID, key ci.PrivKey) *Transport {
|
||||
return &Transport{
|
||||
|
@ -57,12 +55,6 @@ func (t *Transport) LocalPeer() peer.ID {
|
|||
return t.id
|
||||
}
|
||||
|
||||
// LocalPrivateKey returns the local private key.
|
||||
// This key is used only for identity generation and provides no security.
|
||||
func (t *Transport) LocalPrivateKey() ci.PrivKey {
|
||||
return t.key
|
||||
}
|
||||
|
||||
// SecureInbound *pretends to secure* an inbound connection to the given peer.
|
||||
// It sends the local peer's ID and public key, and receives the same from the remote peer.
|
||||
// No validation is performed as to the authenticity or ownership of the provided public key,
|
||||
|
@ -70,19 +62,18 @@ func (t *Transport) LocalPrivateKey() ci.PrivKey {
|
|||
//
|
||||
// SecureInbound may fail if the remote peer sends an ID and public key that are inconsistent
|
||||
// with each other, or if a network error occurs during the ID exchange.
|
||||
func (t *Transport) SecureInbound(ctx context.Context, insecure net.Conn, p peer.ID) (sec.SecureConn, error) {
|
||||
func (t *Transport) SecureInbound(_ context.Context, insecure net.Conn, p peer.ID) (sec.SecureConn, error) {
|
||||
conn := &Conn{
|
||||
Conn: insecure,
|
||||
local: t.id,
|
||||
localPrivKey: t.key,
|
||||
Conn: insecure,
|
||||
local: t.id,
|
||||
localPubKey: t.key.GetPublic(),
|
||||
}
|
||||
|
||||
err := conn.runHandshakeSync()
|
||||
if err != nil {
|
||||
if err := conn.runHandshakeSync(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if t.key != nil && p != "" && p != conn.remote {
|
||||
if p != "" && p != conn.remote {
|
||||
return nil, fmt.Errorf("remote peer sent unexpected peer ID. expected=%s received=%s", p, conn.remote)
|
||||
}
|
||||
|
||||
|
@ -97,19 +88,18 @@ func (t *Transport) SecureInbound(ctx context.Context, insecure net.Conn, p peer
|
|||
// SecureOutbound may fail if the remote peer sends an ID and public key that are inconsistent
|
||||
// with each other, or if the ID sent by the remote peer does not match the one dialed. It may
|
||||
// also fail if a network error occurs during the ID exchange.
|
||||
func (t *Transport) SecureOutbound(ctx context.Context, insecure net.Conn, p peer.ID) (sec.SecureConn, error) {
|
||||
func (t *Transport) SecureOutbound(_ context.Context, insecure net.Conn, p peer.ID) (sec.SecureConn, error) {
|
||||
conn := &Conn{
|
||||
Conn: insecure,
|
||||
local: t.id,
|
||||
localPrivKey: t.key,
|
||||
Conn: insecure,
|
||||
local: t.id,
|
||||
localPubKey: t.key.GetPublic(),
|
||||
}
|
||||
|
||||
err := conn.runHandshakeSync()
|
||||
if err != nil {
|
||||
if err := conn.runHandshakeSync(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if t.key != nil && p != conn.remote {
|
||||
if p != conn.remote {
|
||||
return nil, fmt.Errorf("remote peer sent unexpected peer ID. expected=%s received=%s",
|
||||
p, conn.remote)
|
||||
}
|
||||
|
@ -117,19 +107,14 @@ func (t *Transport) SecureOutbound(ctx context.Context, insecure net.Conn, p pee
|
|||
return conn, nil
|
||||
}
|
||||
|
||||
func (t *Transport) ID() protocol.ID {
|
||||
return t.protocolID
|
||||
}
|
||||
func (t *Transport) ID() protocol.ID { return t.protocolID }
|
||||
|
||||
// Conn is the connection type returned by the insecure transport.
|
||||
type Conn struct {
|
||||
net.Conn
|
||||
|
||||
local peer.ID
|
||||
remote peer.ID
|
||||
|
||||
localPrivKey ci.PrivKey
|
||||
remotePubKey ci.PubKey
|
||||
local, remote peer.ID
|
||||
localPubKey, remotePubKey ci.PubKey
|
||||
}
|
||||
|
||||
func makeExchangeMessage(pubkey ci.PubKey) (*pb.Exchange, error) {
|
||||
|
@ -150,12 +135,12 @@ func makeExchangeMessage(pubkey ci.PubKey) (*pb.Exchange, error) {
|
|||
|
||||
func (ic *Conn) runHandshakeSync() error {
|
||||
// If we were initialized without keys, behave as in plaintext/1.0.0 (do nothing)
|
||||
if ic.localPrivKey == nil {
|
||||
if ic.localPubKey == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Generate an Exchange message
|
||||
msg, err := makeExchangeMessage(ic.localPrivKey.GetPublic())
|
||||
msg, err := makeExchangeMessage(ic.localPubKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -239,11 +224,6 @@ func (ic *Conn) RemotePublicKey() ci.PubKey {
|
|||
return ic.remotePubKey
|
||||
}
|
||||
|
||||
// LocalPrivateKey returns the private key for the local peer.
|
||||
func (ic *Conn) LocalPrivateKey() ci.PrivKey {
|
||||
return ic.localPrivKey
|
||||
}
|
||||
|
||||
// ConnState returns the security connection's state information.
|
||||
func (ic *Conn) ConnState() network.ConnectionState {
|
||||
return network.ConnectionState{}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.28.1
|
||||
// protoc-gen-go v1.30.0
|
||||
// protoc v3.21.12
|
||||
// source: pb/plaintext.proto
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ type BackoffStrategy interface {
|
|||
// Jitter must return a duration between min and max. Min must be lower than, or equal to, max.
|
||||
type Jitter func(duration, min, max time.Duration, rng *rand.Rand) time.Duration
|
||||
|
||||
// FullJitter returns a random number uniformly chose from the range [min, boundedDur].
|
||||
// FullJitter returns a random number, uniformly chosen from the range [min, boundedDur].
|
||||
// boundedDur is the duration bounded between min and max.
|
||||
func FullJitter(duration, min, max time.Duration, rng *rand.Rand) time.Duration {
|
||||
if duration <= min {
|
||||
|
|
|
@ -2,7 +2,6 @@ package autonat
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"math/rand"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
@ -20,6 +19,8 @@ import (
|
|||
|
||||
var log = logging.Logger("autonat")
|
||||
|
||||
const maxConfidence = 3
|
||||
|
||||
// AmbientAutoNAT is the implementation of ambient NAT autodiscovery
|
||||
type AmbientAutoNAT struct {
|
||||
host host.Host
|
||||
|
@ -30,10 +31,10 @@ type AmbientAutoNAT struct {
|
|||
ctxCancel context.CancelFunc // is closed when Close is called
|
||||
backgroundRunning chan struct{} // is closed when the background go routine exits
|
||||
|
||||
inboundConn chan network.Conn
|
||||
observations chan autoNATResult
|
||||
inboundConn chan network.Conn
|
||||
dialResponses chan error
|
||||
// status is an autoNATResult reflecting current status.
|
||||
status atomic.Pointer[autoNATResult]
|
||||
status atomic.Pointer[network.Reachability]
|
||||
// Reflects the confidence on of the NATStatus being private, as a single
|
||||
// dialback may fail for reasons unrelated to NAT.
|
||||
// If it is <3, then multiple autoNAT peers may be contacted for dialback
|
||||
|
@ -58,11 +59,6 @@ type StaticAutoNAT struct {
|
|||
service *autoNATService
|
||||
}
|
||||
|
||||
type autoNATResult struct {
|
||||
network.Reachability
|
||||
address ma.Multiaddr
|
||||
}
|
||||
|
||||
// New creates a new NAT autodiscovery system attached to a host
|
||||
func New(h host.Host, options ...Option) (AutoNAT, error) {
|
||||
var err error
|
||||
|
@ -111,13 +107,14 @@ func New(h host.Host, options ...Option) (AutoNAT, error) {
|
|||
host: h,
|
||||
config: conf,
|
||||
inboundConn: make(chan network.Conn, 5),
|
||||
observations: make(chan autoNATResult, 1),
|
||||
dialResponses: make(chan error, 1),
|
||||
|
||||
emitReachabilityChanged: emitReachabilityChanged,
|
||||
service: service,
|
||||
recentProbes: make(map[peer.ID]time.Time),
|
||||
}
|
||||
as.status.Store(&autoNATResult{network.ReachabilityUnknown, nil})
|
||||
reachability := network.ReachabilityUnknown
|
||||
as.status.Store(&reachability)
|
||||
|
||||
subscriber, err := as.host.EventBus().Subscribe(
|
||||
[]any{new(event.EvtLocalAddressesUpdated), new(event.EvtPeerIdentificationCompleted)},
|
||||
|
@ -137,27 +134,17 @@ func New(h host.Host, options ...Option) (AutoNAT, error) {
|
|||
// Status returns the AutoNAT observed reachability status.
|
||||
func (as *AmbientAutoNAT) Status() network.Reachability {
|
||||
s := as.status.Load()
|
||||
return s.Reachability
|
||||
return *s
|
||||
}
|
||||
|
||||
func (as *AmbientAutoNAT) emitStatus() {
|
||||
status := as.status.Load()
|
||||
as.emitReachabilityChanged.Emit(event.EvtLocalReachabilityChanged{Reachability: status.Reachability})
|
||||
status := *as.status.Load()
|
||||
as.emitReachabilityChanged.Emit(event.EvtLocalReachabilityChanged{Reachability: status})
|
||||
if as.metricsTracer != nil {
|
||||
as.metricsTracer.ReachabilityStatus(status.Reachability)
|
||||
as.metricsTracer.ReachabilityStatus(status)
|
||||
}
|
||||
}
|
||||
|
||||
// PublicAddr returns the publicly connectable Multiaddr of this node if one is known.
|
||||
func (as *AmbientAutoNAT) PublicAddr() (ma.Multiaddr, error) {
|
||||
s := as.status.Load()
|
||||
if s.Reachability != network.ReachabilityPublic {
|
||||
return nil, errors.New("NAT status is not public")
|
||||
}
|
||||
|
||||
return s.address, nil
|
||||
}
|
||||
|
||||
func ipInList(candidate ma.Multiaddr, list []ma.Multiaddr) bool {
|
||||
candidateIP, _ := manet.ToIP(candidate)
|
||||
for _, i := range list {
|
||||
|
@ -174,7 +161,6 @@ func (as *AmbientAutoNAT) background() {
|
|||
// before starting autodetection
|
||||
delay := as.config.bootDelay
|
||||
|
||||
var lastAddrUpdated time.Time
|
||||
subChan := as.subscriber.Out()
|
||||
defer as.subscriber.Close()
|
||||
defer as.emitReachabilityChanged.Close()
|
||||
|
@ -182,15 +168,12 @@ func (as *AmbientAutoNAT) background() {
|
|||
timer := time.NewTimer(delay)
|
||||
defer timer.Stop()
|
||||
timerRunning := true
|
||||
retryProbe := false
|
||||
for {
|
||||
select {
|
||||
// new inbound connection.
|
||||
case conn := <-as.inboundConn:
|
||||
localAddrs := as.host.Addrs()
|
||||
ca := as.status.Load()
|
||||
if ca.address != nil {
|
||||
localAddrs = append(localAddrs, ca.address)
|
||||
}
|
||||
if manet.IsPublicAddr(conn.RemoteMultiaddr()) &&
|
||||
!ipInList(conn.RemoteMultiaddr(), localAddrs) {
|
||||
as.lastInbound = time.Now()
|
||||
|
@ -199,16 +182,15 @@ func (as *AmbientAutoNAT) background() {
|
|||
case e := <-subChan:
|
||||
switch e := e.(type) {
|
||||
case event.EvtLocalAddressesUpdated:
|
||||
if !lastAddrUpdated.Add(time.Second).After(time.Now()) {
|
||||
lastAddrUpdated = time.Now()
|
||||
if as.confidence > 1 {
|
||||
as.confidence--
|
||||
}
|
||||
// On local address update, reduce confidence from maximum so that we schedule
|
||||
// the next probe sooner
|
||||
if as.confidence == maxConfidence {
|
||||
as.confidence--
|
||||
}
|
||||
case event.EvtPeerIdentificationCompleted:
|
||||
if s, err := as.host.Peerstore().SupportsProtocols(e.Peer, AutoNATProto); err == nil && len(s) > 0 {
|
||||
currentStatus := as.status.Load()
|
||||
if currentStatus.Reachability == network.ReachabilityUnknown {
|
||||
currentStatus := *as.status.Load()
|
||||
if currentStatus == network.ReachabilityUnknown {
|
||||
as.tryProbe(e.Peer)
|
||||
}
|
||||
}
|
||||
|
@ -217,15 +199,20 @@ func (as *AmbientAutoNAT) background() {
|
|||
}
|
||||
|
||||
// probe finished.
|
||||
case result, ok := <-as.observations:
|
||||
case err, ok := <-as.dialResponses:
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
as.recordObservation(result)
|
||||
if IsDialRefused(err) {
|
||||
retryProbe = true
|
||||
} else {
|
||||
as.handleDialResponse(err)
|
||||
}
|
||||
case <-timer.C:
|
||||
peer := as.getPeerToProbe()
|
||||
as.tryProbe(peer)
|
||||
timerRunning = false
|
||||
retryProbe = false
|
||||
case <-as.ctx.Done():
|
||||
return
|
||||
}
|
||||
|
@ -234,7 +221,7 @@ func (as *AmbientAutoNAT) background() {
|
|||
if timerRunning && !timer.Stop() {
|
||||
<-timer.C
|
||||
}
|
||||
timer.Reset(as.scheduleProbe())
|
||||
timer.Reset(as.scheduleProbe(retryProbe))
|
||||
timerRunning = true
|
||||
}
|
||||
}
|
||||
|
@ -249,14 +236,15 @@ func (as *AmbientAutoNAT) cleanupRecentProbes() {
|
|||
}
|
||||
|
||||
// scheduleProbe calculates when the next probe should be scheduled for.
|
||||
func (as *AmbientAutoNAT) scheduleProbe() time.Duration {
|
||||
func (as *AmbientAutoNAT) scheduleProbe(retryProbe bool) time.Duration {
|
||||
// Our baseline is a probe every 'AutoNATRefreshInterval'
|
||||
// This is modulated by:
|
||||
// * if we are in an unknown state, or have low confidence, that should drop to 'AutoNATRetryInterval'
|
||||
// * if we are in an unknown state, have low confidence, or we want to retry because a probe was refused that
|
||||
// should drop to 'AutoNATRetryInterval'
|
||||
// * recent inbound connections (implying continued connectivity) should decrease the retry when public
|
||||
// * recent inbound connections when not public mean we should try more actively to see if we're public.
|
||||
fixedNow := time.Now()
|
||||
currentStatus := as.status.Load()
|
||||
currentStatus := *as.status.Load()
|
||||
|
||||
nextProbe := fixedNow
|
||||
// Don't look for peers in the peer store more than once per second.
|
||||
|
@ -268,13 +256,15 @@ func (as *AmbientAutoNAT) scheduleProbe() time.Duration {
|
|||
}
|
||||
if !as.lastProbe.IsZero() {
|
||||
untilNext := as.config.refreshInterval
|
||||
if currentStatus.Reachability == network.ReachabilityUnknown {
|
||||
if retryProbe {
|
||||
untilNext = as.config.retryInterval
|
||||
} else if as.confidence < 3 {
|
||||
} else if currentStatus == network.ReachabilityUnknown {
|
||||
untilNext = as.config.retryInterval
|
||||
} else if currentStatus.Reachability == network.ReachabilityPublic && as.lastInbound.After(as.lastProbe) {
|
||||
} else if as.confidence < maxConfidence {
|
||||
untilNext = as.config.retryInterval
|
||||
} else if currentStatus == network.ReachabilityPublic && as.lastInbound.After(as.lastProbe) {
|
||||
untilNext *= 2
|
||||
} else if currentStatus.Reachability != network.ReachabilityPublic && as.lastInbound.After(as.lastProbe) {
|
||||
} else if currentStatus != network.ReachabilityPublic && as.lastInbound.After(as.lastProbe) {
|
||||
untilNext /= 5
|
||||
}
|
||||
|
||||
|
@ -288,15 +278,31 @@ func (as *AmbientAutoNAT) scheduleProbe() time.Duration {
|
|||
return nextProbe.Sub(fixedNow)
|
||||
}
|
||||
|
||||
// Update the current status based on an observed result.
|
||||
func (as *AmbientAutoNAT) recordObservation(observation autoNATResult) {
|
||||
currentStatus := as.status.Load()
|
||||
// handleDialResponse updates the current status based on dial response.
|
||||
func (as *AmbientAutoNAT) handleDialResponse(dialErr error) {
|
||||
var observation network.Reachability
|
||||
switch {
|
||||
case dialErr == nil:
|
||||
observation = network.ReachabilityPublic
|
||||
case IsDialError(dialErr):
|
||||
observation = network.ReachabilityPrivate
|
||||
default:
|
||||
observation = network.ReachabilityUnknown
|
||||
}
|
||||
|
||||
if observation.Reachability == network.ReachabilityPublic {
|
||||
log.Debugf("NAT status is public")
|
||||
as.recordObservation(observation)
|
||||
}
|
||||
|
||||
// recordObservation updates NAT status and confidence
|
||||
func (as *AmbientAutoNAT) recordObservation(observation network.Reachability) {
|
||||
|
||||
currentStatus := *as.status.Load()
|
||||
|
||||
if observation == network.ReachabilityPublic {
|
||||
changed := false
|
||||
if currentStatus.Reachability != network.ReachabilityPublic {
|
||||
if currentStatus != network.ReachabilityPublic {
|
||||
// Aggressively switch to public from other states ignoring confidence
|
||||
log.Debugf("NAT status is public")
|
||||
|
||||
// we are flipping our NATStatus, so confidence drops to 0
|
||||
as.confidence = 0
|
||||
|
@ -304,19 +310,20 @@ func (as *AmbientAutoNAT) recordObservation(observation autoNATResult) {
|
|||
as.service.Enable()
|
||||
}
|
||||
changed = true
|
||||
} else if as.confidence < 3 {
|
||||
} else if as.confidence < maxConfidence {
|
||||
as.confidence++
|
||||
}
|
||||
as.status.Store(&observation)
|
||||
if changed {
|
||||
as.emitStatus()
|
||||
}
|
||||
} else if observation.Reachability == network.ReachabilityPrivate {
|
||||
log.Debugf("NAT status is private")
|
||||
if currentStatus.Reachability != network.ReachabilityPrivate {
|
||||
} else if observation == network.ReachabilityPrivate {
|
||||
if currentStatus != network.ReachabilityPrivate {
|
||||
if as.confidence > 0 {
|
||||
as.confidence--
|
||||
} else {
|
||||
log.Debugf("NAT status is private")
|
||||
|
||||
// we are flipping our NATStatus, so confidence drops to 0
|
||||
as.confidence = 0
|
||||
as.status.Store(&observation)
|
||||
|
@ -325,7 +332,7 @@ func (as *AmbientAutoNAT) recordObservation(observation autoNATResult) {
|
|||
}
|
||||
as.emitStatus()
|
||||
}
|
||||
} else if as.confidence < 3 {
|
||||
} else if as.confidence < maxConfidence {
|
||||
as.confidence++
|
||||
as.status.Store(&observation)
|
||||
}
|
||||
|
@ -334,8 +341,8 @@ func (as *AmbientAutoNAT) recordObservation(observation autoNATResult) {
|
|||
as.confidence--
|
||||
} else {
|
||||
log.Debugf("NAT status is unknown")
|
||||
as.status.Store(&autoNATResult{network.ReachabilityUnknown, nil})
|
||||
if currentStatus.Reachability != network.ReachabilityUnknown {
|
||||
as.status.Store(&observation)
|
||||
if currentStatus != network.ReachabilityUnknown {
|
||||
if as.service != nil {
|
||||
as.service.Enable()
|
||||
}
|
||||
|
@ -376,23 +383,11 @@ func (as *AmbientAutoNAT) probe(pi *peer.AddrInfo) {
|
|||
ctx, cancel := context.WithTimeout(as.ctx, as.config.requestTimeout)
|
||||
defer cancel()
|
||||
|
||||
a, err := cli.DialBack(ctx, pi.ID)
|
||||
|
||||
var result autoNATResult
|
||||
switch {
|
||||
case err == nil:
|
||||
log.Debugf("Dialback through %s successful; public address is %s", pi.ID.Pretty(), a.String())
|
||||
result.Reachability = network.ReachabilityPublic
|
||||
result.address = a
|
||||
case IsDialError(err):
|
||||
log.Debugf("Dialback through %s failed", pi.ID.Pretty())
|
||||
result.Reachability = network.ReachabilityPrivate
|
||||
default:
|
||||
result.Reachability = network.ReachabilityUnknown
|
||||
}
|
||||
err := cli.DialBack(ctx, pi.ID)
|
||||
log.Debugf("Dialback through peer %s completed: err: %s", pi.ID, err)
|
||||
|
||||
select {
|
||||
case as.observations <- result:
|
||||
case as.dialResponses <- err:
|
||||
case <-as.ctx.Done():
|
||||
return
|
||||
}
|
||||
|
@ -430,8 +425,7 @@ func (as *AmbientAutoNAT) getPeerToProbe() peer.ID {
|
|||
return ""
|
||||
}
|
||||
|
||||
shufflePeers(candidates)
|
||||
return candidates[0]
|
||||
return candidates[rand.Intn(len(candidates))]
|
||||
}
|
||||
|
||||
func (as *AmbientAutoNAT) Close() error {
|
||||
|
@ -443,26 +437,11 @@ func (as *AmbientAutoNAT) Close() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func shufflePeers(peers []peer.ID) {
|
||||
for i := range peers {
|
||||
j := rand.Intn(i + 1)
|
||||
peers[i], peers[j] = peers[j], peers[i]
|
||||
}
|
||||
}
|
||||
|
||||
// Status returns the AutoNAT observed reachability status.
|
||||
func (s *StaticAutoNAT) Status() network.Reachability {
|
||||
return s.reachability
|
||||
}
|
||||
|
||||
// PublicAddr returns the publicly connectable Multiaddr of this node if one is known.
|
||||
func (s *StaticAutoNAT) PublicAddr() (ma.Multiaddr, error) {
|
||||
if s.reachability != network.ReachabilityPublic {
|
||||
return nil, errors.New("NAT status is not public")
|
||||
}
|
||||
return nil, errors.New("no available address")
|
||||
}
|
||||
|
||||
func (s *StaticAutoNAT) Close() error {
|
||||
if s.service != nil {
|
||||
s.service.Disable()
|
||||
|
|
|
@ -11,8 +11,6 @@ import (
|
|||
"github.com/libp2p/go-libp2p/p2p/host/autonat/pb"
|
||||
|
||||
"github.com/libp2p/go-msgio/pbio"
|
||||
|
||||
ma "github.com/multiformats/go-multiaddr"
|
||||
)
|
||||
|
||||
// NewAutoNATClient creates a fresh instance of an AutoNATClient
|
||||
|
@ -36,22 +34,22 @@ type client struct {
|
|||
// Note: A returned error Message_E_DIAL_ERROR does not imply that the server
|
||||
// actually performed a dial attempt. Servers that run a version < v0.20.0 also
|
||||
// return Message_E_DIAL_ERROR if the dial was skipped due to the dialPolicy.
|
||||
func (c *client) DialBack(ctx context.Context, p peer.ID) (ma.Multiaddr, error) {
|
||||
func (c *client) DialBack(ctx context.Context, p peer.ID) error {
|
||||
s, err := c.h.NewStream(ctx, p, AutoNATProto)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
|
||||
if err := s.Scope().SetService(ServiceName); err != nil {
|
||||
log.Debugf("error attaching stream to autonat service: %s", err)
|
||||
s.Reset()
|
||||
return nil, err
|
||||
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 nil, err
|
||||
return err
|
||||
}
|
||||
defer s.Scope().ReleaseMemory(maxMsgSize)
|
||||
|
||||
|
@ -66,17 +64,17 @@ func (c *client) DialBack(ctx context.Context, p peer.ID) (ma.Multiaddr, error)
|
|||
req := newDialMessage(peer.AddrInfo{ID: c.h.ID(), Addrs: c.addrFunc()})
|
||||
if err := w.WriteMsg(req); err != nil {
|
||||
s.Reset()
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
|
||||
var res pb.Message
|
||||
if err := r.ReadMsg(&res); err != nil {
|
||||
s.Reset()
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
if res.GetType() != pb.Message_DIAL_RESPONSE {
|
||||
s.Reset()
|
||||
return nil, fmt.Errorf("unexpected response: %s", res.GetType().String())
|
||||
return fmt.Errorf("unexpected response: %s", res.GetType().String())
|
||||
}
|
||||
|
||||
status := res.GetDialResponse().GetStatus()
|
||||
|
@ -85,10 +83,9 @@ func (c *client) DialBack(ctx context.Context, p peer.ID) (ma.Multiaddr, error)
|
|||
}
|
||||
switch status {
|
||||
case pb.Message_OK:
|
||||
addr := res.GetDialResponse().GetAddr()
|
||||
return ma.NewMultiaddrBytes(addr)
|
||||
return nil
|
||||
default:
|
||||
return nil, Error{Status: status, Text: res.GetDialResponse().GetStatusText()}
|
||||
return Error{Status: status, Text: res.GetDialResponse().GetStatusText()}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -14,9 +14,6 @@ import (
|
|||
type AutoNAT interface {
|
||||
// Status returns the current NAT status
|
||||
Status() network.Reachability
|
||||
// PublicAddr returns the public dial address when NAT status is public and an
|
||||
// error otherwise
|
||||
PublicAddr() (ma.Multiaddr, error)
|
||||
io.Closer
|
||||
}
|
||||
|
||||
|
@ -24,7 +21,7 @@ type AutoNAT interface {
|
|||
type Client interface {
|
||||
// DialBack requests from a peer providing AutoNAT services to test dial back
|
||||
// and report the address on a successful connection.
|
||||
DialBack(ctx context.Context, p peer.ID) (ma.Multiaddr, error)
|
||||
DialBack(ctx context.Context, p peer.ID) error
|
||||
}
|
||||
|
||||
// AddrFunc is a function returning the candidate addresses for the local host.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.28.1
|
||||
// protoc-gen-go v1.30.0
|
||||
// protoc v3.21.12
|
||||
// source: pb/autonat.proto
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ package autorelay
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"sync"
|
||||
|
||||
"github.com/libp2p/go-libp2p/core/event"
|
||||
|
@ -30,6 +31,8 @@ type AutoRelay struct {
|
|||
|
||||
host host.Host
|
||||
addrsF basic.AddrsFactory
|
||||
|
||||
metricsTracer MetricsTracer
|
||||
}
|
||||
|
||||
func NewAutoRelay(bhost *basic.BasicHost, opts ...Option) (*AutoRelay, error) {
|
||||
|
@ -47,6 +50,7 @@ func NewAutoRelay(bhost *basic.BasicHost, opts ...Option) (*AutoRelay, error) {
|
|||
r.ctx, r.ctxCancel = context.WithCancel(context.Background())
|
||||
r.conf = &conf
|
||||
r.relayFinder = newRelayFinder(bhost, conf.peerSource, &conf)
|
||||
r.metricsTracer = &wrappedMetricsTracer{conf.metricsTracer}
|
||||
bhost.AddrsFactory = r.hostAddrs
|
||||
|
||||
return r, nil
|
||||
|
@ -80,11 +84,17 @@ func (r *AutoRelay) background() {
|
|||
evt := ev.(event.EvtLocalReachabilityChanged)
|
||||
switch evt.Reachability {
|
||||
case network.ReachabilityPrivate, network.ReachabilityUnknown:
|
||||
if err := r.relayFinder.Start(); err != nil {
|
||||
err := r.relayFinder.Start()
|
||||
if errors.Is(err, errAlreadyRunning) {
|
||||
log.Debug("tried to start already running relay finder")
|
||||
} else if err != nil {
|
||||
log.Errorw("failed to start relay finder", "error", err)
|
||||
} else {
|
||||
r.metricsTracer.RelayFinderStatus(true)
|
||||
}
|
||||
case network.ReachabilityPublic:
|
||||
r.relayFinder.Stop()
|
||||
r.metricsTracer.RelayFinderStatus(false)
|
||||
}
|
||||
r.mx.Lock()
|
||||
r.status = evt.Reachability
|
||||
|
|
|
@ -0,0 +1,373 @@
|
|||
package autorelay
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/libp2p/go-libp2p/p2p/metricshelper"
|
||||
"github.com/libp2p/go-libp2p/p2p/protocol/circuitv2/client"
|
||||
pbv2 "github.com/libp2p/go-libp2p/p2p/protocol/circuitv2/pb"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
)
|
||||
|
||||
const metricNamespace = "libp2p_autorelay"
|
||||
|
||||
var (
|
||||
status = prometheus.NewGauge(prometheus.GaugeOpts{
|
||||
Namespace: metricNamespace,
|
||||
Name: "status",
|
||||
Help: "relay finder active",
|
||||
})
|
||||
reservationsOpenedTotal = prometheus.NewCounter(
|
||||
prometheus.CounterOpts{
|
||||
Namespace: metricNamespace,
|
||||
Name: "reservations_opened_total",
|
||||
Help: "Reservations Opened",
|
||||
},
|
||||
)
|
||||
reservationsClosedTotal = prometheus.NewCounter(
|
||||
prometheus.CounterOpts{
|
||||
Namespace: metricNamespace,
|
||||
Name: "reservations_closed_total",
|
||||
Help: "Reservations Closed",
|
||||
},
|
||||
)
|
||||
reservationRequestsOutcomeTotal = prometheus.NewCounterVec(
|
||||
prometheus.CounterOpts{
|
||||
Namespace: metricNamespace,
|
||||
Name: "reservation_requests_outcome_total",
|
||||
Help: "Reservation Request Outcome",
|
||||
},
|
||||
[]string{"request_type", "outcome"},
|
||||
)
|
||||
|
||||
relayAddressesUpdatedTotal = prometheus.NewCounter(
|
||||
prometheus.CounterOpts{
|
||||
Namespace: metricNamespace,
|
||||
Name: "relay_addresses_updated_total",
|
||||
Help: "Relay Addresses Updated Count",
|
||||
},
|
||||
)
|
||||
relayAddressesCount = prometheus.NewGauge(
|
||||
prometheus.GaugeOpts{
|
||||
Namespace: metricNamespace,
|
||||
Name: "relay_addresses_count",
|
||||
Help: "Relay Addresses Count",
|
||||
},
|
||||
)
|
||||
|
||||
candidatesCircuitV2SupportTotal = prometheus.NewCounterVec(
|
||||
prometheus.CounterOpts{
|
||||
Namespace: metricNamespace,
|
||||
Name: "candidates_circuit_v2_support_total",
|
||||
Help: "Candidiates supporting circuit v2",
|
||||
},
|
||||
[]string{"support"},
|
||||
)
|
||||
candidatesTotal = prometheus.NewCounterVec(
|
||||
prometheus.CounterOpts{
|
||||
Namespace: metricNamespace,
|
||||
Name: "candidates_total",
|
||||
Help: "Candidates Total",
|
||||
},
|
||||
[]string{"type"},
|
||||
)
|
||||
candLoopState = prometheus.NewGauge(
|
||||
prometheus.GaugeOpts{
|
||||
Namespace: metricNamespace,
|
||||
Name: "candidate_loop_state",
|
||||
Help: "Candidate Loop State",
|
||||
},
|
||||
)
|
||||
|
||||
scheduledWorkTime = prometheus.NewGaugeVec(
|
||||
prometheus.GaugeOpts{
|
||||
Namespace: metricNamespace,
|
||||
Name: "scheduled_work_time",
|
||||
Help: "Scheduled Work Times",
|
||||
},
|
||||
[]string{"work_type"},
|
||||
)
|
||||
|
||||
desiredReservations = prometheus.NewGauge(
|
||||
prometheus.GaugeOpts{
|
||||
Namespace: metricNamespace,
|
||||
Name: "desired_reservations",
|
||||
Help: "Desired Reservations",
|
||||
},
|
||||
)
|
||||
|
||||
collectors = []prometheus.Collector{
|
||||
status,
|
||||
reservationsOpenedTotal,
|
||||
reservationsClosedTotal,
|
||||
reservationRequestsOutcomeTotal,
|
||||
relayAddressesUpdatedTotal,
|
||||
relayAddressesCount,
|
||||
candidatesCircuitV2SupportTotal,
|
||||
candidatesTotal,
|
||||
candLoopState,
|
||||
scheduledWorkTime,
|
||||
desiredReservations,
|
||||
}
|
||||
)
|
||||
|
||||
type candidateLoopState int
|
||||
|
||||
const (
|
||||
peerSourceRateLimited candidateLoopState = iota
|
||||
waitingOnPeerChan
|
||||
waitingForTrigger
|
||||
stopped
|
||||
)
|
||||
|
||||
// MetricsTracer is the interface for tracking metrics for autorelay
|
||||
type MetricsTracer interface {
|
||||
RelayFinderStatus(isActive bool)
|
||||
|
||||
ReservationEnded(cnt int)
|
||||
ReservationOpened(cnt int)
|
||||
ReservationRequestFinished(isRefresh bool, err error)
|
||||
|
||||
RelayAddressCount(int)
|
||||
RelayAddressUpdated()
|
||||
|
||||
CandidateChecked(supportsCircuitV2 bool)
|
||||
CandidateAdded(cnt int)
|
||||
CandidateRemoved(cnt int)
|
||||
CandidateLoopState(state candidateLoopState)
|
||||
|
||||
ScheduledWorkUpdated(scheduledWork *scheduledWorkTimes)
|
||||
|
||||
DesiredReservations(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...)
|
||||
|
||||
// Initialise these counters to 0 otherwise the first reservation requests aren't handled
|
||||
// correctly when using promql increse function
|
||||
reservationRequestsOutcomeTotal.WithLabelValues("refresh", "success")
|
||||
reservationRequestsOutcomeTotal.WithLabelValues("new", "success")
|
||||
candidatesCircuitV2SupportTotal.WithLabelValues("yes")
|
||||
candidatesCircuitV2SupportTotal.WithLabelValues("no")
|
||||
return &metricsTracer{}
|
||||
}
|
||||
|
||||
func (mt *metricsTracer) RelayFinderStatus(isActive bool) {
|
||||
if isActive {
|
||||
status.Set(1)
|
||||
} else {
|
||||
status.Set(0)
|
||||
}
|
||||
}
|
||||
|
||||
func (mt *metricsTracer) ReservationEnded(cnt int) {
|
||||
reservationsClosedTotal.Add(float64(cnt))
|
||||
}
|
||||
|
||||
func (mt *metricsTracer) ReservationOpened(cnt int) {
|
||||
reservationsOpenedTotal.Add(float64(cnt))
|
||||
}
|
||||
|
||||
func (mt *metricsTracer) ReservationRequestFinished(isRefresh bool, err error) {
|
||||
tags := metricshelper.GetStringSlice()
|
||||
defer metricshelper.PutStringSlice(tags)
|
||||
|
||||
if isRefresh {
|
||||
*tags = append(*tags, "refresh")
|
||||
} else {
|
||||
*tags = append(*tags, "new")
|
||||
}
|
||||
*tags = append(*tags, getReservationRequestStatus(err))
|
||||
reservationRequestsOutcomeTotal.WithLabelValues(*tags...).Inc()
|
||||
|
||||
if !isRefresh && err == nil {
|
||||
reservationsOpenedTotal.Inc()
|
||||
}
|
||||
}
|
||||
|
||||
func (mt *metricsTracer) RelayAddressUpdated() {
|
||||
relayAddressesUpdatedTotal.Inc()
|
||||
}
|
||||
|
||||
func (mt *metricsTracer) RelayAddressCount(cnt int) {
|
||||
relayAddressesCount.Set(float64(cnt))
|
||||
}
|
||||
|
||||
func (mt *metricsTracer) CandidateChecked(supportsCircuitV2 bool) {
|
||||
tags := metricshelper.GetStringSlice()
|
||||
defer metricshelper.PutStringSlice(tags)
|
||||
if supportsCircuitV2 {
|
||||
*tags = append(*tags, "yes")
|
||||
} else {
|
||||
*tags = append(*tags, "no")
|
||||
}
|
||||
candidatesCircuitV2SupportTotal.WithLabelValues(*tags...).Inc()
|
||||
}
|
||||
|
||||
func (mt *metricsTracer) CandidateAdded(cnt int) {
|
||||
tags := metricshelper.GetStringSlice()
|
||||
defer metricshelper.PutStringSlice(tags)
|
||||
*tags = append(*tags, "added")
|
||||
candidatesTotal.WithLabelValues(*tags...).Add(float64(cnt))
|
||||
}
|
||||
|
||||
func (mt *metricsTracer) CandidateRemoved(cnt int) {
|
||||
tags := metricshelper.GetStringSlice()
|
||||
defer metricshelper.PutStringSlice(tags)
|
||||
*tags = append(*tags, "removed")
|
||||
candidatesTotal.WithLabelValues(*tags...).Add(float64(cnt))
|
||||
}
|
||||
|
||||
func (mt *metricsTracer) CandidateLoopState(state candidateLoopState) {
|
||||
candLoopState.Set(float64(state))
|
||||
}
|
||||
|
||||
func (mt *metricsTracer) ScheduledWorkUpdated(scheduledWork *scheduledWorkTimes) {
|
||||
tags := metricshelper.GetStringSlice()
|
||||
defer metricshelper.PutStringSlice(tags)
|
||||
|
||||
*tags = append(*tags, "allowed peer source call")
|
||||
scheduledWorkTime.WithLabelValues(*tags...).Set(float64(scheduledWork.nextAllowedCallToPeerSource.Unix()))
|
||||
*tags = (*tags)[:0]
|
||||
|
||||
*tags = append(*tags, "reservation refresh")
|
||||
scheduledWorkTime.WithLabelValues(*tags...).Set(float64(scheduledWork.nextRefresh.Unix()))
|
||||
*tags = (*tags)[:0]
|
||||
|
||||
*tags = append(*tags, "clear backoff")
|
||||
scheduledWorkTime.WithLabelValues(*tags...).Set(float64(scheduledWork.nextBackoff.Unix()))
|
||||
*tags = (*tags)[:0]
|
||||
|
||||
*tags = append(*tags, "old candidate check")
|
||||
scheduledWorkTime.WithLabelValues(*tags...).Set(float64(scheduledWork.nextOldCandidateCheck.Unix()))
|
||||
}
|
||||
|
||||
func (mt *metricsTracer) DesiredReservations(cnt int) {
|
||||
desiredReservations.Set(float64(cnt))
|
||||
}
|
||||
|
||||
func getReservationRequestStatus(err error) string {
|
||||
if err == nil {
|
||||
return "success"
|
||||
}
|
||||
|
||||
status := "err other"
|
||||
var re client.ReservationError
|
||||
if errors.As(err, &re) {
|
||||
switch re.Status {
|
||||
case pbv2.Status_CONNECTION_FAILED:
|
||||
return "connection failed"
|
||||
case pbv2.Status_MALFORMED_MESSAGE:
|
||||
return "malformed message"
|
||||
case pbv2.Status_RESERVATION_REFUSED:
|
||||
return "reservation refused"
|
||||
case pbv2.Status_PERMISSION_DENIED:
|
||||
return "permission denied"
|
||||
case pbv2.Status_RESOURCE_LIMIT_EXCEEDED:
|
||||
return "resource limit exceeded"
|
||||
}
|
||||
}
|
||||
return status
|
||||
}
|
||||
|
||||
// wrappedMetricsTracer wraps MetricsTracer and ignores all calls when mt is nil
|
||||
type wrappedMetricsTracer struct {
|
||||
mt MetricsTracer
|
||||
}
|
||||
|
||||
var _ MetricsTracer = &wrappedMetricsTracer{}
|
||||
|
||||
func (mt *wrappedMetricsTracer) RelayFinderStatus(isActive bool) {
|
||||
if mt.mt != nil {
|
||||
mt.mt.RelayFinderStatus(isActive)
|
||||
}
|
||||
}
|
||||
|
||||
func (mt *wrappedMetricsTracer) ReservationEnded(cnt int) {
|
||||
if mt.mt != nil {
|
||||
mt.mt.ReservationEnded(cnt)
|
||||
}
|
||||
}
|
||||
|
||||
func (mt *wrappedMetricsTracer) ReservationOpened(cnt int) {
|
||||
if mt.mt != nil {
|
||||
mt.mt.ReservationOpened(cnt)
|
||||
}
|
||||
}
|
||||
|
||||
func (mt *wrappedMetricsTracer) ReservationRequestFinished(isRefresh bool, err error) {
|
||||
if mt.mt != nil {
|
||||
mt.mt.ReservationRequestFinished(isRefresh, err)
|
||||
}
|
||||
}
|
||||
|
||||
func (mt *wrappedMetricsTracer) RelayAddressUpdated() {
|
||||
if mt.mt != nil {
|
||||
mt.mt.RelayAddressUpdated()
|
||||
}
|
||||
}
|
||||
|
||||
func (mt *wrappedMetricsTracer) RelayAddressCount(cnt int) {
|
||||
if mt.mt != nil {
|
||||
mt.mt.RelayAddressCount(cnt)
|
||||
}
|
||||
}
|
||||
|
||||
func (mt *wrappedMetricsTracer) CandidateChecked(supportsCircuitV2 bool) {
|
||||
if mt.mt != nil {
|
||||
mt.mt.CandidateChecked(supportsCircuitV2)
|
||||
}
|
||||
}
|
||||
|
||||
func (mt *wrappedMetricsTracer) CandidateAdded(cnt int) {
|
||||
if mt.mt != nil {
|
||||
mt.mt.CandidateAdded(cnt)
|
||||
}
|
||||
}
|
||||
|
||||
func (mt *wrappedMetricsTracer) CandidateRemoved(cnt int) {
|
||||
if mt.mt != nil {
|
||||
mt.mt.CandidateRemoved(cnt)
|
||||
}
|
||||
}
|
||||
|
||||
func (mt *wrappedMetricsTracer) ScheduledWorkUpdated(scheduledWork *scheduledWorkTimes) {
|
||||
if mt.mt != nil {
|
||||
mt.mt.ScheduledWorkUpdated(scheduledWork)
|
||||
}
|
||||
}
|
||||
|
||||
func (mt *wrappedMetricsTracer) DesiredReservations(cnt int) {
|
||||
if mt.mt != nil {
|
||||
mt.mt.DesiredReservations(cnt)
|
||||
}
|
||||
}
|
||||
|
||||
func (mt *wrappedMetricsTracer) CandidateLoopState(state candidateLoopState) {
|
||||
if mt.mt != nil {
|
||||
mt.mt.CandidateLoopState(state)
|
||||
}
|
||||
}
|
|
@ -40,6 +40,8 @@ type config struct {
|
|||
// see WithMaxCandidateAge
|
||||
maxCandidateAge time.Duration
|
||||
setMinCandidates bool
|
||||
// see WithMetricsTracer
|
||||
metricsTracer MetricsTracer
|
||||
}
|
||||
|
||||
var defaultConfig = config{
|
||||
|
@ -221,3 +223,11 @@ func WithMinInterval(interval time.Duration) Option {
|
|||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithMetricsTracer configures autorelay to use mt to track metrics
|
||||
func WithMetricsTracer(mt MetricsTracer) Option {
|
||||
return func(c *config) error {
|
||||
c.metricsTracer = mt
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
|
|
@ -80,8 +80,11 @@ type relayFinder struct {
|
|||
|
||||
// A channel that triggers a run of `runScheduledWork`.
|
||||
triggerRunScheduledWork chan struct{}
|
||||
metricsTracer MetricsTracer
|
||||
}
|
||||
|
||||
var errAlreadyRunning = errors.New("relayFinder already running")
|
||||
|
||||
func newRelayFinder(host *basic.BasicHost, peerSource PeerSource, conf *config) *relayFinder {
|
||||
if peerSource == nil {
|
||||
panic("Can not create a new relayFinder. Need a Peer Source fn or a list of static relays. Refer to the documentation around `libp2p.EnableAutoRelay`")
|
||||
|
@ -100,6 +103,7 @@ func newRelayFinder(host *basic.BasicHost, peerSource PeerSource, conf *config)
|
|||
triggerRunScheduledWork: make(chan struct{}, 1),
|
||||
relays: make(map[peer.ID]*circuitv2.Reservation),
|
||||
relayUpdated: make(chan struct{}, 1),
|
||||
metricsTracer: &wrappedMetricsTracer{conf.metricsTracer},
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -184,6 +188,7 @@ func (rf *relayFinder) background(ctx context.Context) {
|
|||
|
||||
if push {
|
||||
rf.clearCachedAddrsAndSignalAddressChange()
|
||||
rf.metricsTracer.ReservationEnded(1)
|
||||
}
|
||||
case <-rf.candidateFound:
|
||||
rf.notifyMaybeConnectToRelay()
|
||||
|
@ -211,6 +216,8 @@ func (rf *relayFinder) clearCachedAddrsAndSignalAddressChange() {
|
|||
rf.cachedAddrs = nil
|
||||
rf.relayMx.Unlock()
|
||||
rf.host.SignalAddressChange()
|
||||
|
||||
rf.metricsTracer.RelayAddressUpdated()
|
||||
}
|
||||
|
||||
func (rf *relayFinder) runScheduledWork(ctx context.Context, now time.Time, scheduledWork *scheduledWorkTimes, peerSourceRateLimiter chan<- struct{}) time.Time {
|
||||
|
@ -262,6 +269,8 @@ func (rf *relayFinder) runScheduledWork(ctx context.Context, now time.Time, sche
|
|||
nextTime = nextTime.Add(1) // avoids an infinite loop
|
||||
}
|
||||
|
||||
rf.metricsTracer.ScheduledWorkUpdated(scheduledWork)
|
||||
|
||||
return nextTime
|
||||
}
|
||||
|
||||
|
@ -281,10 +290,9 @@ func (rf *relayFinder) clearOldCandidates(now time.Time) time.Time {
|
|||
nextTime = expiry
|
||||
}
|
||||
} else {
|
||||
deleted = true
|
||||
log.Debugw("deleting candidate due to age", "id", id)
|
||||
delete(rf.candidates, id)
|
||||
|
||||
deleted = true
|
||||
rf.removeCandidate(id)
|
||||
}
|
||||
}
|
||||
if deleted {
|
||||
|
@ -330,6 +338,8 @@ func (rf *relayFinder) findNodes(ctx context.Context, peerSourceRateLimiter <-ch
|
|||
rf.candidateMx.Unlock()
|
||||
|
||||
if peerChan == nil && numCandidates < rf.conf.minCandidates {
|
||||
rf.metricsTracer.CandidateLoopState(peerSourceRateLimited)
|
||||
|
||||
select {
|
||||
case <-peerSourceRateLimiter:
|
||||
peerChan = rf.peerSource(ctx, rf.conf.maxCandidates)
|
||||
|
@ -342,6 +352,12 @@ func (rf *relayFinder) findNodes(ctx context.Context, peerSourceRateLimiter <-ch
|
|||
}
|
||||
}
|
||||
|
||||
if peerChan == nil {
|
||||
rf.metricsTracer.CandidateLoopState(waitingForTrigger)
|
||||
} else {
|
||||
rf.metricsTracer.CandidateLoopState(waitingOnPeerChan)
|
||||
}
|
||||
|
||||
select {
|
||||
case <-rf.maybeRequestNewCandidates:
|
||||
continue
|
||||
|
@ -374,6 +390,7 @@ func (rf *relayFinder) findNodes(ctx context.Context, peerSourceRateLimiter <-ch
|
|||
}
|
||||
}()
|
||||
case <-ctx.Done():
|
||||
rf.metricsTracer.CandidateLoopState(stopped)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
@ -417,23 +434,30 @@ func (rf *relayFinder) handleNewNode(ctx context.Context, pi peer.AddrInfo) (add
|
|||
supportsV2, err := rf.tryNode(ctx, pi)
|
||||
if err != nil {
|
||||
log.Debugf("node %s not accepted as a candidate: %s", pi.ID, err)
|
||||
if err == errProtocolNotSupported {
|
||||
rf.metricsTracer.CandidateChecked(false)
|
||||
}
|
||||
return false
|
||||
}
|
||||
rf.metricsTracer.CandidateChecked(true)
|
||||
|
||||
rf.candidateMx.Lock()
|
||||
if len(rf.candidates) > rf.conf.maxCandidates {
|
||||
rf.candidateMx.Unlock()
|
||||
return false
|
||||
}
|
||||
log.Debugw("node supports relay protocol", "peer", pi.ID, "supports circuit v2", supportsV2)
|
||||
rf.candidates[pi.ID] = &candidate{
|
||||
rf.addCandidate(&candidate{
|
||||
added: rf.conf.clock.Now(),
|
||||
ai: pi,
|
||||
supportsRelayV2: supportsV2,
|
||||
}
|
||||
})
|
||||
rf.candidateMx.Unlock()
|
||||
return true
|
||||
}
|
||||
|
||||
var errProtocolNotSupported = errors.New("doesn't speak circuit v2")
|
||||
|
||||
// tryNode checks if a peer actually supports either circuit v2.
|
||||
// It does not modify any internal state.
|
||||
func (rf *relayFinder) tryNode(ctx context.Context, pi peer.AddrInfo) (supportsRelayV2 bool, err error) {
|
||||
|
@ -474,7 +498,7 @@ func (rf *relayFinder) tryNode(ctx context.Context, pi peer.AddrInfo) (supportsR
|
|||
return false, fmt.Errorf("error checking relay protocol support for peer %s: %w", pi.ID, err)
|
||||
}
|
||||
if len(protos) == 0 {
|
||||
return false, errors.New("doesn't speak circuit v2")
|
||||
return false, errProtocolNotSupported
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
@ -483,19 +507,12 @@ func (rf *relayFinder) tryNode(ctx context.Context, pi peer.AddrInfo) (supportsR
|
|||
// This function makes sure that we only run one instance of maybeConnectToRelay at once, and buffers
|
||||
// exactly one more trigger event to run maybeConnectToRelay.
|
||||
func (rf *relayFinder) handleNewCandidates(ctx context.Context) {
|
||||
sem := make(chan struct{}, 1)
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case <-rf.maybeConnectToRelayTrigger:
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case sem <- struct{}{}:
|
||||
}
|
||||
rf.maybeConnectToRelay(ctx)
|
||||
<-sem
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -533,7 +550,7 @@ func (rf *relayFinder) maybeConnectToRelay(ctx context.Context) {
|
|||
rf.relayMx.Unlock()
|
||||
if usingRelay {
|
||||
rf.candidateMx.Lock()
|
||||
delete(rf.candidates, id)
|
||||
rf.removeCandidate(id)
|
||||
rf.candidateMx.Unlock()
|
||||
rf.notifyMaybeNeedNewCandidates()
|
||||
continue
|
||||
|
@ -542,6 +559,7 @@ func (rf *relayFinder) maybeConnectToRelay(ctx context.Context) {
|
|||
if err != nil {
|
||||
log.Debugw("failed to connect to relay", "peer", id, "error", err)
|
||||
rf.notifyMaybeNeedNewCandidates()
|
||||
rf.metricsTracer.ReservationRequestFinished(false, err)
|
||||
continue
|
||||
}
|
||||
log.Debugw("adding new relay", "id", id)
|
||||
|
@ -558,6 +576,8 @@ func (rf *relayFinder) maybeConnectToRelay(ctx context.Context) {
|
|||
default:
|
||||
}
|
||||
|
||||
rf.metricsTracer.ReservationRequestFinished(false, nil)
|
||||
|
||||
if numRelays >= rf.conf.desiredRelays {
|
||||
break
|
||||
}
|
||||
|
@ -576,7 +596,7 @@ func (rf *relayFinder) connectToRelay(ctx context.Context, cand *candidate) (*ci
|
|||
if rf.host.Network().Connectedness(id) != network.Connected {
|
||||
if err := rf.host.Connect(ctx, cand.ai); err != nil {
|
||||
rf.candidateMx.Lock()
|
||||
delete(rf.candidates, cand.ai.ID)
|
||||
rf.removeCandidate(cand.ai.ID)
|
||||
rf.candidateMx.Unlock()
|
||||
return nil, fmt.Errorf("failed to connect: %w", err)
|
||||
}
|
||||
|
@ -593,7 +613,7 @@ func (rf *relayFinder) connectToRelay(ctx context.Context, cand *candidate) (*ci
|
|||
}
|
||||
}
|
||||
rf.candidateMx.Lock()
|
||||
delete(rf.candidates, id)
|
||||
rf.removeCandidate(id)
|
||||
rf.candidateMx.Unlock()
|
||||
return rsvp, err
|
||||
}
|
||||
|
@ -609,7 +629,12 @@ func (rf *relayFinder) refreshReservations(ctx context.Context, now time.Time) b
|
|||
}
|
||||
|
||||
p := p
|
||||
g.Go(func() error { return rf.refreshRelayReservation(ctx, p) })
|
||||
g.Go(func() error {
|
||||
err := rf.refreshRelayReservation(ctx, p)
|
||||
rf.metricsTracer.ReservationRequestFinished(true, err)
|
||||
|
||||
return err
|
||||
})
|
||||
}
|
||||
rf.relayMx.Unlock()
|
||||
|
||||
|
@ -621,19 +646,22 @@ func (rf *relayFinder) refreshRelayReservation(ctx context.Context, p peer.ID) e
|
|||
rsvp, err := circuitv2.Reserve(ctx, rf.host, peer.AddrInfo{ID: p})
|
||||
|
||||
rf.relayMx.Lock()
|
||||
defer rf.relayMx.Unlock()
|
||||
|
||||
if err != nil {
|
||||
log.Debugw("failed to refresh relay slot reservation", "relay", p, "error", err)
|
||||
|
||||
_, exists := rf.relays[p]
|
||||
delete(rf.relays, p)
|
||||
// unprotect the connection
|
||||
rf.host.ConnManager().Unprotect(p, autorelayTag)
|
||||
rf.relayMx.Unlock()
|
||||
if exists {
|
||||
rf.metricsTracer.ReservationEnded(1)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
log.Debugw("refreshed relay slot reservation", "relay", p)
|
||||
rf.relays[p] = rsvp
|
||||
rf.relayMx.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -643,6 +671,23 @@ func (rf *relayFinder) usingRelay(p peer.ID) bool {
|
|||
return ok
|
||||
}
|
||||
|
||||
// addCandidates adds a candidate to the candidates set. Assumes caller holds candidateMx mutex
|
||||
func (rf *relayFinder) addCandidate(cand *candidate) {
|
||||
_, exists := rf.candidates[cand.ai.ID]
|
||||
rf.candidates[cand.ai.ID] = cand
|
||||
if !exists {
|
||||
rf.metricsTracer.CandidateAdded(1)
|
||||
}
|
||||
}
|
||||
|
||||
func (rf *relayFinder) removeCandidate(id peer.ID) {
|
||||
_, exists := rf.candidates[id]
|
||||
if exists {
|
||||
delete(rf.candidates, id)
|
||||
rf.metricsTracer.CandidateRemoved(1)
|
||||
}
|
||||
}
|
||||
|
||||
// selectCandidates returns an ordered slice of relay candidates.
|
||||
// Callers should attempt to obtain reservations with the candidates in this order.
|
||||
func (rf *relayFinder) selectCandidates() []*candidate {
|
||||
|
@ -687,9 +732,10 @@ func (rf *relayFinder) relayAddrs(addrs []ma.Multiaddr) []ma.Multiaddr {
|
|||
}
|
||||
|
||||
// add relay specific addrs to the list
|
||||
relayAddrCnt := 0
|
||||
for p := range rf.relays {
|
||||
addrs := cleanupAddressSet(rf.host.Peerstore().Addrs(p))
|
||||
|
||||
relayAddrCnt += len(addrs)
|
||||
circuit := ma.StringCast(fmt.Sprintf("/p2p/%s/p2p-circuit", p.Pretty()))
|
||||
for _, addr := range addrs {
|
||||
pub := addr.Encapsulate(circuit)
|
||||
|
@ -700,6 +746,7 @@ func (rf *relayFinder) relayAddrs(addrs []ma.Multiaddr) []ma.Multiaddr {
|
|||
rf.cachedAddrs = raddrs
|
||||
rf.cachedAddrsExpiry = rf.conf.clock.Now().Add(30 * time.Second)
|
||||
|
||||
rf.metricsTracer.RelayAddressCount(relayAddrCnt)
|
||||
return raddrs
|
||||
}
|
||||
|
||||
|
@ -707,9 +754,12 @@ func (rf *relayFinder) Start() error {
|
|||
rf.ctxCancelMx.Lock()
|
||||
defer rf.ctxCancelMx.Unlock()
|
||||
if rf.ctxCancel != nil {
|
||||
return errors.New("relayFinder already running")
|
||||
return errAlreadyRunning
|
||||
}
|
||||
log.Debug("starting relay finder")
|
||||
|
||||
rf.initMetrics()
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
rf.ctxCancel = cancel
|
||||
rf.refCount.Add(1)
|
||||
|
@ -729,5 +779,32 @@ func (rf *relayFinder) Stop() error {
|
|||
}
|
||||
rf.refCount.Wait()
|
||||
rf.ctxCancel = nil
|
||||
|
||||
rf.resetMetrics()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (rf *relayFinder) initMetrics() {
|
||||
rf.metricsTracer.DesiredReservations(rf.conf.desiredRelays)
|
||||
|
||||
rf.relayMx.Lock()
|
||||
rf.metricsTracer.ReservationOpened(len(rf.relays))
|
||||
rf.relayMx.Unlock()
|
||||
|
||||
rf.candidateMx.Lock()
|
||||
rf.metricsTracer.CandidateAdded(len(rf.candidates))
|
||||
rf.candidateMx.Unlock()
|
||||
}
|
||||
|
||||
func (rf *relayFinder) resetMetrics() {
|
||||
rf.relayMx.Lock()
|
||||
rf.metricsTracer.ReservationEnded(len(rf.relays))
|
||||
rf.relayMx.Unlock()
|
||||
|
||||
rf.candidateMx.Lock()
|
||||
rf.metricsTracer.CandidateRemoved(len(rf.candidates))
|
||||
rf.candidateMx.Unlock()
|
||||
|
||||
rf.metricsTracer.RelayAddressCount(0)
|
||||
rf.metricsTracer.ScheduledWorkUpdated(&scheduledWorkTimes{})
|
||||
}
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
package basichost
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"sort"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
|
@ -18,6 +20,7 @@ import (
|
|||
"github.com/libp2p/go-libp2p/core/peerstore"
|
||||
"github.com/libp2p/go-libp2p/core/protocol"
|
||||
"github.com/libp2p/go-libp2p/core/record"
|
||||
"github.com/libp2p/go-libp2p/core/transport"
|
||||
"github.com/libp2p/go-libp2p/p2p/host/autonat"
|
||||
"github.com/libp2p/go-libp2p/p2p/host/eventbus"
|
||||
"github.com/libp2p/go-libp2p/p2p/host/pstoremanager"
|
||||
|
@ -27,12 +30,12 @@ import (
|
|||
"github.com/libp2p/go-libp2p/p2p/protocol/holepunch"
|
||||
"github.com/libp2p/go-libp2p/p2p/protocol/identify"
|
||||
"github.com/libp2p/go-libp2p/p2p/protocol/ping"
|
||||
libp2pwebtransport "github.com/libp2p/go-libp2p/p2p/transport/webtransport"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
|
||||
"github.com/libp2p/go-netroute"
|
||||
|
||||
logging "github.com/ipfs/go-log/v2"
|
||||
|
||||
ma "github.com/multiformats/go-multiaddr"
|
||||
madns "github.com/multiformats/go-multiaddr-dns"
|
||||
manet "github.com/multiformats/go-multiaddr/net"
|
||||
|
@ -108,6 +111,9 @@ var _ host.Host = (*BasicHost)(nil)
|
|||
// HostOpts holds options that can be passed to NewHost in order to
|
||||
// customize construction of the *BasicHost.
|
||||
type HostOpts struct {
|
||||
// EventBus sets the event bus. Will construct a new event bus if omitted.
|
||||
EventBus event.Bus
|
||||
|
||||
// MultistreamMuxer is essential for the *BasicHost and will use a sensible default value if omitted.
|
||||
MultistreamMuxer *msmux.MultistreamMuxer[protocol.ID]
|
||||
|
||||
|
@ -164,16 +170,11 @@ func NewHost(n network.Network, opts *HostOpts) (*BasicHost, error) {
|
|||
if opts == nil {
|
||||
opts = &HostOpts{}
|
||||
}
|
||||
|
||||
var eventBus event.Bus
|
||||
if opts.EnableMetrics {
|
||||
eventBus = eventbus.NewBus(
|
||||
eventbus.WithMetricsTracer(eventbus.NewMetricsTracer(eventbus.WithRegisterer(opts.PrometheusRegisterer))))
|
||||
} else {
|
||||
eventBus = eventbus.NewBus()
|
||||
if opts.EventBus == nil {
|
||||
opts.EventBus = eventbus.NewBus()
|
||||
}
|
||||
|
||||
psManager, err := pstoremanager.NewPeerstoreManager(n.Peerstore(), eventBus)
|
||||
psManager, err := pstoremanager.NewPeerstoreManager(n.Peerstore(), opts.EventBus)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -186,7 +187,7 @@ func NewHost(n network.Network, opts *HostOpts) (*BasicHost, error) {
|
|||
negtimeout: DefaultNegotiationTimeout,
|
||||
AddrsFactory: DefaultAddrsFactory,
|
||||
maResolver: madns.DefaultResolver,
|
||||
eventbus: eventBus,
|
||||
eventbus: opts.EventBus,
|
||||
addrChangeChan: make(chan struct{}, 1),
|
||||
ctx: hostCtx,
|
||||
ctxCancel: cancel,
|
||||
|
@ -201,11 +202,6 @@ func NewHost(n network.Network, opts *HostOpts) (*BasicHost, error) {
|
|||
if h.emitters.evtLocalAddrsUpdated, err = h.eventbus.Emitter(&event.EvtLocalAddressesUpdated{}, eventbus.Stateful); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
evtPeerConnectednessChanged, err := h.eventbus.Emitter(&event.EvtPeerConnectednessChanged{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
h.Network().Notify(newPeerConnectWatcher(evtPeerConnectednessChanged))
|
||||
|
||||
if !h.disableSignedPeerRecord {
|
||||
cab, ok := peerstore.GetCertifiedAddrBook(n.Peerstore())
|
||||
|
@ -288,6 +284,13 @@ func NewHost(n network.Network, opts *HostOpts) (*BasicHost, error) {
|
|||
}
|
||||
|
||||
if opts.EnableRelayService {
|
||||
if opts.EnableMetrics {
|
||||
// Prefer explicitly provided metrics tracer
|
||||
metricsOpt := []relayv2.Option{
|
||||
relayv2.WithMetricsTracer(
|
||||
relayv2.NewMetricsTracer(relayv2.WithRegisterer(opts.PrometheusRegisterer)))}
|
||||
opts.RelayServiceOpts = append(metricsOpt, opts.RelayServiceOpts...)
|
||||
}
|
||||
h.relayManager = relaysvc.NewRelayManager(h, opts.RelayServiceOpts...)
|
||||
}
|
||||
|
||||
|
@ -636,8 +639,13 @@ func (h *BasicHost) NewStream(ctx context.Context, p peer.ID, pids ...protocol.I
|
|||
}
|
||||
}
|
||||
|
||||
s, err := h.Network().NewStream(ctx, p)
|
||||
s, err := h.Network().NewStream(network.WithNoDial(ctx, "already dialed"), p)
|
||||
if err != nil {
|
||||
// TODO: It would be nicer to get the actual error from the swarm,
|
||||
// but this will require some more work.
|
||||
if errors.Is(err, network.ErrNoConn) {
|
||||
return nil, errors.New("connection failed")
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
@ -756,21 +764,76 @@ func (h *BasicHost) ConnManager() connmgr.ConnManager {
|
|||
// Addrs returns listening addresses that are safe to announce to the network.
|
||||
// The output is the same as AllAddrs, but processed by AddrsFactory.
|
||||
func (h *BasicHost) Addrs() []ma.Multiaddr {
|
||||
return h.AddrsFactory(h.AllAddrs())
|
||||
// This is a temporary workaround/hack that fixes #2233. Once we have a
|
||||
// proper address pipeline, rework this. See the issue for more context.
|
||||
type transportForListeninger interface {
|
||||
TransportForListening(a ma.Multiaddr) transport.Transport
|
||||
}
|
||||
|
||||
type addCertHasher interface {
|
||||
AddCertHashes(m ma.Multiaddr) (ma.Multiaddr, bool)
|
||||
}
|
||||
|
||||
addrs := h.AddrsFactory(h.AllAddrs())
|
||||
|
||||
s, ok := h.Network().(transportForListeninger)
|
||||
if !ok {
|
||||
return addrs
|
||||
}
|
||||
|
||||
// Copy addrs slice since we'll be modifying it.
|
||||
addrsOld := addrs
|
||||
addrs = make([]ma.Multiaddr, len(addrsOld))
|
||||
copy(addrs, addrsOld)
|
||||
|
||||
for i, addr := range addrs {
|
||||
if ok, n := libp2pwebtransport.IsWebtransportMultiaddr(addr); ok && n == 0 {
|
||||
t := s.TransportForListening(addr)
|
||||
tpt, ok := t.(addCertHasher)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
addrWithCerthash, added := tpt.AddCertHashes(addr)
|
||||
addrs[i] = addrWithCerthash
|
||||
if !added {
|
||||
log.Debug("Couldn't add certhashes to webtransport multiaddr because we aren't listening on webtransport")
|
||||
}
|
||||
}
|
||||
}
|
||||
return addrs
|
||||
}
|
||||
|
||||
// mergeAddrs merges input address lists, leave only unique addresses
|
||||
func dedupAddrs(addrs []ma.Multiaddr) (uniqueAddrs []ma.Multiaddr) {
|
||||
exists := make(map[string]bool)
|
||||
for _, addr := range addrs {
|
||||
k := string(addr.Bytes())
|
||||
if exists[k] {
|
||||
continue
|
||||
// NormalizeMultiaddr returns a multiaddr suitable for equality checks.
|
||||
// If the multiaddr is a webtransport component, it removes the certhashes.
|
||||
func (h *BasicHost) NormalizeMultiaddr(addr ma.Multiaddr) ma.Multiaddr {
|
||||
if ok, n := libp2pwebtransport.IsWebtransportMultiaddr(addr); ok && n > 0 {
|
||||
out := addr
|
||||
for i := 0; i < n; i++ {
|
||||
out, _ = ma.SplitLast(out)
|
||||
}
|
||||
exists[k] = true
|
||||
uniqueAddrs = append(uniqueAddrs, addr)
|
||||
return out
|
||||
}
|
||||
return uniqueAddrs
|
||||
return addr
|
||||
}
|
||||
|
||||
// dedupAddrs deduplicates addresses in place, leave only unique addresses.
|
||||
// It doesn't allocate.
|
||||
func dedupAddrs(addrs []ma.Multiaddr) []ma.Multiaddr {
|
||||
if len(addrs) == 0 {
|
||||
return addrs
|
||||
}
|
||||
sort.Slice(addrs, func(i, j int) bool { return bytes.Compare(addrs[i].Bytes(), addrs[j].Bytes()) < 0 })
|
||||
idx := 1
|
||||
for i := 1; i < len(addrs); i++ {
|
||||
if !addrs[i-1].Equal(addrs[i]) {
|
||||
addrs[idx] = addrs[i]
|
||||
idx++
|
||||
}
|
||||
}
|
||||
for i := idx; i < len(addrs); i++ {
|
||||
addrs[i] = nil
|
||||
}
|
||||
return addrs[:idx]
|
||||
}
|
||||
|
||||
// AllAddrs returns all the addresses of BasicHost at this moment in time.
|
||||
|
@ -784,7 +847,6 @@ func (h *BasicHost) AllAddrs() []ma.Multiaddr {
|
|||
h.addrMu.RLock()
|
||||
filteredIfaceAddrs := h.filteredInterfaceAddrs
|
||||
allIfaceAddrs := h.allInterfaceAddrs
|
||||
autonat := h.autoNat
|
||||
h.addrMu.RUnlock()
|
||||
|
||||
// Iterate over all _unresolved_ listen addresses, resolving our primary
|
||||
|
@ -798,19 +860,6 @@ func (h *BasicHost) AllAddrs() []ma.Multiaddr {
|
|||
finalAddrs = append(finalAddrs, resolved...)
|
||||
}
|
||||
|
||||
// add autonat PublicAddr Consider the following scenario
|
||||
// For example, it is deployed on a cloud server,
|
||||
// it provides an elastic ip accessible to the public network,
|
||||
// but not have an external network card,
|
||||
// so net.InterfaceAddrs() not has the public ip
|
||||
// The host can indeed be dialed !!!
|
||||
if autonat != nil {
|
||||
publicAddr, _ := autonat.PublicAddr()
|
||||
if publicAddr != nil {
|
||||
finalAddrs = append(finalAddrs, publicAddr)
|
||||
}
|
||||
}
|
||||
|
||||
finalAddrs = dedupAddrs(finalAddrs)
|
||||
|
||||
var natMappings []inat.Mapping
|
||||
|
@ -961,8 +1010,83 @@ func (h *BasicHost) AllAddrs() []ma.Multiaddr {
|
|||
}
|
||||
finalAddrs = append(finalAddrs, observedAddrs...)
|
||||
}
|
||||
finalAddrs = dedupAddrs(finalAddrs)
|
||||
finalAddrs = inferWebtransportAddrsFromQuic(finalAddrs)
|
||||
|
||||
return dedupAddrs(finalAddrs)
|
||||
return finalAddrs
|
||||
}
|
||||
|
||||
var wtComponent = ma.StringCast("/webtransport")
|
||||
|
||||
// inferWebtransportAddrsFromQuic infers more webtransport addresses from QUIC addresses.
|
||||
// This is useful when we discover our public QUIC address, but haven't discovered our public WebTransport addrs.
|
||||
// If we see that we are listening on the same port for QUIC and WebTransport,
|
||||
// we can be pretty sure that the WebTransport addr will be reachable if the
|
||||
// QUIC one is.
|
||||
// We assume the input is deduped.
|
||||
func inferWebtransportAddrsFromQuic(in []ma.Multiaddr) []ma.Multiaddr {
|
||||
// We need to check if we are listening on the same ip+port for QUIC and WebTransport.
|
||||
// If not, there's nothing to do since we can't infer anything.
|
||||
|
||||
// Count the number of QUIC addrs, this will let us allocate just once at the beginning.
|
||||
quicAddrCount := 0
|
||||
for _, addr := range in {
|
||||
if _, lastComponent := ma.SplitLast(addr); lastComponent.Protocol().Code == ma.P_QUIC_V1 {
|
||||
quicAddrCount++
|
||||
}
|
||||
}
|
||||
quicOrWebtransportAddrs := make(map[string]struct{}, quicAddrCount)
|
||||
webtransportAddrs := make(map[string]struct{}, quicAddrCount)
|
||||
foundSameListeningAddr := false
|
||||
for _, addr := range in {
|
||||
isWebtransport, numCertHashes := libp2pwebtransport.IsWebtransportMultiaddr(addr)
|
||||
if isWebtransport {
|
||||
for i := 0; i < numCertHashes; i++ {
|
||||
// Remove certhashes
|
||||
addr, _ = ma.SplitLast(addr)
|
||||
}
|
||||
webtransportAddrs[addr.String()] = struct{}{}
|
||||
// Remove webtransport component, now it's a multiaddr that ends in /quic-v1
|
||||
addr, _ = ma.SplitLast(addr)
|
||||
}
|
||||
|
||||
if _, lastComponent := ma.SplitLast(addr); lastComponent.Protocol().Code == ma.P_QUIC_V1 {
|
||||
addrStr := addr.String()
|
||||
if _, ok := quicOrWebtransportAddrs[addrStr]; ok {
|
||||
foundSameListeningAddr = true
|
||||
} else {
|
||||
quicOrWebtransportAddrs[addrStr] = struct{}{}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !foundSameListeningAddr {
|
||||
return in
|
||||
}
|
||||
|
||||
if len(webtransportAddrs) == 0 {
|
||||
// No webtransport addresses, we aren't listening on any webtransport
|
||||
// address, so we shouldn't add any.
|
||||
return in
|
||||
}
|
||||
|
||||
out := make([]ma.Multiaddr, 0, len(in)+(quicAddrCount-len(webtransportAddrs)))
|
||||
for _, addr := range in {
|
||||
// Add all the original addresses
|
||||
out = append(out, addr)
|
||||
if _, lastComponent := ma.SplitLast(addr); lastComponent.Protocol().Code == ma.P_QUIC_V1 {
|
||||
// Convert quic to webtransport
|
||||
addr = addr.Encapsulate(wtComponent)
|
||||
if _, ok := webtransportAddrs[addr.String()]; ok {
|
||||
// We already have this address
|
||||
continue
|
||||
}
|
||||
// Add the new inferred address
|
||||
out = append(out, addr)
|
||||
}
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
// SetAutoNat sets the autonat service for the host.
|
||||
|
|
|
@ -1,71 +0,0 @@
|
|||
package basichost
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/libp2p/go-libp2p/core/event"
|
||||
"github.com/libp2p/go-libp2p/core/network"
|
||||
"github.com/libp2p/go-libp2p/core/peer"
|
||||
|
||||
ma "github.com/multiformats/go-multiaddr"
|
||||
)
|
||||
|
||||
type peerConnectWatcher struct {
|
||||
emitter event.Emitter
|
||||
|
||||
mutex sync.Mutex
|
||||
connected map[peer.ID]struct{}
|
||||
}
|
||||
|
||||
var _ network.Notifiee = &peerConnectWatcher{}
|
||||
|
||||
func newPeerConnectWatcher(emitter event.Emitter) *peerConnectWatcher {
|
||||
return &peerConnectWatcher{
|
||||
emitter: emitter,
|
||||
connected: make(map[peer.ID]struct{}),
|
||||
}
|
||||
}
|
||||
|
||||
func (w *peerConnectWatcher) Listen(network.Network, ma.Multiaddr) {}
|
||||
func (w *peerConnectWatcher) ListenClose(network.Network, ma.Multiaddr) {}
|
||||
|
||||
func (w *peerConnectWatcher) Connected(n network.Network, conn network.Conn) {
|
||||
p := conn.RemotePeer()
|
||||
w.handleTransition(p, n.Connectedness(p))
|
||||
}
|
||||
|
||||
func (w *peerConnectWatcher) Disconnected(n network.Network, conn network.Conn) {
|
||||
p := conn.RemotePeer()
|
||||
w.handleTransition(p, n.Connectedness(p))
|
||||
}
|
||||
|
||||
func (w *peerConnectWatcher) handleTransition(p peer.ID, state network.Connectedness) {
|
||||
if changed := w.checkTransition(p, state); !changed {
|
||||
return
|
||||
}
|
||||
w.emitter.Emit(event.EvtPeerConnectednessChanged{
|
||||
Peer: p,
|
||||
Connectedness: state,
|
||||
})
|
||||
}
|
||||
|
||||
func (w *peerConnectWatcher) checkTransition(p peer.ID, state network.Connectedness) bool {
|
||||
w.mutex.Lock()
|
||||
defer w.mutex.Unlock()
|
||||
switch state {
|
||||
case network.Connected:
|
||||
if _, ok := w.connected[p]; ok {
|
||||
return false
|
||||
}
|
||||
w.connected[p] = struct{}{}
|
||||
return true
|
||||
case network.NotConnected:
|
||||
if _, ok := w.connected[p]; ok {
|
||||
delete(w.connected, p)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue