chore: upgrade libp2p

This commit is contained in:
Richard Ramos 2023-05-19 16:23:55 -04:00 committed by RichΛrd
parent 3e4fe1e12f
commit b1a6607dbb
336 changed files with 10407 additions and 5067 deletions

View File

@ -1 +1 @@
0.153
0.153.0

62
go.mod
View File

@ -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
View File

@ -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=

View File

@ -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

View File

@ -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

View File

@ -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 {

View File

@ -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
}

View File

@ -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

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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) {

View File

@ -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 {

View File

@ -1,3 +1,6 @@
# Copyright (c) HashiCorp, Inc.
# SPDX-License-Identifier: MPL-2.0
linters:
enable:
- megacheck

View File

@ -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
}

View File

@ -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)
}

View File

@ -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{}{})
}
}
}

View File

@ -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

View File

@ -1,3 +1,6 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package lru
import (

View File

@ -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)
}
}

View File

@ -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

View File

@ -1,3 +1,6 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package lru
import (

View File

@ -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.

View File

@ -1,2 +1,2 @@
//go:generate goupnpdcpgen -dcp_name internetgateway1
//go:generate goupnpdcpgen -dcp_name internetgateway1 -code_tmpl_file ../dcps.gotemplate
package internetgateway1

View File

@ -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

View File

@ -1,2 +1,2 @@
//go:generate goupnpdcpgen -dcp_name internetgateway2
//go:generate goupnpdcpgen -dcp_name internetgateway2 -code_tmpl_file ../dcps.gotemplate
package internetgateway2

View File

@ -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

View File

@ -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) {

6
vendor/github.com/huin/goupnp/go.work generated vendored Normal file
View File

@ -0,0 +1,6 @@
go 1.18
use (
.
./v2alpha
)

View File

@ -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
}

View File

@ -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)
}()
}
}

View File

@ -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).

View File

@ -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"},
}

View File

@ -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)
}

11
vendor/github.com/huin/goupnp/workspace.code-workspace generated vendored Normal file
View File

@ -0,0 +1,11 @@
{
"folders": [
{
"path": "."
},
{
"path": "v2alpha"
}
],
"settings": {}
}

View File

@ -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
}

102
vendor/github.com/ipfs/go-cid/cid.go generated vendored
View File

@ -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

View File

@ -1,3 +1,3 @@
{
"version": "v0.3.2"
"version": "v0.4.1"
}

View File

@ -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:
-

View File

@ -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

View File

@ -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.

View File

@ -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 {

View File

@ -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 {

View File

@ -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")

View File

@ -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.

View File

@ -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)

View File

@ -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.

View File

@ -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:]

View File

@ -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())

View File

@ -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
}

View File

@ -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
}

View File

@ -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) {

View File

@ -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)
}
}

View File

@ -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

View File

@ -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()
}
}
}

View File

@ -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)
}

View File

@ -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)

View File

@ -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

View File

@ -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 {

View File

@ -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 |

View File

@ -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)

View File

@ -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) {

View File

@ -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

View File

@ -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
}

View File

@ -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

View File

@ -1,4 +1,4 @@
/*
Package ssdp provides ...
Package ssdp provides SSDP advertiser or so.
*/
package ssdp

View File

@ -0,0 +1,4 @@
/*
Package multicast provides utilities for network multicast.
*/
package multicast

View File

@ -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()

View File

@ -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))

View File

@ -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
}

View File

@ -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...)
}
}
}

40
vendor/github.com/koron/go-ssdp/location.go generated vendored Normal file
View File

@ -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)
}
}

View File

@ -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...)
}
}

View File

@ -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
}

View File

@ -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
}

37
vendor/github.com/koron/go-ssdp/ssdp.go generated vendored Normal file
View File

@ -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)
}

View File

@ -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
}

View File

@ -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
}

View File

@ -1,3 +1,3 @@
{
"version": "v0.2.0"
"version": "v0.3.0"
}

View File

@ -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 -->

View File

@ -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

20
vendor/github.com/libp2p/go-libp2p/SECURITY.md generated vendored Normal file
View File

@ -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).

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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{}

View File

@ -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

View File

@ -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 {

View File

@ -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()

View File

@ -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()}
}
}

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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)
}
}

View File

@ -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
}
}

View File

@ -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{})
}

View File

@ -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.

View File

@ -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