mirror of
https://github.com/DNSCrypt/dnscrypt-proxy.git
synced 2024-09-11 21:17:40 +03:00
Update deps
This commit is contained in:
parent
f4389559ef
commit
4aa415de6e
30
go.mod
30
go.mod
@ -3,7 +3,7 @@ module github.com/dnscrypt/dnscrypt-proxy
|
||||
go 1.19
|
||||
|
||||
require (
|
||||
github.com/BurntSushi/toml v1.2.0
|
||||
github.com/BurntSushi/toml v1.2.1
|
||||
github.com/VividCortex/ewma v1.2.0
|
||||
github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf
|
||||
github.com/dchest/safefile v0.0.0-20151022103144-855e8d98f185
|
||||
@ -18,12 +18,12 @@ require (
|
||||
github.com/jedisct1/xsecretbox v0.0.0-20210927135450-ebe41aef7bef
|
||||
github.com/k-sone/critbitgo v1.4.0
|
||||
github.com/kardianos/service v1.2.2
|
||||
github.com/lucas-clemente/quic-go v0.29.2
|
||||
github.com/lucas-clemente/quic-go v0.30.0
|
||||
github.com/miekg/dns v1.1.50
|
||||
github.com/powerman/check v1.6.0
|
||||
golang.org/x/crypto v0.0.0-20221012134737-56aed061732a
|
||||
golang.org/x/net v0.0.0-20221014081412-f15817d10f9b
|
||||
golang.org/x/sys v0.0.0-20221013171732-95e765b1cc43
|
||||
golang.org/x/crypto v0.1.0
|
||||
golang.org/x/net v0.1.0
|
||||
golang.org/x/sys v0.1.0
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0
|
||||
)
|
||||
|
||||
@ -63,7 +63,7 @@ require (
|
||||
github.com/gobwas/glob v0.2.3 // indirect
|
||||
github.com/gofrs/flock v0.8.0 // indirect
|
||||
github.com/golang/mock v1.6.0 // indirect
|
||||
github.com/golang/protobuf v1.5.0 // indirect
|
||||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
github.com/golangci/check v0.0.0-20180506172741-cfe4005ccda2 // indirect
|
||||
github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a // indirect
|
||||
github.com/golangci/go-misc v0.0.0-20180628070357-927a3d87b613 // indirect
|
||||
@ -75,6 +75,7 @@ require (
|
||||
github.com/golangci/revgrep v0.0.0-20210208091834-cd28932614b5 // indirect
|
||||
github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4 // indirect
|
||||
github.com/google/go-cmp v0.5.8 // indirect
|
||||
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 // indirect
|
||||
github.com/gordonklaus/ineffassign v0.0.0-20210225214923-2e10b2664254 // indirect
|
||||
github.com/gostaticanalysis/analysisutil v0.4.1 // indirect
|
||||
github.com/gostaticanalysis/comment v1.4.1 // indirect
|
||||
@ -98,7 +99,7 @@ require (
|
||||
github.com/ldez/tagliatelle v0.2.0 // indirect
|
||||
github.com/magiconair/properties v1.8.1 // indirect
|
||||
github.com/maratori/testpackage v1.0.1 // indirect
|
||||
github.com/marten-seemann/qpack v0.2.1 // indirect
|
||||
github.com/marten-seemann/qpack v0.3.0 // indirect
|
||||
github.com/marten-seemann/qtls-go1-18 v0.1.3 // indirect
|
||||
github.com/marten-seemann/qtls-go1-19 v0.1.1 // indirect
|
||||
github.com/matoous/godox v0.0.0-20210227103229-6504466cf951 // indirect
|
||||
@ -117,9 +118,8 @@ require (
|
||||
github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354 // indirect
|
||||
github.com/nishanths/exhaustive v0.1.0 // indirect
|
||||
github.com/nishanths/predeclared v0.2.1 // indirect
|
||||
github.com/nxadm/tail v1.4.8 // indirect
|
||||
github.com/olekukonko/tablewriter v0.0.5 // indirect
|
||||
github.com/onsi/ginkgo v1.16.4 // indirect
|
||||
github.com/onsi/ginkgo/v2 v2.2.0 // indirect
|
||||
github.com/pelletier/go-toml v1.2.0 // indirect
|
||||
github.com/phayes/checkstyle v0.0.0-20170904204023-bfd46e6a821d // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
@ -161,17 +161,15 @@ require (
|
||||
github.com/uudashr/gocognit v1.0.1 // indirect
|
||||
github.com/yeya24/promlinter v0.1.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e // indirect
|
||||
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect
|
||||
golang.org/x/text v0.3.7 // indirect
|
||||
golang.org/x/tools v0.1.10 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
|
||||
golang.org/x/text v0.4.0 // indirect
|
||||
golang.org/x/tools v0.1.12 // indirect
|
||||
google.golang.org/genproto v0.0.0-20200707001353-8e8330bf89df // indirect
|
||||
google.golang.org/grpc v1.38.0 // indirect
|
||||
google.golang.org/protobuf v1.27.0 // indirect
|
||||
google.golang.org/protobuf v1.28.0 // indirect
|
||||
gopkg.in/ini.v1 v1.51.0 // indirect
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
honnef.co/go/tools v0.2.0 // indirect
|
||||
mvdan.cc/gofumpt v0.1.1 // indirect
|
||||
mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed // indirect
|
||||
|
62
go.sum
62
go.sum
@ -37,8 +37,8 @@ cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RX
|
||||
contrib.go.opencensus.io/exporter/stackdriver v0.13.4/go.mod h1:aXENhDJ1Y4lIg4EUaVTwzvYETVNZk10Pu26tevFKLUc=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/toml v1.2.0 h1:Rt8g24XnyGTyglgET/PRUNlrUeu9F5L+7FilkXfZgs0=
|
||||
github.com/BurntSushi/toml v1.2.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
||||
github.com/BurntSushi/toml v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak=
|
||||
github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24 h1:sHglBQTwgx+rWPdisA5ynNEsoARbiCBOyGcJM4/OzsM=
|
||||
github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24/go.mod h1:4UJr5HIiMZrwgkSPdsjy2uOQExX/WEILpIrO9UPGuXs=
|
||||
@ -229,8 +229,9 @@ github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvq
|
||||
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.5.0 h1:LUVKkCeviFUMKqHa4tXIIij/lbhnMbP7Fn5wKdKkRh4=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
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/golangci/check v0.0.0-20180506172741-cfe4005ccda2 h1:23T5iq8rbUYlhpt5DB4XJkc6BU31uODLD1o1gKvZmD0=
|
||||
github.com/golangci/check v0.0.0-20180506172741-cfe4005ccda2/go.mod h1:k9Qvh+8juN+UKMCS/3jFtGICgW8O96FVaZsaxdzDkR4=
|
||||
github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a h1:w8hkcTqaFpzKqonE9uMCefW1WDie15eSP/4MssdenaM=
|
||||
@ -275,6 +276,8 @@ github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hf
|
||||
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200507031123-427632fa3b1c/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE=
|
||||
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/trillian v1.3.11/go.mod h1:0tPraVHrSDkA3BO6vKX67zgLXs6SsOAbHEivX+9mPgw=
|
||||
github.com/google/uuid v0.0.0-20161128191214-064e2069ce9c/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
@ -350,6 +353,7 @@ github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpO
|
||||
github.com/huandu/xstrings v1.0.0/go.mod h1:4qWG/gcEcfX4z/mBDHJ++3ReCw9ibxbsNJbcucJdbSo=
|
||||
github.com/huandu/xstrings v1.2.0/go.mod h1:DvyZB1rfVYsBIigL8HwpZgxHwXozlTgGqn63UyNX5k4=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/imdario/mergo v0.3.4/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
||||
github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
||||
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
|
||||
@ -428,15 +432,15 @@ github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.8.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/lib/pq v1.9.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
|
||||
github.com/lucas-clemente/quic-go v0.29.2 h1:O8Mt0O6LpvEW+wfC40vZdcw0DngwYzoxq5xULZNzSI8=
|
||||
github.com/lucas-clemente/quic-go v0.29.2/go.mod h1:g6/h9YMmLuU54tL1gW25uIi3VlBp3uv+sBihplIuskE=
|
||||
github.com/lucas-clemente/quic-go v0.30.0 h1:nwLW0h8ahVQ5EPTIM7uhl/stHqQDea15oRlYKZmw2O0=
|
||||
github.com/lucas-clemente/quic-go v0.30.0/go.mod h1:ssOrRsOmdxa768Wr78vnh2B8JozgLsMzG/g+0qEC7uk=
|
||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
|
||||
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/maratori/testpackage v1.0.1 h1:QtJ5ZjqapShm0w5DosRjg0PRlSdAdlx+W6cCKoALdbQ=
|
||||
github.com/maratori/testpackage v1.0.1/go.mod h1:ddKdw+XG0Phzhx8BFDTKgpWP4i7MpApTE5fXSKAqwDU=
|
||||
github.com/marten-seemann/qpack v0.2.1 h1:jvTsT/HpCn2UZJdP+UUB53FfUUgeOyG5K1ns0OJOGVs=
|
||||
github.com/marten-seemann/qpack v0.2.1/go.mod h1:F7Gl5L1jIgN1D11ucXefiuJS9UMVP2opoCp2jDKb7wc=
|
||||
github.com/marten-seemann/qpack v0.3.0 h1:UiWstOgT8+znlkDPOg2+3rIuYXJ2CnGDkGUXN6ki6hE=
|
||||
github.com/marten-seemann/qpack v0.3.0/go.mod h1:cGfKPBiP4a9EQdxCwEwI/GEeWAsjSekBvx/X8mh58+g=
|
||||
github.com/marten-seemann/qtls-go1-18 v0.1.3 h1:R4H2Ks8P6pAtUagjFty2p7BVHn3XiwDAl7TTQf5h7TI=
|
||||
github.com/marten-seemann/qtls-go1-18 v0.1.3/go.mod h1:mJttiymBAByA49mhlNZZGrH5u1uXYZJ+RW28Py7f4m4=
|
||||
github.com/marten-seemann/qtls-go1-19 v0.1.1 h1:mnbxeq3oEyQxQXwI4ReCgW9DPoPR94sNlqWoDZnjRIE=
|
||||
@ -526,14 +530,14 @@ github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
|
||||
github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
|
||||
github.com/onsi/ginkgo v1.16.1 h1:foqVmeWDD6yYpK+Yz3fHyNIxFYNxswxqNFjSKe+vI54=
|
||||
github.com/onsi/ginkgo v1.16.1/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E=
|
||||
github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc=
|
||||
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
|
||||
github.com/onsi/ginkgo/v2 v2.2.0 h1:3ZNA3L1c5FYDFTTxbFeVGGD8jYvjYauHD30YgLxVsNI=
|
||||
github.com/onsi/ginkgo/v2 v2.2.0/go.mod h1:MEH45j8TBi6u9BMogfbp0stKC5cdGjumZj5Y7AG4VIk=
|
||||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
||||
github.com/onsi/gomega v1.11.0/go.mod h1:azGKhqFUon9Vuj0YmTfLSmx0FUwqXYSTl5re8lQLTUg=
|
||||
github.com/onsi/gomega v1.13.0 h1:7lLHu94wT9Ij0o6EWWclhu0aOh32VxhkwEJvzuWPeak=
|
||||
github.com/onsi/gomega v1.20.1 h1:PA/3qinGoukvymdIDV8pii6tiZgC8kbmJO6Z5+b002Q=
|
||||
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
|
||||
@ -735,8 +739,8 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||
golang.org/x/crypto v0.0.0-20221012134737-56aed061732a h1:NmSIgad6KjE6VvHciPZuNRTKxGhlPfD6OA87W/PLkqg=
|
||||
golang.org/x/crypto v0.0.0-20221012134737-56aed061732a/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU=
|
||||
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
@ -773,8 +777,8 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
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.6.0-dev.0.20220106191415-9b9b3d81d5e3 h1:kQgndtyPBW/JIYERgdxfwMYh3AVStj88WQTlNDi2a+o=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
@ -810,7 +814,6 @@ golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/
|
||||
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
@ -818,8 +821,8 @@ golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwY
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20221014081412-f15817d10f9b h1:tvrvnPFcdzp294diPnrdZZZ8XUt2Tyj7svb7X52iDuU=
|
||||
golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
||||
golang.org/x/net v0.1.0 h1:hZ/3BUoy5aId7sCpA/Tc5lt8DkFgdVS2onTpJsZ/fl0=
|
||||
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
@ -835,8 +838,8 @@ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJ
|
||||
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 h1:uVc8UZUe6tr40fFVnUP5Oj+veunVezqYl9z7DYw9xzw=
|
||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@ -880,7 +883,6 @@ golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@ -895,8 +897,8 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20221013171732-95e765b1cc43 h1:OK7RB6t2WQX54srQQYSXMW8dF5C6/8+oA/s5QBmmto4=
|
||||
golang.org/x/sys v0.0.0-20221013171732-95e765b1cc43/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U=
|
||||
golang.org/x/sys v0.1.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/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
@ -906,8 +908,8 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg=
|
||||
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
@ -1000,12 +1002,11 @@ golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
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.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.10 h1:QjFRCZxdOhBJ/UNgnBZLbNV13DlbnK0quyivTnXJM20=
|
||||
golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
|
||||
golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
||||
@ -1089,8 +1090,10 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD
|
||||
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
|
||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.27.0 h1:KhgSLlr/moiqjv0qUsSnLvdUL7NH7PHW8aZGn7Jpjko=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.27.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
|
||||
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
@ -1122,8 +1125,9 @@ gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
|
42
vendor/github.com/BurntSushi/toml/decode.go
generated
vendored
42
vendor/github.com/BurntSushi/toml/decode.go
generated
vendored
@ -21,7 +21,9 @@ type Unmarshaler interface {
|
||||
UnmarshalTOML(interface{}) error
|
||||
}
|
||||
|
||||
// Unmarshal decodes the contents of `data` in TOML format into a pointer `v`.
|
||||
// Unmarshal decodes the contents of data in TOML format into a pointer v.
|
||||
//
|
||||
// See [Decoder] for a description of the decoding process.
|
||||
func Unmarshal(data []byte, v interface{}) error {
|
||||
_, err := NewDecoder(bytes.NewReader(data)).Decode(v)
|
||||
return err
|
||||
@ -29,13 +31,12 @@ func Unmarshal(data []byte, v interface{}) error {
|
||||
|
||||
// Decode the TOML data in to the pointer v.
|
||||
//
|
||||
// See the documentation on Decoder for a description of the decoding process.
|
||||
// See [Decoder] for a description of the decoding process.
|
||||
func Decode(data string, v interface{}) (MetaData, error) {
|
||||
return NewDecoder(strings.NewReader(data)).Decode(v)
|
||||
}
|
||||
|
||||
// DecodeFile is just like Decode, except it will automatically read the
|
||||
// contents of the file at path and decode it for you.
|
||||
// DecodeFile reads the contents of a file and decodes it with [Decode].
|
||||
func DecodeFile(path string, v interface{}) (MetaData, error) {
|
||||
fp, err := os.Open(path)
|
||||
if err != nil {
|
||||
@ -48,7 +49,7 @@ func DecodeFile(path string, v interface{}) (MetaData, error) {
|
||||
// Primitive is a TOML value that hasn't been decoded into a Go value.
|
||||
//
|
||||
// This type can be used for any value, which will cause decoding to be delayed.
|
||||
// You can use the PrimitiveDecode() function to "manually" decode these values.
|
||||
// You can use [PrimitiveDecode] to "manually" decode these values.
|
||||
//
|
||||
// NOTE: The underlying representation of a `Primitive` value is subject to
|
||||
// change. Do not rely on it.
|
||||
@ -70,15 +71,15 @@ type Primitive struct {
|
||||
|
||||
// Decoder decodes TOML data.
|
||||
//
|
||||
// TOML tables correspond to Go structs or maps (dealer's choice – they can be
|
||||
// used interchangeably).
|
||||
// TOML tables correspond to Go structs or maps; they can be used
|
||||
// interchangeably, but structs offer better type safety.
|
||||
//
|
||||
// TOML table arrays correspond to either a slice of structs or a slice of maps.
|
||||
//
|
||||
// TOML datetimes correspond to Go time.Time values. Local datetimes are parsed
|
||||
// in the local timezone.
|
||||
// TOML datetimes correspond to [time.Time]. Local datetimes are parsed in the
|
||||
// local timezone.
|
||||
//
|
||||
// time.Duration types are treated as nanoseconds if the TOML value is an
|
||||
// [time.Duration] types are treated as nanoseconds if the TOML value is an
|
||||
// integer, or they're parsed with time.ParseDuration() if they're strings.
|
||||
//
|
||||
// All other TOML types (float, string, int, bool and array) correspond to the
|
||||
@ -90,7 +91,7 @@ type Primitive struct {
|
||||
// UnmarshalText method. See the Unmarshaler example for a demonstration with
|
||||
// email addresses.
|
||||
//
|
||||
// Key mapping
|
||||
// ### Key mapping
|
||||
//
|
||||
// TOML keys can map to either keys in a Go map or field names in a Go struct.
|
||||
// The special `toml` struct tag can be used to map TOML keys to struct fields
|
||||
@ -168,17 +169,16 @@ func (dec *Decoder) Decode(v interface{}) (MetaData, error) {
|
||||
return md, md.unify(p.mapping, rv)
|
||||
}
|
||||
|
||||
// PrimitiveDecode is just like the other `Decode*` functions, except it
|
||||
// decodes a TOML value that has already been parsed. Valid primitive values
|
||||
// can *only* be obtained from values filled by the decoder functions,
|
||||
// including this method. (i.e., `v` may contain more `Primitive`
|
||||
// values.)
|
||||
// PrimitiveDecode is just like the other Decode* functions, except it decodes a
|
||||
// TOML value that has already been parsed. Valid primitive values can *only* be
|
||||
// obtained from values filled by the decoder functions, including this method.
|
||||
// (i.e., v may contain more [Primitive] values.)
|
||||
//
|
||||
// Meta data for primitive values is included in the meta data returned by
|
||||
// the `Decode*` functions with one exception: keys returned by the Undecoded
|
||||
// method will only reflect keys that were decoded. Namely, any keys hidden
|
||||
// behind a Primitive will be considered undecoded. Executing this method will
|
||||
// update the undecoded keys in the meta data. (See the example.)
|
||||
// Meta data for primitive values is included in the meta data returned by the
|
||||
// Decode* functions with one exception: keys returned by the Undecoded method
|
||||
// will only reflect keys that were decoded. Namely, any keys hidden behind a
|
||||
// Primitive will be considered undecoded. Executing this method will update the
|
||||
// undecoded keys in the meta data. (See the example.)
|
||||
func (md *MetaData) PrimitiveDecode(primValue Primitive, v interface{}) error {
|
||||
md.context = primValue.context
|
||||
defer func() { md.context = nil }()
|
||||
|
4
vendor/github.com/BurntSushi/toml/decode_go116.go
generated
vendored
4
vendor/github.com/BurntSushi/toml/decode_go116.go
generated
vendored
@ -7,8 +7,8 @@
|
||||
"io/fs"
|
||||
)
|
||||
|
||||
// DecodeFS is just like Decode, except it will automatically read the contents
|
||||
// of the file at `path` from a fs.FS instance.
|
||||
// DecodeFS reads the contents of a file from [fs.FS] and decodes it with
|
||||
// [Decode].
|
||||
func DecodeFS(fsys fs.FS, path string, v interface{}) (MetaData, error) {
|
||||
fp, err := fsys.Open(path)
|
||||
if err != nil {
|
||||
|
22
vendor/github.com/BurntSushi/toml/doc.go
generated
vendored
22
vendor/github.com/BurntSushi/toml/doc.go
generated
vendored
@ -1,13 +1,11 @@
|
||||
/*
|
||||
Package toml implements decoding and encoding of TOML files.
|
||||
|
||||
This package supports TOML v1.0.0, as listed on https://toml.io
|
||||
|
||||
There is also support for delaying decoding with the Primitive type, and
|
||||
querying the set of keys in a TOML document with the MetaData type.
|
||||
|
||||
The github.com/BurntSushi/toml/cmd/tomlv package implements a TOML validator,
|
||||
and can be used to verify if TOML document is valid. It can also be used to
|
||||
print the type of each key.
|
||||
*/
|
||||
// Package toml implements decoding and encoding of TOML files.
|
||||
//
|
||||
// This package supports TOML v1.0.0, as specified at https://toml.io
|
||||
//
|
||||
// There is also support for delaying decoding with the Primitive type, and
|
||||
// querying the set of keys in a TOML document with the MetaData type.
|
||||
//
|
||||
// The github.com/BurntSushi/toml/cmd/tomlv package implements a TOML validator,
|
||||
// and can be used to verify if TOML document is valid. It can also be used to
|
||||
// print the type of each key.
|
||||
package toml
|
||||
|
40
vendor/github.com/BurntSushi/toml/encode.go
generated
vendored
40
vendor/github.com/BurntSushi/toml/encode.go
generated
vendored
@ -79,12 +79,12 @@ type Marshaler interface {
|
||||
// Encoder encodes a Go to a TOML document.
|
||||
//
|
||||
// The mapping between Go values and TOML values should be precisely the same as
|
||||
// for the Decode* functions.
|
||||
// for [Decode].
|
||||
//
|
||||
// time.Time is encoded as a RFC 3339 string, and time.Duration as its string
|
||||
// representation.
|
||||
//
|
||||
// The toml.Marshaler and encoder.TextMarshaler interfaces are supported to
|
||||
// The [Marshaler] and [encoding.TextMarshaler] interfaces are supported to
|
||||
// encoding the value as custom TOML.
|
||||
//
|
||||
// If you want to write arbitrary binary data then you will need to use
|
||||
@ -130,7 +130,7 @@ func NewEncoder(w io.Writer) *Encoder {
|
||||
}
|
||||
}
|
||||
|
||||
// Encode writes a TOML representation of the Go value to the Encoder's writer.
|
||||
// Encode writes a TOML representation of the Go value to the [Encoder]'s writer.
|
||||
//
|
||||
// An error is returned if the value given cannot be encoded to a valid TOML
|
||||
// document.
|
||||
@ -261,7 +261,7 @@ func (enc *Encoder) eElement(rv reflect.Value) {
|
||||
enc.eElement(reflect.ValueOf(v))
|
||||
return
|
||||
}
|
||||
encPanic(errors.New(fmt.Sprintf("Unable to convert \"%s\" to neither int64 nor float64", n)))
|
||||
encPanic(fmt.Errorf("unable to convert %q to int64 or float64", n))
|
||||
}
|
||||
|
||||
switch rv.Kind() {
|
||||
@ -504,7 +504,8 @@ func (enc *Encoder) eStruct(key Key, rv reflect.Value, inline bool) {
|
||||
if opts.name != "" {
|
||||
keyName = opts.name
|
||||
}
|
||||
if opts.omitempty && isEmpty(fieldVal) {
|
||||
|
||||
if opts.omitempty && enc.isEmpty(fieldVal) {
|
||||
continue
|
||||
}
|
||||
if opts.omitzero && isZero(fieldVal) {
|
||||
@ -648,12 +649,26 @@ func isZero(rv reflect.Value) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func isEmpty(rv reflect.Value) bool {
|
||||
func (enc *Encoder) isEmpty(rv reflect.Value) bool {
|
||||
switch rv.Kind() {
|
||||
case reflect.Array, reflect.Slice, reflect.Map, reflect.String:
|
||||
return rv.Len() == 0
|
||||
case reflect.Struct:
|
||||
return reflect.Zero(rv.Type()).Interface() == rv.Interface()
|
||||
if rv.Type().Comparable() {
|
||||
return reflect.Zero(rv.Type()).Interface() == rv.Interface()
|
||||
}
|
||||
// Need to also check if all the fields are empty, otherwise something
|
||||
// like this with uncomparable types will always return true:
|
||||
//
|
||||
// type a struct{ field b }
|
||||
// type b struct{ s []string }
|
||||
// s := a{field: b{s: []string{"AAA"}}}
|
||||
for i := 0; i < rv.NumField(); i++ {
|
||||
if !enc.isEmpty(rv.Field(i)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
case reflect.Bool:
|
||||
return !rv.Bool()
|
||||
}
|
||||
@ -668,16 +683,15 @@ func (enc *Encoder) newline() {
|
||||
|
||||
// Write a key/value pair:
|
||||
//
|
||||
// key = <any value>
|
||||
// key = <any value>
|
||||
//
|
||||
// This is also used for "k = v" in inline tables; so something like this will
|
||||
// be written in three calls:
|
||||
//
|
||||
// ┌────────────────────┐
|
||||
// │ ┌───┐ ┌─────┐│
|
||||
// v v v v vv
|
||||
// key = {k = v, k2 = v2}
|
||||
//
|
||||
// ┌───────────────────┐
|
||||
// │ ┌───┐ ┌────┐│
|
||||
// v v v v vv
|
||||
// key = {k = 1, k2 = 2}
|
||||
func (enc *Encoder) writeKeyValue(key Key, val reflect.Value, inline bool) {
|
||||
if len(key) == 0 {
|
||||
encPanic(errNoKey)
|
||||
|
67
vendor/github.com/BurntSushi/toml/error.go
generated
vendored
67
vendor/github.com/BurntSushi/toml/error.go
generated
vendored
@ -5,57 +5,60 @@
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ParseError is returned when there is an error parsing the TOML syntax.
|
||||
//
|
||||
// For example invalid syntax, duplicate keys, etc.
|
||||
// ParseError is returned when there is an error parsing the TOML syntax such as
|
||||
// invalid syntax, duplicate keys, etc.
|
||||
//
|
||||
// In addition to the error message itself, you can also print detailed location
|
||||
// information with context by using ErrorWithPosition():
|
||||
// information with context by using [ErrorWithPosition]:
|
||||
//
|
||||
// toml: error: Key 'fruit' was already created and cannot be used as an array.
|
||||
// toml: error: Key 'fruit' was already created and cannot be used as an array.
|
||||
//
|
||||
// At line 4, column 2-7:
|
||||
// At line 4, column 2-7:
|
||||
//
|
||||
// 2 | fruit = []
|
||||
// 3 |
|
||||
// 4 | [[fruit]] # Not allowed
|
||||
// ^^^^^
|
||||
// 2 | fruit = []
|
||||
// 3 |
|
||||
// 4 | [[fruit]] # Not allowed
|
||||
// ^^^^^
|
||||
//
|
||||
// Furthermore, the ErrorWithUsage() can be used to print the above with some
|
||||
// more detailed usage guidance:
|
||||
// [ErrorWithUsage] can be used to print the above with some more detailed usage
|
||||
// guidance:
|
||||
//
|
||||
// toml: error: newlines not allowed within inline tables
|
||||
// toml: error: newlines not allowed within inline tables
|
||||
//
|
||||
// At line 1, column 18:
|
||||
// At line 1, column 18:
|
||||
//
|
||||
// 1 | x = [{ key = 42 #
|
||||
// ^
|
||||
// 1 | x = [{ key = 42 #
|
||||
// ^
|
||||
//
|
||||
// Error help:
|
||||
// Error help:
|
||||
//
|
||||
// Inline tables must always be on a single line:
|
||||
// Inline tables must always be on a single line:
|
||||
//
|
||||
// table = {key = 42, second = 43}
|
||||
// table = {key = 42, second = 43}
|
||||
//
|
||||
// It is invalid to split them over multiple lines like so:
|
||||
// It is invalid to split them over multiple lines like so:
|
||||
//
|
||||
// # INVALID
|
||||
// table = {
|
||||
// key = 42,
|
||||
// second = 43
|
||||
// }
|
||||
// # INVALID
|
||||
// table = {
|
||||
// key = 42,
|
||||
// second = 43
|
||||
// }
|
||||
//
|
||||
// Use regular for this:
|
||||
// Use regular for this:
|
||||
//
|
||||
// [table]
|
||||
// key = 42
|
||||
// second = 43
|
||||
// [table]
|
||||
// key = 42
|
||||
// second = 43
|
||||
type ParseError struct {
|
||||
Message string // Short technical message.
|
||||
Usage string // Longer message with usage guidance; may be blank.
|
||||
Position Position // Position of the error
|
||||
LastKey string // Last parsed key, may be blank.
|
||||
Line int // Line the error occurred. Deprecated: use Position.
|
||||
|
||||
// Line the error occurred.
|
||||
//
|
||||
// Deprecated: use [Position].
|
||||
Line int
|
||||
|
||||
err error
|
||||
input string
|
||||
@ -83,7 +86,7 @@ func (pe ParseError) Error() string {
|
||||
|
||||
// ErrorWithUsage() returns the error with detailed location context.
|
||||
//
|
||||
// See the documentation on ParseError.
|
||||
// See the documentation on [ParseError].
|
||||
func (pe ParseError) ErrorWithPosition() string {
|
||||
if pe.input == "" { // Should never happen, but just in case.
|
||||
return pe.Error()
|
||||
@ -124,7 +127,7 @@ func (pe ParseError) ErrorWithPosition() string {
|
||||
// ErrorWithUsage() returns the error with detailed location context and usage
|
||||
// guidance.
|
||||
//
|
||||
// See the documentation on ParseError.
|
||||
// See the documentation on [ParseError].
|
||||
func (pe ParseError) ErrorWithUsage() string {
|
||||
m := pe.ErrorWithPosition()
|
||||
if u, ok := pe.err.(interface{ Usage() string }); ok && u.Usage() != "" {
|
||||
|
2
vendor/github.com/BurntSushi/toml/lex.go
generated
vendored
2
vendor/github.com/BurntSushi/toml/lex.go
generated
vendored
@ -771,7 +771,7 @@ func lexRawString(lx *lexer) stateFn {
|
||||
}
|
||||
|
||||
// lexMultilineRawString consumes a raw string. Nothing can be escaped in such
|
||||
// a string. It assumes that the beginning "'''" has already been consumed and
|
||||
// a string. It assumes that the beginning ''' has already been consumed and
|
||||
// ignored.
|
||||
func lexMultilineRawString(lx *lexer) stateFn {
|
||||
r := lx.next()
|
||||
|
4
vendor/github.com/BurntSushi/toml/meta.go
generated
vendored
4
vendor/github.com/BurntSushi/toml/meta.go
generated
vendored
@ -71,7 +71,7 @@ func (md *MetaData) Keys() []Key {
|
||||
// Undecoded returns all keys that have not been decoded in the order in which
|
||||
// they appear in the original TOML document.
|
||||
//
|
||||
// This includes keys that haven't been decoded because of a Primitive value.
|
||||
// This includes keys that haven't been decoded because of a [Primitive] value.
|
||||
// Once the Primitive value is decoded, the keys will be considered decoded.
|
||||
//
|
||||
// Also note that decoding into an empty interface will result in no decoding,
|
||||
@ -89,7 +89,7 @@ func (md *MetaData) Undecoded() []Key {
|
||||
return undecoded
|
||||
}
|
||||
|
||||
// Key represents any TOML key, including key groups. Use (MetaData).Keys to get
|
||||
// Key represents any TOML key, including key groups. Use [MetaData.Keys] to get
|
||||
// values of this type.
|
||||
type Key []string
|
||||
|
||||
|
7
vendor/github.com/google/pprof/AUTHORS
generated
vendored
Normal file
7
vendor/github.com/google/pprof/AUTHORS
generated
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
# This is the official list of pprof authors for copyright purposes.
|
||||
# This file is distinct from the CONTRIBUTORS files.
|
||||
# See the latter for an explanation.
|
||||
# Names should be added to this file as:
|
||||
# Name or Organization <email address>
|
||||
# The email address is not required for organizations.
|
||||
Google Inc.
|
16
vendor/github.com/google/pprof/CONTRIBUTORS
generated
vendored
Normal file
16
vendor/github.com/google/pprof/CONTRIBUTORS
generated
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
# People who have agreed to one of the CLAs and can contribute patches.
|
||||
# The AUTHORS file lists the copyright holders; this file
|
||||
# lists people. For example, Google employees are listed here
|
||||
# but not in AUTHORS, because Google holds the copyright.
|
||||
#
|
||||
# https://developers.google.com/open-source/cla/individual
|
||||
# https://developers.google.com/open-source/cla/corporate
|
||||
#
|
||||
# Names should be added to this file as:
|
||||
# Name <email address>
|
||||
Raul Silvera <rsilvera@google.com>
|
||||
Tipp Moseley <tipp@google.com>
|
||||
Hyoun Kyu Cho <netforce@google.com>
|
||||
Martin Spier <spiermar@gmail.com>
|
||||
Taco de Wolff <tacodewolff@gmail.com>
|
||||
Andrew Hunter <andrewhhunter@gmail.com>
|
202
vendor/github.com/google/pprof/LICENSE
generated
vendored
Normal file
202
vendor/github.com/google/pprof/LICENSE
generated
vendored
Normal file
@ -0,0 +1,202 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
567
vendor/github.com/google/pprof/profile/encode.go
generated
vendored
Normal file
567
vendor/github.com/google/pprof/profile/encode.go
generated
vendored
Normal file
@ -0,0 +1,567 @@
|
||||
// Copyright 2014 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package profile
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"sort"
|
||||
)
|
||||
|
||||
func (p *Profile) decoder() []decoder {
|
||||
return profileDecoder
|
||||
}
|
||||
|
||||
// preEncode populates the unexported fields to be used by encode
|
||||
// (with suffix X) from the corresponding exported fields. The
|
||||
// exported fields are cleared up to facilitate testing.
|
||||
func (p *Profile) preEncode() {
|
||||
strings := make(map[string]int)
|
||||
addString(strings, "")
|
||||
|
||||
for _, st := range p.SampleType {
|
||||
st.typeX = addString(strings, st.Type)
|
||||
st.unitX = addString(strings, st.Unit)
|
||||
}
|
||||
|
||||
for _, s := range p.Sample {
|
||||
s.labelX = nil
|
||||
var keys []string
|
||||
for k := range s.Label {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
for _, k := range keys {
|
||||
vs := s.Label[k]
|
||||
for _, v := range vs {
|
||||
s.labelX = append(s.labelX,
|
||||
label{
|
||||
keyX: addString(strings, k),
|
||||
strX: addString(strings, v),
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
var numKeys []string
|
||||
for k := range s.NumLabel {
|
||||
numKeys = append(numKeys, k)
|
||||
}
|
||||
sort.Strings(numKeys)
|
||||
for _, k := range numKeys {
|
||||
keyX := addString(strings, k)
|
||||
vs := s.NumLabel[k]
|
||||
units := s.NumUnit[k]
|
||||
for i, v := range vs {
|
||||
var unitX int64
|
||||
if len(units) != 0 {
|
||||
unitX = addString(strings, units[i])
|
||||
}
|
||||
s.labelX = append(s.labelX,
|
||||
label{
|
||||
keyX: keyX,
|
||||
numX: v,
|
||||
unitX: unitX,
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
s.locationIDX = make([]uint64, len(s.Location))
|
||||
for i, loc := range s.Location {
|
||||
s.locationIDX[i] = loc.ID
|
||||
}
|
||||
}
|
||||
|
||||
for _, m := range p.Mapping {
|
||||
m.fileX = addString(strings, m.File)
|
||||
m.buildIDX = addString(strings, m.BuildID)
|
||||
}
|
||||
|
||||
for _, l := range p.Location {
|
||||
for i, ln := range l.Line {
|
||||
if ln.Function != nil {
|
||||
l.Line[i].functionIDX = ln.Function.ID
|
||||
} else {
|
||||
l.Line[i].functionIDX = 0
|
||||
}
|
||||
}
|
||||
if l.Mapping != nil {
|
||||
l.mappingIDX = l.Mapping.ID
|
||||
} else {
|
||||
l.mappingIDX = 0
|
||||
}
|
||||
}
|
||||
for _, f := range p.Function {
|
||||
f.nameX = addString(strings, f.Name)
|
||||
f.systemNameX = addString(strings, f.SystemName)
|
||||
f.filenameX = addString(strings, f.Filename)
|
||||
}
|
||||
|
||||
p.dropFramesX = addString(strings, p.DropFrames)
|
||||
p.keepFramesX = addString(strings, p.KeepFrames)
|
||||
|
||||
if pt := p.PeriodType; pt != nil {
|
||||
pt.typeX = addString(strings, pt.Type)
|
||||
pt.unitX = addString(strings, pt.Unit)
|
||||
}
|
||||
|
||||
p.commentX = nil
|
||||
for _, c := range p.Comments {
|
||||
p.commentX = append(p.commentX, addString(strings, c))
|
||||
}
|
||||
|
||||
p.defaultSampleTypeX = addString(strings, p.DefaultSampleType)
|
||||
|
||||
p.stringTable = make([]string, len(strings))
|
||||
for s, i := range strings {
|
||||
p.stringTable[i] = s
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Profile) encode(b *buffer) {
|
||||
for _, x := range p.SampleType {
|
||||
encodeMessage(b, 1, x)
|
||||
}
|
||||
for _, x := range p.Sample {
|
||||
encodeMessage(b, 2, x)
|
||||
}
|
||||
for _, x := range p.Mapping {
|
||||
encodeMessage(b, 3, x)
|
||||
}
|
||||
for _, x := range p.Location {
|
||||
encodeMessage(b, 4, x)
|
||||
}
|
||||
for _, x := range p.Function {
|
||||
encodeMessage(b, 5, x)
|
||||
}
|
||||
encodeStrings(b, 6, p.stringTable)
|
||||
encodeInt64Opt(b, 7, p.dropFramesX)
|
||||
encodeInt64Opt(b, 8, p.keepFramesX)
|
||||
encodeInt64Opt(b, 9, p.TimeNanos)
|
||||
encodeInt64Opt(b, 10, p.DurationNanos)
|
||||
if pt := p.PeriodType; pt != nil && (pt.typeX != 0 || pt.unitX != 0) {
|
||||
encodeMessage(b, 11, p.PeriodType)
|
||||
}
|
||||
encodeInt64Opt(b, 12, p.Period)
|
||||
encodeInt64s(b, 13, p.commentX)
|
||||
encodeInt64(b, 14, p.defaultSampleTypeX)
|
||||
}
|
||||
|
||||
var profileDecoder = []decoder{
|
||||
nil, // 0
|
||||
// repeated ValueType sample_type = 1
|
||||
func(b *buffer, m message) error {
|
||||
x := new(ValueType)
|
||||
pp := m.(*Profile)
|
||||
pp.SampleType = append(pp.SampleType, x)
|
||||
return decodeMessage(b, x)
|
||||
},
|
||||
// repeated Sample sample = 2
|
||||
func(b *buffer, m message) error {
|
||||
x := new(Sample)
|
||||
pp := m.(*Profile)
|
||||
pp.Sample = append(pp.Sample, x)
|
||||
return decodeMessage(b, x)
|
||||
},
|
||||
// repeated Mapping mapping = 3
|
||||
func(b *buffer, m message) error {
|
||||
x := new(Mapping)
|
||||
pp := m.(*Profile)
|
||||
pp.Mapping = append(pp.Mapping, x)
|
||||
return decodeMessage(b, x)
|
||||
},
|
||||
// repeated Location location = 4
|
||||
func(b *buffer, m message) error {
|
||||
x := new(Location)
|
||||
x.Line = make([]Line, 0, 8) // Pre-allocate Line buffer
|
||||
pp := m.(*Profile)
|
||||
pp.Location = append(pp.Location, x)
|
||||
err := decodeMessage(b, x)
|
||||
var tmp []Line
|
||||
x.Line = append(tmp, x.Line...) // Shrink to allocated size
|
||||
return err
|
||||
},
|
||||
// repeated Function function = 5
|
||||
func(b *buffer, m message) error {
|
||||
x := new(Function)
|
||||
pp := m.(*Profile)
|
||||
pp.Function = append(pp.Function, x)
|
||||
return decodeMessage(b, x)
|
||||
},
|
||||
// repeated string string_table = 6
|
||||
func(b *buffer, m message) error {
|
||||
err := decodeStrings(b, &m.(*Profile).stringTable)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if m.(*Profile).stringTable[0] != "" {
|
||||
return errors.New("string_table[0] must be ''")
|
||||
}
|
||||
return nil
|
||||
},
|
||||
// int64 drop_frames = 7
|
||||
func(b *buffer, m message) error { return decodeInt64(b, &m.(*Profile).dropFramesX) },
|
||||
// int64 keep_frames = 8
|
||||
func(b *buffer, m message) error { return decodeInt64(b, &m.(*Profile).keepFramesX) },
|
||||
// int64 time_nanos = 9
|
||||
func(b *buffer, m message) error {
|
||||
if m.(*Profile).TimeNanos != 0 {
|
||||
return errConcatProfile
|
||||
}
|
||||
return decodeInt64(b, &m.(*Profile).TimeNanos)
|
||||
},
|
||||
// int64 duration_nanos = 10
|
||||
func(b *buffer, m message) error { return decodeInt64(b, &m.(*Profile).DurationNanos) },
|
||||
// ValueType period_type = 11
|
||||
func(b *buffer, m message) error {
|
||||
x := new(ValueType)
|
||||
pp := m.(*Profile)
|
||||
pp.PeriodType = x
|
||||
return decodeMessage(b, x)
|
||||
},
|
||||
// int64 period = 12
|
||||
func(b *buffer, m message) error { return decodeInt64(b, &m.(*Profile).Period) },
|
||||
// repeated int64 comment = 13
|
||||
func(b *buffer, m message) error { return decodeInt64s(b, &m.(*Profile).commentX) },
|
||||
// int64 defaultSampleType = 14
|
||||
func(b *buffer, m message) error { return decodeInt64(b, &m.(*Profile).defaultSampleTypeX) },
|
||||
}
|
||||
|
||||
// postDecode takes the unexported fields populated by decode (with
|
||||
// suffix X) and populates the corresponding exported fields.
|
||||
// The unexported fields are cleared up to facilitate testing.
|
||||
func (p *Profile) postDecode() error {
|
||||
var err error
|
||||
mappings := make(map[uint64]*Mapping, len(p.Mapping))
|
||||
mappingIds := make([]*Mapping, len(p.Mapping)+1)
|
||||
for _, m := range p.Mapping {
|
||||
m.File, err = getString(p.stringTable, &m.fileX, err)
|
||||
m.BuildID, err = getString(p.stringTable, &m.buildIDX, err)
|
||||
if m.ID < uint64(len(mappingIds)) {
|
||||
mappingIds[m.ID] = m
|
||||
} else {
|
||||
mappings[m.ID] = m
|
||||
}
|
||||
}
|
||||
|
||||
functions := make(map[uint64]*Function, len(p.Function))
|
||||
functionIds := make([]*Function, len(p.Function)+1)
|
||||
for _, f := range p.Function {
|
||||
f.Name, err = getString(p.stringTable, &f.nameX, err)
|
||||
f.SystemName, err = getString(p.stringTable, &f.systemNameX, err)
|
||||
f.Filename, err = getString(p.stringTable, &f.filenameX, err)
|
||||
if f.ID < uint64(len(functionIds)) {
|
||||
functionIds[f.ID] = f
|
||||
} else {
|
||||
functions[f.ID] = f
|
||||
}
|
||||
}
|
||||
|
||||
locations := make(map[uint64]*Location, len(p.Location))
|
||||
locationIds := make([]*Location, len(p.Location)+1)
|
||||
for _, l := range p.Location {
|
||||
if id := l.mappingIDX; id < uint64(len(mappingIds)) {
|
||||
l.Mapping = mappingIds[id]
|
||||
} else {
|
||||
l.Mapping = mappings[id]
|
||||
}
|
||||
l.mappingIDX = 0
|
||||
for i, ln := range l.Line {
|
||||
if id := ln.functionIDX; id != 0 {
|
||||
l.Line[i].functionIDX = 0
|
||||
if id < uint64(len(functionIds)) {
|
||||
l.Line[i].Function = functionIds[id]
|
||||
} else {
|
||||
l.Line[i].Function = functions[id]
|
||||
}
|
||||
}
|
||||
}
|
||||
if l.ID < uint64(len(locationIds)) {
|
||||
locationIds[l.ID] = l
|
||||
} else {
|
||||
locations[l.ID] = l
|
||||
}
|
||||
}
|
||||
|
||||
for _, st := range p.SampleType {
|
||||
st.Type, err = getString(p.stringTable, &st.typeX, err)
|
||||
st.Unit, err = getString(p.stringTable, &st.unitX, err)
|
||||
}
|
||||
|
||||
for _, s := range p.Sample {
|
||||
labels := make(map[string][]string, len(s.labelX))
|
||||
numLabels := make(map[string][]int64, len(s.labelX))
|
||||
numUnits := make(map[string][]string, len(s.labelX))
|
||||
for _, l := range s.labelX {
|
||||
var key, value string
|
||||
key, err = getString(p.stringTable, &l.keyX, err)
|
||||
if l.strX != 0 {
|
||||
value, err = getString(p.stringTable, &l.strX, err)
|
||||
labels[key] = append(labels[key], value)
|
||||
} else if l.numX != 0 || l.unitX != 0 {
|
||||
numValues := numLabels[key]
|
||||
units := numUnits[key]
|
||||
if l.unitX != 0 {
|
||||
var unit string
|
||||
unit, err = getString(p.stringTable, &l.unitX, err)
|
||||
units = padStringArray(units, len(numValues))
|
||||
numUnits[key] = append(units, unit)
|
||||
}
|
||||
numLabels[key] = append(numLabels[key], l.numX)
|
||||
}
|
||||
}
|
||||
if len(labels) > 0 {
|
||||
s.Label = labels
|
||||
}
|
||||
if len(numLabels) > 0 {
|
||||
s.NumLabel = numLabels
|
||||
for key, units := range numUnits {
|
||||
if len(units) > 0 {
|
||||
numUnits[key] = padStringArray(units, len(numLabels[key]))
|
||||
}
|
||||
}
|
||||
s.NumUnit = numUnits
|
||||
}
|
||||
s.Location = make([]*Location, len(s.locationIDX))
|
||||
for i, lid := range s.locationIDX {
|
||||
if lid < uint64(len(locationIds)) {
|
||||
s.Location[i] = locationIds[lid]
|
||||
} else {
|
||||
s.Location[i] = locations[lid]
|
||||
}
|
||||
}
|
||||
s.locationIDX = nil
|
||||
}
|
||||
|
||||
p.DropFrames, err = getString(p.stringTable, &p.dropFramesX, err)
|
||||
p.KeepFrames, err = getString(p.stringTable, &p.keepFramesX, err)
|
||||
|
||||
if pt := p.PeriodType; pt == nil {
|
||||
p.PeriodType = &ValueType{}
|
||||
}
|
||||
|
||||
if pt := p.PeriodType; pt != nil {
|
||||
pt.Type, err = getString(p.stringTable, &pt.typeX, err)
|
||||
pt.Unit, err = getString(p.stringTable, &pt.unitX, err)
|
||||
}
|
||||
|
||||
for _, i := range p.commentX {
|
||||
var c string
|
||||
c, err = getString(p.stringTable, &i, err)
|
||||
p.Comments = append(p.Comments, c)
|
||||
}
|
||||
|
||||
p.commentX = nil
|
||||
p.DefaultSampleType, err = getString(p.stringTable, &p.defaultSampleTypeX, err)
|
||||
p.stringTable = nil
|
||||
return err
|
||||
}
|
||||
|
||||
// padStringArray pads arr with enough empty strings to make arr
|
||||
// length l when arr's length is less than l.
|
||||
func padStringArray(arr []string, l int) []string {
|
||||
if l <= len(arr) {
|
||||
return arr
|
||||
}
|
||||
return append(arr, make([]string, l-len(arr))...)
|
||||
}
|
||||
|
||||
func (p *ValueType) decoder() []decoder {
|
||||
return valueTypeDecoder
|
||||
}
|
||||
|
||||
func (p *ValueType) encode(b *buffer) {
|
||||
encodeInt64Opt(b, 1, p.typeX)
|
||||
encodeInt64Opt(b, 2, p.unitX)
|
||||
}
|
||||
|
||||
var valueTypeDecoder = []decoder{
|
||||
nil, // 0
|
||||
// optional int64 type = 1
|
||||
func(b *buffer, m message) error { return decodeInt64(b, &m.(*ValueType).typeX) },
|
||||
// optional int64 unit = 2
|
||||
func(b *buffer, m message) error { return decodeInt64(b, &m.(*ValueType).unitX) },
|
||||
}
|
||||
|
||||
func (p *Sample) decoder() []decoder {
|
||||
return sampleDecoder
|
||||
}
|
||||
|
||||
func (p *Sample) encode(b *buffer) {
|
||||
encodeUint64s(b, 1, p.locationIDX)
|
||||
encodeInt64s(b, 2, p.Value)
|
||||
for _, x := range p.labelX {
|
||||
encodeMessage(b, 3, x)
|
||||
}
|
||||
}
|
||||
|
||||
var sampleDecoder = []decoder{
|
||||
nil, // 0
|
||||
// repeated uint64 location = 1
|
||||
func(b *buffer, m message) error { return decodeUint64s(b, &m.(*Sample).locationIDX) },
|
||||
// repeated int64 value = 2
|
||||
func(b *buffer, m message) error { return decodeInt64s(b, &m.(*Sample).Value) },
|
||||
// repeated Label label = 3
|
||||
func(b *buffer, m message) error {
|
||||
s := m.(*Sample)
|
||||
n := len(s.labelX)
|
||||
s.labelX = append(s.labelX, label{})
|
||||
return decodeMessage(b, &s.labelX[n])
|
||||
},
|
||||
}
|
||||
|
||||
func (p label) decoder() []decoder {
|
||||
return labelDecoder
|
||||
}
|
||||
|
||||
func (p label) encode(b *buffer) {
|
||||
encodeInt64Opt(b, 1, p.keyX)
|
||||
encodeInt64Opt(b, 2, p.strX)
|
||||
encodeInt64Opt(b, 3, p.numX)
|
||||
encodeInt64Opt(b, 4, p.unitX)
|
||||
}
|
||||
|
||||
var labelDecoder = []decoder{
|
||||
nil, // 0
|
||||
// optional int64 key = 1
|
||||
func(b *buffer, m message) error { return decodeInt64(b, &m.(*label).keyX) },
|
||||
// optional int64 str = 2
|
||||
func(b *buffer, m message) error { return decodeInt64(b, &m.(*label).strX) },
|
||||
// optional int64 num = 3
|
||||
func(b *buffer, m message) error { return decodeInt64(b, &m.(*label).numX) },
|
||||
// optional int64 num = 4
|
||||
func(b *buffer, m message) error { return decodeInt64(b, &m.(*label).unitX) },
|
||||
}
|
||||
|
||||
func (p *Mapping) decoder() []decoder {
|
||||
return mappingDecoder
|
||||
}
|
||||
|
||||
func (p *Mapping) encode(b *buffer) {
|
||||
encodeUint64Opt(b, 1, p.ID)
|
||||
encodeUint64Opt(b, 2, p.Start)
|
||||
encodeUint64Opt(b, 3, p.Limit)
|
||||
encodeUint64Opt(b, 4, p.Offset)
|
||||
encodeInt64Opt(b, 5, p.fileX)
|
||||
encodeInt64Opt(b, 6, p.buildIDX)
|
||||
encodeBoolOpt(b, 7, p.HasFunctions)
|
||||
encodeBoolOpt(b, 8, p.HasFilenames)
|
||||
encodeBoolOpt(b, 9, p.HasLineNumbers)
|
||||
encodeBoolOpt(b, 10, p.HasInlineFrames)
|
||||
}
|
||||
|
||||
var mappingDecoder = []decoder{
|
||||
nil, // 0
|
||||
func(b *buffer, m message) error { return decodeUint64(b, &m.(*Mapping).ID) }, // optional uint64 id = 1
|
||||
func(b *buffer, m message) error { return decodeUint64(b, &m.(*Mapping).Start) }, // optional uint64 memory_offset = 2
|
||||
func(b *buffer, m message) error { return decodeUint64(b, &m.(*Mapping).Limit) }, // optional uint64 memory_limit = 3
|
||||
func(b *buffer, m message) error { return decodeUint64(b, &m.(*Mapping).Offset) }, // optional uint64 file_offset = 4
|
||||
func(b *buffer, m message) error { return decodeInt64(b, &m.(*Mapping).fileX) }, // optional int64 filename = 5
|
||||
func(b *buffer, m message) error { return decodeInt64(b, &m.(*Mapping).buildIDX) }, // optional int64 build_id = 6
|
||||
func(b *buffer, m message) error { return decodeBool(b, &m.(*Mapping).HasFunctions) }, // optional bool has_functions = 7
|
||||
func(b *buffer, m message) error { return decodeBool(b, &m.(*Mapping).HasFilenames) }, // optional bool has_filenames = 8
|
||||
func(b *buffer, m message) error { return decodeBool(b, &m.(*Mapping).HasLineNumbers) }, // optional bool has_line_numbers = 9
|
||||
func(b *buffer, m message) error { return decodeBool(b, &m.(*Mapping).HasInlineFrames) }, // optional bool has_inline_frames = 10
|
||||
}
|
||||
|
||||
func (p *Location) decoder() []decoder {
|
||||
return locationDecoder
|
||||
}
|
||||
|
||||
func (p *Location) encode(b *buffer) {
|
||||
encodeUint64Opt(b, 1, p.ID)
|
||||
encodeUint64Opt(b, 2, p.mappingIDX)
|
||||
encodeUint64Opt(b, 3, p.Address)
|
||||
for i := range p.Line {
|
||||
encodeMessage(b, 4, &p.Line[i])
|
||||
}
|
||||
encodeBoolOpt(b, 5, p.IsFolded)
|
||||
}
|
||||
|
||||
var locationDecoder = []decoder{
|
||||
nil, // 0
|
||||
func(b *buffer, m message) error { return decodeUint64(b, &m.(*Location).ID) }, // optional uint64 id = 1;
|
||||
func(b *buffer, m message) error { return decodeUint64(b, &m.(*Location).mappingIDX) }, // optional uint64 mapping_id = 2;
|
||||
func(b *buffer, m message) error { return decodeUint64(b, &m.(*Location).Address) }, // optional uint64 address = 3;
|
||||
func(b *buffer, m message) error { // repeated Line line = 4
|
||||
pp := m.(*Location)
|
||||
n := len(pp.Line)
|
||||
pp.Line = append(pp.Line, Line{})
|
||||
return decodeMessage(b, &pp.Line[n])
|
||||
},
|
||||
func(b *buffer, m message) error { return decodeBool(b, &m.(*Location).IsFolded) }, // optional bool is_folded = 5;
|
||||
}
|
||||
|
||||
func (p *Line) decoder() []decoder {
|
||||
return lineDecoder
|
||||
}
|
||||
|
||||
func (p *Line) encode(b *buffer) {
|
||||
encodeUint64Opt(b, 1, p.functionIDX)
|
||||
encodeInt64Opt(b, 2, p.Line)
|
||||
}
|
||||
|
||||
var lineDecoder = []decoder{
|
||||
nil, // 0
|
||||
// optional uint64 function_id = 1
|
||||
func(b *buffer, m message) error { return decodeUint64(b, &m.(*Line).functionIDX) },
|
||||
// optional int64 line = 2
|
||||
func(b *buffer, m message) error { return decodeInt64(b, &m.(*Line).Line) },
|
||||
}
|
||||
|
||||
func (p *Function) decoder() []decoder {
|
||||
return functionDecoder
|
||||
}
|
||||
|
||||
func (p *Function) encode(b *buffer) {
|
||||
encodeUint64Opt(b, 1, p.ID)
|
||||
encodeInt64Opt(b, 2, p.nameX)
|
||||
encodeInt64Opt(b, 3, p.systemNameX)
|
||||
encodeInt64Opt(b, 4, p.filenameX)
|
||||
encodeInt64Opt(b, 5, p.StartLine)
|
||||
}
|
||||
|
||||
var functionDecoder = []decoder{
|
||||
nil, // 0
|
||||
// optional uint64 id = 1
|
||||
func(b *buffer, m message) error { return decodeUint64(b, &m.(*Function).ID) },
|
||||
// optional int64 function_name = 2
|
||||
func(b *buffer, m message) error { return decodeInt64(b, &m.(*Function).nameX) },
|
||||
// optional int64 function_system_name = 3
|
||||
func(b *buffer, m message) error { return decodeInt64(b, &m.(*Function).systemNameX) },
|
||||
// repeated int64 filename = 4
|
||||
func(b *buffer, m message) error { return decodeInt64(b, &m.(*Function).filenameX) },
|
||||
// optional int64 start_line = 5
|
||||
func(b *buffer, m message) error { return decodeInt64(b, &m.(*Function).StartLine) },
|
||||
}
|
||||
|
||||
func addString(strings map[string]int, s string) int64 {
|
||||
i, ok := strings[s]
|
||||
if !ok {
|
||||
i = len(strings)
|
||||
strings[s] = i
|
||||
}
|
||||
return int64(i)
|
||||
}
|
||||
|
||||
func getString(strings []string, strng *int64, err error) (string, error) {
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
s := int(*strng)
|
||||
if s < 0 || s >= len(strings) {
|
||||
return "", errMalformed
|
||||
}
|
||||
*strng = 0
|
||||
return strings[s], nil
|
||||
}
|
270
vendor/github.com/google/pprof/profile/filter.go
generated
vendored
Normal file
270
vendor/github.com/google/pprof/profile/filter.go
generated
vendored
Normal file
@ -0,0 +1,270 @@
|
||||
// Copyright 2014 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package profile
|
||||
|
||||
// Implements methods to filter samples from profiles.
|
||||
|
||||
import "regexp"
|
||||
|
||||
// FilterSamplesByName filters the samples in a profile and only keeps
|
||||
// samples where at least one frame matches focus but none match ignore.
|
||||
// Returns true is the corresponding regexp matched at least one sample.
|
||||
func (p *Profile) FilterSamplesByName(focus, ignore, hide, show *regexp.Regexp) (fm, im, hm, hnm bool) {
|
||||
focusOrIgnore := make(map[uint64]bool)
|
||||
hidden := make(map[uint64]bool)
|
||||
for _, l := range p.Location {
|
||||
if ignore != nil && l.matchesName(ignore) {
|
||||
im = true
|
||||
focusOrIgnore[l.ID] = false
|
||||
} else if focus == nil || l.matchesName(focus) {
|
||||
fm = true
|
||||
focusOrIgnore[l.ID] = true
|
||||
}
|
||||
|
||||
if hide != nil && l.matchesName(hide) {
|
||||
hm = true
|
||||
l.Line = l.unmatchedLines(hide)
|
||||
if len(l.Line) == 0 {
|
||||
hidden[l.ID] = true
|
||||
}
|
||||
}
|
||||
if show != nil {
|
||||
l.Line = l.matchedLines(show)
|
||||
if len(l.Line) == 0 {
|
||||
hidden[l.ID] = true
|
||||
} else {
|
||||
hnm = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
s := make([]*Sample, 0, len(p.Sample))
|
||||
for _, sample := range p.Sample {
|
||||
if focusedAndNotIgnored(sample.Location, focusOrIgnore) {
|
||||
if len(hidden) > 0 {
|
||||
var locs []*Location
|
||||
for _, loc := range sample.Location {
|
||||
if !hidden[loc.ID] {
|
||||
locs = append(locs, loc)
|
||||
}
|
||||
}
|
||||
if len(locs) == 0 {
|
||||
// Remove sample with no locations (by not adding it to s).
|
||||
continue
|
||||
}
|
||||
sample.Location = locs
|
||||
}
|
||||
s = append(s, sample)
|
||||
}
|
||||
}
|
||||
p.Sample = s
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// ShowFrom drops all stack frames above the highest matching frame and returns
|
||||
// whether a match was found. If showFrom is nil it returns false and does not
|
||||
// modify the profile.
|
||||
//
|
||||
// Example: consider a sample with frames [A, B, C, B], where A is the root.
|
||||
// ShowFrom(nil) returns false and has frames [A, B, C, B].
|
||||
// ShowFrom(A) returns true and has frames [A, B, C, B].
|
||||
// ShowFrom(B) returns true and has frames [B, C, B].
|
||||
// ShowFrom(C) returns true and has frames [C, B].
|
||||
// ShowFrom(D) returns false and drops the sample because no frames remain.
|
||||
func (p *Profile) ShowFrom(showFrom *regexp.Regexp) (matched bool) {
|
||||
if showFrom == nil {
|
||||
return false
|
||||
}
|
||||
// showFromLocs stores location IDs that matched ShowFrom.
|
||||
showFromLocs := make(map[uint64]bool)
|
||||
// Apply to locations.
|
||||
for _, loc := range p.Location {
|
||||
if filterShowFromLocation(loc, showFrom) {
|
||||
showFromLocs[loc.ID] = true
|
||||
matched = true
|
||||
}
|
||||
}
|
||||
// For all samples, strip locations after the highest matching one.
|
||||
s := make([]*Sample, 0, len(p.Sample))
|
||||
for _, sample := range p.Sample {
|
||||
for i := len(sample.Location) - 1; i >= 0; i-- {
|
||||
if showFromLocs[sample.Location[i].ID] {
|
||||
sample.Location = sample.Location[:i+1]
|
||||
s = append(s, sample)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
p.Sample = s
|
||||
return matched
|
||||
}
|
||||
|
||||
// filterShowFromLocation tests a showFrom regex against a location, removes
|
||||
// lines after the last match and returns whether a match was found. If the
|
||||
// mapping is matched, then all lines are kept.
|
||||
func filterShowFromLocation(loc *Location, showFrom *regexp.Regexp) bool {
|
||||
if m := loc.Mapping; m != nil && showFrom.MatchString(m.File) {
|
||||
return true
|
||||
}
|
||||
if i := loc.lastMatchedLineIndex(showFrom); i >= 0 {
|
||||
loc.Line = loc.Line[:i+1]
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// lastMatchedLineIndex returns the index of the last line that matches a regex,
|
||||
// or -1 if no match is found.
|
||||
func (loc *Location) lastMatchedLineIndex(re *regexp.Regexp) int {
|
||||
for i := len(loc.Line) - 1; i >= 0; i-- {
|
||||
if fn := loc.Line[i].Function; fn != nil {
|
||||
if re.MatchString(fn.Name) || re.MatchString(fn.Filename) {
|
||||
return i
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
// FilterTagsByName filters the tags in a profile and only keeps
|
||||
// tags that match show and not hide.
|
||||
func (p *Profile) FilterTagsByName(show, hide *regexp.Regexp) (sm, hm bool) {
|
||||
matchRemove := func(name string) bool {
|
||||
matchShow := show == nil || show.MatchString(name)
|
||||
matchHide := hide != nil && hide.MatchString(name)
|
||||
|
||||
if matchShow {
|
||||
sm = true
|
||||
}
|
||||
if matchHide {
|
||||
hm = true
|
||||
}
|
||||
return !matchShow || matchHide
|
||||
}
|
||||
for _, s := range p.Sample {
|
||||
for lab := range s.Label {
|
||||
if matchRemove(lab) {
|
||||
delete(s.Label, lab)
|
||||
}
|
||||
}
|
||||
for lab := range s.NumLabel {
|
||||
if matchRemove(lab) {
|
||||
delete(s.NumLabel, lab)
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// matchesName returns whether the location matches the regular
|
||||
// expression. It checks any available function names, file names, and
|
||||
// mapping object filename.
|
||||
func (loc *Location) matchesName(re *regexp.Regexp) bool {
|
||||
for _, ln := range loc.Line {
|
||||
if fn := ln.Function; fn != nil {
|
||||
if re.MatchString(fn.Name) || re.MatchString(fn.Filename) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
if m := loc.Mapping; m != nil && re.MatchString(m.File) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// unmatchedLines returns the lines in the location that do not match
|
||||
// the regular expression.
|
||||
func (loc *Location) unmatchedLines(re *regexp.Regexp) []Line {
|
||||
if m := loc.Mapping; m != nil && re.MatchString(m.File) {
|
||||
return nil
|
||||
}
|
||||
var lines []Line
|
||||
for _, ln := range loc.Line {
|
||||
if fn := ln.Function; fn != nil {
|
||||
if re.MatchString(fn.Name) || re.MatchString(fn.Filename) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
lines = append(lines, ln)
|
||||
}
|
||||
return lines
|
||||
}
|
||||
|
||||
// matchedLines returns the lines in the location that match
|
||||
// the regular expression.
|
||||
func (loc *Location) matchedLines(re *regexp.Regexp) []Line {
|
||||
if m := loc.Mapping; m != nil && re.MatchString(m.File) {
|
||||
return loc.Line
|
||||
}
|
||||
var lines []Line
|
||||
for _, ln := range loc.Line {
|
||||
if fn := ln.Function; fn != nil {
|
||||
if !re.MatchString(fn.Name) && !re.MatchString(fn.Filename) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
lines = append(lines, ln)
|
||||
}
|
||||
return lines
|
||||
}
|
||||
|
||||
// focusedAndNotIgnored looks up a slice of ids against a map of
|
||||
// focused/ignored locations. The map only contains locations that are
|
||||
// explicitly focused or ignored. Returns whether there is at least
|
||||
// one focused location but no ignored locations.
|
||||
func focusedAndNotIgnored(locs []*Location, m map[uint64]bool) bool {
|
||||
var f bool
|
||||
for _, loc := range locs {
|
||||
if focus, focusOrIgnore := m[loc.ID]; focusOrIgnore {
|
||||
if focus {
|
||||
// Found focused location. Must keep searching in case there
|
||||
// is an ignored one as well.
|
||||
f = true
|
||||
} else {
|
||||
// Found ignored location. Can return false right away.
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return f
|
||||
}
|
||||
|
||||
// TagMatch selects tags for filtering
|
||||
type TagMatch func(s *Sample) bool
|
||||
|
||||
// FilterSamplesByTag removes all samples from the profile, except
|
||||
// those that match focus and do not match the ignore regular
|
||||
// expression.
|
||||
func (p *Profile) FilterSamplesByTag(focus, ignore TagMatch) (fm, im bool) {
|
||||
samples := make([]*Sample, 0, len(p.Sample))
|
||||
for _, s := range p.Sample {
|
||||
focused, ignored := true, false
|
||||
if focus != nil {
|
||||
focused = focus(s)
|
||||
}
|
||||
if ignore != nil {
|
||||
ignored = ignore(s)
|
||||
}
|
||||
fm = fm || focused
|
||||
im = im || ignored
|
||||
if focused && !ignored {
|
||||
samples = append(samples, s)
|
||||
}
|
||||
}
|
||||
p.Sample = samples
|
||||
return
|
||||
}
|
64
vendor/github.com/google/pprof/profile/index.go
generated
vendored
Normal file
64
vendor/github.com/google/pprof/profile/index.go
generated
vendored
Normal file
@ -0,0 +1,64 @@
|
||||
// Copyright 2016 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package profile
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// SampleIndexByName returns the appropriate index for a value of sample index.
|
||||
// If numeric, it returns the number, otherwise it looks up the text in the
|
||||
// profile sample types.
|
||||
func (p *Profile) SampleIndexByName(sampleIndex string) (int, error) {
|
||||
if sampleIndex == "" {
|
||||
if dst := p.DefaultSampleType; dst != "" {
|
||||
for i, t := range sampleTypes(p) {
|
||||
if t == dst {
|
||||
return i, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
// By default select the last sample value
|
||||
return len(p.SampleType) - 1, nil
|
||||
}
|
||||
if i, err := strconv.Atoi(sampleIndex); err == nil {
|
||||
if i < 0 || i >= len(p.SampleType) {
|
||||
return 0, fmt.Errorf("sample_index %s is outside the range [0..%d]", sampleIndex, len(p.SampleType)-1)
|
||||
}
|
||||
return i, nil
|
||||
}
|
||||
|
||||
// Remove the inuse_ prefix to support legacy pprof options
|
||||
// "inuse_space" and "inuse_objects" for profiles containing types
|
||||
// "space" and "objects".
|
||||
noInuse := strings.TrimPrefix(sampleIndex, "inuse_")
|
||||
for i, t := range p.SampleType {
|
||||
if t.Type == sampleIndex || t.Type == noInuse {
|
||||
return i, nil
|
||||
}
|
||||
}
|
||||
|
||||
return 0, fmt.Errorf("sample_index %q must be one of: %v", sampleIndex, sampleTypes(p))
|
||||
}
|
||||
|
||||
func sampleTypes(p *Profile) []string {
|
||||
types := make([]string, len(p.SampleType))
|
||||
for i, t := range p.SampleType {
|
||||
types[i] = t.Type
|
||||
}
|
||||
return types
|
||||
}
|
315
vendor/github.com/google/pprof/profile/legacy_java_profile.go
generated
vendored
Normal file
315
vendor/github.com/google/pprof/profile/legacy_java_profile.go
generated
vendored
Normal file
@ -0,0 +1,315 @@
|
||||
// Copyright 2014 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// This file implements parsers to convert java legacy profiles into
|
||||
// the profile.proto format.
|
||||
|
||||
package profile
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
attributeRx = regexp.MustCompile(`([\w ]+)=([\w ]+)`)
|
||||
javaSampleRx = regexp.MustCompile(` *(\d+) +(\d+) +@ +([ x0-9a-f]*)`)
|
||||
javaLocationRx = regexp.MustCompile(`^\s*0x([[:xdigit:]]+)\s+(.*)\s*$`)
|
||||
javaLocationFileLineRx = regexp.MustCompile(`^(.*)\s+\((.+):(-?[[:digit:]]+)\)$`)
|
||||
javaLocationPathRx = regexp.MustCompile(`^(.*)\s+\((.*)\)$`)
|
||||
)
|
||||
|
||||
// javaCPUProfile returns a new Profile from profilez data.
|
||||
// b is the profile bytes after the header, period is the profiling
|
||||
// period, and parse is a function to parse 8-byte chunks from the
|
||||
// profile in its native endianness.
|
||||
func javaCPUProfile(b []byte, period int64, parse func(b []byte) (uint64, []byte)) (*Profile, error) {
|
||||
p := &Profile{
|
||||
Period: period * 1000,
|
||||
PeriodType: &ValueType{Type: "cpu", Unit: "nanoseconds"},
|
||||
SampleType: []*ValueType{{Type: "samples", Unit: "count"}, {Type: "cpu", Unit: "nanoseconds"}},
|
||||
}
|
||||
var err error
|
||||
var locs map[uint64]*Location
|
||||
if b, locs, err = parseCPUSamples(b, parse, false, p); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err = parseJavaLocations(b, locs, p); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Strip out addresses for better merge.
|
||||
if err = p.Aggregate(true, true, true, true, false); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return p, nil
|
||||
}
|
||||
|
||||
// parseJavaProfile returns a new profile from heapz or contentionz
|
||||
// data. b is the profile bytes after the header.
|
||||
func parseJavaProfile(b []byte) (*Profile, error) {
|
||||
h := bytes.SplitAfterN(b, []byte("\n"), 2)
|
||||
if len(h) < 2 {
|
||||
return nil, errUnrecognized
|
||||
}
|
||||
|
||||
p := &Profile{
|
||||
PeriodType: &ValueType{},
|
||||
}
|
||||
header := string(bytes.TrimSpace(h[0]))
|
||||
|
||||
var err error
|
||||
var pType string
|
||||
switch header {
|
||||
case "--- heapz 1 ---":
|
||||
pType = "heap"
|
||||
case "--- contentionz 1 ---":
|
||||
pType = "contention"
|
||||
default:
|
||||
return nil, errUnrecognized
|
||||
}
|
||||
|
||||
if b, err = parseJavaHeader(pType, h[1], p); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var locs map[uint64]*Location
|
||||
if b, locs, err = parseJavaSamples(pType, b, p); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = parseJavaLocations(b, locs, p); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Strip out addresses for better merge.
|
||||
if err = p.Aggregate(true, true, true, true, false); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return p, nil
|
||||
}
|
||||
|
||||
// parseJavaHeader parses the attribute section on a java profile and
|
||||
// populates a profile. Returns the remainder of the buffer after all
|
||||
// attributes.
|
||||
func parseJavaHeader(pType string, b []byte, p *Profile) ([]byte, error) {
|
||||
nextNewLine := bytes.IndexByte(b, byte('\n'))
|
||||
for nextNewLine != -1 {
|
||||
line := string(bytes.TrimSpace(b[0:nextNewLine]))
|
||||
if line != "" {
|
||||
h := attributeRx.FindStringSubmatch(line)
|
||||
if h == nil {
|
||||
// Not a valid attribute, exit.
|
||||
return b, nil
|
||||
}
|
||||
|
||||
attribute, value := strings.TrimSpace(h[1]), strings.TrimSpace(h[2])
|
||||
var err error
|
||||
switch pType + "/" + attribute {
|
||||
case "heap/format", "cpu/format", "contention/format":
|
||||
if value != "java" {
|
||||
return nil, errUnrecognized
|
||||
}
|
||||
case "heap/resolution":
|
||||
p.SampleType = []*ValueType{
|
||||
{Type: "inuse_objects", Unit: "count"},
|
||||
{Type: "inuse_space", Unit: value},
|
||||
}
|
||||
case "contention/resolution":
|
||||
p.SampleType = []*ValueType{
|
||||
{Type: "contentions", Unit: "count"},
|
||||
{Type: "delay", Unit: value},
|
||||
}
|
||||
case "contention/sampling period":
|
||||
p.PeriodType = &ValueType{
|
||||
Type: "contentions", Unit: "count",
|
||||
}
|
||||
if p.Period, err = strconv.ParseInt(value, 0, 64); err != nil {
|
||||
return nil, fmt.Errorf("failed to parse attribute %s: %v", line, err)
|
||||
}
|
||||
case "contention/ms since reset":
|
||||
millis, err := strconv.ParseInt(value, 0, 64)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse attribute %s: %v", line, err)
|
||||
}
|
||||
p.DurationNanos = millis * 1000 * 1000
|
||||
default:
|
||||
return nil, errUnrecognized
|
||||
}
|
||||
}
|
||||
// Grab next line.
|
||||
b = b[nextNewLine+1:]
|
||||
nextNewLine = bytes.IndexByte(b, byte('\n'))
|
||||
}
|
||||
return b, nil
|
||||
}
|
||||
|
||||
// parseJavaSamples parses the samples from a java profile and
|
||||
// populates the Samples in a profile. Returns the remainder of the
|
||||
// buffer after the samples.
|
||||
func parseJavaSamples(pType string, b []byte, p *Profile) ([]byte, map[uint64]*Location, error) {
|
||||
nextNewLine := bytes.IndexByte(b, byte('\n'))
|
||||
locs := make(map[uint64]*Location)
|
||||
for nextNewLine != -1 {
|
||||
line := string(bytes.TrimSpace(b[0:nextNewLine]))
|
||||
if line != "" {
|
||||
sample := javaSampleRx.FindStringSubmatch(line)
|
||||
if sample == nil {
|
||||
// Not a valid sample, exit.
|
||||
return b, locs, nil
|
||||
}
|
||||
|
||||
// Java profiles have data/fields inverted compared to other
|
||||
// profile types.
|
||||
var err error
|
||||
value1, value2, value3 := sample[2], sample[1], sample[3]
|
||||
addrs, err := parseHexAddresses(value3)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("malformed sample: %s: %v", line, err)
|
||||
}
|
||||
|
||||
var sloc []*Location
|
||||
for _, addr := range addrs {
|
||||
loc := locs[addr]
|
||||
if locs[addr] == nil {
|
||||
loc = &Location{
|
||||
Address: addr,
|
||||
}
|
||||
p.Location = append(p.Location, loc)
|
||||
locs[addr] = loc
|
||||
}
|
||||
sloc = append(sloc, loc)
|
||||
}
|
||||
s := &Sample{
|
||||
Value: make([]int64, 2),
|
||||
Location: sloc,
|
||||
}
|
||||
|
||||
if s.Value[0], err = strconv.ParseInt(value1, 0, 64); err != nil {
|
||||
return nil, nil, fmt.Errorf("parsing sample %s: %v", line, err)
|
||||
}
|
||||
if s.Value[1], err = strconv.ParseInt(value2, 0, 64); err != nil {
|
||||
return nil, nil, fmt.Errorf("parsing sample %s: %v", line, err)
|
||||
}
|
||||
|
||||
switch pType {
|
||||
case "heap":
|
||||
const javaHeapzSamplingRate = 524288 // 512K
|
||||
if s.Value[0] == 0 {
|
||||
return nil, nil, fmt.Errorf("parsing sample %s: second value must be non-zero", line)
|
||||
}
|
||||
s.NumLabel = map[string][]int64{"bytes": {s.Value[1] / s.Value[0]}}
|
||||
s.Value[0], s.Value[1] = scaleHeapSample(s.Value[0], s.Value[1], javaHeapzSamplingRate)
|
||||
case "contention":
|
||||
if period := p.Period; period != 0 {
|
||||
s.Value[0] = s.Value[0] * p.Period
|
||||
s.Value[1] = s.Value[1] * p.Period
|
||||
}
|
||||
}
|
||||
p.Sample = append(p.Sample, s)
|
||||
}
|
||||
// Grab next line.
|
||||
b = b[nextNewLine+1:]
|
||||
nextNewLine = bytes.IndexByte(b, byte('\n'))
|
||||
}
|
||||
return b, locs, nil
|
||||
}
|
||||
|
||||
// parseJavaLocations parses the location information in a java
|
||||
// profile and populates the Locations in a profile. It uses the
|
||||
// location addresses from the profile as both the ID of each
|
||||
// location.
|
||||
func parseJavaLocations(b []byte, locs map[uint64]*Location, p *Profile) error {
|
||||
r := bytes.NewBuffer(b)
|
||||
fns := make(map[string]*Function)
|
||||
for {
|
||||
line, err := r.ReadString('\n')
|
||||
if err != nil {
|
||||
if err != io.EOF {
|
||||
return err
|
||||
}
|
||||
if line == "" {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if line = strings.TrimSpace(line); line == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
jloc := javaLocationRx.FindStringSubmatch(line)
|
||||
if len(jloc) != 3 {
|
||||
continue
|
||||
}
|
||||
addr, err := strconv.ParseUint(jloc[1], 16, 64)
|
||||
if err != nil {
|
||||
return fmt.Errorf("parsing sample %s: %v", line, err)
|
||||
}
|
||||
loc := locs[addr]
|
||||
if loc == nil {
|
||||
// Unused/unseen
|
||||
continue
|
||||
}
|
||||
var lineFunc, lineFile string
|
||||
var lineNo int64
|
||||
|
||||
if fileLine := javaLocationFileLineRx.FindStringSubmatch(jloc[2]); len(fileLine) == 4 {
|
||||
// Found a line of the form: "function (file:line)"
|
||||
lineFunc, lineFile = fileLine[1], fileLine[2]
|
||||
if n, err := strconv.ParseInt(fileLine[3], 10, 64); err == nil && n > 0 {
|
||||
lineNo = n
|
||||
}
|
||||
} else if filePath := javaLocationPathRx.FindStringSubmatch(jloc[2]); len(filePath) == 3 {
|
||||
// If there's not a file:line, it's a shared library path.
|
||||
// The path isn't interesting, so just give the .so.
|
||||
lineFunc, lineFile = filePath[1], filepath.Base(filePath[2])
|
||||
} else if strings.Contains(jloc[2], "generated stub/JIT") {
|
||||
lineFunc = "STUB"
|
||||
} else {
|
||||
// Treat whole line as the function name. This is used by the
|
||||
// java agent for internal states such as "GC" or "VM".
|
||||
lineFunc = jloc[2]
|
||||
}
|
||||
fn := fns[lineFunc]
|
||||
|
||||
if fn == nil {
|
||||
fn = &Function{
|
||||
Name: lineFunc,
|
||||
SystemName: lineFunc,
|
||||
Filename: lineFile,
|
||||
}
|
||||
fns[lineFunc] = fn
|
||||
p.Function = append(p.Function, fn)
|
||||
}
|
||||
loc.Line = []Line{
|
||||
{
|
||||
Function: fn,
|
||||
Line: lineNo,
|
||||
},
|
||||
}
|
||||
loc.Address = 0
|
||||
}
|
||||
|
||||
p.remapLocationIDs()
|
||||
p.remapFunctionIDs()
|
||||
p.remapMappingIDs()
|
||||
|
||||
return nil
|
||||
}
|
1225
vendor/github.com/google/pprof/profile/legacy_profile.go
generated
vendored
Normal file
1225
vendor/github.com/google/pprof/profile/legacy_profile.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
481
vendor/github.com/google/pprof/profile/merge.go
generated
vendored
Normal file
481
vendor/github.com/google/pprof/profile/merge.go
generated
vendored
Normal file
@ -0,0 +1,481 @@
|
||||
// Copyright 2014 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package profile
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Compact performs garbage collection on a profile to remove any
|
||||
// unreferenced fields. This is useful to reduce the size of a profile
|
||||
// after samples or locations have been removed.
|
||||
func (p *Profile) Compact() *Profile {
|
||||
p, _ = Merge([]*Profile{p})
|
||||
return p
|
||||
}
|
||||
|
||||
// Merge merges all the profiles in profs into a single Profile.
|
||||
// Returns a new profile independent of the input profiles. The merged
|
||||
// profile is compacted to eliminate unused samples, locations,
|
||||
// functions and mappings. Profiles must have identical profile sample
|
||||
// and period types or the merge will fail. profile.Period of the
|
||||
// resulting profile will be the maximum of all profiles, and
|
||||
// profile.TimeNanos will be the earliest nonzero one. Merges are
|
||||
// associative with the caveat of the first profile having some
|
||||
// specialization in how headers are combined. There may be other
|
||||
// subtleties now or in the future regarding associativity.
|
||||
func Merge(srcs []*Profile) (*Profile, error) {
|
||||
if len(srcs) == 0 {
|
||||
return nil, fmt.Errorf("no profiles to merge")
|
||||
}
|
||||
p, err := combineHeaders(srcs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pm := &profileMerger{
|
||||
p: p,
|
||||
samples: make(map[sampleKey]*Sample, len(srcs[0].Sample)),
|
||||
locations: make(map[locationKey]*Location, len(srcs[0].Location)),
|
||||
functions: make(map[functionKey]*Function, len(srcs[0].Function)),
|
||||
mappings: make(map[mappingKey]*Mapping, len(srcs[0].Mapping)),
|
||||
}
|
||||
|
||||
for _, src := range srcs {
|
||||
// Clear the profile-specific hash tables
|
||||
pm.locationsByID = make(map[uint64]*Location, len(src.Location))
|
||||
pm.functionsByID = make(map[uint64]*Function, len(src.Function))
|
||||
pm.mappingsByID = make(map[uint64]mapInfo, len(src.Mapping))
|
||||
|
||||
if len(pm.mappings) == 0 && len(src.Mapping) > 0 {
|
||||
// The Mapping list has the property that the first mapping
|
||||
// represents the main binary. Take the first Mapping we see,
|
||||
// otherwise the operations below will add mappings in an
|
||||
// arbitrary order.
|
||||
pm.mapMapping(src.Mapping[0])
|
||||
}
|
||||
|
||||
for _, s := range src.Sample {
|
||||
if !isZeroSample(s) {
|
||||
pm.mapSample(s)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, s := range p.Sample {
|
||||
if isZeroSample(s) {
|
||||
// If there are any zero samples, re-merge the profile to GC
|
||||
// them.
|
||||
return Merge([]*Profile{p})
|
||||
}
|
||||
}
|
||||
|
||||
return p, nil
|
||||
}
|
||||
|
||||
// Normalize normalizes the source profile by multiplying each value in profile by the
|
||||
// ratio of the sum of the base profile's values of that sample type to the sum of the
|
||||
// source profile's value of that sample type.
|
||||
func (p *Profile) Normalize(pb *Profile) error {
|
||||
|
||||
if err := p.compatible(pb); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
baseVals := make([]int64, len(p.SampleType))
|
||||
for _, s := range pb.Sample {
|
||||
for i, v := range s.Value {
|
||||
baseVals[i] += v
|
||||
}
|
||||
}
|
||||
|
||||
srcVals := make([]int64, len(p.SampleType))
|
||||
for _, s := range p.Sample {
|
||||
for i, v := range s.Value {
|
||||
srcVals[i] += v
|
||||
}
|
||||
}
|
||||
|
||||
normScale := make([]float64, len(baseVals))
|
||||
for i := range baseVals {
|
||||
if srcVals[i] == 0 {
|
||||
normScale[i] = 0.0
|
||||
} else {
|
||||
normScale[i] = float64(baseVals[i]) / float64(srcVals[i])
|
||||
}
|
||||
}
|
||||
p.ScaleN(normScale)
|
||||
return nil
|
||||
}
|
||||
|
||||
func isZeroSample(s *Sample) bool {
|
||||
for _, v := range s.Value {
|
||||
if v != 0 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
type profileMerger struct {
|
||||
p *Profile
|
||||
|
||||
// Memoization tables within a profile.
|
||||
locationsByID map[uint64]*Location
|
||||
functionsByID map[uint64]*Function
|
||||
mappingsByID map[uint64]mapInfo
|
||||
|
||||
// Memoization tables for profile entities.
|
||||
samples map[sampleKey]*Sample
|
||||
locations map[locationKey]*Location
|
||||
functions map[functionKey]*Function
|
||||
mappings map[mappingKey]*Mapping
|
||||
}
|
||||
|
||||
type mapInfo struct {
|
||||
m *Mapping
|
||||
offset int64
|
||||
}
|
||||
|
||||
func (pm *profileMerger) mapSample(src *Sample) *Sample {
|
||||
s := &Sample{
|
||||
Location: make([]*Location, len(src.Location)),
|
||||
Value: make([]int64, len(src.Value)),
|
||||
Label: make(map[string][]string, len(src.Label)),
|
||||
NumLabel: make(map[string][]int64, len(src.NumLabel)),
|
||||
NumUnit: make(map[string][]string, len(src.NumLabel)),
|
||||
}
|
||||
for i, l := range src.Location {
|
||||
s.Location[i] = pm.mapLocation(l)
|
||||
}
|
||||
for k, v := range src.Label {
|
||||
vv := make([]string, len(v))
|
||||
copy(vv, v)
|
||||
s.Label[k] = vv
|
||||
}
|
||||
for k, v := range src.NumLabel {
|
||||
u := src.NumUnit[k]
|
||||
vv := make([]int64, len(v))
|
||||
uu := make([]string, len(u))
|
||||
copy(vv, v)
|
||||
copy(uu, u)
|
||||
s.NumLabel[k] = vv
|
||||
s.NumUnit[k] = uu
|
||||
}
|
||||
// Check memoization table. Must be done on the remapped location to
|
||||
// account for the remapped mapping. Add current values to the
|
||||
// existing sample.
|
||||
k := s.key()
|
||||
if ss, ok := pm.samples[k]; ok {
|
||||
for i, v := range src.Value {
|
||||
ss.Value[i] += v
|
||||
}
|
||||
return ss
|
||||
}
|
||||
copy(s.Value, src.Value)
|
||||
pm.samples[k] = s
|
||||
pm.p.Sample = append(pm.p.Sample, s)
|
||||
return s
|
||||
}
|
||||
|
||||
// key generates sampleKey to be used as a key for maps.
|
||||
func (sample *Sample) key() sampleKey {
|
||||
ids := make([]string, len(sample.Location))
|
||||
for i, l := range sample.Location {
|
||||
ids[i] = strconv.FormatUint(l.ID, 16)
|
||||
}
|
||||
|
||||
labels := make([]string, 0, len(sample.Label))
|
||||
for k, v := range sample.Label {
|
||||
labels = append(labels, fmt.Sprintf("%q%q", k, v))
|
||||
}
|
||||
sort.Strings(labels)
|
||||
|
||||
numlabels := make([]string, 0, len(sample.NumLabel))
|
||||
for k, v := range sample.NumLabel {
|
||||
numlabels = append(numlabels, fmt.Sprintf("%q%x%x", k, v, sample.NumUnit[k]))
|
||||
}
|
||||
sort.Strings(numlabels)
|
||||
|
||||
return sampleKey{
|
||||
strings.Join(ids, "|"),
|
||||
strings.Join(labels, ""),
|
||||
strings.Join(numlabels, ""),
|
||||
}
|
||||
}
|
||||
|
||||
type sampleKey struct {
|
||||
locations string
|
||||
labels string
|
||||
numlabels string
|
||||
}
|
||||
|
||||
func (pm *profileMerger) mapLocation(src *Location) *Location {
|
||||
if src == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if l, ok := pm.locationsByID[src.ID]; ok {
|
||||
return l
|
||||
}
|
||||
|
||||
mi := pm.mapMapping(src.Mapping)
|
||||
l := &Location{
|
||||
ID: uint64(len(pm.p.Location) + 1),
|
||||
Mapping: mi.m,
|
||||
Address: uint64(int64(src.Address) + mi.offset),
|
||||
Line: make([]Line, len(src.Line)),
|
||||
IsFolded: src.IsFolded,
|
||||
}
|
||||
for i, ln := range src.Line {
|
||||
l.Line[i] = pm.mapLine(ln)
|
||||
}
|
||||
// Check memoization table. Must be done on the remapped location to
|
||||
// account for the remapped mapping ID.
|
||||
k := l.key()
|
||||
if ll, ok := pm.locations[k]; ok {
|
||||
pm.locationsByID[src.ID] = ll
|
||||
return ll
|
||||
}
|
||||
pm.locationsByID[src.ID] = l
|
||||
pm.locations[k] = l
|
||||
pm.p.Location = append(pm.p.Location, l)
|
||||
return l
|
||||
}
|
||||
|
||||
// key generates locationKey to be used as a key for maps.
|
||||
func (l *Location) key() locationKey {
|
||||
key := locationKey{
|
||||
addr: l.Address,
|
||||
isFolded: l.IsFolded,
|
||||
}
|
||||
if l.Mapping != nil {
|
||||
// Normalizes address to handle address space randomization.
|
||||
key.addr -= l.Mapping.Start
|
||||
key.mappingID = l.Mapping.ID
|
||||
}
|
||||
lines := make([]string, len(l.Line)*2)
|
||||
for i, line := range l.Line {
|
||||
if line.Function != nil {
|
||||
lines[i*2] = strconv.FormatUint(line.Function.ID, 16)
|
||||
}
|
||||
lines[i*2+1] = strconv.FormatInt(line.Line, 16)
|
||||
}
|
||||
key.lines = strings.Join(lines, "|")
|
||||
return key
|
||||
}
|
||||
|
||||
type locationKey struct {
|
||||
addr, mappingID uint64
|
||||
lines string
|
||||
isFolded bool
|
||||
}
|
||||
|
||||
func (pm *profileMerger) mapMapping(src *Mapping) mapInfo {
|
||||
if src == nil {
|
||||
return mapInfo{}
|
||||
}
|
||||
|
||||
if mi, ok := pm.mappingsByID[src.ID]; ok {
|
||||
return mi
|
||||
}
|
||||
|
||||
// Check memoization tables.
|
||||
mk := src.key()
|
||||
if m, ok := pm.mappings[mk]; ok {
|
||||
mi := mapInfo{m, int64(m.Start) - int64(src.Start)}
|
||||
pm.mappingsByID[src.ID] = mi
|
||||
return mi
|
||||
}
|
||||
m := &Mapping{
|
||||
ID: uint64(len(pm.p.Mapping) + 1),
|
||||
Start: src.Start,
|
||||
Limit: src.Limit,
|
||||
Offset: src.Offset,
|
||||
File: src.File,
|
||||
BuildID: src.BuildID,
|
||||
HasFunctions: src.HasFunctions,
|
||||
HasFilenames: src.HasFilenames,
|
||||
HasLineNumbers: src.HasLineNumbers,
|
||||
HasInlineFrames: src.HasInlineFrames,
|
||||
}
|
||||
pm.p.Mapping = append(pm.p.Mapping, m)
|
||||
|
||||
// Update memoization tables.
|
||||
pm.mappings[mk] = m
|
||||
mi := mapInfo{m, 0}
|
||||
pm.mappingsByID[src.ID] = mi
|
||||
return mi
|
||||
}
|
||||
|
||||
// key generates encoded strings of Mapping to be used as a key for
|
||||
// maps.
|
||||
func (m *Mapping) key() mappingKey {
|
||||
// Normalize addresses to handle address space randomization.
|
||||
// Round up to next 4K boundary to avoid minor discrepancies.
|
||||
const mapsizeRounding = 0x1000
|
||||
|
||||
size := m.Limit - m.Start
|
||||
size = size + mapsizeRounding - 1
|
||||
size = size - (size % mapsizeRounding)
|
||||
key := mappingKey{
|
||||
size: size,
|
||||
offset: m.Offset,
|
||||
}
|
||||
|
||||
switch {
|
||||
case m.BuildID != "":
|
||||
key.buildIDOrFile = m.BuildID
|
||||
case m.File != "":
|
||||
key.buildIDOrFile = m.File
|
||||
default:
|
||||
// A mapping containing neither build ID nor file name is a fake mapping. A
|
||||
// key with empty buildIDOrFile is used for fake mappings so that they are
|
||||
// treated as the same mapping during merging.
|
||||
}
|
||||
return key
|
||||
}
|
||||
|
||||
type mappingKey struct {
|
||||
size, offset uint64
|
||||
buildIDOrFile string
|
||||
}
|
||||
|
||||
func (pm *profileMerger) mapLine(src Line) Line {
|
||||
ln := Line{
|
||||
Function: pm.mapFunction(src.Function),
|
||||
Line: src.Line,
|
||||
}
|
||||
return ln
|
||||
}
|
||||
|
||||
func (pm *profileMerger) mapFunction(src *Function) *Function {
|
||||
if src == nil {
|
||||
return nil
|
||||
}
|
||||
if f, ok := pm.functionsByID[src.ID]; ok {
|
||||
return f
|
||||
}
|
||||
k := src.key()
|
||||
if f, ok := pm.functions[k]; ok {
|
||||
pm.functionsByID[src.ID] = f
|
||||
return f
|
||||
}
|
||||
f := &Function{
|
||||
ID: uint64(len(pm.p.Function) + 1),
|
||||
Name: src.Name,
|
||||
SystemName: src.SystemName,
|
||||
Filename: src.Filename,
|
||||
StartLine: src.StartLine,
|
||||
}
|
||||
pm.functions[k] = f
|
||||
pm.functionsByID[src.ID] = f
|
||||
pm.p.Function = append(pm.p.Function, f)
|
||||
return f
|
||||
}
|
||||
|
||||
// key generates a struct to be used as a key for maps.
|
||||
func (f *Function) key() functionKey {
|
||||
return functionKey{
|
||||
f.StartLine,
|
||||
f.Name,
|
||||
f.SystemName,
|
||||
f.Filename,
|
||||
}
|
||||
}
|
||||
|
||||
type functionKey struct {
|
||||
startLine int64
|
||||
name, systemName, fileName string
|
||||
}
|
||||
|
||||
// combineHeaders checks that all profiles can be merged and returns
|
||||
// their combined profile.
|
||||
func combineHeaders(srcs []*Profile) (*Profile, error) {
|
||||
for _, s := range srcs[1:] {
|
||||
if err := srcs[0].compatible(s); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
var timeNanos, durationNanos, period int64
|
||||
var comments []string
|
||||
seenComments := map[string]bool{}
|
||||
var defaultSampleType string
|
||||
for _, s := range srcs {
|
||||
if timeNanos == 0 || s.TimeNanos < timeNanos {
|
||||
timeNanos = s.TimeNanos
|
||||
}
|
||||
durationNanos += s.DurationNanos
|
||||
if period == 0 || period < s.Period {
|
||||
period = s.Period
|
||||
}
|
||||
for _, c := range s.Comments {
|
||||
if seen := seenComments[c]; !seen {
|
||||
comments = append(comments, c)
|
||||
seenComments[c] = true
|
||||
}
|
||||
}
|
||||
if defaultSampleType == "" {
|
||||
defaultSampleType = s.DefaultSampleType
|
||||
}
|
||||
}
|
||||
|
||||
p := &Profile{
|
||||
SampleType: make([]*ValueType, len(srcs[0].SampleType)),
|
||||
|
||||
DropFrames: srcs[0].DropFrames,
|
||||
KeepFrames: srcs[0].KeepFrames,
|
||||
|
||||
TimeNanos: timeNanos,
|
||||
DurationNanos: durationNanos,
|
||||
PeriodType: srcs[0].PeriodType,
|
||||
Period: period,
|
||||
|
||||
Comments: comments,
|
||||
DefaultSampleType: defaultSampleType,
|
||||
}
|
||||
copy(p.SampleType, srcs[0].SampleType)
|
||||
return p, nil
|
||||
}
|
||||
|
||||
// compatible determines if two profiles can be compared/merged.
|
||||
// returns nil if the profiles are compatible; otherwise an error with
|
||||
// details on the incompatibility.
|
||||
func (p *Profile) compatible(pb *Profile) error {
|
||||
if !equalValueType(p.PeriodType, pb.PeriodType) {
|
||||
return fmt.Errorf("incompatible period types %v and %v", p.PeriodType, pb.PeriodType)
|
||||
}
|
||||
|
||||
if len(p.SampleType) != len(pb.SampleType) {
|
||||
return fmt.Errorf("incompatible sample types %v and %v", p.SampleType, pb.SampleType)
|
||||
}
|
||||
|
||||
for i := range p.SampleType {
|
||||
if !equalValueType(p.SampleType[i], pb.SampleType[i]) {
|
||||
return fmt.Errorf("incompatible sample types %v and %v", p.SampleType, pb.SampleType)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// equalValueType returns true if the two value types are semantically
|
||||
// equal. It ignores the internal fields used during encode/decode.
|
||||
func equalValueType(st1, st2 *ValueType) bool {
|
||||
return st1.Type == st2.Type && st1.Unit == st2.Unit
|
||||
}
|
805
vendor/github.com/google/pprof/profile/profile.go
generated
vendored
Normal file
805
vendor/github.com/google/pprof/profile/profile.go
generated
vendored
Normal file
@ -0,0 +1,805 @@
|
||||
// Copyright 2014 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package profile provides a representation of profile.proto and
|
||||
// methods to encode/decode profiles in this format.
|
||||
package profile
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"math"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Profile is an in-memory representation of profile.proto.
|
||||
type Profile struct {
|
||||
SampleType []*ValueType
|
||||
DefaultSampleType string
|
||||
Sample []*Sample
|
||||
Mapping []*Mapping
|
||||
Location []*Location
|
||||
Function []*Function
|
||||
Comments []string
|
||||
|
||||
DropFrames string
|
||||
KeepFrames string
|
||||
|
||||
TimeNanos int64
|
||||
DurationNanos int64
|
||||
PeriodType *ValueType
|
||||
Period int64
|
||||
|
||||
// The following fields are modified during encoding and copying,
|
||||
// so are protected by a Mutex.
|
||||
encodeMu sync.Mutex
|
||||
|
||||
commentX []int64
|
||||
dropFramesX int64
|
||||
keepFramesX int64
|
||||
stringTable []string
|
||||
defaultSampleTypeX int64
|
||||
}
|
||||
|
||||
// ValueType corresponds to Profile.ValueType
|
||||
type ValueType struct {
|
||||
Type string // cpu, wall, inuse_space, etc
|
||||
Unit string // seconds, nanoseconds, bytes, etc
|
||||
|
||||
typeX int64
|
||||
unitX int64
|
||||
}
|
||||
|
||||
// Sample corresponds to Profile.Sample
|
||||
type Sample struct {
|
||||
Location []*Location
|
||||
Value []int64
|
||||
Label map[string][]string
|
||||
NumLabel map[string][]int64
|
||||
NumUnit map[string][]string
|
||||
|
||||
locationIDX []uint64
|
||||
labelX []label
|
||||
}
|
||||
|
||||
// label corresponds to Profile.Label
|
||||
type label struct {
|
||||
keyX int64
|
||||
// Exactly one of the two following values must be set
|
||||
strX int64
|
||||
numX int64 // Integer value for this label
|
||||
// can be set if numX has value
|
||||
unitX int64
|
||||
}
|
||||
|
||||
// Mapping corresponds to Profile.Mapping
|
||||
type Mapping struct {
|
||||
ID uint64
|
||||
Start uint64
|
||||
Limit uint64
|
||||
Offset uint64
|
||||
File string
|
||||
BuildID string
|
||||
HasFunctions bool
|
||||
HasFilenames bool
|
||||
HasLineNumbers bool
|
||||
HasInlineFrames bool
|
||||
|
||||
fileX int64
|
||||
buildIDX int64
|
||||
}
|
||||
|
||||
// Location corresponds to Profile.Location
|
||||
type Location struct {
|
||||
ID uint64
|
||||
Mapping *Mapping
|
||||
Address uint64
|
||||
Line []Line
|
||||
IsFolded bool
|
||||
|
||||
mappingIDX uint64
|
||||
}
|
||||
|
||||
// Line corresponds to Profile.Line
|
||||
type Line struct {
|
||||
Function *Function
|
||||
Line int64
|
||||
|
||||
functionIDX uint64
|
||||
}
|
||||
|
||||
// Function corresponds to Profile.Function
|
||||
type Function struct {
|
||||
ID uint64
|
||||
Name string
|
||||
SystemName string
|
||||
Filename string
|
||||
StartLine int64
|
||||
|
||||
nameX int64
|
||||
systemNameX int64
|
||||
filenameX int64
|
||||
}
|
||||
|
||||
// Parse parses a profile and checks for its validity. The input
|
||||
// may be a gzip-compressed encoded protobuf or one of many legacy
|
||||
// profile formats which may be unsupported in the future.
|
||||
func Parse(r io.Reader) (*Profile, error) {
|
||||
data, err := ioutil.ReadAll(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ParseData(data)
|
||||
}
|
||||
|
||||
// ParseData parses a profile from a buffer and checks for its
|
||||
// validity.
|
||||
func ParseData(data []byte) (*Profile, error) {
|
||||
var p *Profile
|
||||
var err error
|
||||
if len(data) >= 2 && data[0] == 0x1f && data[1] == 0x8b {
|
||||
gz, err := gzip.NewReader(bytes.NewBuffer(data))
|
||||
if err == nil {
|
||||
data, err = ioutil.ReadAll(gz)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("decompressing profile: %v", err)
|
||||
}
|
||||
}
|
||||
if p, err = ParseUncompressed(data); err != nil && err != errNoData && err != errConcatProfile {
|
||||
p, err = parseLegacy(data)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parsing profile: %v", err)
|
||||
}
|
||||
|
||||
if err := p.CheckValid(); err != nil {
|
||||
return nil, fmt.Errorf("malformed profile: %v", err)
|
||||
}
|
||||
return p, nil
|
||||
}
|
||||
|
||||
var errUnrecognized = fmt.Errorf("unrecognized profile format")
|
||||
var errMalformed = fmt.Errorf("malformed profile format")
|
||||
var errNoData = fmt.Errorf("empty input file")
|
||||
var errConcatProfile = fmt.Errorf("concatenated profiles detected")
|
||||
|
||||
func parseLegacy(data []byte) (*Profile, error) {
|
||||
parsers := []func([]byte) (*Profile, error){
|
||||
parseCPU,
|
||||
parseHeap,
|
||||
parseGoCount, // goroutine, threadcreate
|
||||
parseThread,
|
||||
parseContention,
|
||||
parseJavaProfile,
|
||||
}
|
||||
|
||||
for _, parser := range parsers {
|
||||
p, err := parser(data)
|
||||
if err == nil {
|
||||
p.addLegacyFrameInfo()
|
||||
return p, nil
|
||||
}
|
||||
if err != errUnrecognized {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return nil, errUnrecognized
|
||||
}
|
||||
|
||||
// ParseUncompressed parses an uncompressed protobuf into a profile.
|
||||
func ParseUncompressed(data []byte) (*Profile, error) {
|
||||
if len(data) == 0 {
|
||||
return nil, errNoData
|
||||
}
|
||||
p := &Profile{}
|
||||
if err := unmarshal(data, p); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := p.postDecode(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return p, nil
|
||||
}
|
||||
|
||||
var libRx = regexp.MustCompile(`([.]so$|[.]so[._][0-9]+)`)
|
||||
|
||||
// massageMappings applies heuristic-based changes to the profile
|
||||
// mappings to account for quirks of some environments.
|
||||
func (p *Profile) massageMappings() {
|
||||
// Merge adjacent regions with matching names, checking that the offsets match
|
||||
if len(p.Mapping) > 1 {
|
||||
mappings := []*Mapping{p.Mapping[0]}
|
||||
for _, m := range p.Mapping[1:] {
|
||||
lm := mappings[len(mappings)-1]
|
||||
if adjacent(lm, m) {
|
||||
lm.Limit = m.Limit
|
||||
if m.File != "" {
|
||||
lm.File = m.File
|
||||
}
|
||||
if m.BuildID != "" {
|
||||
lm.BuildID = m.BuildID
|
||||
}
|
||||
p.updateLocationMapping(m, lm)
|
||||
continue
|
||||
}
|
||||
mappings = append(mappings, m)
|
||||
}
|
||||
p.Mapping = mappings
|
||||
}
|
||||
|
||||
// Use heuristics to identify main binary and move it to the top of the list of mappings
|
||||
for i, m := range p.Mapping {
|
||||
file := strings.TrimSpace(strings.Replace(m.File, "(deleted)", "", -1))
|
||||
if len(file) == 0 {
|
||||
continue
|
||||
}
|
||||
if len(libRx.FindStringSubmatch(file)) > 0 {
|
||||
continue
|
||||
}
|
||||
if file[0] == '[' {
|
||||
continue
|
||||
}
|
||||
// Swap what we guess is main to position 0.
|
||||
p.Mapping[0], p.Mapping[i] = p.Mapping[i], p.Mapping[0]
|
||||
break
|
||||
}
|
||||
|
||||
// Keep the mapping IDs neatly sorted
|
||||
for i, m := range p.Mapping {
|
||||
m.ID = uint64(i + 1)
|
||||
}
|
||||
}
|
||||
|
||||
// adjacent returns whether two mapping entries represent the same
|
||||
// mapping that has been split into two. Check that their addresses are adjacent,
|
||||
// and if the offsets match, if they are available.
|
||||
func adjacent(m1, m2 *Mapping) bool {
|
||||
if m1.File != "" && m2.File != "" {
|
||||
if m1.File != m2.File {
|
||||
return false
|
||||
}
|
||||
}
|
||||
if m1.BuildID != "" && m2.BuildID != "" {
|
||||
if m1.BuildID != m2.BuildID {
|
||||
return false
|
||||
}
|
||||
}
|
||||
if m1.Limit != m2.Start {
|
||||
return false
|
||||
}
|
||||
if m1.Offset != 0 && m2.Offset != 0 {
|
||||
offset := m1.Offset + (m1.Limit - m1.Start)
|
||||
if offset != m2.Offset {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (p *Profile) updateLocationMapping(from, to *Mapping) {
|
||||
for _, l := range p.Location {
|
||||
if l.Mapping == from {
|
||||
l.Mapping = to
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func serialize(p *Profile) []byte {
|
||||
p.encodeMu.Lock()
|
||||
p.preEncode()
|
||||
b := marshal(p)
|
||||
p.encodeMu.Unlock()
|
||||
return b
|
||||
}
|
||||
|
||||
// Write writes the profile as a gzip-compressed marshaled protobuf.
|
||||
func (p *Profile) Write(w io.Writer) error {
|
||||
zw := gzip.NewWriter(w)
|
||||
defer zw.Close()
|
||||
_, err := zw.Write(serialize(p))
|
||||
return err
|
||||
}
|
||||
|
||||
// WriteUncompressed writes the profile as a marshaled protobuf.
|
||||
func (p *Profile) WriteUncompressed(w io.Writer) error {
|
||||
_, err := w.Write(serialize(p))
|
||||
return err
|
||||
}
|
||||
|
||||
// CheckValid tests whether the profile is valid. Checks include, but are
|
||||
// not limited to:
|
||||
// - len(Profile.Sample[n].value) == len(Profile.value_unit)
|
||||
// - Sample.id has a corresponding Profile.Location
|
||||
func (p *Profile) CheckValid() error {
|
||||
// Check that sample values are consistent
|
||||
sampleLen := len(p.SampleType)
|
||||
if sampleLen == 0 && len(p.Sample) != 0 {
|
||||
return fmt.Errorf("missing sample type information")
|
||||
}
|
||||
for _, s := range p.Sample {
|
||||
if s == nil {
|
||||
return fmt.Errorf("profile has nil sample")
|
||||
}
|
||||
if len(s.Value) != sampleLen {
|
||||
return fmt.Errorf("mismatch: sample has %d values vs. %d types", len(s.Value), len(p.SampleType))
|
||||
}
|
||||
for _, l := range s.Location {
|
||||
if l == nil {
|
||||
return fmt.Errorf("sample has nil location")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check that all mappings/locations/functions are in the tables
|
||||
// Check that there are no duplicate ids
|
||||
mappings := make(map[uint64]*Mapping, len(p.Mapping))
|
||||
for _, m := range p.Mapping {
|
||||
if m == nil {
|
||||
return fmt.Errorf("profile has nil mapping")
|
||||
}
|
||||
if m.ID == 0 {
|
||||
return fmt.Errorf("found mapping with reserved ID=0")
|
||||
}
|
||||
if mappings[m.ID] != nil {
|
||||
return fmt.Errorf("multiple mappings with same id: %d", m.ID)
|
||||
}
|
||||
mappings[m.ID] = m
|
||||
}
|
||||
functions := make(map[uint64]*Function, len(p.Function))
|
||||
for _, f := range p.Function {
|
||||
if f == nil {
|
||||
return fmt.Errorf("profile has nil function")
|
||||
}
|
||||
if f.ID == 0 {
|
||||
return fmt.Errorf("found function with reserved ID=0")
|
||||
}
|
||||
if functions[f.ID] != nil {
|
||||
return fmt.Errorf("multiple functions with same id: %d", f.ID)
|
||||
}
|
||||
functions[f.ID] = f
|
||||
}
|
||||
locations := make(map[uint64]*Location, len(p.Location))
|
||||
for _, l := range p.Location {
|
||||
if l == nil {
|
||||
return fmt.Errorf("profile has nil location")
|
||||
}
|
||||
if l.ID == 0 {
|
||||
return fmt.Errorf("found location with reserved id=0")
|
||||
}
|
||||
if locations[l.ID] != nil {
|
||||
return fmt.Errorf("multiple locations with same id: %d", l.ID)
|
||||
}
|
||||
locations[l.ID] = l
|
||||
if m := l.Mapping; m != nil {
|
||||
if m.ID == 0 || mappings[m.ID] != m {
|
||||
return fmt.Errorf("inconsistent mapping %p: %d", m, m.ID)
|
||||
}
|
||||
}
|
||||
for _, ln := range l.Line {
|
||||
f := ln.Function
|
||||
if f == nil {
|
||||
return fmt.Errorf("location id: %d has a line with nil function", l.ID)
|
||||
}
|
||||
if f.ID == 0 || functions[f.ID] != f {
|
||||
return fmt.Errorf("inconsistent function %p: %d", f, f.ID)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Aggregate merges the locations in the profile into equivalence
|
||||
// classes preserving the request attributes. It also updates the
|
||||
// samples to point to the merged locations.
|
||||
func (p *Profile) Aggregate(inlineFrame, function, filename, linenumber, address bool) error {
|
||||
for _, m := range p.Mapping {
|
||||
m.HasInlineFrames = m.HasInlineFrames && inlineFrame
|
||||
m.HasFunctions = m.HasFunctions && function
|
||||
m.HasFilenames = m.HasFilenames && filename
|
||||
m.HasLineNumbers = m.HasLineNumbers && linenumber
|
||||
}
|
||||
|
||||
// Aggregate functions
|
||||
if !function || !filename {
|
||||
for _, f := range p.Function {
|
||||
if !function {
|
||||
f.Name = ""
|
||||
f.SystemName = ""
|
||||
}
|
||||
if !filename {
|
||||
f.Filename = ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Aggregate locations
|
||||
if !inlineFrame || !address || !linenumber {
|
||||
for _, l := range p.Location {
|
||||
if !inlineFrame && len(l.Line) > 1 {
|
||||
l.Line = l.Line[len(l.Line)-1:]
|
||||
}
|
||||
if !linenumber {
|
||||
for i := range l.Line {
|
||||
l.Line[i].Line = 0
|
||||
}
|
||||
}
|
||||
if !address {
|
||||
l.Address = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return p.CheckValid()
|
||||
}
|
||||
|
||||
// NumLabelUnits returns a map of numeric label keys to the units
|
||||
// associated with those keys and a map of those keys to any units
|
||||
// that were encountered but not used.
|
||||
// Unit for a given key is the first encountered unit for that key. If multiple
|
||||
// units are encountered for values paired with a particular key, then the first
|
||||
// unit encountered is used and all other units are returned in sorted order
|
||||
// in map of ignored units.
|
||||
// If no units are encountered for a particular key, the unit is then inferred
|
||||
// based on the key.
|
||||
func (p *Profile) NumLabelUnits() (map[string]string, map[string][]string) {
|
||||
numLabelUnits := map[string]string{}
|
||||
ignoredUnits := map[string]map[string]bool{}
|
||||
encounteredKeys := map[string]bool{}
|
||||
|
||||
// Determine units based on numeric tags for each sample.
|
||||
for _, s := range p.Sample {
|
||||
for k := range s.NumLabel {
|
||||
encounteredKeys[k] = true
|
||||
for _, unit := range s.NumUnit[k] {
|
||||
if unit == "" {
|
||||
continue
|
||||
}
|
||||
if wantUnit, ok := numLabelUnits[k]; !ok {
|
||||
numLabelUnits[k] = unit
|
||||
} else if wantUnit != unit {
|
||||
if v, ok := ignoredUnits[k]; ok {
|
||||
v[unit] = true
|
||||
} else {
|
||||
ignoredUnits[k] = map[string]bool{unit: true}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Infer units for keys without any units associated with
|
||||
// numeric tag values.
|
||||
for key := range encounteredKeys {
|
||||
unit := numLabelUnits[key]
|
||||
if unit == "" {
|
||||
switch key {
|
||||
case "alignment", "request":
|
||||
numLabelUnits[key] = "bytes"
|
||||
default:
|
||||
numLabelUnits[key] = key
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Copy ignored units into more readable format
|
||||
unitsIgnored := make(map[string][]string, len(ignoredUnits))
|
||||
for key, values := range ignoredUnits {
|
||||
units := make([]string, len(values))
|
||||
i := 0
|
||||
for unit := range values {
|
||||
units[i] = unit
|
||||
i++
|
||||
}
|
||||
sort.Strings(units)
|
||||
unitsIgnored[key] = units
|
||||
}
|
||||
|
||||
return numLabelUnits, unitsIgnored
|
||||
}
|
||||
|
||||
// String dumps a text representation of a profile. Intended mainly
|
||||
// for debugging purposes.
|
||||
func (p *Profile) String() string {
|
||||
ss := make([]string, 0, len(p.Comments)+len(p.Sample)+len(p.Mapping)+len(p.Location))
|
||||
for _, c := range p.Comments {
|
||||
ss = append(ss, "Comment: "+c)
|
||||
}
|
||||
if pt := p.PeriodType; pt != nil {
|
||||
ss = append(ss, fmt.Sprintf("PeriodType: %s %s", pt.Type, pt.Unit))
|
||||
}
|
||||
ss = append(ss, fmt.Sprintf("Period: %d", p.Period))
|
||||
if p.TimeNanos != 0 {
|
||||
ss = append(ss, fmt.Sprintf("Time: %v", time.Unix(0, p.TimeNanos)))
|
||||
}
|
||||
if p.DurationNanos != 0 {
|
||||
ss = append(ss, fmt.Sprintf("Duration: %.4v", time.Duration(p.DurationNanos)))
|
||||
}
|
||||
|
||||
ss = append(ss, "Samples:")
|
||||
var sh1 string
|
||||
for _, s := range p.SampleType {
|
||||
dflt := ""
|
||||
if s.Type == p.DefaultSampleType {
|
||||
dflt = "[dflt]"
|
||||
}
|
||||
sh1 = sh1 + fmt.Sprintf("%s/%s%s ", s.Type, s.Unit, dflt)
|
||||
}
|
||||
ss = append(ss, strings.TrimSpace(sh1))
|
||||
for _, s := range p.Sample {
|
||||
ss = append(ss, s.string())
|
||||
}
|
||||
|
||||
ss = append(ss, "Locations")
|
||||
for _, l := range p.Location {
|
||||
ss = append(ss, l.string())
|
||||
}
|
||||
|
||||
ss = append(ss, "Mappings")
|
||||
for _, m := range p.Mapping {
|
||||
ss = append(ss, m.string())
|
||||
}
|
||||
|
||||
return strings.Join(ss, "\n") + "\n"
|
||||
}
|
||||
|
||||
// string dumps a text representation of a mapping. Intended mainly
|
||||
// for debugging purposes.
|
||||
func (m *Mapping) string() string {
|
||||
bits := ""
|
||||
if m.HasFunctions {
|
||||
bits = bits + "[FN]"
|
||||
}
|
||||
if m.HasFilenames {
|
||||
bits = bits + "[FL]"
|
||||
}
|
||||
if m.HasLineNumbers {
|
||||
bits = bits + "[LN]"
|
||||
}
|
||||
if m.HasInlineFrames {
|
||||
bits = bits + "[IN]"
|
||||
}
|
||||
return fmt.Sprintf("%d: %#x/%#x/%#x %s %s %s",
|
||||
m.ID,
|
||||
m.Start, m.Limit, m.Offset,
|
||||
m.File,
|
||||
m.BuildID,
|
||||
bits)
|
||||
}
|
||||
|
||||
// string dumps a text representation of a location. Intended mainly
|
||||
// for debugging purposes.
|
||||
func (l *Location) string() string {
|
||||
ss := []string{}
|
||||
locStr := fmt.Sprintf("%6d: %#x ", l.ID, l.Address)
|
||||
if m := l.Mapping; m != nil {
|
||||
locStr = locStr + fmt.Sprintf("M=%d ", m.ID)
|
||||
}
|
||||
if l.IsFolded {
|
||||
locStr = locStr + "[F] "
|
||||
}
|
||||
if len(l.Line) == 0 {
|
||||
ss = append(ss, locStr)
|
||||
}
|
||||
for li := range l.Line {
|
||||
lnStr := "??"
|
||||
if fn := l.Line[li].Function; fn != nil {
|
||||
lnStr = fmt.Sprintf("%s %s:%d s=%d",
|
||||
fn.Name,
|
||||
fn.Filename,
|
||||
l.Line[li].Line,
|
||||
fn.StartLine)
|
||||
if fn.Name != fn.SystemName {
|
||||
lnStr = lnStr + "(" + fn.SystemName + ")"
|
||||
}
|
||||
}
|
||||
ss = append(ss, locStr+lnStr)
|
||||
// Do not print location details past the first line
|
||||
locStr = " "
|
||||
}
|
||||
return strings.Join(ss, "\n")
|
||||
}
|
||||
|
||||
// string dumps a text representation of a sample. Intended mainly
|
||||
// for debugging purposes.
|
||||
func (s *Sample) string() string {
|
||||
ss := []string{}
|
||||
var sv string
|
||||
for _, v := range s.Value {
|
||||
sv = fmt.Sprintf("%s %10d", sv, v)
|
||||
}
|
||||
sv = sv + ": "
|
||||
for _, l := range s.Location {
|
||||
sv = sv + fmt.Sprintf("%d ", l.ID)
|
||||
}
|
||||
ss = append(ss, sv)
|
||||
const labelHeader = " "
|
||||
if len(s.Label) > 0 {
|
||||
ss = append(ss, labelHeader+labelsToString(s.Label))
|
||||
}
|
||||
if len(s.NumLabel) > 0 {
|
||||
ss = append(ss, labelHeader+numLabelsToString(s.NumLabel, s.NumUnit))
|
||||
}
|
||||
return strings.Join(ss, "\n")
|
||||
}
|
||||
|
||||
// labelsToString returns a string representation of a
|
||||
// map representing labels.
|
||||
func labelsToString(labels map[string][]string) string {
|
||||
ls := []string{}
|
||||
for k, v := range labels {
|
||||
ls = append(ls, fmt.Sprintf("%s:%v", k, v))
|
||||
}
|
||||
sort.Strings(ls)
|
||||
return strings.Join(ls, " ")
|
||||
}
|
||||
|
||||
// numLabelsToString returns a string representation of a map
|
||||
// representing numeric labels.
|
||||
func numLabelsToString(numLabels map[string][]int64, numUnits map[string][]string) string {
|
||||
ls := []string{}
|
||||
for k, v := range numLabels {
|
||||
units := numUnits[k]
|
||||
var labelString string
|
||||
if len(units) == len(v) {
|
||||
values := make([]string, len(v))
|
||||
for i, vv := range v {
|
||||
values[i] = fmt.Sprintf("%d %s", vv, units[i])
|
||||
}
|
||||
labelString = fmt.Sprintf("%s:%v", k, values)
|
||||
} else {
|
||||
labelString = fmt.Sprintf("%s:%v", k, v)
|
||||
}
|
||||
ls = append(ls, labelString)
|
||||
}
|
||||
sort.Strings(ls)
|
||||
return strings.Join(ls, " ")
|
||||
}
|
||||
|
||||
// SetLabel sets the specified key to the specified value for all samples in the
|
||||
// profile.
|
||||
func (p *Profile) SetLabel(key string, value []string) {
|
||||
for _, sample := range p.Sample {
|
||||
if sample.Label == nil {
|
||||
sample.Label = map[string][]string{key: value}
|
||||
} else {
|
||||
sample.Label[key] = value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// RemoveLabel removes all labels associated with the specified key for all
|
||||
// samples in the profile.
|
||||
func (p *Profile) RemoveLabel(key string) {
|
||||
for _, sample := range p.Sample {
|
||||
delete(sample.Label, key)
|
||||
}
|
||||
}
|
||||
|
||||
// HasLabel returns true if a sample has a label with indicated key and value.
|
||||
func (s *Sample) HasLabel(key, value string) bool {
|
||||
for _, v := range s.Label[key] {
|
||||
if v == value {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// DiffBaseSample returns true if a sample belongs to the diff base and false
|
||||
// otherwise.
|
||||
func (s *Sample) DiffBaseSample() bool {
|
||||
return s.HasLabel("pprof::base", "true")
|
||||
}
|
||||
|
||||
// Scale multiplies all sample values in a profile by a constant and keeps
|
||||
// only samples that have at least one non-zero value.
|
||||
func (p *Profile) Scale(ratio float64) {
|
||||
if ratio == 1 {
|
||||
return
|
||||
}
|
||||
ratios := make([]float64, len(p.SampleType))
|
||||
for i := range p.SampleType {
|
||||
ratios[i] = ratio
|
||||
}
|
||||
p.ScaleN(ratios)
|
||||
}
|
||||
|
||||
// ScaleN multiplies each sample values in a sample by a different amount
|
||||
// and keeps only samples that have at least one non-zero value.
|
||||
func (p *Profile) ScaleN(ratios []float64) error {
|
||||
if len(p.SampleType) != len(ratios) {
|
||||
return fmt.Errorf("mismatched scale ratios, got %d, want %d", len(ratios), len(p.SampleType))
|
||||
}
|
||||
allOnes := true
|
||||
for _, r := range ratios {
|
||||
if r != 1 {
|
||||
allOnes = false
|
||||
break
|
||||
}
|
||||
}
|
||||
if allOnes {
|
||||
return nil
|
||||
}
|
||||
fillIdx := 0
|
||||
for _, s := range p.Sample {
|
||||
keepSample := false
|
||||
for i, v := range s.Value {
|
||||
if ratios[i] != 1 {
|
||||
val := int64(math.Round(float64(v) * ratios[i]))
|
||||
s.Value[i] = val
|
||||
keepSample = keepSample || val != 0
|
||||
}
|
||||
}
|
||||
if keepSample {
|
||||
p.Sample[fillIdx] = s
|
||||
fillIdx++
|
||||
}
|
||||
}
|
||||
p.Sample = p.Sample[:fillIdx]
|
||||
return nil
|
||||
}
|
||||
|
||||
// HasFunctions determines if all locations in this profile have
|
||||
// symbolized function information.
|
||||
func (p *Profile) HasFunctions() bool {
|
||||
for _, l := range p.Location {
|
||||
if l.Mapping != nil && !l.Mapping.HasFunctions {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// HasFileLines determines if all locations in this profile have
|
||||
// symbolized file and line number information.
|
||||
func (p *Profile) HasFileLines() bool {
|
||||
for _, l := range p.Location {
|
||||
if l.Mapping != nil && (!l.Mapping.HasFilenames || !l.Mapping.HasLineNumbers) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Unsymbolizable returns true if a mapping points to a binary for which
|
||||
// locations can't be symbolized in principle, at least now. Examples are
|
||||
// "[vdso]", [vsyscall]" and some others, see the code.
|
||||
func (m *Mapping) Unsymbolizable() bool {
|
||||
name := filepath.Base(m.File)
|
||||
return strings.HasPrefix(name, "[") || strings.HasPrefix(name, "linux-vdso") || strings.HasPrefix(m.File, "/dev/dri/")
|
||||
}
|
||||
|
||||
// Copy makes a fully independent copy of a profile.
|
||||
func (p *Profile) Copy() *Profile {
|
||||
pp := &Profile{}
|
||||
if err := unmarshal(serialize(p), pp); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if err := pp.postDecode(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return pp
|
||||
}
|
370
vendor/github.com/google/pprof/profile/proto.go
generated
vendored
Normal file
370
vendor/github.com/google/pprof/profile/proto.go
generated
vendored
Normal file
@ -0,0 +1,370 @@
|
||||
// Copyright 2014 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// This file is a simple protocol buffer encoder and decoder.
|
||||
// The format is described at
|
||||
// https://developers.google.com/protocol-buffers/docs/encoding
|
||||
//
|
||||
// A protocol message must implement the message interface:
|
||||
// decoder() []decoder
|
||||
// encode(*buffer)
|
||||
//
|
||||
// The decode method returns a slice indexed by field number that gives the
|
||||
// function to decode that field.
|
||||
// The encode method encodes its receiver into the given buffer.
|
||||
//
|
||||
// The two methods are simple enough to be implemented by hand rather than
|
||||
// by using a protocol compiler.
|
||||
//
|
||||
// See profile.go for examples of messages implementing this interface.
|
||||
//
|
||||
// There is no support for groups, message sets, or "has" bits.
|
||||
|
||||
package profile
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type buffer struct {
|
||||
field int // field tag
|
||||
typ int // proto wire type code for field
|
||||
u64 uint64
|
||||
data []byte
|
||||
tmp [16]byte
|
||||
}
|
||||
|
||||
type decoder func(*buffer, message) error
|
||||
|
||||
type message interface {
|
||||
decoder() []decoder
|
||||
encode(*buffer)
|
||||
}
|
||||
|
||||
func marshal(m message) []byte {
|
||||
var b buffer
|
||||
m.encode(&b)
|
||||
return b.data
|
||||
}
|
||||
|
||||
func encodeVarint(b *buffer, x uint64) {
|
||||
for x >= 128 {
|
||||
b.data = append(b.data, byte(x)|0x80)
|
||||
x >>= 7
|
||||
}
|
||||
b.data = append(b.data, byte(x))
|
||||
}
|
||||
|
||||
func encodeLength(b *buffer, tag int, len int) {
|
||||
encodeVarint(b, uint64(tag)<<3|2)
|
||||
encodeVarint(b, uint64(len))
|
||||
}
|
||||
|
||||
func encodeUint64(b *buffer, tag int, x uint64) {
|
||||
// append varint to b.data
|
||||
encodeVarint(b, uint64(tag)<<3)
|
||||
encodeVarint(b, x)
|
||||
}
|
||||
|
||||
func encodeUint64s(b *buffer, tag int, x []uint64) {
|
||||
if len(x) > 2 {
|
||||
// Use packed encoding
|
||||
n1 := len(b.data)
|
||||
for _, u := range x {
|
||||
encodeVarint(b, u)
|
||||
}
|
||||
n2 := len(b.data)
|
||||
encodeLength(b, tag, n2-n1)
|
||||
n3 := len(b.data)
|
||||
copy(b.tmp[:], b.data[n2:n3])
|
||||
copy(b.data[n1+(n3-n2):], b.data[n1:n2])
|
||||
copy(b.data[n1:], b.tmp[:n3-n2])
|
||||
return
|
||||
}
|
||||
for _, u := range x {
|
||||
encodeUint64(b, tag, u)
|
||||
}
|
||||
}
|
||||
|
||||
func encodeUint64Opt(b *buffer, tag int, x uint64) {
|
||||
if x == 0 {
|
||||
return
|
||||
}
|
||||
encodeUint64(b, tag, x)
|
||||
}
|
||||
|
||||
func encodeInt64(b *buffer, tag int, x int64) {
|
||||
u := uint64(x)
|
||||
encodeUint64(b, tag, u)
|
||||
}
|
||||
|
||||
func encodeInt64s(b *buffer, tag int, x []int64) {
|
||||
if len(x) > 2 {
|
||||
// Use packed encoding
|
||||
n1 := len(b.data)
|
||||
for _, u := range x {
|
||||
encodeVarint(b, uint64(u))
|
||||
}
|
||||
n2 := len(b.data)
|
||||
encodeLength(b, tag, n2-n1)
|
||||
n3 := len(b.data)
|
||||
copy(b.tmp[:], b.data[n2:n3])
|
||||
copy(b.data[n1+(n3-n2):], b.data[n1:n2])
|
||||
copy(b.data[n1:], b.tmp[:n3-n2])
|
||||
return
|
||||
}
|
||||
for _, u := range x {
|
||||
encodeInt64(b, tag, u)
|
||||
}
|
||||
}
|
||||
|
||||
func encodeInt64Opt(b *buffer, tag int, x int64) {
|
||||
if x == 0 {
|
||||
return
|
||||
}
|
||||
encodeInt64(b, tag, x)
|
||||
}
|
||||
|
||||
func encodeString(b *buffer, tag int, x string) {
|
||||
encodeLength(b, tag, len(x))
|
||||
b.data = append(b.data, x...)
|
||||
}
|
||||
|
||||
func encodeStrings(b *buffer, tag int, x []string) {
|
||||
for _, s := range x {
|
||||
encodeString(b, tag, s)
|
||||
}
|
||||
}
|
||||
|
||||
func encodeBool(b *buffer, tag int, x bool) {
|
||||
if x {
|
||||
encodeUint64(b, tag, 1)
|
||||
} else {
|
||||
encodeUint64(b, tag, 0)
|
||||
}
|
||||
}
|
||||
|
||||
func encodeBoolOpt(b *buffer, tag int, x bool) {
|
||||
if x {
|
||||
encodeBool(b, tag, x)
|
||||
}
|
||||
}
|
||||
|
||||
func encodeMessage(b *buffer, tag int, m message) {
|
||||
n1 := len(b.data)
|
||||
m.encode(b)
|
||||
n2 := len(b.data)
|
||||
encodeLength(b, tag, n2-n1)
|
||||
n3 := len(b.data)
|
||||
copy(b.tmp[:], b.data[n2:n3])
|
||||
copy(b.data[n1+(n3-n2):], b.data[n1:n2])
|
||||
copy(b.data[n1:], b.tmp[:n3-n2])
|
||||
}
|
||||
|
||||
func unmarshal(data []byte, m message) (err error) {
|
||||
b := buffer{data: data, typ: 2}
|
||||
return decodeMessage(&b, m)
|
||||
}
|
||||
|
||||
func le64(p []byte) uint64 {
|
||||
return uint64(p[0]) | uint64(p[1])<<8 | uint64(p[2])<<16 | uint64(p[3])<<24 | uint64(p[4])<<32 | uint64(p[5])<<40 | uint64(p[6])<<48 | uint64(p[7])<<56
|
||||
}
|
||||
|
||||
func le32(p []byte) uint32 {
|
||||
return uint32(p[0]) | uint32(p[1])<<8 | uint32(p[2])<<16 | uint32(p[3])<<24
|
||||
}
|
||||
|
||||
func decodeVarint(data []byte) (uint64, []byte, error) {
|
||||
var u uint64
|
||||
for i := 0; ; i++ {
|
||||
if i >= 10 || i >= len(data) {
|
||||
return 0, nil, errors.New("bad varint")
|
||||
}
|
||||
u |= uint64(data[i]&0x7F) << uint(7*i)
|
||||
if data[i]&0x80 == 0 {
|
||||
return u, data[i+1:], nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func decodeField(b *buffer, data []byte) ([]byte, error) {
|
||||
x, data, err := decodeVarint(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b.field = int(x >> 3)
|
||||
b.typ = int(x & 7)
|
||||
b.data = nil
|
||||
b.u64 = 0
|
||||
switch b.typ {
|
||||
case 0:
|
||||
b.u64, data, err = decodeVarint(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case 1:
|
||||
if len(data) < 8 {
|
||||
return nil, errors.New("not enough data")
|
||||
}
|
||||
b.u64 = le64(data[:8])
|
||||
data = data[8:]
|
||||
case 2:
|
||||
var n uint64
|
||||
n, data, err = decodeVarint(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if n > uint64(len(data)) {
|
||||
return nil, errors.New("too much data")
|
||||
}
|
||||
b.data = data[:n]
|
||||
data = data[n:]
|
||||
case 5:
|
||||
if len(data) < 4 {
|
||||
return nil, errors.New("not enough data")
|
||||
}
|
||||
b.u64 = uint64(le32(data[:4]))
|
||||
data = data[4:]
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown wire type: %d", b.typ)
|
||||
}
|
||||
|
||||
return data, nil
|
||||
}
|
||||
|
||||
func checkType(b *buffer, typ int) error {
|
||||
if b.typ != typ {
|
||||
return errors.New("type mismatch")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func decodeMessage(b *buffer, m message) error {
|
||||
if err := checkType(b, 2); err != nil {
|
||||
return err
|
||||
}
|
||||
dec := m.decoder()
|
||||
data := b.data
|
||||
for len(data) > 0 {
|
||||
// pull varint field# + type
|
||||
var err error
|
||||
data, err = decodeField(b, data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if b.field >= len(dec) || dec[b.field] == nil {
|
||||
continue
|
||||
}
|
||||
if err := dec[b.field](b, m); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func decodeInt64(b *buffer, x *int64) error {
|
||||
if err := checkType(b, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
*x = int64(b.u64)
|
||||
return nil
|
||||
}
|
||||
|
||||
func decodeInt64s(b *buffer, x *[]int64) error {
|
||||
if b.typ == 2 {
|
||||
// Packed encoding
|
||||
data := b.data
|
||||
tmp := make([]int64, 0, len(data)) // Maximally sized
|
||||
for len(data) > 0 {
|
||||
var u uint64
|
||||
var err error
|
||||
|
||||
if u, data, err = decodeVarint(data); err != nil {
|
||||
return err
|
||||
}
|
||||
tmp = append(tmp, int64(u))
|
||||
}
|
||||
*x = append(*x, tmp...)
|
||||
return nil
|
||||
}
|
||||
var i int64
|
||||
if err := decodeInt64(b, &i); err != nil {
|
||||
return err
|
||||
}
|
||||
*x = append(*x, i)
|
||||
return nil
|
||||
}
|
||||
|
||||
func decodeUint64(b *buffer, x *uint64) error {
|
||||
if err := checkType(b, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
*x = b.u64
|
||||
return nil
|
||||
}
|
||||
|
||||
func decodeUint64s(b *buffer, x *[]uint64) error {
|
||||
if b.typ == 2 {
|
||||
data := b.data
|
||||
// Packed encoding
|
||||
tmp := make([]uint64, 0, len(data)) // Maximally sized
|
||||
for len(data) > 0 {
|
||||
var u uint64
|
||||
var err error
|
||||
|
||||
if u, data, err = decodeVarint(data); err != nil {
|
||||
return err
|
||||
}
|
||||
tmp = append(tmp, u)
|
||||
}
|
||||
*x = append(*x, tmp...)
|
||||
return nil
|
||||
}
|
||||
var u uint64
|
||||
if err := decodeUint64(b, &u); err != nil {
|
||||
return err
|
||||
}
|
||||
*x = append(*x, u)
|
||||
return nil
|
||||
}
|
||||
|
||||
func decodeString(b *buffer, x *string) error {
|
||||
if err := checkType(b, 2); err != nil {
|
||||
return err
|
||||
}
|
||||
*x = string(b.data)
|
||||
return nil
|
||||
}
|
||||
|
||||
func decodeStrings(b *buffer, x *[]string) error {
|
||||
var s string
|
||||
if err := decodeString(b, &s); err != nil {
|
||||
return err
|
||||
}
|
||||
*x = append(*x, s)
|
||||
return nil
|
||||
}
|
||||
|
||||
func decodeBool(b *buffer, x *bool) error {
|
||||
if err := checkType(b, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if int64(b.u64) == 0 {
|
||||
*x = false
|
||||
} else {
|
||||
*x = true
|
||||
}
|
||||
return nil
|
||||
}
|
178
vendor/github.com/google/pprof/profile/prune.go
generated
vendored
Normal file
178
vendor/github.com/google/pprof/profile/prune.go
generated
vendored
Normal file
@ -0,0 +1,178 @@
|
||||
// Copyright 2014 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Implements methods to remove frames from profiles.
|
||||
|
||||
package profile
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
reservedNames = []string{"(anonymous namespace)", "operator()"}
|
||||
bracketRx = func() *regexp.Regexp {
|
||||
var quotedNames []string
|
||||
for _, name := range append(reservedNames, "(") {
|
||||
quotedNames = append(quotedNames, regexp.QuoteMeta(name))
|
||||
}
|
||||
return regexp.MustCompile(strings.Join(quotedNames, "|"))
|
||||
}()
|
||||
)
|
||||
|
||||
// simplifyFunc does some primitive simplification of function names.
|
||||
func simplifyFunc(f string) string {
|
||||
// Account for leading '.' on the PPC ELF v1 ABI.
|
||||
funcName := strings.TrimPrefix(f, ".")
|
||||
// Account for unsimplified names -- try to remove the argument list by trimming
|
||||
// starting from the first '(', but skipping reserved names that have '('.
|
||||
for _, ind := range bracketRx.FindAllStringSubmatchIndex(funcName, -1) {
|
||||
foundReserved := false
|
||||
for _, res := range reservedNames {
|
||||
if funcName[ind[0]:ind[1]] == res {
|
||||
foundReserved = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !foundReserved {
|
||||
funcName = funcName[:ind[0]]
|
||||
break
|
||||
}
|
||||
}
|
||||
return funcName
|
||||
}
|
||||
|
||||
// Prune removes all nodes beneath a node matching dropRx, and not
|
||||
// matching keepRx. If the root node of a Sample matches, the sample
|
||||
// will have an empty stack.
|
||||
func (p *Profile) Prune(dropRx, keepRx *regexp.Regexp) {
|
||||
prune := make(map[uint64]bool)
|
||||
pruneBeneath := make(map[uint64]bool)
|
||||
|
||||
for _, loc := range p.Location {
|
||||
var i int
|
||||
for i = len(loc.Line) - 1; i >= 0; i-- {
|
||||
if fn := loc.Line[i].Function; fn != nil && fn.Name != "" {
|
||||
funcName := simplifyFunc(fn.Name)
|
||||
if dropRx.MatchString(funcName) {
|
||||
if keepRx == nil || !keepRx.MatchString(funcName) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if i >= 0 {
|
||||
// Found matching entry to prune.
|
||||
pruneBeneath[loc.ID] = true
|
||||
|
||||
// Remove the matching location.
|
||||
if i == len(loc.Line)-1 {
|
||||
// Matched the top entry: prune the whole location.
|
||||
prune[loc.ID] = true
|
||||
} else {
|
||||
loc.Line = loc.Line[i+1:]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Prune locs from each Sample
|
||||
for _, sample := range p.Sample {
|
||||
// Scan from the root to the leaves to find the prune location.
|
||||
// Do not prune frames before the first user frame, to avoid
|
||||
// pruning everything.
|
||||
foundUser := false
|
||||
for i := len(sample.Location) - 1; i >= 0; i-- {
|
||||
id := sample.Location[i].ID
|
||||
if !prune[id] && !pruneBeneath[id] {
|
||||
foundUser = true
|
||||
continue
|
||||
}
|
||||
if !foundUser {
|
||||
continue
|
||||
}
|
||||
if prune[id] {
|
||||
sample.Location = sample.Location[i+1:]
|
||||
break
|
||||
}
|
||||
if pruneBeneath[id] {
|
||||
sample.Location = sample.Location[i:]
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// RemoveUninteresting prunes and elides profiles using built-in
|
||||
// tables of uninteresting function names.
|
||||
func (p *Profile) RemoveUninteresting() error {
|
||||
var keep, drop *regexp.Regexp
|
||||
var err error
|
||||
|
||||
if p.DropFrames != "" {
|
||||
if drop, err = regexp.Compile("^(" + p.DropFrames + ")$"); err != nil {
|
||||
return fmt.Errorf("failed to compile regexp %s: %v", p.DropFrames, err)
|
||||
}
|
||||
if p.KeepFrames != "" {
|
||||
if keep, err = regexp.Compile("^(" + p.KeepFrames + ")$"); err != nil {
|
||||
return fmt.Errorf("failed to compile regexp %s: %v", p.KeepFrames, err)
|
||||
}
|
||||
}
|
||||
p.Prune(drop, keep)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// PruneFrom removes all nodes beneath the lowest node matching dropRx, not including itself.
|
||||
//
|
||||
// Please see the example below to understand this method as well as
|
||||
// the difference from Prune method.
|
||||
//
|
||||
// A sample contains Location of [A,B,C,B,D] where D is the top frame and there's no inline.
|
||||
//
|
||||
// PruneFrom(A) returns [A,B,C,B,D] because there's no node beneath A.
|
||||
// Prune(A, nil) returns [B,C,B,D] by removing A itself.
|
||||
//
|
||||
// PruneFrom(B) returns [B,C,B,D] by removing all nodes beneath the first B when scanning from the bottom.
|
||||
// Prune(B, nil) returns [D] because a matching node is found by scanning from the root.
|
||||
func (p *Profile) PruneFrom(dropRx *regexp.Regexp) {
|
||||
pruneBeneath := make(map[uint64]bool)
|
||||
|
||||
for _, loc := range p.Location {
|
||||
for i := 0; i < len(loc.Line); i++ {
|
||||
if fn := loc.Line[i].Function; fn != nil && fn.Name != "" {
|
||||
funcName := simplifyFunc(fn.Name)
|
||||
if dropRx.MatchString(funcName) {
|
||||
// Found matching entry to prune.
|
||||
pruneBeneath[loc.ID] = true
|
||||
loc.Line = loc.Line[i:]
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Prune locs from each Sample
|
||||
for _, sample := range p.Sample {
|
||||
// Scan from the bottom leaf to the root to find the prune location.
|
||||
for i, loc := range sample.Location {
|
||||
if pruneBeneath[loc.ID] {
|
||||
sample.Location = sample.Location[i:]
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
3
vendor/github.com/lucas-clemente/quic-go/README.md
generated
vendored
3
vendor/github.com/lucas-clemente/quic-go/README.md
generated
vendored
@ -5,7 +5,8 @@
|
||||
[![PkgGoDev](https://pkg.go.dev/badge/github.com/lucas-clemente/quic-go)](https://pkg.go.dev/github.com/lucas-clemente/quic-go)
|
||||
[![Code Coverage](https://img.shields.io/codecov/c/github/lucas-clemente/quic-go/master.svg?style=flat-square)](https://codecov.io/gh/lucas-clemente/quic-go/)
|
||||
|
||||
quic-go is an implementation of the QUIC protocol ([RFC 9000](https://datatracker.ietf.org/doc/html/rfc9000), [RFC 9001](https://datatracker.ietf.org/doc/html/rfc9001), [RFC 9002](https://datatracker.ietf.org/doc/html/rfc9002)) in Go, including the Unreliable Datagram Extension ([RFC 9221](https://datatracker.ietf.org/doc/html/rfc9221)). It has support for HTTP/3 ([RFC 9114](https://datatracker.ietf.org/doc/html/rfc9114)), including QPACK ([RFC 9204](https://datatracker.ietf.org/doc/html/rfc9204)).
|
||||
quic-go is an implementation of the QUIC protocol ([RFC 9000](https://datatracker.ietf.org/doc/html/rfc9000), [RFC 9001](https://datatracker.ietf.org/doc/html/rfc9001), [RFC 9002](https://datatracker.ietf.org/doc/html/rfc9002)) in Go, including the Unreliable Datagram Extension ([RFC 9221](https://datatracker.ietf.org/doc/html/rfc9221)) and Datagram Packetization Layer Path MTU
|
||||
Discovery (DPLPMTUD, [RFC 8899](https://datatracker.ietf.org/doc/html/rfc8899)). It has support for HTTP/3 ([RFC 9114](https://datatracker.ietf.org/doc/html/rfc9114)), including QPACK ([RFC 9204](https://datatracker.ietf.org/doc/html/rfc9204)).
|
||||
|
||||
In addition to the RFCs listed above, it currently implements the [IETF QUIC draft-29](https://tools.ietf.org/html/draft-ietf-quic-transport-29). Support for draft-29 will eventually be dropped, as it is phased out of the ecosystem.
|
||||
|
||||
|
12
vendor/github.com/lucas-clemente/quic-go/conn_id_generator.go
generated
vendored
12
vendor/github.com/lucas-clemente/quic-go/conn_id_generator.go
generated
vendored
@ -14,7 +14,7 @@ type connIDGenerator struct {
|
||||
highestSeq uint64
|
||||
|
||||
activeSrcConnIDs map[uint64]protocol.ConnectionID
|
||||
initialClientDestConnID protocol.ConnectionID
|
||||
initialClientDestConnID *protocol.ConnectionID // nil for the client
|
||||
|
||||
addConnectionID func(protocol.ConnectionID)
|
||||
getStatelessResetToken func(protocol.ConnectionID) protocol.StatelessResetToken
|
||||
@ -28,7 +28,7 @@ type connIDGenerator struct {
|
||||
|
||||
func newConnIDGenerator(
|
||||
initialConnectionID protocol.ConnectionID,
|
||||
initialClientDestConnID protocol.ConnectionID, // nil for the client
|
||||
initialClientDestConnID *protocol.ConnectionID, // nil for the client
|
||||
addConnectionID func(protocol.ConnectionID),
|
||||
getStatelessResetToken func(protocol.ConnectionID) protocol.StatelessResetToken,
|
||||
removeConnectionID func(protocol.ConnectionID),
|
||||
@ -84,7 +84,7 @@ func (m *connIDGenerator) Retire(seq uint64, sentWithDestConnID protocol.Connect
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
if connID.Equal(sentWithDestConnID) {
|
||||
if connID == sentWithDestConnID {
|
||||
return &qerr.TransportError{
|
||||
ErrorCode: qerr.ProtocolViolation,
|
||||
ErrorMessage: fmt.Sprintf("retired connection ID %d (%s), which was used as the Destination Connection ID on this packet", seq, connID),
|
||||
@ -117,14 +117,14 @@ func (m *connIDGenerator) issueNewConnID() error {
|
||||
|
||||
func (m *connIDGenerator) SetHandshakeComplete() {
|
||||
if m.initialClientDestConnID != nil {
|
||||
m.retireConnectionID(m.initialClientDestConnID)
|
||||
m.retireConnectionID(*m.initialClientDestConnID)
|
||||
m.initialClientDestConnID = nil
|
||||
}
|
||||
}
|
||||
|
||||
func (m *connIDGenerator) RemoveAll() {
|
||||
if m.initialClientDestConnID != nil {
|
||||
m.removeConnectionID(m.initialClientDestConnID)
|
||||
m.removeConnectionID(*m.initialClientDestConnID)
|
||||
}
|
||||
for _, connID := range m.activeSrcConnIDs {
|
||||
m.removeConnectionID(connID)
|
||||
@ -134,7 +134,7 @@ func (m *connIDGenerator) RemoveAll() {
|
||||
func (m *connIDGenerator) ReplaceWithClosed(pers protocol.Perspective, connClose []byte) {
|
||||
connIDs := make([]protocol.ConnectionID, 0, len(m.activeSrcConnIDs)+1)
|
||||
if m.initialClientDestConnID != nil {
|
||||
connIDs = append(connIDs, m.initialClientDestConnID)
|
||||
connIDs = append(connIDs, *m.initialClientDestConnID)
|
||||
}
|
||||
for _, connID := range m.activeSrcConnIDs {
|
||||
connIDs = append(connIDs, connID)
|
||||
|
2
vendor/github.com/lucas-clemente/quic-go/conn_id_manager.go
generated
vendored
2
vendor/github.com/lucas-clemente/quic-go/conn_id_manager.go
generated
vendored
@ -121,7 +121,7 @@ func (h *connIDManager) addConnectionID(seq uint64, connID protocol.ConnectionID
|
||||
// insert a new element somewhere in the middle
|
||||
for el := h.queue.Front(); el != nil; el = el.Next() {
|
||||
if el.Value.SequenceNumber == seq {
|
||||
if !el.Value.ConnectionID.Equal(connID) {
|
||||
if el.Value.ConnectionID != connID {
|
||||
return fmt.Errorf("received conflicting connection IDs for sequence number %d", seq)
|
||||
}
|
||||
if el.Value.StatelessResetToken != resetToken {
|
||||
|
377
vendor/github.com/lucas-clemente/quic-go/connection.go
generated
vendored
377
vendor/github.com/lucas-clemente/quic-go/connection.go
generated
vendored
@ -25,7 +25,8 @@
|
||||
)
|
||||
|
||||
type unpacker interface {
|
||||
Unpack(hdr *wire.Header, rcvTime time.Time, data []byte) (*unpackedPacket, error)
|
||||
UnpackLongHeader(hdr *wire.Header, rcvTime time.Time, data []byte) (*unpackedPacket, error)
|
||||
UnpackShortHeader(rcvTime time.Time, data []byte) (protocol.PacketNumber, protocol.PacketNumberLen, protocol.KeyPhaseBit, []byte, error)
|
||||
}
|
||||
|
||||
type streamGetter interface {
|
||||
@ -260,7 +261,7 @@ type connection struct {
|
||||
logger: logger,
|
||||
version: v,
|
||||
}
|
||||
if origDestConnID != nil {
|
||||
if origDestConnID.Len() > 0 {
|
||||
s.logID = origDestConnID.String()
|
||||
} else {
|
||||
s.logID = destConnID.String()
|
||||
@ -273,7 +274,7 @@ func(token protocol.StatelessResetToken) { runner.AddResetToken(token, s) },
|
||||
)
|
||||
s.connIDGenerator = newConnIDGenerator(
|
||||
srcConnID,
|
||||
clientDestConnID,
|
||||
&clientDestConnID,
|
||||
func(connID protocol.ConnectionID) { runner.Add(connID, s) },
|
||||
runner.GetStatelessResetToken,
|
||||
runner.Remove,
|
||||
@ -361,7 +362,7 @@ func(connID protocol.ConnectionID) { runner.Add(connID, s) },
|
||||
s.perspective,
|
||||
s.version,
|
||||
)
|
||||
s.unpacker = newPacketUnpacker(cs, s.version)
|
||||
s.unpacker = newPacketUnpacker(cs, s.srcConnIDLen, s.version)
|
||||
s.cryptoStreamManager = newCryptoStreamManager(cs, initialStream, handshakeStream, s.oneRTTStream)
|
||||
return s
|
||||
}
|
||||
@ -473,7 +474,7 @@ func(connID protocol.ConnectionID) { runner.Add(connID, s) },
|
||||
s.clientHelloWritten = clientHelloWritten
|
||||
s.cryptoStreamHandler = cs
|
||||
s.cryptoStreamManager = newCryptoStreamManager(cs, initialStream, handshakeStream, newCryptoStream())
|
||||
s.unpacker = newPacketUnpacker(cs, s.version)
|
||||
s.unpacker = newPacketUnpacker(cs, s.srcConnIDLen, s.version)
|
||||
s.packer = newPacketPacker(
|
||||
srcConnID,
|
||||
s.connIDManager.Get,
|
||||
@ -849,61 +850,133 @@ func (s *connection) handlePacketImpl(rp *receivedPacket) bool {
|
||||
data := rp.data
|
||||
p := rp
|
||||
for len(data) > 0 {
|
||||
var destConnID protocol.ConnectionID
|
||||
if counter > 0 {
|
||||
p = p.Clone()
|
||||
p.data = data
|
||||
}
|
||||
|
||||
hdr, packetData, rest, err := wire.ParsePacket(p.data, s.srcConnIDLen)
|
||||
if err != nil {
|
||||
if s.tracer != nil {
|
||||
dropReason := logging.PacketDropHeaderParseError
|
||||
if err == wire.ErrUnsupportedVersion {
|
||||
dropReason = logging.PacketDropUnsupportedVersion
|
||||
var err error
|
||||
destConnID, err = wire.ParseConnectionID(p.data, s.srcConnIDLen)
|
||||
if err != nil {
|
||||
if s.tracer != nil {
|
||||
s.tracer.DroppedPacket(logging.PacketTypeNotDetermined, protocol.ByteCount(len(data)), logging.PacketDropHeaderParseError)
|
||||
}
|
||||
s.tracer.DroppedPacket(logging.PacketTypeNotDetermined, protocol.ByteCount(len(data)), dropReason)
|
||||
s.logger.Debugf("error parsing packet, couldn't parse connection ID: %s", err)
|
||||
break
|
||||
}
|
||||
s.logger.Debugf("error parsing packet: %s", err)
|
||||
if destConnID != lastConnID {
|
||||
if s.tracer != nil {
|
||||
s.tracer.DroppedPacket(logging.PacketTypeNotDetermined, protocol.ByteCount(len(data)), logging.PacketDropUnknownConnectionID)
|
||||
}
|
||||
s.logger.Debugf("coalesced packet has different destination connection ID: %s, expected %s", destConnID, lastConnID)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if wire.IsLongHeaderPacket(p.data[0]) {
|
||||
hdr, packetData, rest, err := wire.ParsePacket(p.data, s.srcConnIDLen)
|
||||
if err != nil {
|
||||
if s.tracer != nil {
|
||||
dropReason := logging.PacketDropHeaderParseError
|
||||
if err == wire.ErrUnsupportedVersion {
|
||||
dropReason = logging.PacketDropUnsupportedVersion
|
||||
}
|
||||
s.tracer.DroppedPacket(logging.PacketTypeNotDetermined, protocol.ByteCount(len(data)), dropReason)
|
||||
}
|
||||
s.logger.Debugf("error parsing packet: %s", err)
|
||||
break
|
||||
}
|
||||
lastConnID = hdr.DestConnectionID
|
||||
|
||||
if hdr.Version != s.version {
|
||||
if s.tracer != nil {
|
||||
s.tracer.DroppedPacket(logging.PacketTypeFromHeader(hdr), protocol.ByteCount(len(data)), logging.PacketDropUnexpectedVersion)
|
||||
}
|
||||
s.logger.Debugf("Dropping packet with version %x. Expected %x.", hdr.Version, s.version)
|
||||
break
|
||||
}
|
||||
|
||||
if counter > 0 {
|
||||
p.buffer.Split()
|
||||
}
|
||||
counter++
|
||||
|
||||
// only log if this actually a coalesced packet
|
||||
if s.logger.Debug() && (counter > 1 || len(rest) > 0) {
|
||||
s.logger.Debugf("Parsed a coalesced packet. Part %d: %d bytes. Remaining: %d bytes.", counter, len(packetData), len(rest))
|
||||
}
|
||||
|
||||
p.data = packetData
|
||||
|
||||
if wasProcessed := s.handleLongHeaderPacket(p, hdr); wasProcessed {
|
||||
processed = true
|
||||
}
|
||||
data = rest
|
||||
} else {
|
||||
if counter > 0 {
|
||||
p.buffer.Split()
|
||||
}
|
||||
processed = s.handleShortHeaderPacket(p, destConnID)
|
||||
break
|
||||
}
|
||||
|
||||
if hdr.IsLongHeader && hdr.Version != s.version {
|
||||
if s.tracer != nil {
|
||||
s.tracer.DroppedPacket(logging.PacketTypeFromHeader(hdr), protocol.ByteCount(len(data)), logging.PacketDropUnexpectedVersion)
|
||||
}
|
||||
s.logger.Debugf("Dropping packet with version %x. Expected %x.", hdr.Version, s.version)
|
||||
break
|
||||
}
|
||||
|
||||
if counter > 0 && !hdr.DestConnectionID.Equal(lastConnID) {
|
||||
if s.tracer != nil {
|
||||
s.tracer.DroppedPacket(logging.PacketTypeFromHeader(hdr), protocol.ByteCount(len(data)), logging.PacketDropUnknownConnectionID)
|
||||
}
|
||||
s.logger.Debugf("coalesced packet has different destination connection ID: %s, expected %s", hdr.DestConnectionID, lastConnID)
|
||||
break
|
||||
}
|
||||
lastConnID = hdr.DestConnectionID
|
||||
|
||||
if counter > 0 {
|
||||
p.buffer.Split()
|
||||
}
|
||||
counter++
|
||||
|
||||
// only log if this actually a coalesced packet
|
||||
if s.logger.Debug() && (counter > 1 || len(rest) > 0) {
|
||||
s.logger.Debugf("Parsed a coalesced packet. Part %d: %d bytes. Remaining: %d bytes.", counter, len(packetData), len(rest))
|
||||
}
|
||||
p.data = packetData
|
||||
if wasProcessed := s.handleSinglePacket(p, hdr); wasProcessed {
|
||||
processed = true
|
||||
}
|
||||
data = rest
|
||||
}
|
||||
|
||||
p.buffer.MaybeRelease()
|
||||
return processed
|
||||
}
|
||||
|
||||
func (s *connection) handleSinglePacket(p *receivedPacket, hdr *wire.Header) bool /* was the packet successfully processed */ {
|
||||
func (s *connection) handleShortHeaderPacket(p *receivedPacket, destConnID protocol.ConnectionID) bool {
|
||||
var wasQueued bool
|
||||
|
||||
defer func() {
|
||||
// Put back the packet buffer if the packet wasn't queued for later decryption.
|
||||
if !wasQueued {
|
||||
p.buffer.Decrement()
|
||||
}
|
||||
}()
|
||||
|
||||
pn, pnLen, keyPhase, data, err := s.unpacker.UnpackShortHeader(p.rcvTime, p.data)
|
||||
if err != nil {
|
||||
wasQueued = s.handleUnpackError(err, p, logging.PacketType1RTT)
|
||||
return false
|
||||
}
|
||||
|
||||
if s.logger.Debug() {
|
||||
s.logger.Debugf("<- Reading packet %d (%d bytes) for connection %s, 1-RTT", pn, p.Size(), destConnID)
|
||||
wire.LogShortHeader(s.logger, destConnID, pn, pnLen, keyPhase)
|
||||
}
|
||||
|
||||
if s.receivedPacketHandler.IsPotentiallyDuplicate(pn, protocol.Encryption1RTT) {
|
||||
s.logger.Debugf("Dropping (potentially) duplicate packet.")
|
||||
if s.tracer != nil {
|
||||
s.tracer.DroppedPacket(logging.PacketType1RTT, p.Size(), logging.PacketDropDuplicate)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
var log func([]logging.Frame)
|
||||
if s.tracer != nil {
|
||||
log = func(frames []logging.Frame) {
|
||||
s.tracer.ReceivedShortHeaderPacket(
|
||||
&logging.ShortHeader{
|
||||
DestConnectionID: destConnID,
|
||||
PacketNumber: pn,
|
||||
PacketNumberLen: pnLen,
|
||||
KeyPhase: keyPhase,
|
||||
},
|
||||
p.Size(),
|
||||
frames,
|
||||
)
|
||||
}
|
||||
}
|
||||
if err := s.handleUnpackedShortHeaderPacket(destConnID, pn, data, p.ecn, p.rcvTime, log); err != nil {
|
||||
s.closeLocal(err)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (s *connection) handleLongHeaderPacket(p *receivedPacket, hdr *wire.Header) bool /* was the packet successfully processed */ {
|
||||
var wasQueued bool
|
||||
|
||||
defer func() {
|
||||
@ -919,7 +992,7 @@ func (s *connection) handleSinglePacket(p *receivedPacket, hdr *wire.Header) boo
|
||||
|
||||
// The server can change the source connection ID with the first Handshake packet.
|
||||
// After this, all packets with a different source connection have to be ignored.
|
||||
if s.receivedFirstPacket && hdr.IsLongHeader && hdr.Type == protocol.PacketTypeInitial && !hdr.SrcConnectionID.Equal(s.handshakeDestConnID) {
|
||||
if s.receivedFirstPacket && hdr.Type == protocol.PacketTypeInitial && hdr.SrcConnectionID != s.handshakeDestConnID {
|
||||
if s.tracer != nil {
|
||||
s.tracer.DroppedPacket(logging.PacketTypeInitial, p.Size(), logging.PacketDropUnknownConnectionID)
|
||||
}
|
||||
@ -934,53 +1007,18 @@ func (s *connection) handleSinglePacket(p *receivedPacket, hdr *wire.Header) boo
|
||||
return false
|
||||
}
|
||||
|
||||
packet, err := s.unpacker.Unpack(hdr, p.rcvTime, p.data)
|
||||
packet, err := s.unpacker.UnpackLongHeader(hdr, p.rcvTime, p.data)
|
||||
if err != nil {
|
||||
switch err {
|
||||
case handshake.ErrKeysDropped:
|
||||
if s.tracer != nil {
|
||||
s.tracer.DroppedPacket(logging.PacketTypeFromHeader(hdr), p.Size(), logging.PacketDropKeyUnavailable)
|
||||
}
|
||||
s.logger.Debugf("Dropping %s packet (%d bytes) because we already dropped the keys.", hdr.PacketType(), p.Size())
|
||||
case handshake.ErrKeysNotYetAvailable:
|
||||
// Sealer for this encryption level not yet available.
|
||||
// Try again later.
|
||||
wasQueued = true
|
||||
s.tryQueueingUndecryptablePacket(p, hdr)
|
||||
case wire.ErrInvalidReservedBits:
|
||||
s.closeLocal(&qerr.TransportError{
|
||||
ErrorCode: qerr.ProtocolViolation,
|
||||
ErrorMessage: err.Error(),
|
||||
})
|
||||
case handshake.ErrDecryptionFailed:
|
||||
// This might be a packet injected by an attacker. Drop it.
|
||||
if s.tracer != nil {
|
||||
s.tracer.DroppedPacket(logging.PacketTypeFromHeader(hdr), p.Size(), logging.PacketDropPayloadDecryptError)
|
||||
}
|
||||
s.logger.Debugf("Dropping %s packet (%d bytes) that could not be unpacked. Error: %s", hdr.PacketType(), p.Size(), err)
|
||||
default:
|
||||
var headerErr *headerParseError
|
||||
if errors.As(err, &headerErr) {
|
||||
// This might be a packet injected by an attacker. Drop it.
|
||||
if s.tracer != nil {
|
||||
s.tracer.DroppedPacket(logging.PacketTypeFromHeader(hdr), p.Size(), logging.PacketDropHeaderParseError)
|
||||
}
|
||||
s.logger.Debugf("Dropping %s packet (%d bytes) for which we couldn't unpack the header. Error: %s", hdr.PacketType(), p.Size(), err)
|
||||
} else {
|
||||
// This is an error returned by the AEAD (other than ErrDecryptionFailed).
|
||||
// For example, a PROTOCOL_VIOLATION due to key updates.
|
||||
s.closeLocal(err)
|
||||
}
|
||||
}
|
||||
wasQueued = s.handleUnpackError(err, p, logging.PacketTypeFromHeader(hdr))
|
||||
return false
|
||||
}
|
||||
|
||||
if s.logger.Debug() {
|
||||
s.logger.Debugf("<- Reading packet %d (%d bytes) for connection %s, %s", packet.packetNumber, p.Size(), hdr.DestConnectionID, packet.encryptionLevel)
|
||||
s.logger.Debugf("<- Reading packet %d (%d bytes) for connection %s, %s", packet.hdr.PacketNumber, p.Size(), hdr.DestConnectionID, packet.encryptionLevel)
|
||||
packet.hdr.Log(s.logger)
|
||||
}
|
||||
|
||||
if s.receivedPacketHandler.IsPotentiallyDuplicate(packet.packetNumber, packet.encryptionLevel) {
|
||||
if s.receivedPacketHandler.IsPotentiallyDuplicate(packet.hdr.PacketNumber, packet.encryptionLevel) {
|
||||
s.logger.Debugf("Dropping (potentially) duplicate packet.")
|
||||
if s.tracer != nil {
|
||||
s.tracer.DroppedPacket(logging.PacketTypeFromHeader(hdr), p.Size(), logging.PacketDropDuplicate)
|
||||
@ -995,6 +1033,46 @@ func (s *connection) handleSinglePacket(p *receivedPacket, hdr *wire.Header) boo
|
||||
return true
|
||||
}
|
||||
|
||||
func (s *connection) handleUnpackError(err error, p *receivedPacket, pt logging.PacketType) (wasQueued bool) {
|
||||
switch err {
|
||||
case handshake.ErrKeysDropped:
|
||||
if s.tracer != nil {
|
||||
s.tracer.DroppedPacket(pt, p.Size(), logging.PacketDropKeyUnavailable)
|
||||
}
|
||||
s.logger.Debugf("Dropping %s packet (%d bytes) because we already dropped the keys.", pt, p.Size())
|
||||
case handshake.ErrKeysNotYetAvailable:
|
||||
// Sealer for this encryption level not yet available.
|
||||
// Try again later.
|
||||
s.tryQueueingUndecryptablePacket(p, pt)
|
||||
return true
|
||||
case wire.ErrInvalidReservedBits:
|
||||
s.closeLocal(&qerr.TransportError{
|
||||
ErrorCode: qerr.ProtocolViolation,
|
||||
ErrorMessage: err.Error(),
|
||||
})
|
||||
case handshake.ErrDecryptionFailed:
|
||||
// This might be a packet injected by an attacker. Drop it.
|
||||
if s.tracer != nil {
|
||||
s.tracer.DroppedPacket(pt, p.Size(), logging.PacketDropPayloadDecryptError)
|
||||
}
|
||||
s.logger.Debugf("Dropping %s packet (%d bytes) that could not be unpacked. Error: %s", pt, p.Size(), err)
|
||||
default:
|
||||
var headerErr *headerParseError
|
||||
if errors.As(err, &headerErr) {
|
||||
// This might be a packet injected by an attacker. Drop it.
|
||||
if s.tracer != nil {
|
||||
s.tracer.DroppedPacket(pt, p.Size(), logging.PacketDropHeaderParseError)
|
||||
}
|
||||
s.logger.Debugf("Dropping %s packet (%d bytes) for which we couldn't unpack the header. Error: %s", pt, p.Size(), err)
|
||||
} else {
|
||||
// This is an error returned by the AEAD (other than ErrDecryptionFailed).
|
||||
// For example, a PROTOCOL_VIOLATION due to key updates.
|
||||
s.closeLocal(err)
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (s *connection) handleRetryPacket(hdr *wire.Header, data []byte) bool /* was this a valid Retry */ {
|
||||
if s.perspective == protocol.PerspectiveServer {
|
||||
if s.tracer != nil {
|
||||
@ -1011,7 +1089,7 @@ func (s *connection) handleRetryPacket(hdr *wire.Header, data []byte) bool /* wa
|
||||
return false
|
||||
}
|
||||
destConnID := s.connIDManager.Get()
|
||||
if hdr.SrcConnectionID.Equal(destConnID) {
|
||||
if hdr.SrcConnectionID == destConnID {
|
||||
if s.tracer != nil {
|
||||
s.tracer.DroppedPacket(logging.PacketTypeRetry, protocol.ByteCount(len(data)), logging.PacketDropUnexpectedPacket)
|
||||
}
|
||||
@ -1066,7 +1144,7 @@ func (s *connection) handleVersionNegotiationPacket(p *receivedPacket) {
|
||||
return
|
||||
}
|
||||
|
||||
hdr, supportedVersions, err := wire.ParseVersionNegotiationPacket(bytes.NewReader(p.data))
|
||||
src, dest, supportedVersions, err := wire.ParseVersionNegotiationPacket(p.data)
|
||||
if err != nil {
|
||||
if s.tracer != nil {
|
||||
s.tracer.DroppedPacket(logging.PacketTypeVersionNegotiation, p.Size(), logging.PacketDropHeaderParseError)
|
||||
@ -1088,7 +1166,7 @@ func (s *connection) handleVersionNegotiationPacket(p *receivedPacket) {
|
||||
|
||||
s.logger.Infof("Received a Version Negotiation packet. Supported Versions: %s", supportedVersions)
|
||||
if s.tracer != nil {
|
||||
s.tracer.ReceivedVersionNegotiationPacket(hdr, supportedVersions)
|
||||
s.tracer.ReceivedVersionNegotiationPacket(dest, src, supportedVersions)
|
||||
}
|
||||
newVersion, ok := protocol.ChooseSupportedVersion(s.config.Versions, supportedVersions)
|
||||
if !ok {
|
||||
@ -1117,13 +1195,6 @@ func (s *connection) handleUnpackedPacket(
|
||||
rcvTime time.Time,
|
||||
packetSize protocol.ByteCount, // only for logging
|
||||
) error {
|
||||
if len(packet.data) == 0 {
|
||||
return &qerr.TransportError{
|
||||
ErrorCode: qerr.ProtocolViolation,
|
||||
ErrorMessage: "empty packet",
|
||||
}
|
||||
}
|
||||
|
||||
if !s.receivedFirstPacket {
|
||||
s.receivedFirstPacket = true
|
||||
if !s.versionNegotiated && s.tracer != nil {
|
||||
@ -1137,7 +1208,7 @@ func (s *connection) handleUnpackedPacket(
|
||||
s.tracer.NegotiatedVersion(s.version, clientVersions, serverVersions)
|
||||
}
|
||||
// The server can change the source connection ID with the first Handshake packet.
|
||||
if s.perspective == protocol.PerspectiveClient && packet.hdr.IsLongHeader && !packet.hdr.SrcConnectionID.Equal(s.handshakeDestConnID) {
|
||||
if s.perspective == protocol.PerspectiveClient && packet.hdr.IsLongHeader && packet.hdr.SrcConnectionID != s.handshakeDestConnID {
|
||||
cid := packet.hdr.SrcConnectionID
|
||||
s.logger.Debugf("Received first packet. Switching destination connection ID to: %s", cid)
|
||||
s.handshakeDestConnID = cid
|
||||
@ -1149,7 +1220,7 @@ func (s *connection) handleUnpackedPacket(
|
||||
// we might have create a connection with an incorrect source connection ID.
|
||||
// Once we authenticate the first packet, we need to update it.
|
||||
if s.perspective == protocol.PerspectiveServer {
|
||||
if !packet.hdr.SrcConnectionID.Equal(s.handshakeDestConnID) {
|
||||
if packet.hdr.SrcConnectionID != s.handshakeDestConnID {
|
||||
s.handshakeDestConnID = packet.hdr.SrcConnectionID
|
||||
s.connIDManager.ChangeInitialConnID(packet.hdr.SrcConnectionID)
|
||||
}
|
||||
@ -1168,16 +1239,53 @@ func (s *connection) handleUnpackedPacket(
|
||||
s.firstAckElicitingPacketAfterIdleSentTime = time.Time{}
|
||||
s.keepAlivePingSent = false
|
||||
|
||||
var log func([]logging.Frame)
|
||||
if s.tracer != nil {
|
||||
log = func(frames []logging.Frame) {
|
||||
s.tracer.ReceivedLongHeaderPacket(packet.hdr, packetSize, frames)
|
||||
}
|
||||
}
|
||||
isAckEliciting, err := s.handleFrames(packet.data, packet.hdr.DestConnectionID, packet.encryptionLevel, log)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return s.receivedPacketHandler.ReceivedPacket(packet.hdr.PacketNumber, ecn, packet.encryptionLevel, rcvTime, isAckEliciting)
|
||||
}
|
||||
|
||||
func (s *connection) handleUnpackedShortHeaderPacket(
|
||||
destConnID protocol.ConnectionID,
|
||||
pn protocol.PacketNumber,
|
||||
data []byte,
|
||||
ecn protocol.ECN,
|
||||
rcvTime time.Time,
|
||||
log func([]logging.Frame),
|
||||
) error {
|
||||
s.lastPacketReceivedTime = rcvTime
|
||||
s.firstAckElicitingPacketAfterIdleSentTime = time.Time{}
|
||||
s.keepAlivePingSent = false
|
||||
|
||||
isAckEliciting, err := s.handleFrames(data, destConnID, protocol.Encryption1RTT, log)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return s.receivedPacketHandler.ReceivedPacket(pn, ecn, protocol.Encryption1RTT, rcvTime, isAckEliciting)
|
||||
}
|
||||
|
||||
func (s *connection) handleFrames(
|
||||
data []byte,
|
||||
destConnID protocol.ConnectionID,
|
||||
encLevel protocol.EncryptionLevel,
|
||||
log func([]logging.Frame),
|
||||
) (isAckEliciting bool, _ error) {
|
||||
// Only used for tracing.
|
||||
// If we're not tracing, this slice will always remain empty.
|
||||
var frames []wire.Frame
|
||||
r := bytes.NewReader(packet.data)
|
||||
var isAckEliciting bool
|
||||
for {
|
||||
frame, err := s.frameParser.ParseNext(r, packet.encryptionLevel)
|
||||
for len(data) > 0 {
|
||||
l, frame, err := s.frameParser.ParseNext(data, encLevel)
|
||||
if err != nil {
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
data = data[l:]
|
||||
if frame == nil {
|
||||
break
|
||||
}
|
||||
@ -1186,29 +1294,28 @@ func (s *connection) handleUnpackedPacket(
|
||||
}
|
||||
// Only process frames now if we're not logging.
|
||||
// If we're logging, we need to make sure that the packet_received event is logged first.
|
||||
if s.tracer == nil {
|
||||
if err := s.handleFrame(frame, packet.encryptionLevel, packet.hdr.DestConnectionID); err != nil {
|
||||
return err
|
||||
if log == nil {
|
||||
if err := s.handleFrame(frame, encLevel, destConnID); err != nil {
|
||||
return false, err
|
||||
}
|
||||
} else {
|
||||
frames = append(frames, frame)
|
||||
}
|
||||
}
|
||||
|
||||
if s.tracer != nil {
|
||||
if log != nil {
|
||||
fs := make([]logging.Frame, len(frames))
|
||||
for i, frame := range frames {
|
||||
fs[i] = logutils.ConvertFrame(frame)
|
||||
}
|
||||
s.tracer.ReceivedPacket(packet.hdr, packetSize, fs)
|
||||
log(fs)
|
||||
for _, frame := range frames {
|
||||
if err := s.handleFrame(frame, packet.encryptionLevel, packet.hdr.DestConnectionID); err != nil {
|
||||
return err
|
||||
if err := s.handleFrame(frame, encLevel, destConnID); err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return s.receivedPacketHandler.ReceivedPacket(packet.packetNumber, ecn, packet.encryptionLevel, rcvTime, isAckEliciting)
|
||||
return
|
||||
}
|
||||
|
||||
func (s *connection) handleFrame(f wire.Frame, encLevel protocol.EncryptionLevel, destConnID protocol.ConnectionID) error {
|
||||
@ -1221,6 +1328,7 @@ func (s *connection) handleFrame(f wire.Frame, encLevel protocol.EncryptionLevel
|
||||
err = s.handleStreamFrame(frame)
|
||||
case *wire.AckFrame:
|
||||
err = s.handleAckFrame(frame, encLevel)
|
||||
wire.PutAckFrame(frame)
|
||||
case *wire.ConnectionCloseFrame:
|
||||
s.handleConnectionCloseFrame(frame)
|
||||
case *wire.ResetStreamFrame:
|
||||
@ -1595,7 +1703,7 @@ func (s *connection) checkTransportParameters(params *wire.TransportParameters)
|
||||
}
|
||||
|
||||
// check the initial_source_connection_id
|
||||
if !params.InitialSourceConnectionID.Equal(s.handshakeDestConnID) {
|
||||
if params.InitialSourceConnectionID != s.handshakeDestConnID {
|
||||
return fmt.Errorf("expected initial_source_connection_id to equal %s, is %s", s.handshakeDestConnID, params.InitialSourceConnectionID)
|
||||
}
|
||||
|
||||
@ -1603,14 +1711,14 @@ func (s *connection) checkTransportParameters(params *wire.TransportParameters)
|
||||
return nil
|
||||
}
|
||||
// check the original_destination_connection_id
|
||||
if !params.OriginalDestinationConnectionID.Equal(s.origDestConnID) {
|
||||
if params.OriginalDestinationConnectionID != s.origDestConnID {
|
||||
return fmt.Errorf("expected original_destination_connection_id to equal %s, is %s", s.origDestConnID, params.OriginalDestinationConnectionID)
|
||||
}
|
||||
if s.retrySrcConnID != nil { // a Retry was performed
|
||||
if params.RetrySourceConnectionID == nil {
|
||||
return errors.New("missing retry_source_connection_id")
|
||||
}
|
||||
if !(*params.RetrySourceConnectionID).Equal(*s.retrySrcConnID) {
|
||||
if *params.RetrySourceConnectionID != *s.retrySrcConnID {
|
||||
return fmt.Errorf("expected retry_source_connection_id to equal %s, is %s", s.retrySrcConnID, *params.RetrySourceConnectionID)
|
||||
}
|
||||
} else if params.RetrySourceConnectionID != nil {
|
||||
@ -1707,7 +1815,24 @@ func (s *connection) sendPackets() error {
|
||||
}
|
||||
|
||||
func (s *connection) maybeSendAckOnlyPacket() error {
|
||||
packet, err := s.packer.MaybePackAckPacket(s.handshakeConfirmed)
|
||||
if !s.handshakeConfirmed {
|
||||
packet, err := s.packer.PackCoalescedPacket(true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if packet == nil {
|
||||
return nil
|
||||
}
|
||||
s.logCoalescedPacket(packet)
|
||||
for _, p := range packet.packets {
|
||||
s.sentPacketHandler.SentPacket(p.ToAckHandlerPacket(time.Now(), s.retransmissionQueue))
|
||||
}
|
||||
s.connIDManager.SentPacket()
|
||||
s.sendQueue.Send(packet.buffer)
|
||||
return nil
|
||||
}
|
||||
|
||||
packet, err := s.packer.PackPacket(true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -1768,7 +1893,7 @@ func (s *connection) sendPacket() (bool, error) {
|
||||
|
||||
now := time.Now()
|
||||
if !s.handshakeConfirmed {
|
||||
packet, err := s.packer.PackCoalescedPacket()
|
||||
packet, err := s.packer.PackCoalescedPacket(false)
|
||||
if err != nil || packet == nil {
|
||||
return false, err
|
||||
}
|
||||
@ -1792,7 +1917,7 @@ func (s *connection) sendPacket() (bool, error) {
|
||||
s.sendPackedPacket(packet, now)
|
||||
return true, nil
|
||||
}
|
||||
packet, err := s.packer.PackPacket()
|
||||
packet, err := s.packer.PackPacket(false)
|
||||
if err != nil || packet == nil {
|
||||
return false, err
|
||||
}
|
||||
@ -1839,7 +1964,11 @@ func (s *connection) logPacketContents(p *packetContents) {
|
||||
for _, f := range p.frames {
|
||||
frames = append(frames, logutils.ConvertFrame(f.Frame))
|
||||
}
|
||||
s.tracer.SentPacket(p.header, p.length, p.ack, frames)
|
||||
var ack *logging.AckFrame
|
||||
if p.ack != nil {
|
||||
ack = logutils.ConvertAckFrame(p.ack)
|
||||
}
|
||||
s.tracer.SentPacket(p.header, p.length, ack, frames)
|
||||
}
|
||||
|
||||
// quic-go logging
|
||||
@ -1930,20 +2059,22 @@ func (s *connection) scheduleSending() {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *connection) tryQueueingUndecryptablePacket(p *receivedPacket, hdr *wire.Header) {
|
||||
// tryQueueingUndecryptablePacket queues a packet for which we're missing the decryption keys.
|
||||
// The logging.PacketType is only used for logging purposes.
|
||||
func (s *connection) tryQueueingUndecryptablePacket(p *receivedPacket, pt logging.PacketType) {
|
||||
if s.handshakeComplete {
|
||||
panic("shouldn't queue undecryptable packets after handshake completion")
|
||||
}
|
||||
if len(s.undecryptablePackets)+1 > protocol.MaxUndecryptablePackets {
|
||||
if s.tracer != nil {
|
||||
s.tracer.DroppedPacket(logging.PacketTypeFromHeader(hdr), p.Size(), logging.PacketDropDOSPrevention)
|
||||
s.tracer.DroppedPacket(pt, p.Size(), logging.PacketDropDOSPrevention)
|
||||
}
|
||||
s.logger.Infof("Dropping undecryptable packet (%d bytes). Undecryptable packet queue full.", p.Size())
|
||||
return
|
||||
}
|
||||
s.logger.Infof("Queueing packet (%d bytes) for later decryption", p.Size())
|
||||
if s.tracer != nil {
|
||||
s.tracer.BufferedPacket(logging.PacketTypeFromHeader(hdr))
|
||||
s.tracer.BufferedPacket(pt, p.Size())
|
||||
}
|
||||
s.undecryptablePackets = append(s.undecryptablePackets, p)
|
||||
}
|
||||
|
20
vendor/github.com/lucas-clemente/quic-go/datagram_queue.go
generated
vendored
20
vendor/github.com/lucas-clemente/quic-go/datagram_queue.go
generated
vendored
@ -8,6 +8,7 @@
|
||||
|
||||
type datagramQueue struct {
|
||||
sendQueue chan *wire.DatagramFrame
|
||||
nextFrame *wire.DatagramFrame
|
||||
rcvQueue chan []byte
|
||||
|
||||
closeErr error
|
||||
@ -49,15 +50,26 @@ func (h *datagramQueue) AddAndWait(f *wire.DatagramFrame) error {
|
||||
}
|
||||
}
|
||||
|
||||
// Get dequeues a DATAGRAM frame for sending.
|
||||
func (h *datagramQueue) Get() *wire.DatagramFrame {
|
||||
// Peek gets the next DATAGRAM frame for sending.
|
||||
// If actually sent out, Pop needs to be called before the next call to Peek.
|
||||
func (h *datagramQueue) Peek() *wire.DatagramFrame {
|
||||
if h.nextFrame != nil {
|
||||
return h.nextFrame
|
||||
}
|
||||
select {
|
||||
case f := <-h.sendQueue:
|
||||
case h.nextFrame = <-h.sendQueue:
|
||||
h.dequeued <- struct{}{}
|
||||
return f
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
return h.nextFrame
|
||||
}
|
||||
|
||||
func (h *datagramQueue) Pop() {
|
||||
if h.nextFrame == nil {
|
||||
panic("datagramQueue BUG: Pop called for nil frame")
|
||||
}
|
||||
h.nextFrame = nil
|
||||
}
|
||||
|
||||
// HandleDatagramFrame handles a received DATAGRAM frame.
|
||||
|
3
vendor/github.com/lucas-clemente/quic-go/http3/body.go
generated
vendored
3
vendor/github.com/lucas-clemente/quic-go/http3/body.go
generated
vendored
@ -18,12 +18,15 @@ type HTTPStreamer interface {
|
||||
}
|
||||
|
||||
type StreamCreator interface {
|
||||
// Context returns a context that is cancelled when the underlying connection is closed.
|
||||
Context() context.Context
|
||||
OpenStream() (quic.Stream, error)
|
||||
OpenStreamSync(context.Context) (quic.Stream, error)
|
||||
OpenUniStream() (quic.SendStream, error)
|
||||
OpenUniStreamSync(context.Context) (quic.SendStream, error)
|
||||
LocalAddr() net.Addr
|
||||
RemoteAddr() net.Addr
|
||||
ConnectionState() quic.ConnectionState
|
||||
}
|
||||
|
||||
var _ StreamCreator = quic.Connection(nil)
|
||||
|
9
vendor/github.com/lucas-clemente/quic-go/http3/client.go
generated
vendored
9
vendor/github.com/lucas-clemente/quic-go/http3/client.go
generated
vendored
@ -1,7 +1,6 @@
|
||||
package http3
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
@ -136,11 +135,11 @@ func (c *client) setupConn() error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
buf := &bytes.Buffer{}
|
||||
quicvarint.Write(buf, streamTypeControlStream)
|
||||
b := make([]byte, 0, 64)
|
||||
b = quicvarint.Append(b, streamTypeControlStream)
|
||||
// send the SETTINGS frame
|
||||
(&settingsFrame{Datagram: c.opts.EnableDatagram, Other: c.opts.AdditionalSettings}).Write(buf)
|
||||
_, err = str.Write(buf.Bytes())
|
||||
b = (&settingsFrame{Datagram: c.opts.EnableDatagram, Other: c.opts.AdditionalSettings}).Append(b)
|
||||
_, err = str.Write(b)
|
||||
return err
|
||||
}
|
||||
|
||||
|
27
vendor/github.com/lucas-clemente/quic-go/http3/frames.go
generated
vendored
27
vendor/github.com/lucas-clemente/quic-go/http3/frames.go
generated
vendored
@ -74,18 +74,18 @@ type dataFrame struct {
|
||||
Length uint64
|
||||
}
|
||||
|
||||
func (f *dataFrame) Write(b *bytes.Buffer) {
|
||||
quicvarint.Write(b, 0x0)
|
||||
quicvarint.Write(b, f.Length)
|
||||
func (f *dataFrame) Append(b []byte) []byte {
|
||||
b = quicvarint.Append(b, 0x0)
|
||||
return quicvarint.Append(b, f.Length)
|
||||
}
|
||||
|
||||
type headersFrame struct {
|
||||
Length uint64
|
||||
}
|
||||
|
||||
func (f *headersFrame) Write(b *bytes.Buffer) {
|
||||
quicvarint.Write(b, 0x1)
|
||||
quicvarint.Write(b, f.Length)
|
||||
func (f *headersFrame) Append(b []byte) []byte {
|
||||
b = quicvarint.Append(b, 0x1)
|
||||
return quicvarint.Append(b, f.Length)
|
||||
}
|
||||
|
||||
const settingDatagram = 0xffd277
|
||||
@ -142,8 +142,8 @@ func parseSettingsFrame(r io.Reader, l uint64) (*settingsFrame, error) {
|
||||
return frame, nil
|
||||
}
|
||||
|
||||
func (f *settingsFrame) Write(b *bytes.Buffer) {
|
||||
quicvarint.Write(b, 0x4)
|
||||
func (f *settingsFrame) Append(b []byte) []byte {
|
||||
b = quicvarint.Append(b, 0x4)
|
||||
var l protocol.ByteCount
|
||||
for id, val := range f.Other {
|
||||
l += quicvarint.Len(id) + quicvarint.Len(val)
|
||||
@ -151,13 +151,14 @@ func (f *settingsFrame) Write(b *bytes.Buffer) {
|
||||
if f.Datagram {
|
||||
l += quicvarint.Len(settingDatagram) + quicvarint.Len(1)
|
||||
}
|
||||
quicvarint.Write(b, uint64(l))
|
||||
b = quicvarint.Append(b, uint64(l))
|
||||
if f.Datagram {
|
||||
quicvarint.Write(b, settingDatagram)
|
||||
quicvarint.Write(b, 1)
|
||||
b = quicvarint.Append(b, settingDatagram)
|
||||
b = quicvarint.Append(b, 1)
|
||||
}
|
||||
for id, val := range f.Other {
|
||||
quicvarint.Write(b, id)
|
||||
quicvarint.Write(b, val)
|
||||
b = quicvarint.Append(b, id)
|
||||
b = quicvarint.Append(b, val)
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
15
vendor/github.com/lucas-clemente/quic-go/http3/http_stream.go
generated
vendored
15
vendor/github.com/lucas-clemente/quic-go/http3/http_stream.go
generated
vendored
@ -1,7 +1,6 @@
|
||||
package http3
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
|
||||
"github.com/lucas-clemente/quic-go"
|
||||
@ -16,6 +15,8 @@
|
||||
type stream struct {
|
||||
quic.Stream
|
||||
|
||||
buf []byte
|
||||
|
||||
onFrameError func()
|
||||
bytesRemainingInFrame uint64
|
||||
}
|
||||
@ -23,7 +24,11 @@ type stream struct {
|
||||
var _ Stream = &stream{}
|
||||
|
||||
func newStream(str quic.Stream, onFrameError func()) *stream {
|
||||
return &stream{Stream: str, onFrameError: onFrameError}
|
||||
return &stream{
|
||||
Stream: str,
|
||||
onFrameError: onFrameError,
|
||||
buf: make([]byte, 0, 16),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *stream) Read(b []byte) (int, error) {
|
||||
@ -62,9 +67,9 @@ func (s *stream) Read(b []byte) (int, error) {
|
||||
}
|
||||
|
||||
func (s *stream) Write(b []byte) (int, error) {
|
||||
buf := &bytes.Buffer{}
|
||||
(&dataFrame{Length: uint64(len(b))}).Write(buf)
|
||||
if _, err := s.Stream.Write(buf.Bytes()); err != nil {
|
||||
s.buf = s.buf[:0]
|
||||
s.buf = (&dataFrame{Length: uint64(len(b))}).Append(s.buf)
|
||||
if _, err := s.Stream.Write(s.buf); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return s.Stream.Write(b)
|
||||
|
7
vendor/github.com/lucas-clemente/quic-go/http3/request_writer.go
generated
vendored
7
vendor/github.com/lucas-clemente/quic-go/http3/request_writer.go
generated
vendored
@ -58,10 +58,9 @@ func (w *requestWriter) writeHeaders(wr io.Writer, req *http.Request, gzip bool)
|
||||
return err
|
||||
}
|
||||
|
||||
buf := &bytes.Buffer{}
|
||||
hf := headersFrame{Length: uint64(w.headerBuf.Len())}
|
||||
hf.Write(buf)
|
||||
if _, err := wr.Write(buf.Bytes()); err != nil {
|
||||
b := make([]byte, 0, 128)
|
||||
b = (&headersFrame{Length: uint64(w.headerBuf.Len())}).Append(b)
|
||||
if _, err := wr.Write(b); err != nil {
|
||||
return err
|
||||
}
|
||||
_, err := wr.Write(w.headerBuf.Bytes())
|
||||
|
14
vendor/github.com/lucas-clemente/quic-go/http3/response_writer.go
generated
vendored
14
vendor/github.com/lucas-clemente/quic-go/http3/response_writer.go
generated
vendored
@ -15,6 +15,7 @@
|
||||
type responseWriter struct {
|
||||
conn quic.Connection
|
||||
bufferedStr *bufio.Writer
|
||||
buf []byte
|
||||
|
||||
header http.Header
|
||||
status int // status code passed to WriteHeader
|
||||
@ -32,6 +33,7 @@ type responseWriter struct {
|
||||
func newResponseWriter(str quic.Stream, conn quic.Connection, logger utils.Logger) *responseWriter {
|
||||
return &responseWriter{
|
||||
header: http.Header{},
|
||||
buf: make([]byte, 16),
|
||||
conn: conn,
|
||||
bufferedStr: bufio.NewWriter(str),
|
||||
logger: logger,
|
||||
@ -62,10 +64,10 @@ func (w *responseWriter) WriteHeader(status int) {
|
||||
}
|
||||
}
|
||||
|
||||
buf := &bytes.Buffer{}
|
||||
(&headersFrame{Length: uint64(headers.Len())}).Write(buf)
|
||||
w.buf = w.buf[:0]
|
||||
w.buf = (&headersFrame{Length: uint64(headers.Len())}).Append(w.buf)
|
||||
w.logger.Infof("Responding with %d", status)
|
||||
if _, err := w.bufferedStr.Write(buf.Bytes()); err != nil {
|
||||
if _, err := w.bufferedStr.Write(w.buf); err != nil {
|
||||
w.logger.Errorf("could not write headers frame: %s", err.Error())
|
||||
}
|
||||
if _, err := w.bufferedStr.Write(headers.Bytes()); err != nil {
|
||||
@ -84,9 +86,9 @@ func (w *responseWriter) Write(p []byte) (int, error) {
|
||||
return 0, http.ErrBodyNotAllowed
|
||||
}
|
||||
df := &dataFrame{Length: uint64(len(p))}
|
||||
buf := &bytes.Buffer{}
|
||||
df.Write(buf)
|
||||
if _, err := w.bufferedStr.Write(buf.Bytes()); err != nil {
|
||||
w.buf = w.buf[:0]
|
||||
w.buf = df.Append(w.buf)
|
||||
if _, err := w.bufferedStr.Write(w.buf); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return w.bufferedStr.Write(p)
|
||||
|
59
vendor/github.com/lucas-clemente/quic-go/http3/server.go
generated
vendored
59
vendor/github.com/lucas-clemente/quic-go/http3/server.go
generated
vendored
@ -1,7 +1,6 @@
|
||||
package http3
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
@ -29,8 +28,10 @@
|
||||
)
|
||||
|
||||
const (
|
||||
nextProtoH3Draft29 = "h3-29"
|
||||
nextProtoH3 = "h3"
|
||||
// NextProtoH3Draft29 is the ALPN protocol negotiated during the TLS handshake, for QUIC draft 29.
|
||||
NextProtoH3Draft29 = "h3-29"
|
||||
// NextProtoH3 is the ALPN protocol negotiated during the TLS handshake, for QUIC v1 and v2.
|
||||
NextProtoH3 = "h3"
|
||||
)
|
||||
|
||||
// StreamType is the stream type of a unidirectional stream.
|
||||
@ -45,10 +46,10 @@
|
||||
|
||||
func versionToALPN(v protocol.VersionNumber) string {
|
||||
if v == protocol.Version1 || v == protocol.Version2 {
|
||||
return nextProtoH3
|
||||
return NextProtoH3
|
||||
}
|
||||
if v == protocol.VersionTLS || v == protocol.VersionDraft29 {
|
||||
return nextProtoH3Draft29
|
||||
return NextProtoH3Draft29
|
||||
}
|
||||
return ""
|
||||
}
|
||||
@ -63,7 +64,7 @@ func ConfigureTLSConfig(tlsConf *tls.Config) *tls.Config {
|
||||
return &tls.Config{
|
||||
GetConfigForClient: func(ch *tls.ClientHelloInfo) (*tls.Config, error) {
|
||||
// determine the ALPN from the QUIC version used
|
||||
proto := nextProtoH3
|
||||
proto := NextProtoH3
|
||||
if qconn, ok := ch.Conn.(handshake.ConnWithVersion); ok {
|
||||
proto = versionToALPN(qconn.GetQUICVersion())
|
||||
}
|
||||
@ -225,11 +226,22 @@ func (s *Server) ListenAndServeTLS(certFile, keyFile string) error {
|
||||
|
||||
// Serve an existing UDP connection.
|
||||
// It is possible to reuse the same connection for outgoing connections.
|
||||
// Closing the server does not close the packet conn.
|
||||
// Closing the server does not close the connection.
|
||||
func (s *Server) Serve(conn net.PacketConn) error {
|
||||
return s.serveConn(s.TLSConfig, conn)
|
||||
}
|
||||
|
||||
// ServeQUICConn serves a single QUIC connection.
|
||||
func (s *Server) ServeQUICConn(conn quic.Connection) error {
|
||||
s.mutex.Lock()
|
||||
if s.logger == nil {
|
||||
s.logger = utils.DefaultLogger.WithPrefix("server")
|
||||
}
|
||||
s.mutex.Unlock()
|
||||
|
||||
return s.handleConn(conn)
|
||||
}
|
||||
|
||||
// ServeListener serves an existing QUIC listener.
|
||||
// Make sure you use http3.ConfigureTLSConfig to configure a tls.Config
|
||||
// and use it to construct a http3-friendly QUIC listener.
|
||||
@ -296,7 +308,11 @@ func (s *Server) serveListener(ln quic.EarlyListener) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
go s.handleConn(conn)
|
||||
go func() {
|
||||
if err := s.handleConn(conn); err != nil {
|
||||
s.logger.Debugf(err.Error())
|
||||
}
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
||||
@ -404,19 +420,18 @@ func (s *Server) removeListener(l *quic.EarlyListener) {
|
||||
s.mutex.Unlock()
|
||||
}
|
||||
|
||||
func (s *Server) handleConn(conn quic.EarlyConnection) {
|
||||
func (s *Server) handleConn(conn quic.Connection) error {
|
||||
decoder := qpack.NewDecoder(nil)
|
||||
|
||||
// send a SETTINGS frame
|
||||
str, err := conn.OpenUniStream()
|
||||
if err != nil {
|
||||
s.logger.Debugf("Opening the control stream failed.")
|
||||
return
|
||||
return fmt.Errorf("opening the control stream failed: %w", err)
|
||||
}
|
||||
buf := &bytes.Buffer{}
|
||||
quicvarint.Write(buf, streamTypeControlStream) // stream type
|
||||
(&settingsFrame{Datagram: s.EnableDatagrams, Other: s.AdditionalSettings}).Write(buf)
|
||||
str.Write(buf.Bytes())
|
||||
b := make([]byte, 0, 64)
|
||||
b = quicvarint.Append(b, streamTypeControlStream) // stream type
|
||||
b = (&settingsFrame{Datagram: s.EnableDatagrams, Other: s.AdditionalSettings}).Append(b)
|
||||
str.Write(b)
|
||||
|
||||
go s.handleUnidirectionalStreams(conn)
|
||||
|
||||
@ -425,8 +440,11 @@ func (s *Server) handleConn(conn quic.EarlyConnection) {
|
||||
for {
|
||||
str, err := conn.AcceptStream(context.Background())
|
||||
if err != nil {
|
||||
s.logger.Debugf("Accepting stream failed: %s", err)
|
||||
return
|
||||
var appErr *quic.ApplicationError
|
||||
if errors.As(err, &appErr) && appErr.ErrorCode == quic.ApplicationErrorCode(errorNoError) {
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("accepting stream failed: %w", err)
|
||||
}
|
||||
go func() {
|
||||
rerr := s.handleRequest(conn, str, decoder, func() {
|
||||
@ -454,7 +472,7 @@ func (s *Server) handleConn(conn quic.EarlyConnection) {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) handleUnidirectionalStreams(conn quic.EarlyConnection) {
|
||||
func (s *Server) handleUnidirectionalStreams(conn quic.Connection) {
|
||||
for {
|
||||
str, err := conn.AcceptUniStream(context.Background())
|
||||
if err != nil {
|
||||
@ -577,12 +595,15 @@ func (s *Server) handleRequest(conn quic.Connection, str quic.Stream, decoder *q
|
||||
func() {
|
||||
defer func() {
|
||||
if p := recover(); p != nil {
|
||||
panicked = true
|
||||
if p == http.ErrAbortHandler {
|
||||
return
|
||||
}
|
||||
// Copied from net/http/server.go
|
||||
const size = 64 << 10
|
||||
buf := make([]byte, size)
|
||||
buf = buf[:runtime.Stack(buf, false)]
|
||||
s.logger.Errorf("http: panic serving: %v\n%s", p, buf)
|
||||
panicked = true
|
||||
}
|
||||
}()
|
||||
handler.ServeHTTP(r, req)
|
||||
|
14
vendor/github.com/lucas-clemente/quic-go/interface.go
generated
vendored
14
vendor/github.com/lucas-clemente/quic-go/interface.go
generated
vendored
@ -173,7 +173,7 @@ type Connection interface {
|
||||
// CloseWithError closes the connection with an error.
|
||||
// The error string will be sent to the peer.
|
||||
CloseWithError(ApplicationErrorCode, string) error
|
||||
// The context is cancelled when the connection is closed.
|
||||
// Context returns a context that is cancelled when the connection is closed.
|
||||
Context() context.Context
|
||||
// ConnectionState returns basic details about the QUIC connection.
|
||||
// It blocks until the handshake completes.
|
||||
@ -201,6 +201,11 @@ type EarlyConnection interface {
|
||||
NextConnection() Connection
|
||||
}
|
||||
|
||||
// A ConnectionID is a QUIC Connection ID, as defined in RFC 9000.
|
||||
// It is not able to handle QUIC Connection IDs longer than 20 bytes,
|
||||
// as they are allowed by RFC 8999.
|
||||
type ConnectionID = protocol.ConnectionID
|
||||
|
||||
// A ConnectionIDGenerator is an interface that allows clients to implement their own format
|
||||
// for the Connection IDs that servers/clients use as SrcConnectionID in QUIC packets.
|
||||
//
|
||||
@ -208,7 +213,7 @@ type EarlyConnection interface {
|
||||
type ConnectionIDGenerator interface {
|
||||
// GenerateConnectionID generates a new ConnectionID.
|
||||
// Generated ConnectionIDs should be unique and observers should not be able to correlate two ConnectionIDs.
|
||||
GenerateConnectionID() ([]byte, error)
|
||||
GenerateConnectionID() (ConnectionID, error)
|
||||
|
||||
// ConnectionIDLen tells what is the length of the ConnectionIDs generated by the implementation of
|
||||
// this interface.
|
||||
@ -285,7 +290,7 @@ type Config struct {
|
||||
// limit the memory usage.
|
||||
// To avoid deadlocks, it is not valid to call other functions on the connection or on streams
|
||||
// in this callback.
|
||||
AllowConnectionWindowIncrease func(sess Connection, delta uint64) bool
|
||||
AllowConnectionWindowIncrease func(conn Connection, delta uint64) bool
|
||||
// MaxIncomingStreams is the maximum number of concurrent bidirectional streams that a peer is allowed to open.
|
||||
// Values above 2^60 are invalid.
|
||||
// If not set, it will default to 100.
|
||||
@ -311,8 +316,7 @@ type Config struct {
|
||||
// This can be useful if version information is exchanged out-of-band.
|
||||
// It has no effect for a client.
|
||||
DisableVersionNegotiationPackets bool
|
||||
// See https://datatracker.ietf.org/doc/draft-ietf-quic-datagram/.
|
||||
// Datagrams will only be available when both peers enable datagram support.
|
||||
// Enable QUIC datagram support (RFC 9221).
|
||||
EnableDatagrams bool
|
||||
Tracer logging.Tracer
|
||||
}
|
||||
|
20
vendor/github.com/lucas-clemente/quic-go/internal/ackhandler/interfaces.go
generated
vendored
20
vendor/github.com/lucas-clemente/quic-go/internal/ackhandler/interfaces.go
generated
vendored
@ -7,26 +7,6 @@
|
||||
"github.com/lucas-clemente/quic-go/internal/wire"
|
||||
)
|
||||
|
||||
// A Packet is a packet
|
||||
type Packet struct {
|
||||
PacketNumber protocol.PacketNumber
|
||||
Frames []Frame
|
||||
LargestAcked protocol.PacketNumber // InvalidPacketNumber if the packet doesn't contain an ACK
|
||||
Length protocol.ByteCount
|
||||
EncryptionLevel protocol.EncryptionLevel
|
||||
SendTime time.Time
|
||||
|
||||
IsPathMTUProbePacket bool // We don't report the loss of Path MTU probe packets to the congestion controller.
|
||||
|
||||
includedInBytesInFlight bool
|
||||
declaredLost bool
|
||||
skippedPacket bool
|
||||
}
|
||||
|
||||
func (p *Packet) outstanding() bool {
|
||||
return !p.declaredLost && !p.skippedPacket && !p.IsPathMTUProbePacket
|
||||
}
|
||||
|
||||
// SentPacketHandler handles ACKs received for outgoing packets
|
||||
type SentPacketHandler interface {
|
||||
// SentPacket may modify the packet
|
||||
|
49
vendor/github.com/lucas-clemente/quic-go/internal/ackhandler/packet.go
generated
vendored
Normal file
49
vendor/github.com/lucas-clemente/quic-go/internal/ackhandler/packet.go
generated
vendored
Normal file
@ -0,0 +1,49 @@
|
||||
package ackhandler
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/lucas-clemente/quic-go/internal/protocol"
|
||||
)
|
||||
|
||||
// A Packet is a packet
|
||||
type Packet struct {
|
||||
PacketNumber protocol.PacketNumber
|
||||
Frames []Frame
|
||||
LargestAcked protocol.PacketNumber // InvalidPacketNumber if the packet doesn't contain an ACK
|
||||
Length protocol.ByteCount
|
||||
EncryptionLevel protocol.EncryptionLevel
|
||||
SendTime time.Time
|
||||
|
||||
IsPathMTUProbePacket bool // We don't report the loss of Path MTU probe packets to the congestion controller.
|
||||
|
||||
includedInBytesInFlight bool
|
||||
declaredLost bool
|
||||
skippedPacket bool
|
||||
}
|
||||
|
||||
func (p *Packet) outstanding() bool {
|
||||
return !p.declaredLost && !p.skippedPacket && !p.IsPathMTUProbePacket
|
||||
}
|
||||
|
||||
var packetPool = sync.Pool{New: func() any { return &Packet{} }}
|
||||
|
||||
func GetPacket() *Packet {
|
||||
p := packetPool.Get().(*Packet)
|
||||
p.PacketNumber = 0
|
||||
p.Frames = nil
|
||||
p.LargestAcked = 0
|
||||
p.Length = 0
|
||||
p.EncryptionLevel = protocol.EncryptionLevel(0)
|
||||
p.SendTime = time.Time{}
|
||||
p.IsPathMTUProbePacket = false
|
||||
p.includedInBytesInFlight = false
|
||||
p.declaredLost = false
|
||||
p.skippedPacket = false
|
||||
return p
|
||||
}
|
||||
|
||||
// We currently only return Packets back into the pool when they're acknowledged (not when they're lost).
|
||||
// This simplifies the code, and gives the vast majority of the performance benefit we can gain from using the pool.
|
||||
func putPacket(p *Packet) { packetPool.Put(p) }
|
12
vendor/github.com/lucas-clemente/quic-go/internal/ackhandler/received_packet_handler.go
generated
vendored
12
vendor/github.com/lucas-clemente/quic-go/internal/ackhandler/received_packet_handler.go
generated
vendored
@ -46,24 +46,26 @@ func (h *receivedPacketHandler) ReceivedPacket(
|
||||
h.sentPackets.ReceivedPacket(encLevel)
|
||||
switch encLevel {
|
||||
case protocol.EncryptionInitial:
|
||||
h.initialPackets.ReceivedPacket(pn, ecn, rcvTime, shouldInstigateAck)
|
||||
return h.initialPackets.ReceivedPacket(pn, ecn, rcvTime, shouldInstigateAck)
|
||||
case protocol.EncryptionHandshake:
|
||||
h.handshakePackets.ReceivedPacket(pn, ecn, rcvTime, shouldInstigateAck)
|
||||
return h.handshakePackets.ReceivedPacket(pn, ecn, rcvTime, shouldInstigateAck)
|
||||
case protocol.Encryption0RTT:
|
||||
if h.lowest1RTTPacket != protocol.InvalidPacketNumber && pn > h.lowest1RTTPacket {
|
||||
return fmt.Errorf("received packet number %d on a 0-RTT packet after receiving %d on a 1-RTT packet", pn, h.lowest1RTTPacket)
|
||||
}
|
||||
h.appDataPackets.ReceivedPacket(pn, ecn, rcvTime, shouldInstigateAck)
|
||||
return h.appDataPackets.ReceivedPacket(pn, ecn, rcvTime, shouldInstigateAck)
|
||||
case protocol.Encryption1RTT:
|
||||
if h.lowest1RTTPacket == protocol.InvalidPacketNumber || pn < h.lowest1RTTPacket {
|
||||
h.lowest1RTTPacket = pn
|
||||
}
|
||||
if err := h.appDataPackets.ReceivedPacket(pn, ecn, rcvTime, shouldInstigateAck); err != nil {
|
||||
return err
|
||||
}
|
||||
h.appDataPackets.IgnoreBelow(h.sentPackets.GetLowestPacketNotConfirmedAcked())
|
||||
h.appDataPackets.ReceivedPacket(pn, ecn, rcvTime, shouldInstigateAck)
|
||||
return nil
|
||||
default:
|
||||
panic(fmt.Sprintf("received packet with unknown encryption level: %s", encLevel))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *receivedPacketHandler) DropPackets(encLevel protocol.EncryptionLevel) {
|
||||
|
17
vendor/github.com/lucas-clemente/quic-go/internal/ackhandler/received_packet_history.go
generated
vendored
17
vendor/github.com/lucas-clemente/quic-go/internal/ackhandler/received_packet_history.go
generated
vendored
@ -107,17 +107,12 @@ func (h *receivedPacketHistory) DeleteBelow(p protocol.PacketNumber) {
|
||||
}
|
||||
}
|
||||
|
||||
// GetAckRanges gets a slice of all AckRanges that can be used in an AckFrame
|
||||
func (h *receivedPacketHistory) GetAckRanges() []wire.AckRange {
|
||||
if h.ranges.Len() == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
ackRanges := make([]wire.AckRange, h.ranges.Len())
|
||||
i := 0
|
||||
for el := h.ranges.Back(); el != nil; el = el.Prev() {
|
||||
ackRanges[i] = wire.AckRange{Smallest: el.Value.Start, Largest: el.Value.End}
|
||||
i++
|
||||
// AppendAckRanges appends to a slice of all AckRanges that can be used in an AckFrame
|
||||
func (h *receivedPacketHistory) AppendAckRanges(ackRanges []wire.AckRange) []wire.AckRange {
|
||||
if h.ranges.Len() > 0 {
|
||||
for el := h.ranges.Back(); el != nil; el = el.Prev() {
|
||||
ackRanges = append(ackRanges, wire.AckRange{Smallest: el.Value.Start, Largest: el.Value.End})
|
||||
}
|
||||
}
|
||||
return ackRanges
|
||||
}
|
||||
|
28
vendor/github.com/lucas-clemente/quic-go/internal/ackhandler/received_packet_tracker.go
generated
vendored
28
vendor/github.com/lucas-clemente/quic-go/internal/ackhandler/received_packet_tracker.go
generated
vendored
@ -1,6 +1,7 @@
|
||||
package ackhandler
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/lucas-clemente/quic-go/internal/protocol"
|
||||
@ -48,9 +49,9 @@ func newReceivedPacketTracker(
|
||||
}
|
||||
}
|
||||
|
||||
func (h *receivedPacketTracker) ReceivedPacket(packetNumber protocol.PacketNumber, ecn protocol.ECN, rcvTime time.Time, shouldInstigateAck bool) {
|
||||
if packetNumber < h.ignoreBelow {
|
||||
return
|
||||
func (h *receivedPacketTracker) ReceivedPacket(packetNumber protocol.PacketNumber, ecn protocol.ECN, rcvTime time.Time, shouldInstigateAck bool) error {
|
||||
if isNew := h.packetHistory.ReceivedPacket(packetNumber); !isNew {
|
||||
return fmt.Errorf("recevedPacketTracker BUG: ReceivedPacket called for old / duplicate packet %d", packetNumber)
|
||||
}
|
||||
|
||||
isMissing := h.isMissing(packetNumber)
|
||||
@ -59,7 +60,7 @@ func (h *receivedPacketTracker) ReceivedPacket(packetNumber protocol.PacketNumbe
|
||||
h.largestObservedReceivedTime = rcvTime
|
||||
}
|
||||
|
||||
if isNew := h.packetHistory.ReceivedPacket(packetNumber); isNew && shouldInstigateAck {
|
||||
if shouldInstigateAck {
|
||||
h.hasNewAck = true
|
||||
}
|
||||
if shouldInstigateAck {
|
||||
@ -74,6 +75,7 @@ func (h *receivedPacketTracker) ReceivedPacket(packetNumber protocol.PacketNumbe
|
||||
case protocol.ECNCE:
|
||||
h.ecnce++
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// IgnoreBelow sets a lower limit for acknowledging packets.
|
||||
@ -171,16 +173,16 @@ func (h *receivedPacketTracker) GetAckFrame(onlyIfQueued bool) *wire.AckFrame {
|
||||
}
|
||||
}
|
||||
|
||||
ack := &wire.AckFrame{
|
||||
AckRanges: h.packetHistory.GetAckRanges(),
|
||||
// Make sure that the DelayTime is always positive.
|
||||
// This is not guaranteed on systems that don't have a monotonic clock.
|
||||
DelayTime: utils.Max(0, now.Sub(h.largestObservedReceivedTime)),
|
||||
ECT0: h.ect0,
|
||||
ECT1: h.ect1,
|
||||
ECNCE: h.ecnce,
|
||||
}
|
||||
ack := wire.GetAckFrame()
|
||||
ack.DelayTime = utils.Max(0, now.Sub(h.largestObservedReceivedTime))
|
||||
ack.ECT0 = h.ect0
|
||||
ack.ECT1 = h.ect1
|
||||
ack.ECNCE = h.ecnce
|
||||
ack.AckRanges = h.packetHistory.AppendAckRanges(ack.AckRanges)
|
||||
|
||||
if h.lastAck != nil {
|
||||
wire.PutAckFrame(h.lastAck)
|
||||
}
|
||||
h.lastAck = ack
|
||||
h.ackAlarm = time.Time{}
|
||||
h.ackQueued = false
|
||||
|
20
vendor/github.com/lucas-clemente/quic-go/internal/ackhandler/sent_packet_handler.go
generated
vendored
20
vendor/github.com/lucas-clemente/quic-go/internal/ackhandler/sent_packet_handler.go
generated
vendored
@ -226,14 +226,20 @@ func (h *sentPacketHandler) packetsInFlight() int {
|
||||
return packetsInFlight
|
||||
}
|
||||
|
||||
func (h *sentPacketHandler) SentPacket(packet *Packet) {
|
||||
h.bytesSent += packet.Length
|
||||
func (h *sentPacketHandler) SentPacket(p *Packet) {
|
||||
h.bytesSent += p.Length
|
||||
// For the client, drop the Initial packet number space when the first Handshake packet is sent.
|
||||
if h.perspective == protocol.PerspectiveClient && packet.EncryptionLevel == protocol.EncryptionHandshake && h.initialPackets != nil {
|
||||
if h.perspective == protocol.PerspectiveClient && p.EncryptionLevel == protocol.EncryptionHandshake && h.initialPackets != nil {
|
||||
h.dropPackets(protocol.EncryptionInitial)
|
||||
}
|
||||
isAckEliciting := h.sentPacketImpl(packet)
|
||||
h.getPacketNumberSpace(packet.EncryptionLevel).history.SentPacket(packet, isAckEliciting)
|
||||
isAckEliciting := h.sentPacketImpl(p)
|
||||
if isAckEliciting {
|
||||
h.getPacketNumberSpace(p.EncryptionLevel).history.SentAckElicitingPacket(p)
|
||||
} else {
|
||||
h.getPacketNumberSpace(p.EncryptionLevel).history.SentNonAckElicitingPacket(p.PacketNumber, p.EncryptionLevel, p.SendTime)
|
||||
putPacket(p)
|
||||
p = nil //nolint:ineffassign // This is just to be on the safe side.
|
||||
}
|
||||
if h.tracer != nil && isAckEliciting {
|
||||
h.tracer.UpdatedMetrics(h.rttStats, h.congestion.GetCongestionWindow(), h.bytesInFlight, h.packetsInFlight())
|
||||
}
|
||||
@ -334,7 +340,11 @@ func (h *sentPacketHandler) ReceivedAck(ack *wire.AckFrame, encLevel protocol.En
|
||||
acked1RTTPacket = true
|
||||
}
|
||||
h.removeFromBytesInFlight(p)
|
||||
putPacket(p)
|
||||
}
|
||||
// After this point, we must not use ackedPackets any longer!
|
||||
// We've already returned the buffers.
|
||||
ackedPackets = nil //nolint:ineffassign // This is just to be on the safe side.
|
||||
|
||||
// Reset the pto_count unless the client is unsure if the server has validated the client's address.
|
||||
if h.peerCompletedAddressValidation {
|
||||
|
70
vendor/github.com/lucas-clemente/quic-go/internal/ackhandler/sent_packet_history.go
generated
vendored
70
vendor/github.com/lucas-clemente/quic-go/internal/ackhandler/sent_packet_history.go
generated
vendored
@ -11,47 +11,53 @@
|
||||
|
||||
type sentPacketHistory struct {
|
||||
rttStats *utils.RTTStats
|
||||
outstandingPacketList *list.List[Packet]
|
||||
etcPacketList *list.List[Packet]
|
||||
packetMap map[protocol.PacketNumber]*list.Element[Packet]
|
||||
outstandingPacketList *list.List[*Packet]
|
||||
etcPacketList *list.List[*Packet]
|
||||
packetMap map[protocol.PacketNumber]*list.Element[*Packet]
|
||||
highestSent protocol.PacketNumber
|
||||
}
|
||||
|
||||
func newSentPacketHistory(rttStats *utils.RTTStats) *sentPacketHistory {
|
||||
return &sentPacketHistory{
|
||||
rttStats: rttStats,
|
||||
outstandingPacketList: list.New[Packet](),
|
||||
etcPacketList: list.New[Packet](),
|
||||
packetMap: make(map[protocol.PacketNumber]*list.Element[Packet]),
|
||||
outstandingPacketList: list.New[*Packet](),
|
||||
etcPacketList: list.New[*Packet](),
|
||||
packetMap: make(map[protocol.PacketNumber]*list.Element[*Packet]),
|
||||
highestSent: protocol.InvalidPacketNumber,
|
||||
}
|
||||
}
|
||||
|
||||
func (h *sentPacketHistory) SentPacket(p *Packet, isAckEliciting bool) {
|
||||
if p.PacketNumber <= h.highestSent {
|
||||
func (h *sentPacketHistory) SentNonAckElicitingPacket(pn protocol.PacketNumber, encLevel protocol.EncryptionLevel, t time.Time) {
|
||||
h.registerSentPacket(pn, encLevel, t)
|
||||
}
|
||||
|
||||
func (h *sentPacketHistory) SentAckElicitingPacket(p *Packet) {
|
||||
h.registerSentPacket(p.PacketNumber, p.EncryptionLevel, p.SendTime)
|
||||
|
||||
var el *list.Element[*Packet]
|
||||
if p.outstanding() {
|
||||
el = h.outstandingPacketList.PushBack(p)
|
||||
} else {
|
||||
el = h.etcPacketList.PushBack(p)
|
||||
}
|
||||
h.packetMap[p.PacketNumber] = el
|
||||
}
|
||||
|
||||
func (h *sentPacketHistory) registerSentPacket(pn protocol.PacketNumber, encLevel protocol.EncryptionLevel, t time.Time) {
|
||||
if pn <= h.highestSent {
|
||||
panic("non-sequential packet number use")
|
||||
}
|
||||
// Skipped packet numbers.
|
||||
for pn := h.highestSent + 1; pn < p.PacketNumber; pn++ {
|
||||
el := h.etcPacketList.PushBack(Packet{
|
||||
PacketNumber: pn,
|
||||
EncryptionLevel: p.EncryptionLevel,
|
||||
SendTime: p.SendTime,
|
||||
for p := h.highestSent + 1; p < pn; p++ {
|
||||
el := h.etcPacketList.PushBack(&Packet{
|
||||
PacketNumber: p,
|
||||
EncryptionLevel: encLevel,
|
||||
SendTime: t,
|
||||
skippedPacket: true,
|
||||
})
|
||||
h.packetMap[pn] = el
|
||||
}
|
||||
h.highestSent = p.PacketNumber
|
||||
|
||||
if isAckEliciting {
|
||||
var el *list.Element[Packet]
|
||||
if p.outstanding() {
|
||||
el = h.outstandingPacketList.PushBack(*p)
|
||||
} else {
|
||||
el = h.etcPacketList.PushBack(*p)
|
||||
}
|
||||
h.packetMap[p.PacketNumber] = el
|
||||
h.packetMap[p] = el
|
||||
}
|
||||
h.highestSent = pn
|
||||
}
|
||||
|
||||
// Iterate iterates through all packets.
|
||||
@ -59,7 +65,7 @@ func (h *sentPacketHistory) Iterate(cb func(*Packet) (cont bool, err error)) err
|
||||
cont := true
|
||||
outstandingEl := h.outstandingPacketList.Front()
|
||||
etcEl := h.etcPacketList.Front()
|
||||
var el *list.Element[Packet]
|
||||
var el *list.Element[*Packet]
|
||||
// whichever has the next packet number is returned first
|
||||
for cont {
|
||||
if outstandingEl == nil || (etcEl != nil && etcEl.Value.PacketNumber < outstandingEl.Value.PacketNumber) {
|
||||
@ -76,7 +82,7 @@ func (h *sentPacketHistory) Iterate(cb func(*Packet) (cont bool, err error)) err
|
||||
etcEl = etcEl.Next()
|
||||
}
|
||||
var err error
|
||||
cont, err = cb(&el.Value)
|
||||
cont, err = cb(el.Value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -90,7 +96,7 @@ func (h *sentPacketHistory) FirstOutstanding() *Packet {
|
||||
if el == nil {
|
||||
return nil
|
||||
}
|
||||
return &el.Value
|
||||
return el.Value
|
||||
}
|
||||
|
||||
func (h *sentPacketHistory) Len() int {
|
||||
@ -114,7 +120,7 @@ func (h *sentPacketHistory) HasOutstandingPackets() bool {
|
||||
|
||||
func (h *sentPacketHistory) DeleteOldPackets(now time.Time) {
|
||||
maxAge := 3 * h.rttStats.PTO(false)
|
||||
var nextEl *list.Element[Packet]
|
||||
var nextEl *list.Element[*Packet]
|
||||
// we don't iterate outstandingPacketList, as we should not delete outstanding packets.
|
||||
// being outstanding for more than 3*PTO should only happen in the case of drastic RTT changes.
|
||||
for el := h.etcPacketList.Front(); el != nil; el = nextEl {
|
||||
@ -145,10 +151,10 @@ func (h *sentPacketHistory) DeclareLost(p *Packet) *Packet {
|
||||
}
|
||||
}
|
||||
if el == nil {
|
||||
el = h.etcPacketList.PushFront(*p)
|
||||
el = h.etcPacketList.PushFront(p)
|
||||
} else {
|
||||
el = h.etcPacketList.InsertAfter(*p, el)
|
||||
el = h.etcPacketList.InsertAfter(p, el)
|
||||
}
|
||||
h.packetMap[p.PacketNumber] = el
|
||||
return &el.Value
|
||||
return el.Value
|
||||
}
|
||||
|
9
vendor/github.com/lucas-clemente/quic-go/internal/handshake/crypto_setup.go
generated
vendored
9
vendor/github.com/lucas-clemente/quic-go/internal/handshake/crypto_setup.go
generated
vendored
@ -432,11 +432,10 @@ func (h *cryptoSetup) handleTransportParameters(data []byte) {
|
||||
|
||||
// must be called after receiving the transport parameters
|
||||
func (h *cryptoSetup) marshalDataForSessionState() []byte {
|
||||
buf := &bytes.Buffer{}
|
||||
quicvarint.Write(buf, clientSessionStateRevision)
|
||||
quicvarint.Write(buf, uint64(h.rttStats.SmoothedRTT().Microseconds()))
|
||||
h.peerParams.MarshalForSessionTicket(buf)
|
||||
return buf.Bytes()
|
||||
b := make([]byte, 0, 256)
|
||||
b = quicvarint.Append(b, clientSessionStateRevision)
|
||||
b = quicvarint.Append(b, uint64(h.rttStats.SmoothedRTT().Microseconds()))
|
||||
return h.peerParams.MarshalForSessionTicket(b)
|
||||
}
|
||||
|
||||
func (h *cryptoSetup) handleDataFromSessionState(data []byte) {
|
||||
|
2
vendor/github.com/lucas-clemente/quic-go/internal/handshake/initial_aead.go
generated
vendored
2
vendor/github.com/lucas-clemente/quic-go/internal/handshake/initial_aead.go
generated
vendored
@ -62,7 +62,7 @@ func NewInitialAEAD(connID protocol.ConnectionID, pers protocol.Perspective, v p
|
||||
}
|
||||
|
||||
func computeSecrets(connID protocol.ConnectionID, v protocol.VersionNumber) (clientSecret, serverSecret []byte) {
|
||||
initialSecret := hkdf.Extract(crypto.SHA256.New, connID, getSalt(v))
|
||||
initialSecret := hkdf.Extract(crypto.SHA256.New, connID.Bytes(), getSalt(v))
|
||||
clientSecret = hkdfExpandLabel(crypto.SHA256, initialSecret, []byte{}, "client in", crypto.SHA256.Size())
|
||||
serverSecret = hkdfExpandLabel(crypto.SHA256, initialSecret, []byte{}, "server in", crypto.SHA256.Size())
|
||||
return
|
||||
|
9
vendor/github.com/lucas-clemente/quic-go/internal/handshake/session_ticket.go
generated
vendored
9
vendor/github.com/lucas-clemente/quic-go/internal/handshake/session_ticket.go
generated
vendored
@ -18,11 +18,10 @@ type sessionTicket struct {
|
||||
}
|
||||
|
||||
func (t *sessionTicket) Marshal() []byte {
|
||||
b := &bytes.Buffer{}
|
||||
quicvarint.Write(b, sessionTicketRevision)
|
||||
quicvarint.Write(b, uint64(t.RTT.Microseconds()))
|
||||
t.Parameters.MarshalForSessionTicket(b)
|
||||
return b.Bytes()
|
||||
b := make([]byte, 0, 256)
|
||||
b = quicvarint.Append(b, sessionTicketRevision)
|
||||
b = quicvarint.Append(b, uint64(t.RTT.Microseconds()))
|
||||
return t.Parameters.MarshalForSessionTicket(b)
|
||||
}
|
||||
|
||||
func (t *sessionTicket) Unmarshal(b []byte) error {
|
||||
|
8
vendor/github.com/lucas-clemente/quic-go/internal/handshake/token_generator.go
generated
vendored
8
vendor/github.com/lucas-clemente/quic-go/internal/handshake/token_generator.go
generated
vendored
@ -65,8 +65,8 @@ func (g *TokenGenerator) NewRetryToken(
|
||||
data, err := asn1.Marshal(token{
|
||||
IsRetryToken: true,
|
||||
RemoteAddr: encodeRemoteAddr(raddr),
|
||||
OriginalDestConnectionID: origDestConnID,
|
||||
RetrySrcConnectionID: retrySrcConnID,
|
||||
OriginalDestConnectionID: origDestConnID.Bytes(),
|
||||
RetrySrcConnectionID: retrySrcConnID.Bytes(),
|
||||
Timestamp: time.Now().UnixNano(),
|
||||
})
|
||||
if err != nil {
|
||||
@ -112,8 +112,8 @@ func (g *TokenGenerator) DecodeToken(encrypted []byte) (*Token, error) {
|
||||
encodedRemoteAddr: t.RemoteAddr,
|
||||
}
|
||||
if t.IsRetryToken {
|
||||
token.OriginalDestConnectionID = protocol.ConnectionID(t.OriginalDestConnectionID)
|
||||
token.RetrySrcConnectionID = protocol.ConnectionID(t.RetrySrcConnectionID)
|
||||
token.OriginalDestConnectionID = protocol.ParseConnectionID(t.OriginalDestConnectionID)
|
||||
token.RetrySrcConnectionID = protocol.ParseConnectionID(t.RetrySrcConnectionID)
|
||||
}
|
||||
return token, nil
|
||||
}
|
||||
|
17
vendor/github.com/lucas-clemente/quic-go/internal/logutils/frame.go
generated
vendored
17
vendor/github.com/lucas-clemente/quic-go/internal/logutils/frame.go
generated
vendored
@ -11,6 +11,10 @@
|
||||
// Furthermore, it removes the data slices from CRYPTO and STREAM frames.
|
||||
func ConvertFrame(frame wire.Frame) logging.Frame {
|
||||
switch f := frame.(type) {
|
||||
case *wire.AckFrame:
|
||||
// We use a pool for ACK frames.
|
||||
// Implementations of the tracer interface may hold on to frames, so we need to make a copy here.
|
||||
return ConvertAckFrame(f)
|
||||
case *wire.CryptoFrame:
|
||||
return &logging.CryptoFrame{
|
||||
Offset: f.Offset,
|
||||
@ -31,3 +35,16 @@ func ConvertFrame(frame wire.Frame) logging.Frame {
|
||||
return logging.Frame(frame)
|
||||
}
|
||||
}
|
||||
|
||||
func ConvertAckFrame(f *wire.AckFrame) *logging.AckFrame {
|
||||
ranges := make([]wire.AckRange, 0, len(f.AckRanges))
|
||||
ranges = append(ranges, f.AckRanges...)
|
||||
ack := &logging.AckFrame{
|
||||
AckRanges: ranges,
|
||||
DelayTime: f.DelayTime,
|
||||
ECNCE: f.ECNCE,
|
||||
ECT0: f.ECT0,
|
||||
ECT1: f.ECT1,
|
||||
}
|
||||
return ack
|
||||
}
|
||||
|
85
vendor/github.com/lucas-clemente/quic-go/internal/protocol/connection_id.go
generated
vendored
85
vendor/github.com/lucas-clemente/quic-go/internal/protocol/connection_id.go
generated
vendored
@ -1,24 +1,60 @@
|
||||
package protocol
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
)
|
||||
|
||||
// A ConnectionID in QUIC
|
||||
type ConnectionID []byte
|
||||
var ErrInvalidConnectionIDLen = errors.New("invalid Connection ID length")
|
||||
|
||||
// An ArbitraryLenConnectionID is a QUIC Connection ID able to represent Connection IDs according to RFC 8999.
|
||||
// Future QUIC versions might allow connection ID lengths up to 255 bytes, while QUIC v1
|
||||
// restricts the length to 20 bytes.
|
||||
type ArbitraryLenConnectionID []byte
|
||||
|
||||
func (c ArbitraryLenConnectionID) Len() int {
|
||||
return len(c)
|
||||
}
|
||||
|
||||
func (c ArbitraryLenConnectionID) Bytes() []byte {
|
||||
return c
|
||||
}
|
||||
|
||||
func (c ArbitraryLenConnectionID) String() string {
|
||||
if c.Len() == 0 {
|
||||
return "(empty)"
|
||||
}
|
||||
return fmt.Sprintf("%x", c.Bytes())
|
||||
}
|
||||
|
||||
const maxConnectionIDLen = 20
|
||||
|
||||
// A ConnectionID in QUIC
|
||||
type ConnectionID struct {
|
||||
b [20]byte
|
||||
l uint8
|
||||
}
|
||||
|
||||
// GenerateConnectionID generates a connection ID using cryptographic random
|
||||
func GenerateConnectionID(len int) (ConnectionID, error) {
|
||||
b := make([]byte, len)
|
||||
if _, err := rand.Read(b); err != nil {
|
||||
return nil, err
|
||||
func GenerateConnectionID(l int) (ConnectionID, error) {
|
||||
var c ConnectionID
|
||||
c.l = uint8(l)
|
||||
_, err := rand.Read(c.b[:l])
|
||||
return c, err
|
||||
}
|
||||
|
||||
// ParseConnectionID interprets b as a Connection ID.
|
||||
// It panics if b is longer than 20 bytes.
|
||||
func ParseConnectionID(b []byte) ConnectionID {
|
||||
if len(b) > maxConnectionIDLen {
|
||||
panic("invalid conn id length")
|
||||
}
|
||||
return ConnectionID(b), nil
|
||||
var c ConnectionID
|
||||
c.l = uint8(len(b))
|
||||
copy(c.b[:c.l], b)
|
||||
return c
|
||||
}
|
||||
|
||||
// GenerateConnectionIDForInitial generates a connection ID for the Initial packet.
|
||||
@ -26,39 +62,38 @@ func GenerateConnectionID(len int) (ConnectionID, error) {
|
||||
func GenerateConnectionIDForInitial() (ConnectionID, error) {
|
||||
r := make([]byte, 1)
|
||||
if _, err := rand.Read(r); err != nil {
|
||||
return nil, err
|
||||
return ConnectionID{}, err
|
||||
}
|
||||
len := MinConnectionIDLenInitial + int(r[0])%(maxConnectionIDLen-MinConnectionIDLenInitial+1)
|
||||
return GenerateConnectionID(len)
|
||||
l := MinConnectionIDLenInitial + int(r[0])%(maxConnectionIDLen-MinConnectionIDLenInitial+1)
|
||||
return GenerateConnectionID(l)
|
||||
}
|
||||
|
||||
// ReadConnectionID reads a connection ID of length len from the given io.Reader.
|
||||
// It returns io.EOF if there are not enough bytes to read.
|
||||
func ReadConnectionID(r io.Reader, len int) (ConnectionID, error) {
|
||||
if len == 0 {
|
||||
return nil, nil
|
||||
func ReadConnectionID(r io.Reader, l int) (ConnectionID, error) {
|
||||
var c ConnectionID
|
||||
if l == 0 {
|
||||
return c, nil
|
||||
}
|
||||
c := make(ConnectionID, len)
|
||||
_, err := io.ReadFull(r, c)
|
||||
if l > maxConnectionIDLen {
|
||||
return c, ErrInvalidConnectionIDLen
|
||||
}
|
||||
c.l = uint8(l)
|
||||
_, err := io.ReadFull(r, c.b[:l])
|
||||
if err == io.ErrUnexpectedEOF {
|
||||
return nil, io.EOF
|
||||
return c, io.EOF
|
||||
}
|
||||
return c, err
|
||||
}
|
||||
|
||||
// Equal says if two connection IDs are equal
|
||||
func (c ConnectionID) Equal(other ConnectionID) bool {
|
||||
return bytes.Equal(c, other)
|
||||
}
|
||||
|
||||
// Len returns the length of the connection ID in bytes
|
||||
func (c ConnectionID) Len() int {
|
||||
return len(c)
|
||||
return int(c.l)
|
||||
}
|
||||
|
||||
// Bytes returns the byte representation
|
||||
func (c ConnectionID) Bytes() []byte {
|
||||
return []byte(c)
|
||||
return c.b[:c.l]
|
||||
}
|
||||
|
||||
func (c ConnectionID) String() string {
|
||||
@ -72,7 +107,7 @@ type DefaultConnectionIDGenerator struct {
|
||||
ConnLen int
|
||||
}
|
||||
|
||||
func (d *DefaultConnectionIDGenerator) GenerateConnectionID() ([]byte, error) {
|
||||
func (d *DefaultConnectionIDGenerator) GenerateConnectionID() (ConnectionID, error) {
|
||||
return GenerateConnectionID(d.ConnLen)
|
||||
}
|
||||
|
||||
|
2
vendor/github.com/lucas-clemente/quic-go/internal/protocol/params.go
generated
vendored
2
vendor/github.com/lucas-clemente/quic-go/internal/protocol/params.go
generated
vendored
@ -134,7 +134,7 @@
|
||||
|
||||
// MaxDatagramFrameSize is the maximum size of a DATAGRAM frame (RFC 9221).
|
||||
// The size is chosen such that a DATAGRAM frame fits into a QUIC packet.
|
||||
const MaxDatagramFrameSize ByteCount = 1220
|
||||
const MaxDatagramFrameSize ByteCount = 1200
|
||||
|
||||
// DatagramRcvQueueLen is the length of the receive queue for DATAGRAM frames (RFC 9221)
|
||||
const DatagramRcvQueueLen = 128
|
||||
|
4
vendor/github.com/lucas-clemente/quic-go/internal/utils/byteorder.go
generated
vendored
4
vendor/github.com/lucas-clemente/quic-go/internal/utils/byteorder.go
generated
vendored
@ -7,6 +7,10 @@
|
||||
|
||||
// A ByteOrder specifies how to convert byte sequences into 16-, 32-, or 64-bit unsigned integers.
|
||||
type ByteOrder interface {
|
||||
Uint32([]byte) uint32
|
||||
Uint24([]byte) uint32
|
||||
Uint16([]byte) uint16
|
||||
|
||||
ReadUint32(io.ByteReader) (uint32, error)
|
||||
ReadUint24(io.ByteReader) (uint32, error)
|
||||
ReadUint16(io.ByteReader) (uint16, error)
|
||||
|
14
vendor/github.com/lucas-clemente/quic-go/internal/utils/byteorder_big_endian.go
generated
vendored
14
vendor/github.com/lucas-clemente/quic-go/internal/utils/byteorder_big_endian.go
generated
vendored
@ -2,6 +2,7 @@
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"io"
|
||||
)
|
||||
|
||||
@ -73,6 +74,19 @@ func (bigEndian) ReadUint16(b io.ByteReader) (uint16, error) {
|
||||
return uint16(b1) + uint16(b2)<<8, nil
|
||||
}
|
||||
|
||||
func (bigEndian) Uint32(b []byte) uint32 {
|
||||
return binary.BigEndian.Uint32(b)
|
||||
}
|
||||
|
||||
func (bigEndian) Uint24(b []byte) uint32 {
|
||||
_ = b[2] // bounds check hint to compiler; see golang.org/issue/14808
|
||||
return uint32(b[2]) | uint32(b[1])<<8 | uint32(b[0])<<16
|
||||
}
|
||||
|
||||
func (bigEndian) Uint16(b []byte) uint16 {
|
||||
return binary.BigEndian.Uint16(b)
|
||||
}
|
||||
|
||||
// WriteUint32 writes a uint32
|
||||
func (bigEndian) WriteUint32(b *bytes.Buffer, i uint32) {
|
||||
b.Write([]byte{uint8(i >> 24), uint8(i >> 16), uint8(i >> 8), uint8(i)})
|
||||
|
32
vendor/github.com/lucas-clemente/quic-go/internal/wire/ack_frame.go
generated
vendored
32
vendor/github.com/lucas-clemente/quic-go/internal/wire/ack_frame.go
generated
vendored
@ -29,7 +29,7 @@ func parseAckFrame(r *bytes.Reader, ackDelayExponent uint8, _ protocol.VersionNu
|
||||
}
|
||||
ecn := typeByte&0x1 > 0
|
||||
|
||||
frame := &AckFrame{}
|
||||
frame := GetAckFrame()
|
||||
|
||||
la, err := quicvarint.Read(r)
|
||||
if err != nil {
|
||||
@ -106,41 +106,41 @@ func parseAckFrame(r *bytes.Reader, ackDelayExponent uint8, _ protocol.VersionNu
|
||||
return frame, nil
|
||||
}
|
||||
|
||||
// Write writes an ACK frame.
|
||||
func (f *AckFrame) Write(b *bytes.Buffer, _ protocol.VersionNumber) error {
|
||||
// Append appends an ACK frame.
|
||||
func (f *AckFrame) Append(b []byte, _ protocol.VersionNumber) ([]byte, error) {
|
||||
hasECN := f.ECT0 > 0 || f.ECT1 > 0 || f.ECNCE > 0
|
||||
if hasECN {
|
||||
b.WriteByte(0x3)
|
||||
b = append(b, 0b11)
|
||||
} else {
|
||||
b.WriteByte(0x2)
|
||||
b = append(b, 0b10)
|
||||
}
|
||||
quicvarint.Write(b, uint64(f.LargestAcked()))
|
||||
quicvarint.Write(b, encodeAckDelay(f.DelayTime))
|
||||
b = quicvarint.Append(b, uint64(f.LargestAcked()))
|
||||
b = quicvarint.Append(b, encodeAckDelay(f.DelayTime))
|
||||
|
||||
numRanges := f.numEncodableAckRanges()
|
||||
quicvarint.Write(b, uint64(numRanges-1))
|
||||
b = quicvarint.Append(b, uint64(numRanges-1))
|
||||
|
||||
// write the first range
|
||||
_, firstRange := f.encodeAckRange(0)
|
||||
quicvarint.Write(b, firstRange)
|
||||
b = quicvarint.Append(b, firstRange)
|
||||
|
||||
// write all the other range
|
||||
for i := 1; i < numRanges; i++ {
|
||||
gap, len := f.encodeAckRange(i)
|
||||
quicvarint.Write(b, gap)
|
||||
quicvarint.Write(b, len)
|
||||
b = quicvarint.Append(b, gap)
|
||||
b = quicvarint.Append(b, len)
|
||||
}
|
||||
|
||||
if hasECN {
|
||||
quicvarint.Write(b, f.ECT0)
|
||||
quicvarint.Write(b, f.ECT1)
|
||||
quicvarint.Write(b, f.ECNCE)
|
||||
b = quicvarint.Append(b, f.ECT0)
|
||||
b = quicvarint.Append(b, f.ECT1)
|
||||
b = quicvarint.Append(b, f.ECNCE)
|
||||
}
|
||||
return nil
|
||||
return b, nil
|
||||
}
|
||||
|
||||
// Length of a written frame
|
||||
func (f *AckFrame) Length(version protocol.VersionNumber) protocol.ByteCount {
|
||||
func (f *AckFrame) Length(_ protocol.VersionNumber) protocol.ByteCount {
|
||||
largestAcked := f.AckRanges[0].Largest
|
||||
numRanges := f.numEncodableAckRanges()
|
||||
|
||||
|
24
vendor/github.com/lucas-clemente/quic-go/internal/wire/ack_frame_pool.go
generated
vendored
Normal file
24
vendor/github.com/lucas-clemente/quic-go/internal/wire/ack_frame_pool.go
generated
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
package wire
|
||||
|
||||
import "sync"
|
||||
|
||||
var ackFramePool = sync.Pool{New: func() any {
|
||||
return &AckFrame{}
|
||||
}}
|
||||
|
||||
func GetAckFrame() *AckFrame {
|
||||
f := ackFramePool.Get().(*AckFrame)
|
||||
f.AckRanges = f.AckRanges[:0]
|
||||
f.ECNCE = 0
|
||||
f.ECT0 = 0
|
||||
f.ECT1 = 0
|
||||
f.DelayTime = 0
|
||||
return f
|
||||
}
|
||||
|
||||
func PutAckFrame(f *AckFrame) {
|
||||
if cap(f.AckRanges) > 4 {
|
||||
return
|
||||
}
|
||||
ackFramePool.Put(f)
|
||||
}
|
16
vendor/github.com/lucas-clemente/quic-go/internal/wire/connection_close_frame.go
generated
vendored
16
vendor/github.com/lucas-clemente/quic-go/internal/wire/connection_close_frame.go
generated
vendored
@ -66,18 +66,18 @@ func (f *ConnectionCloseFrame) Length(protocol.VersionNumber) protocol.ByteCount
|
||||
return length
|
||||
}
|
||||
|
||||
func (f *ConnectionCloseFrame) Write(b *bytes.Buffer, version protocol.VersionNumber) error {
|
||||
func (f *ConnectionCloseFrame) Append(b []byte, _ protocol.VersionNumber) ([]byte, error) {
|
||||
if f.IsApplicationError {
|
||||
b.WriteByte(0x1d)
|
||||
b = append(b, 0x1d)
|
||||
} else {
|
||||
b.WriteByte(0x1c)
|
||||
b = append(b, 0x1c)
|
||||
}
|
||||
|
||||
quicvarint.Write(b, f.ErrorCode)
|
||||
b = quicvarint.Append(b, f.ErrorCode)
|
||||
if !f.IsApplicationError {
|
||||
quicvarint.Write(b, f.FrameType)
|
||||
b = quicvarint.Append(b, f.FrameType)
|
||||
}
|
||||
quicvarint.Write(b, uint64(len(f.ReasonPhrase)))
|
||||
b.WriteString(f.ReasonPhrase)
|
||||
return nil
|
||||
b = quicvarint.Append(b, uint64(len(f.ReasonPhrase)))
|
||||
b = append(b, []byte(f.ReasonPhrase)...)
|
||||
return b, nil
|
||||
}
|
||||
|
12
vendor/github.com/lucas-clemente/quic-go/internal/wire/crypto_frame.go
generated
vendored
12
vendor/github.com/lucas-clemente/quic-go/internal/wire/crypto_frame.go
generated
vendored
@ -42,12 +42,12 @@ func parseCryptoFrame(r *bytes.Reader, _ protocol.VersionNumber) (*CryptoFrame,
|
||||
return frame, nil
|
||||
}
|
||||
|
||||
func (f *CryptoFrame) Write(b *bytes.Buffer, _ protocol.VersionNumber) error {
|
||||
b.WriteByte(0x6)
|
||||
quicvarint.Write(b, uint64(f.Offset))
|
||||
quicvarint.Write(b, uint64(len(f.Data)))
|
||||
b.Write(f.Data)
|
||||
return nil
|
||||
func (f *CryptoFrame) Append(b []byte, _ protocol.VersionNumber) ([]byte, error) {
|
||||
b = append(b, 0x6)
|
||||
b = quicvarint.Append(b, uint64(f.Offset))
|
||||
b = quicvarint.Append(b, uint64(len(f.Data)))
|
||||
b = append(b, f.Data...)
|
||||
return b, nil
|
||||
}
|
||||
|
||||
// Length of a written frame
|
||||
|
9
vendor/github.com/lucas-clemente/quic-go/internal/wire/data_blocked_frame.go
generated
vendored
9
vendor/github.com/lucas-clemente/quic-go/internal/wire/data_blocked_frame.go
generated
vendored
@ -25,11 +25,10 @@ func parseDataBlockedFrame(r *bytes.Reader, _ protocol.VersionNumber) (*DataBloc
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (f *DataBlockedFrame) Write(b *bytes.Buffer, version protocol.VersionNumber) error {
|
||||
typeByte := uint8(0x14)
|
||||
b.WriteByte(typeByte)
|
||||
quicvarint.Write(b, uint64(f.MaximumData))
|
||||
return nil
|
||||
func (f *DataBlockedFrame) Append(b []byte, version protocol.VersionNumber) ([]byte, error) {
|
||||
b = append(b, 0x14)
|
||||
b = quicvarint.Append(b, uint64(f.MaximumData))
|
||||
return b, nil
|
||||
}
|
||||
|
||||
// Length of a written frame
|
||||
|
12
vendor/github.com/lucas-clemente/quic-go/internal/wire/datagram_frame.go
generated
vendored
12
vendor/github.com/lucas-clemente/quic-go/internal/wire/datagram_frame.go
generated
vendored
@ -44,17 +44,17 @@ func parseDatagramFrame(r *bytes.Reader, _ protocol.VersionNumber) (*DatagramFra
|
||||
return f, nil
|
||||
}
|
||||
|
||||
func (f *DatagramFrame) Write(b *bytes.Buffer, _ protocol.VersionNumber) error {
|
||||
func (f *DatagramFrame) Append(b []byte, _ protocol.VersionNumber) ([]byte, error) {
|
||||
typeByte := uint8(0x30)
|
||||
if f.DataLenPresent {
|
||||
typeByte ^= 0x1
|
||||
typeByte ^= 0b1
|
||||
}
|
||||
b.WriteByte(typeByte)
|
||||
b = append(b, typeByte)
|
||||
if f.DataLenPresent {
|
||||
quicvarint.Write(b, uint64(len(f.Data)))
|
||||
b = quicvarint.Append(b, uint64(len(f.Data)))
|
||||
}
|
||||
b.Write(f.Data)
|
||||
return nil
|
||||
b = append(b, f.Data...)
|
||||
return b, nil
|
||||
}
|
||||
|
||||
// MaxDataLen returns the maximum data length
|
||||
|
16
vendor/github.com/lucas-clemente/quic-go/internal/wire/frame_parser.go
generated
vendored
16
vendor/github.com/lucas-clemente/quic-go/internal/wire/frame_parser.go
generated
vendored
@ -11,6 +11,8 @@
|
||||
)
|
||||
|
||||
type frameParser struct {
|
||||
r bytes.Reader // cached bytes.Reader, so we don't have to repeatedly allocate them
|
||||
|
||||
ackDelayExponent uint8
|
||||
|
||||
supportsDatagrams bool
|
||||
@ -21,6 +23,7 @@ type frameParser struct {
|
||||
// NewFrameParser creates a new frame parser.
|
||||
func NewFrameParser(supportsDatagrams bool, v protocol.VersionNumber) FrameParser {
|
||||
return &frameParser{
|
||||
r: *bytes.NewReader(nil),
|
||||
supportsDatagrams: supportsDatagrams,
|
||||
version: v,
|
||||
}
|
||||
@ -28,9 +31,18 @@ func NewFrameParser(supportsDatagrams bool, v protocol.VersionNumber) FrameParse
|
||||
|
||||
// ParseNext parses the next frame.
|
||||
// It skips PADDING frames.
|
||||
func (p *frameParser) ParseNext(r *bytes.Reader, encLevel protocol.EncryptionLevel) (Frame, error) {
|
||||
func (p *frameParser) ParseNext(data []byte, encLevel protocol.EncryptionLevel) (int, Frame, error) {
|
||||
startLen := len(data)
|
||||
p.r.Reset(data)
|
||||
frame, err := p.parseNext(&p.r, encLevel)
|
||||
n := startLen - p.r.Len()
|
||||
p.r.Reset(nil)
|
||||
return n, frame, err
|
||||
}
|
||||
|
||||
func (p *frameParser) parseNext(r *bytes.Reader, encLevel protocol.EncryptionLevel) (Frame, error) {
|
||||
for r.Len() != 0 {
|
||||
typeByte, _ := r.ReadByte()
|
||||
typeByte, _ := p.r.ReadByte()
|
||||
if typeByte == 0x0 { // PADDING frame
|
||||
continue
|
||||
}
|
||||
|
5
vendor/github.com/lucas-clemente/quic-go/internal/wire/handshake_done_frame.go
generated
vendored
5
vendor/github.com/lucas-clemente/quic-go/internal/wire/handshake_done_frame.go
generated
vendored
@ -17,9 +17,8 @@ func parseHandshakeDoneFrame(r *bytes.Reader, _ protocol.VersionNumber) (*Handsh
|
||||
return &HandshakeDoneFrame{}, nil
|
||||
}
|
||||
|
||||
func (f *HandshakeDoneFrame) Write(b *bytes.Buffer, _ protocol.VersionNumber) error {
|
||||
b.WriteByte(0x1e)
|
||||
return nil
|
||||
func (f *HandshakeDoneFrame) Append(b []byte, _ protocol.VersionNumber) ([]byte, error) {
|
||||
return append(b, 0x1e), nil
|
||||
}
|
||||
|
||||
// Length of a written frame
|
||||
|
64
vendor/github.com/lucas-clemente/quic-go/internal/wire/header.go
generated
vendored
64
vendor/github.com/lucas-clemente/quic-go/internal/wire/header.go
generated
vendored
@ -17,22 +17,63 @@
|
||||
// That means that the connection ID must not be used after the packet buffer is released.
|
||||
func ParseConnectionID(data []byte, shortHeaderConnIDLen int) (protocol.ConnectionID, error) {
|
||||
if len(data) == 0 {
|
||||
return nil, io.EOF
|
||||
return protocol.ConnectionID{}, io.EOF
|
||||
}
|
||||
if !IsLongHeaderPacket(data[0]) {
|
||||
if len(data) < shortHeaderConnIDLen+1 {
|
||||
return nil, io.EOF
|
||||
return protocol.ConnectionID{}, io.EOF
|
||||
}
|
||||
return protocol.ConnectionID(data[1 : 1+shortHeaderConnIDLen]), nil
|
||||
return protocol.ParseConnectionID(data[1 : 1+shortHeaderConnIDLen]), nil
|
||||
}
|
||||
if len(data) < 6 {
|
||||
return nil, io.EOF
|
||||
return protocol.ConnectionID{}, io.EOF
|
||||
}
|
||||
destConnIDLen := int(data[5])
|
||||
if len(data) < 6+destConnIDLen {
|
||||
return nil, io.EOF
|
||||
if destConnIDLen > protocol.MaxConnIDLen {
|
||||
return protocol.ConnectionID{}, protocol.ErrInvalidConnectionIDLen
|
||||
}
|
||||
return protocol.ConnectionID(data[6 : 6+destConnIDLen]), nil
|
||||
if len(data) < 6+destConnIDLen {
|
||||
return protocol.ConnectionID{}, io.EOF
|
||||
}
|
||||
return protocol.ParseConnectionID(data[6 : 6+destConnIDLen]), nil
|
||||
}
|
||||
|
||||
// ParseArbitraryLenConnectionIDs parses the most general form of a Long Header packet,
|
||||
// using only the version-independent packet format as described in Section 5.1 of RFC 8999:
|
||||
// https://datatracker.ietf.org/doc/html/rfc8999#section-5.1.
|
||||
// This function should only be called on Long Header packets for which we don't support the version.
|
||||
func ParseArbitraryLenConnectionIDs(data []byte) (bytesParsed int, dest, src protocol.ArbitraryLenConnectionID, _ error) {
|
||||
r := bytes.NewReader(data)
|
||||
remaining := r.Len()
|
||||
src, dest, err := parseArbitraryLenConnectionIDs(r)
|
||||
return remaining - r.Len(), src, dest, err
|
||||
}
|
||||
|
||||
func parseArbitraryLenConnectionIDs(r *bytes.Reader) (dest, src protocol.ArbitraryLenConnectionID, _ error) {
|
||||
r.Seek(5, io.SeekStart) // skip first byte and version field
|
||||
destConnIDLen, err := r.ReadByte()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
destConnID := make(protocol.ArbitraryLenConnectionID, destConnIDLen)
|
||||
if _, err := io.ReadFull(r, destConnID); err != nil {
|
||||
if err == io.ErrUnexpectedEOF {
|
||||
err = io.EOF
|
||||
}
|
||||
return nil, nil, err
|
||||
}
|
||||
srcConnIDLen, err := r.ReadByte()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
srcConnID := make(protocol.ArbitraryLenConnectionID, srcConnIDLen)
|
||||
if _, err := io.ReadFull(r, srcConnID); err != nil {
|
||||
if err == io.ErrUnexpectedEOF {
|
||||
err = io.EOF
|
||||
}
|
||||
return nil, nil, err
|
||||
}
|
||||
return destConnID, srcConnID, nil
|
||||
}
|
||||
|
||||
// IsLongHeaderPacket says if this is a Long Header packet
|
||||
@ -40,6 +81,15 @@ func IsLongHeaderPacket(firstByte byte) bool {
|
||||
return firstByte&0x80 > 0
|
||||
}
|
||||
|
||||
// ParseVersion parses the QUIC version.
|
||||
// It should only be called for Long Header packets (Short Header packets don't contain a version number).
|
||||
func ParseVersion(data []byte) (protocol.VersionNumber, error) {
|
||||
if len(data) < 5 {
|
||||
return 0, io.EOF
|
||||
}
|
||||
return protocol.VersionNumber(binary.BigEndian.Uint32(data[1:5])), nil
|
||||
}
|
||||
|
||||
// IsVersionNegotiationPacket says if this is a version negotiation packet
|
||||
func IsVersionNegotiationPacket(b []byte) bool {
|
||||
if len(b) < 5 {
|
||||
|
6
vendor/github.com/lucas-clemente/quic-go/internal/wire/interface.go
generated
vendored
6
vendor/github.com/lucas-clemente/quic-go/internal/wire/interface.go
generated
vendored
@ -1,19 +1,17 @@
|
||||
package wire
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
|
||||
"github.com/lucas-clemente/quic-go/internal/protocol"
|
||||
)
|
||||
|
||||
// A Frame in QUIC
|
||||
type Frame interface {
|
||||
Write(b *bytes.Buffer, version protocol.VersionNumber) error
|
||||
Append(b []byte, version protocol.VersionNumber) ([]byte, error)
|
||||
Length(version protocol.VersionNumber) protocol.ByteCount
|
||||
}
|
||||
|
||||
// A FrameParser parses QUIC frames, one by one.
|
||||
type FrameParser interface {
|
||||
ParseNext(*bytes.Reader, protocol.EncryptionLevel) (Frame, error)
|
||||
ParseNext([]byte, protocol.EncryptionLevel) (int, Frame, error)
|
||||
SetAckDelayExponent(uint8)
|
||||
}
|
||||
|
10
vendor/github.com/lucas-clemente/quic-go/internal/wire/max_data_frame.go
generated
vendored
10
vendor/github.com/lucas-clemente/quic-go/internal/wire/max_data_frame.go
generated
vendored
@ -28,13 +28,13 @@ func parseMaxDataFrame(r *bytes.Reader, _ protocol.VersionNumber) (*MaxDataFrame
|
||||
}
|
||||
|
||||
// Write writes a MAX_STREAM_DATA frame
|
||||
func (f *MaxDataFrame) Write(b *bytes.Buffer, version protocol.VersionNumber) error {
|
||||
b.WriteByte(0x10)
|
||||
quicvarint.Write(b, uint64(f.MaximumData))
|
||||
return nil
|
||||
func (f *MaxDataFrame) Append(b []byte, _ protocol.VersionNumber) ([]byte, error) {
|
||||
b = append(b, 0x10)
|
||||
b = quicvarint.Append(b, uint64(f.MaximumData))
|
||||
return b, nil
|
||||
}
|
||||
|
||||
// Length of a written frame
|
||||
func (f *MaxDataFrame) Length(version protocol.VersionNumber) protocol.ByteCount {
|
||||
func (f *MaxDataFrame) Length(_ protocol.VersionNumber) protocol.ByteCount {
|
||||
return 1 + quicvarint.Len(uint64(f.MaximumData))
|
||||
}
|
||||
|
10
vendor/github.com/lucas-clemente/quic-go/internal/wire/max_stream_data_frame.go
generated
vendored
10
vendor/github.com/lucas-clemente/quic-go/internal/wire/max_stream_data_frame.go
generated
vendored
@ -33,11 +33,11 @@ func parseMaxStreamDataFrame(r *bytes.Reader, _ protocol.VersionNumber) (*MaxStr
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (f *MaxStreamDataFrame) Write(b *bytes.Buffer, version protocol.VersionNumber) error {
|
||||
b.WriteByte(0x11)
|
||||
quicvarint.Write(b, uint64(f.StreamID))
|
||||
quicvarint.Write(b, uint64(f.MaximumStreamData))
|
||||
return nil
|
||||
func (f *MaxStreamDataFrame) Append(b []byte, version protocol.VersionNumber) ([]byte, error) {
|
||||
b = append(b, 0x11)
|
||||
b = quicvarint.Append(b, uint64(f.StreamID))
|
||||
b = quicvarint.Append(b, uint64(f.MaximumStreamData))
|
||||
return b, nil
|
||||
}
|
||||
|
||||
// Length of a written frame
|
||||
|
10
vendor/github.com/lucas-clemente/quic-go/internal/wire/max_streams_frame.go
generated
vendored
10
vendor/github.com/lucas-clemente/quic-go/internal/wire/max_streams_frame.go
generated
vendored
@ -38,15 +38,15 @@ func parseMaxStreamsFrame(r *bytes.Reader, _ protocol.VersionNumber) (*MaxStream
|
||||
return f, nil
|
||||
}
|
||||
|
||||
func (f *MaxStreamsFrame) Write(b *bytes.Buffer, _ protocol.VersionNumber) error {
|
||||
func (f *MaxStreamsFrame) Append(b []byte, _ protocol.VersionNumber) ([]byte, error) {
|
||||
switch f.Type {
|
||||
case protocol.StreamTypeBidi:
|
||||
b.WriteByte(0x12)
|
||||
b = append(b, 0x12)
|
||||
case protocol.StreamTypeUni:
|
||||
b.WriteByte(0x13)
|
||||
b = append(b, 0x13)
|
||||
}
|
||||
quicvarint.Write(b, uint64(f.MaxStreamNum))
|
||||
return nil
|
||||
b = quicvarint.Append(b, uint64(f.MaxStreamNum))
|
||||
return b, nil
|
||||
}
|
||||
|
||||
// Length of a written frame
|
||||
|
21
vendor/github.com/lucas-clemente/quic-go/internal/wire/new_connection_id_frame.go
generated
vendored
21
vendor/github.com/lucas-clemente/quic-go/internal/wire/new_connection_id_frame.go
generated
vendored
@ -38,9 +38,6 @@ func parseNewConnectionIDFrame(r *bytes.Reader, _ protocol.VersionNumber) (*NewC
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if connIDLen > protocol.MaxConnIDLen {
|
||||
return nil, fmt.Errorf("invalid connection ID length: %d", connIDLen)
|
||||
}
|
||||
connID, err := protocol.ReadConnectionID(r, int(connIDLen))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -60,18 +57,18 @@ func parseNewConnectionIDFrame(r *bytes.Reader, _ protocol.VersionNumber) (*NewC
|
||||
return frame, nil
|
||||
}
|
||||
|
||||
func (f *NewConnectionIDFrame) Write(b *bytes.Buffer, _ protocol.VersionNumber) error {
|
||||
b.WriteByte(0x18)
|
||||
quicvarint.Write(b, f.SequenceNumber)
|
||||
quicvarint.Write(b, f.RetirePriorTo)
|
||||
func (f *NewConnectionIDFrame) Append(b []byte, _ protocol.VersionNumber) ([]byte, error) {
|
||||
b = append(b, 0x18)
|
||||
b = quicvarint.Append(b, f.SequenceNumber)
|
||||
b = quicvarint.Append(b, f.RetirePriorTo)
|
||||
connIDLen := f.ConnectionID.Len()
|
||||
if connIDLen > protocol.MaxConnIDLen {
|
||||
return fmt.Errorf("invalid connection ID length: %d", connIDLen)
|
||||
return nil, fmt.Errorf("invalid connection ID length: %d", connIDLen)
|
||||
}
|
||||
b.WriteByte(uint8(connIDLen))
|
||||
b.Write(f.ConnectionID.Bytes())
|
||||
b.Write(f.StatelessResetToken[:])
|
||||
return nil
|
||||
b = append(b, uint8(connIDLen))
|
||||
b = append(b, f.ConnectionID.Bytes()...)
|
||||
b = append(b, f.StatelessResetToken[:]...)
|
||||
return b, nil
|
||||
}
|
||||
|
||||
// Length of a written frame
|
||||
|
10
vendor/github.com/lucas-clemente/quic-go/internal/wire/new_token_frame.go
generated
vendored
10
vendor/github.com/lucas-clemente/quic-go/internal/wire/new_token_frame.go
generated
vendored
@ -35,11 +35,11 @@ func parseNewTokenFrame(r *bytes.Reader, _ protocol.VersionNumber) (*NewTokenFra
|
||||
return &NewTokenFrame{Token: token}, nil
|
||||
}
|
||||
|
||||
func (f *NewTokenFrame) Write(b *bytes.Buffer, _ protocol.VersionNumber) error {
|
||||
b.WriteByte(0x7)
|
||||
quicvarint.Write(b, uint64(len(f.Token)))
|
||||
b.Write(f.Token)
|
||||
return nil
|
||||
func (f *NewTokenFrame) Append(b []byte, _ protocol.VersionNumber) ([]byte, error) {
|
||||
b = append(b, 0x7)
|
||||
b = quicvarint.Append(b, uint64(len(f.Token)))
|
||||
b = append(b, f.Token...)
|
||||
return b, nil
|
||||
}
|
||||
|
||||
// Length of a written frame
|
||||
|
8
vendor/github.com/lucas-clemente/quic-go/internal/wire/path_challenge_frame.go
generated
vendored
8
vendor/github.com/lucas-clemente/quic-go/internal/wire/path_challenge_frame.go
generated
vendored
@ -26,10 +26,10 @@ func parsePathChallengeFrame(r *bytes.Reader, _ protocol.VersionNumber) (*PathCh
|
||||
return frame, nil
|
||||
}
|
||||
|
||||
func (f *PathChallengeFrame) Write(b *bytes.Buffer, _ protocol.VersionNumber) error {
|
||||
b.WriteByte(0x1a)
|
||||
b.Write(f.Data[:])
|
||||
return nil
|
||||
func (f *PathChallengeFrame) Append(b []byte, _ protocol.VersionNumber) ([]byte, error) {
|
||||
b = append(b, 0x1a)
|
||||
b = append(b, f.Data[:]...)
|
||||
return b, nil
|
||||
}
|
||||
|
||||
// Length of a written frame
|
||||
|
8
vendor/github.com/lucas-clemente/quic-go/internal/wire/path_response_frame.go
generated
vendored
8
vendor/github.com/lucas-clemente/quic-go/internal/wire/path_response_frame.go
generated
vendored
@ -26,10 +26,10 @@ func parsePathResponseFrame(r *bytes.Reader, _ protocol.VersionNumber) (*PathRes
|
||||
return frame, nil
|
||||
}
|
||||
|
||||
func (f *PathResponseFrame) Write(b *bytes.Buffer, _ protocol.VersionNumber) error {
|
||||
b.WriteByte(0x1b)
|
||||
b.Write(f.Data[:])
|
||||
return nil
|
||||
func (f *PathResponseFrame) Append(b []byte, _ protocol.VersionNumber) ([]byte, error) {
|
||||
b = append(b, 0x1b)
|
||||
b = append(b, f.Data[:]...)
|
||||
return b, nil
|
||||
}
|
||||
|
||||
// Length of a written frame
|
||||
|
7
vendor/github.com/lucas-clemente/quic-go/internal/wire/ping_frame.go
generated
vendored
7
vendor/github.com/lucas-clemente/quic-go/internal/wire/ping_frame.go
generated
vendored
@ -16,12 +16,11 @@ func parsePingFrame(r *bytes.Reader, _ protocol.VersionNumber) (*PingFrame, erro
|
||||
return &PingFrame{}, nil
|
||||
}
|
||||
|
||||
func (f *PingFrame) Write(b *bytes.Buffer, version protocol.VersionNumber) error {
|
||||
b.WriteByte(0x1)
|
||||
return nil
|
||||
func (f *PingFrame) Append(b []byte, _ protocol.VersionNumber) ([]byte, error) {
|
||||
return append(b, 0x1), nil
|
||||
}
|
||||
|
||||
// Length of a written frame
|
||||
func (f *PingFrame) Length(version protocol.VersionNumber) protocol.ByteCount {
|
||||
func (f *PingFrame) Length(_ protocol.VersionNumber) protocol.ByteCount {
|
||||
return 1
|
||||
}
|
||||
|
12
vendor/github.com/lucas-clemente/quic-go/internal/wire/reset_stream_frame.go
generated
vendored
12
vendor/github.com/lucas-clemente/quic-go/internal/wire/reset_stream_frame.go
generated
vendored
@ -44,12 +44,12 @@ func parseResetStreamFrame(r *bytes.Reader, _ protocol.VersionNumber) (*ResetStr
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (f *ResetStreamFrame) Write(b *bytes.Buffer, _ protocol.VersionNumber) error {
|
||||
b.WriteByte(0x4)
|
||||
quicvarint.Write(b, uint64(f.StreamID))
|
||||
quicvarint.Write(b, uint64(f.ErrorCode))
|
||||
quicvarint.Write(b, uint64(f.FinalSize))
|
||||
return nil
|
||||
func (f *ResetStreamFrame) Append(b []byte, _ protocol.VersionNumber) ([]byte, error) {
|
||||
b = append(b, 0x4)
|
||||
b = quicvarint.Append(b, uint64(f.StreamID))
|
||||
b = quicvarint.Append(b, uint64(f.ErrorCode))
|
||||
b = quicvarint.Append(b, uint64(f.FinalSize))
|
||||
return b, nil
|
||||
}
|
||||
|
||||
// Length of a written frame
|
||||
|
8
vendor/github.com/lucas-clemente/quic-go/internal/wire/retire_connection_id_frame.go
generated
vendored
8
vendor/github.com/lucas-clemente/quic-go/internal/wire/retire_connection_id_frame.go
generated
vendored
@ -24,10 +24,10 @@ func parseRetireConnectionIDFrame(r *bytes.Reader, _ protocol.VersionNumber) (*R
|
||||
return &RetireConnectionIDFrame{SequenceNumber: seq}, nil
|
||||
}
|
||||
|
||||
func (f *RetireConnectionIDFrame) Write(b *bytes.Buffer, _ protocol.VersionNumber) error {
|
||||
b.WriteByte(0x19)
|
||||
quicvarint.Write(b, f.SequenceNumber)
|
||||
return nil
|
||||
func (f *RetireConnectionIDFrame) Append(b []byte, _ protocol.VersionNumber) ([]byte, error) {
|
||||
b = append(b, 0x19)
|
||||
b = quicvarint.Append(b, f.SequenceNumber)
|
||||
return b, nil
|
||||
}
|
||||
|
||||
// Length of a written frame
|
||||
|
55
vendor/github.com/lucas-clemente/quic-go/internal/wire/short_header.go
generated
vendored
Normal file
55
vendor/github.com/lucas-clemente/quic-go/internal/wire/short_header.go
generated
vendored
Normal file
@ -0,0 +1,55 @@
|
||||
package wire
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/lucas-clemente/quic-go/internal/protocol"
|
||||
"github.com/lucas-clemente/quic-go/internal/utils"
|
||||
)
|
||||
|
||||
func ParseShortHeader(data []byte, connIDLen int) (length int, _ protocol.PacketNumber, _ protocol.PacketNumberLen, _ protocol.KeyPhaseBit, _ error) {
|
||||
if len(data) == 0 {
|
||||
return 0, 0, 0, 0, io.EOF
|
||||
}
|
||||
if data[0]&0x80 > 0 {
|
||||
return 0, 0, 0, 0, errors.New("not a short header packet")
|
||||
}
|
||||
if data[0]&0x40 == 0 {
|
||||
return 0, 0, 0, 0, errors.New("not a QUIC packet")
|
||||
}
|
||||
pnLen := protocol.PacketNumberLen(data[0]&0b11) + 1
|
||||
if len(data) < 1+int(pnLen)+connIDLen {
|
||||
return 0, 0, 0, 0, io.EOF
|
||||
}
|
||||
|
||||
pos := 1 + connIDLen
|
||||
var pn protocol.PacketNumber
|
||||
switch pnLen {
|
||||
case protocol.PacketNumberLen1:
|
||||
pn = protocol.PacketNumber(data[pos])
|
||||
case protocol.PacketNumberLen2:
|
||||
pn = protocol.PacketNumber(utils.BigEndian.Uint16(data[pos : pos+2]))
|
||||
case protocol.PacketNumberLen3:
|
||||
pn = protocol.PacketNumber(utils.BigEndian.Uint24(data[pos : pos+3]))
|
||||
case protocol.PacketNumberLen4:
|
||||
pn = protocol.PacketNumber(utils.BigEndian.Uint32(data[pos : pos+4]))
|
||||
default:
|
||||
return 0, 0, 0, 0, fmt.Errorf("invalid packet number length: %d", pnLen)
|
||||
}
|
||||
kp := protocol.KeyPhaseZero
|
||||
if data[0]&0b100 > 0 {
|
||||
kp = protocol.KeyPhaseOne
|
||||
}
|
||||
|
||||
var err error
|
||||
if data[0]&0x18 != 0 {
|
||||
err = ErrInvalidReservedBits
|
||||
}
|
||||
return 1 + connIDLen + int(pnLen), pn, pnLen, kp, err
|
||||
}
|
||||
|
||||
func LogShortHeader(logger utils.Logger, dest protocol.ConnectionID, pn protocol.PacketNumber, pnLen protocol.PacketNumberLen, kp protocol.KeyPhaseBit) {
|
||||
logger.Debugf("\tShort Header{DestConnectionID: %s, PacketNumber: %d, PacketNumberLen: %d, KeyPhase: %s}", dest, pn, pnLen, kp)
|
||||
}
|
10
vendor/github.com/lucas-clemente/quic-go/internal/wire/stop_sending_frame.go
generated
vendored
10
vendor/github.com/lucas-clemente/quic-go/internal/wire/stop_sending_frame.go
generated
vendored
@ -40,9 +40,9 @@ func (f *StopSendingFrame) Length(_ protocol.VersionNumber) protocol.ByteCount {
|
||||
return 1 + quicvarint.Len(uint64(f.StreamID)) + quicvarint.Len(uint64(f.ErrorCode))
|
||||
}
|
||||
|
||||
func (f *StopSendingFrame) Write(b *bytes.Buffer, _ protocol.VersionNumber) error {
|
||||
b.WriteByte(0x5)
|
||||
quicvarint.Write(b, uint64(f.StreamID))
|
||||
quicvarint.Write(b, uint64(f.ErrorCode))
|
||||
return nil
|
||||
func (f *StopSendingFrame) Append(b []byte, _ protocol.VersionNumber) ([]byte, error) {
|
||||
b = append(b, 0x5)
|
||||
b = quicvarint.Append(b, uint64(f.StreamID))
|
||||
b = quicvarint.Append(b, uint64(f.ErrorCode))
|
||||
return b, nil
|
||||
}
|
||||
|
10
vendor/github.com/lucas-clemente/quic-go/internal/wire/stream_data_blocked_frame.go
generated
vendored
10
vendor/github.com/lucas-clemente/quic-go/internal/wire/stream_data_blocked_frame.go
generated
vendored
@ -33,11 +33,11 @@ func parseStreamDataBlockedFrame(r *bytes.Reader, _ protocol.VersionNumber) (*St
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (f *StreamDataBlockedFrame) Write(b *bytes.Buffer, version protocol.VersionNumber) error {
|
||||
b.WriteByte(0x15)
|
||||
quicvarint.Write(b, uint64(f.StreamID))
|
||||
quicvarint.Write(b, uint64(f.MaximumStreamData))
|
||||
return nil
|
||||
func (f *StreamDataBlockedFrame) Append(b []byte, _ protocol.VersionNumber) ([]byte, error) {
|
||||
b = append(b, 0x15)
|
||||
b = quicvarint.Append(b, uint64(f.StreamID))
|
||||
b = quicvarint.Append(b, uint64(f.MaximumStreamData))
|
||||
return b, nil
|
||||
}
|
||||
|
||||
// Length of a written frame
|
||||
|
28
vendor/github.com/lucas-clemente/quic-go/internal/wire/stream_frame.go
generated
vendored
28
vendor/github.com/lucas-clemente/quic-go/internal/wire/stream_frame.go
generated
vendored
@ -26,9 +26,9 @@ func parseStreamFrame(r *bytes.Reader, _ protocol.VersionNumber) (*StreamFrame,
|
||||
return nil, err
|
||||
}
|
||||
|
||||
hasOffset := typeByte&0x4 > 0
|
||||
fin := typeByte&0x1 > 0
|
||||
hasDataLen := typeByte&0x2 > 0
|
||||
hasOffset := typeByte&0b100 > 0
|
||||
fin := typeByte&0b1 > 0
|
||||
hasDataLen := typeByte&0b10 > 0
|
||||
|
||||
streamID, err := quicvarint.Read(r)
|
||||
if err != nil {
|
||||
@ -84,32 +84,32 @@ func parseStreamFrame(r *bytes.Reader, _ protocol.VersionNumber) (*StreamFrame,
|
||||
}
|
||||
|
||||
// Write writes a STREAM frame
|
||||
func (f *StreamFrame) Write(b *bytes.Buffer, version protocol.VersionNumber) error {
|
||||
func (f *StreamFrame) Append(b []byte, _ protocol.VersionNumber) ([]byte, error) {
|
||||
if len(f.Data) == 0 && !f.Fin {
|
||||
return errors.New("StreamFrame: attempting to write empty frame without FIN")
|
||||
return nil, errors.New("StreamFrame: attempting to write empty frame without FIN")
|
||||
}
|
||||
|
||||
typeByte := byte(0x8)
|
||||
if f.Fin {
|
||||
typeByte ^= 0x1
|
||||
typeByte ^= 0b1
|
||||
}
|
||||
hasOffset := f.Offset != 0
|
||||
if f.DataLenPresent {
|
||||
typeByte ^= 0x2
|
||||
typeByte ^= 0b10
|
||||
}
|
||||
if hasOffset {
|
||||
typeByte ^= 0x4
|
||||
typeByte ^= 0b100
|
||||
}
|
||||
b.WriteByte(typeByte)
|
||||
quicvarint.Write(b, uint64(f.StreamID))
|
||||
b = append(b, typeByte)
|
||||
b = quicvarint.Append(b, uint64(f.StreamID))
|
||||
if hasOffset {
|
||||
quicvarint.Write(b, uint64(f.Offset))
|
||||
b = quicvarint.Append(b, uint64(f.Offset))
|
||||
}
|
||||
if f.DataLenPresent {
|
||||
quicvarint.Write(b, uint64(f.DataLen()))
|
||||
b = quicvarint.Append(b, uint64(f.DataLen()))
|
||||
}
|
||||
b.Write(f.Data)
|
||||
return nil
|
||||
b = append(b, f.Data...)
|
||||
return b, nil
|
||||
}
|
||||
|
||||
// Length returns the total length of the STREAM frame
|
||||
|
10
vendor/github.com/lucas-clemente/quic-go/internal/wire/streams_blocked_frame.go
generated
vendored
10
vendor/github.com/lucas-clemente/quic-go/internal/wire/streams_blocked_frame.go
generated
vendored
@ -38,15 +38,15 @@ func parseStreamsBlockedFrame(r *bytes.Reader, _ protocol.VersionNumber) (*Strea
|
||||
return f, nil
|
||||
}
|
||||
|
||||
func (f *StreamsBlockedFrame) Write(b *bytes.Buffer, _ protocol.VersionNumber) error {
|
||||
func (f *StreamsBlockedFrame) Append(b []byte, _ protocol.VersionNumber) ([]byte, error) {
|
||||
switch f.Type {
|
||||
case protocol.StreamTypeBidi:
|
||||
b.WriteByte(0x16)
|
||||
b = append(b, 0x16)
|
||||
case protocol.StreamTypeUni:
|
||||
b.WriteByte(0x17)
|
||||
b = append(b, 0x17)
|
||||
}
|
||||
quicvarint.Write(b, uint64(f.StreamLimit))
|
||||
return nil
|
||||
b = quicvarint.Append(b, uint64(f.StreamLimit))
|
||||
return b, nil
|
||||
}
|
||||
|
||||
// Length of a written frame
|
||||
|
115
vendor/github.com/lucas-clemente/quic-go/internal/wire/transport_parameters.go
generated
vendored
115
vendor/github.com/lucas-clemente/quic-go/internal/wire/transport_parameters.go
generated
vendored
@ -2,6 +2,7 @@
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
@ -313,94 +314,98 @@ func (p *TransportParameters) readNumericTransportParameter(
|
||||
|
||||
// Marshal the transport parameters
|
||||
func (p *TransportParameters) Marshal(pers protocol.Perspective) []byte {
|
||||
b := &bytes.Buffer{}
|
||||
// Typical Transport Parameters consume around 110 bytes, depending on the exact values,
|
||||
// especially the lengths of the Connection IDs.
|
||||
// Allocate 256 bytes, so we won't have to grow the slice in any case.
|
||||
b := make([]byte, 0, 256)
|
||||
|
||||
// add a greased value
|
||||
quicvarint.Write(b, uint64(27+31*rand.Intn(100)))
|
||||
b = quicvarint.Append(b, uint64(27+31*rand.Intn(100)))
|
||||
length := rand.Intn(16)
|
||||
randomData := make([]byte, length)
|
||||
rand.Read(randomData)
|
||||
quicvarint.Write(b, uint64(length))
|
||||
b.Write(randomData)
|
||||
b = quicvarint.Append(b, uint64(length))
|
||||
b = b[:len(b)+length]
|
||||
rand.Read(b[len(b)-length:])
|
||||
|
||||
// initial_max_stream_data_bidi_local
|
||||
p.marshalVarintParam(b, initialMaxStreamDataBidiLocalParameterID, uint64(p.InitialMaxStreamDataBidiLocal))
|
||||
b = p.marshalVarintParam(b, initialMaxStreamDataBidiLocalParameterID, uint64(p.InitialMaxStreamDataBidiLocal))
|
||||
// initial_max_stream_data_bidi_remote
|
||||
p.marshalVarintParam(b, initialMaxStreamDataBidiRemoteParameterID, uint64(p.InitialMaxStreamDataBidiRemote))
|
||||
b = p.marshalVarintParam(b, initialMaxStreamDataBidiRemoteParameterID, uint64(p.InitialMaxStreamDataBidiRemote))
|
||||
// initial_max_stream_data_uni
|
||||
p.marshalVarintParam(b, initialMaxStreamDataUniParameterID, uint64(p.InitialMaxStreamDataUni))
|
||||
b = p.marshalVarintParam(b, initialMaxStreamDataUniParameterID, uint64(p.InitialMaxStreamDataUni))
|
||||
// initial_max_data
|
||||
p.marshalVarintParam(b, initialMaxDataParameterID, uint64(p.InitialMaxData))
|
||||
b = p.marshalVarintParam(b, initialMaxDataParameterID, uint64(p.InitialMaxData))
|
||||
// initial_max_bidi_streams
|
||||
p.marshalVarintParam(b, initialMaxStreamsBidiParameterID, uint64(p.MaxBidiStreamNum))
|
||||
b = p.marshalVarintParam(b, initialMaxStreamsBidiParameterID, uint64(p.MaxBidiStreamNum))
|
||||
// initial_max_uni_streams
|
||||
p.marshalVarintParam(b, initialMaxStreamsUniParameterID, uint64(p.MaxUniStreamNum))
|
||||
b = p.marshalVarintParam(b, initialMaxStreamsUniParameterID, uint64(p.MaxUniStreamNum))
|
||||
// idle_timeout
|
||||
p.marshalVarintParam(b, maxIdleTimeoutParameterID, uint64(p.MaxIdleTimeout/time.Millisecond))
|
||||
b = p.marshalVarintParam(b, maxIdleTimeoutParameterID, uint64(p.MaxIdleTimeout/time.Millisecond))
|
||||
// max_packet_size
|
||||
p.marshalVarintParam(b, maxUDPPayloadSizeParameterID, uint64(protocol.MaxPacketBufferSize))
|
||||
b = p.marshalVarintParam(b, maxUDPPayloadSizeParameterID, uint64(protocol.MaxPacketBufferSize))
|
||||
// max_ack_delay
|
||||
// Only send it if is different from the default value.
|
||||
if p.MaxAckDelay != protocol.DefaultMaxAckDelay {
|
||||
p.marshalVarintParam(b, maxAckDelayParameterID, uint64(p.MaxAckDelay/time.Millisecond))
|
||||
b = p.marshalVarintParam(b, maxAckDelayParameterID, uint64(p.MaxAckDelay/time.Millisecond))
|
||||
}
|
||||
// ack_delay_exponent
|
||||
// Only send it if is different from the default value.
|
||||
if p.AckDelayExponent != protocol.DefaultAckDelayExponent {
|
||||
p.marshalVarintParam(b, ackDelayExponentParameterID, uint64(p.AckDelayExponent))
|
||||
b = p.marshalVarintParam(b, ackDelayExponentParameterID, uint64(p.AckDelayExponent))
|
||||
}
|
||||
// disable_active_migration
|
||||
if p.DisableActiveMigration {
|
||||
quicvarint.Write(b, uint64(disableActiveMigrationParameterID))
|
||||
quicvarint.Write(b, 0)
|
||||
b = quicvarint.Append(b, uint64(disableActiveMigrationParameterID))
|
||||
b = quicvarint.Append(b, 0)
|
||||
}
|
||||
if pers == protocol.PerspectiveServer {
|
||||
// stateless_reset_token
|
||||
if p.StatelessResetToken != nil {
|
||||
quicvarint.Write(b, uint64(statelessResetTokenParameterID))
|
||||
quicvarint.Write(b, 16)
|
||||
b.Write(p.StatelessResetToken[:])
|
||||
b = quicvarint.Append(b, uint64(statelessResetTokenParameterID))
|
||||
b = quicvarint.Append(b, 16)
|
||||
b = append(b, p.StatelessResetToken[:]...)
|
||||
}
|
||||
// original_destination_connection_id
|
||||
quicvarint.Write(b, uint64(originalDestinationConnectionIDParameterID))
|
||||
quicvarint.Write(b, uint64(p.OriginalDestinationConnectionID.Len()))
|
||||
b.Write(p.OriginalDestinationConnectionID.Bytes())
|
||||
b = quicvarint.Append(b, uint64(originalDestinationConnectionIDParameterID))
|
||||
b = quicvarint.Append(b, uint64(p.OriginalDestinationConnectionID.Len()))
|
||||
b = append(b, p.OriginalDestinationConnectionID.Bytes()...)
|
||||
// preferred_address
|
||||
if p.PreferredAddress != nil {
|
||||
quicvarint.Write(b, uint64(preferredAddressParameterID))
|
||||
quicvarint.Write(b, 4+2+16+2+1+uint64(p.PreferredAddress.ConnectionID.Len())+16)
|
||||
b = quicvarint.Append(b, uint64(preferredAddressParameterID))
|
||||
b = quicvarint.Append(b, 4+2+16+2+1+uint64(p.PreferredAddress.ConnectionID.Len())+16)
|
||||
ipv4 := p.PreferredAddress.IPv4
|
||||
b.Write(ipv4[len(ipv4)-4:])
|
||||
utils.BigEndian.WriteUint16(b, p.PreferredAddress.IPv4Port)
|
||||
b.Write(p.PreferredAddress.IPv6)
|
||||
utils.BigEndian.WriteUint16(b, p.PreferredAddress.IPv6Port)
|
||||
b.WriteByte(uint8(p.PreferredAddress.ConnectionID.Len()))
|
||||
b.Write(p.PreferredAddress.ConnectionID.Bytes())
|
||||
b.Write(p.PreferredAddress.StatelessResetToken[:])
|
||||
b = append(b, ipv4[len(ipv4)-4:]...)
|
||||
b = append(b, []byte{0, 0}...)
|
||||
binary.BigEndian.PutUint16(b[len(b)-2:], p.PreferredAddress.IPv4Port)
|
||||
b = append(b, p.PreferredAddress.IPv6...)
|
||||
b = append(b, []byte{0, 0}...)
|
||||
binary.BigEndian.PutUint16(b[len(b)-2:], p.PreferredAddress.IPv6Port)
|
||||
b = append(b, uint8(p.PreferredAddress.ConnectionID.Len()))
|
||||
b = append(b, p.PreferredAddress.ConnectionID.Bytes()...)
|
||||
b = append(b, p.PreferredAddress.StatelessResetToken[:]...)
|
||||
}
|
||||
}
|
||||
// active_connection_id_limit
|
||||
p.marshalVarintParam(b, activeConnectionIDLimitParameterID, p.ActiveConnectionIDLimit)
|
||||
b = p.marshalVarintParam(b, activeConnectionIDLimitParameterID, p.ActiveConnectionIDLimit)
|
||||
// initial_source_connection_id
|
||||
quicvarint.Write(b, uint64(initialSourceConnectionIDParameterID))
|
||||
quicvarint.Write(b, uint64(p.InitialSourceConnectionID.Len()))
|
||||
b.Write(p.InitialSourceConnectionID.Bytes())
|
||||
b = quicvarint.Append(b, uint64(initialSourceConnectionIDParameterID))
|
||||
b = quicvarint.Append(b, uint64(p.InitialSourceConnectionID.Len()))
|
||||
b = append(b, p.InitialSourceConnectionID.Bytes()...)
|
||||
// retry_source_connection_id
|
||||
if pers == protocol.PerspectiveServer && p.RetrySourceConnectionID != nil {
|
||||
quicvarint.Write(b, uint64(retrySourceConnectionIDParameterID))
|
||||
quicvarint.Write(b, uint64(p.RetrySourceConnectionID.Len()))
|
||||
b.Write(p.RetrySourceConnectionID.Bytes())
|
||||
b = quicvarint.Append(b, uint64(retrySourceConnectionIDParameterID))
|
||||
b = quicvarint.Append(b, uint64(p.RetrySourceConnectionID.Len()))
|
||||
b = append(b, p.RetrySourceConnectionID.Bytes()...)
|
||||
}
|
||||
if p.MaxDatagramFrameSize != protocol.InvalidByteCount {
|
||||
p.marshalVarintParam(b, maxDatagramFrameSizeParameterID, uint64(p.MaxDatagramFrameSize))
|
||||
b = p.marshalVarintParam(b, maxDatagramFrameSizeParameterID, uint64(p.MaxDatagramFrameSize))
|
||||
}
|
||||
return b.Bytes()
|
||||
return b
|
||||
}
|
||||
|
||||
func (p *TransportParameters) marshalVarintParam(b *bytes.Buffer, id transportParameterID, val uint64) {
|
||||
quicvarint.Write(b, uint64(id))
|
||||
quicvarint.Write(b, uint64(quicvarint.Len(val)))
|
||||
quicvarint.Write(b, val)
|
||||
func (p *TransportParameters) marshalVarintParam(b []byte, id transportParameterID, val uint64) []byte {
|
||||
b = quicvarint.Append(b, uint64(id))
|
||||
b = quicvarint.Append(b, uint64(quicvarint.Len(val)))
|
||||
return quicvarint.Append(b, val)
|
||||
}
|
||||
|
||||
// MarshalForSessionTicket marshals the transport parameters we save in the session ticket.
|
||||
@ -411,23 +416,23 @@ func (p *TransportParameters) marshalVarintParam(b *bytes.Buffer, id transportPa
|
||||
// if the transport parameters changed.
|
||||
// Since the session ticket is encrypted, the serialization format is defined by the server.
|
||||
// For convenience, we use the same format that we also use for sending the transport parameters.
|
||||
func (p *TransportParameters) MarshalForSessionTicket(b *bytes.Buffer) {
|
||||
quicvarint.Write(b, transportParameterMarshalingVersion)
|
||||
func (p *TransportParameters) MarshalForSessionTicket(b []byte) []byte {
|
||||
b = quicvarint.Append(b, transportParameterMarshalingVersion)
|
||||
|
||||
// initial_max_stream_data_bidi_local
|
||||
p.marshalVarintParam(b, initialMaxStreamDataBidiLocalParameterID, uint64(p.InitialMaxStreamDataBidiLocal))
|
||||
b = p.marshalVarintParam(b, initialMaxStreamDataBidiLocalParameterID, uint64(p.InitialMaxStreamDataBidiLocal))
|
||||
// initial_max_stream_data_bidi_remote
|
||||
p.marshalVarintParam(b, initialMaxStreamDataBidiRemoteParameterID, uint64(p.InitialMaxStreamDataBidiRemote))
|
||||
b = p.marshalVarintParam(b, initialMaxStreamDataBidiRemoteParameterID, uint64(p.InitialMaxStreamDataBidiRemote))
|
||||
// initial_max_stream_data_uni
|
||||
p.marshalVarintParam(b, initialMaxStreamDataUniParameterID, uint64(p.InitialMaxStreamDataUni))
|
||||
b = p.marshalVarintParam(b, initialMaxStreamDataUniParameterID, uint64(p.InitialMaxStreamDataUni))
|
||||
// initial_max_data
|
||||
p.marshalVarintParam(b, initialMaxDataParameterID, uint64(p.InitialMaxData))
|
||||
b = p.marshalVarintParam(b, initialMaxDataParameterID, uint64(p.InitialMaxData))
|
||||
// initial_max_bidi_streams
|
||||
p.marshalVarintParam(b, initialMaxStreamsBidiParameterID, uint64(p.MaxBidiStreamNum))
|
||||
b = p.marshalVarintParam(b, initialMaxStreamsBidiParameterID, uint64(p.MaxBidiStreamNum))
|
||||
// initial_max_uni_streams
|
||||
p.marshalVarintParam(b, initialMaxStreamsUniParameterID, uint64(p.MaxUniStreamNum))
|
||||
b = p.marshalVarintParam(b, initialMaxStreamsUniParameterID, uint64(p.MaxUniStreamNum))
|
||||
// active_connection_id_limit
|
||||
p.marshalVarintParam(b, activeConnectionIDLimitParameterID, p.ActiveConnectionIDLimit)
|
||||
return p.marshalVarintParam(b, activeConnectionIDLimitParameterID, p.ActiveConnectionIDLimit)
|
||||
}
|
||||
|
||||
// UnmarshalFromSessionTicket unmarshals transport parameters from a session ticket.
|
||||
|
35
vendor/github.com/lucas-clemente/quic-go/internal/wire/version_negotiation.go
generated
vendored
35
vendor/github.com/lucas-clemente/quic-go/internal/wire/version_negotiation.go
generated
vendored
@ -3,6 +3,7 @@
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
|
||||
"github.com/lucas-clemente/quic-go/internal/protocol"
|
||||
@ -10,32 +11,30 @@
|
||||
)
|
||||
|
||||
// ParseVersionNegotiationPacket parses a Version Negotiation packet.
|
||||
func ParseVersionNegotiationPacket(b *bytes.Reader) (*Header, []protocol.VersionNumber, error) {
|
||||
hdr, err := parseHeader(b, 0)
|
||||
func ParseVersionNegotiationPacket(b []byte) (dest, src protocol.ArbitraryLenConnectionID, _ []protocol.VersionNumber, _ error) {
|
||||
n, dest, src, err := ParseArbitraryLenConnectionIDs(b)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
if b.Len() == 0 {
|
||||
b = b[n:]
|
||||
if len(b) == 0 {
|
||||
//nolint:stylecheck
|
||||
return nil, nil, errors.New("Version Negotiation packet has empty version list")
|
||||
return nil, nil, nil, errors.New("Version Negotiation packet has empty version list")
|
||||
}
|
||||
if b.Len()%4 != 0 {
|
||||
if len(b)%4 != 0 {
|
||||
//nolint:stylecheck
|
||||
return nil, nil, errors.New("Version Negotiation packet has a version list with an invalid length")
|
||||
return nil, nil, nil, errors.New("Version Negotiation packet has a version list with an invalid length")
|
||||
}
|
||||
versions := make([]protocol.VersionNumber, b.Len()/4)
|
||||
for i := 0; b.Len() > 0; i++ {
|
||||
v, err := utils.BigEndian.ReadUint32(b)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
versions[i] = protocol.VersionNumber(v)
|
||||
versions := make([]protocol.VersionNumber, len(b)/4)
|
||||
for i := 0; len(b) > 0; i++ {
|
||||
versions[i] = protocol.VersionNumber(binary.BigEndian.Uint32(b[:4]))
|
||||
b = b[4:]
|
||||
}
|
||||
return hdr, versions, nil
|
||||
return dest, src, versions, nil
|
||||
}
|
||||
|
||||
// ComposeVersionNegotiation composes a Version Negotiation
|
||||
func ComposeVersionNegotiation(destConnID, srcConnID protocol.ConnectionID, versions []protocol.VersionNumber) []byte {
|
||||
func ComposeVersionNegotiation(destConnID, srcConnID protocol.ArbitraryLenConnectionID, versions []protocol.VersionNumber) []byte {
|
||||
greasedVersions := protocol.GetGreasedVersions(versions)
|
||||
expectedLen := 1 /* type byte */ + 4 /* version field */ + 1 /* dest connection ID length field */ + destConnID.Len() + 1 /* src connection ID length field */ + srcConnID.Len() + len(greasedVersions)*4
|
||||
buf := bytes.NewBuffer(make([]byte, 0, expectedLen))
|
||||
@ -44,9 +43,9 @@ func ComposeVersionNegotiation(destConnID, srcConnID protocol.ConnectionID, vers
|
||||
buf.WriteByte(r[0] | 0x80)
|
||||
utils.BigEndian.WriteUint32(buf, 0) // version 0
|
||||
buf.WriteByte(uint8(destConnID.Len()))
|
||||
buf.Write(destConnID)
|
||||
buf.Write(destConnID.Bytes())
|
||||
buf.WriteByte(uint8(srcConnID.Len()))
|
||||
buf.Write(srcConnID)
|
||||
buf.Write(srcConnID.Bytes())
|
||||
for _, v := range greasedVersions {
|
||||
utils.BigEndian.WriteUint32(buf, uint32(v))
|
||||
}
|
||||
|
20
vendor/github.com/lucas-clemente/quic-go/logging/interface.go
generated
vendored
20
vendor/github.com/lucas-clemente/quic-go/logging/interface.go
generated
vendored
@ -19,6 +19,8 @@
|
||||
ByteCount = protocol.ByteCount
|
||||
// A ConnectionID is a QUIC Connection ID.
|
||||
ConnectionID = protocol.ConnectionID
|
||||
// An ArbitraryLenConnectionID is a QUIC Connection ID that can be up to 255 bytes long.
|
||||
ArbitraryLenConnectionID = protocol.ArbitraryLenConnectionID
|
||||
// The EncryptionLevel is the encryption level of a packet.
|
||||
EncryptionLevel = protocol.EncryptionLevel
|
||||
// The KeyPhase is the key phase of the 1-RTT keys.
|
||||
@ -42,7 +44,7 @@
|
||||
|
||||
// The Header is the QUIC packet header, before removing header protection.
|
||||
Header = wire.Header
|
||||
// The ExtendedHeader is the QUIC packet header, after removing header protection.
|
||||
// The ExtendedHeader is the QUIC Long Header packet header, after removing header protection.
|
||||
ExtendedHeader = wire.ExtendedHeader
|
||||
// The TransportParameters are QUIC transport parameters.
|
||||
TransportParameters = wire.TransportParameters
|
||||
@ -90,6 +92,14 @@
|
||||
StreamTypeBidi = protocol.StreamTypeBidi
|
||||
)
|
||||
|
||||
// The ShortHeader is the QUIC Short Header packet header, after removing header protection.
|
||||
type ShortHeader struct {
|
||||
DestConnectionID ConnectionID
|
||||
PacketNumber PacketNumber
|
||||
PacketNumberLen protocol.PacketNumberLen
|
||||
KeyPhase KeyPhaseBit
|
||||
}
|
||||
|
||||
// A Tracer traces events.
|
||||
type Tracer interface {
|
||||
// TracerForConnection requests a new tracer for a connection.
|
||||
@ -99,6 +109,7 @@ type Tracer interface {
|
||||
TracerForConnection(ctx context.Context, p Perspective, odcid ConnectionID) ConnectionTracer
|
||||
|
||||
SentPacket(net.Addr, *Header, ByteCount, []Frame)
|
||||
SentVersionNegotiationPacket(_ net.Addr, dest, src ArbitraryLenConnectionID, _ []VersionNumber)
|
||||
DroppedPacket(net.Addr, PacketType, ByteCount, PacketDropReason)
|
||||
}
|
||||
|
||||
@ -111,10 +122,11 @@ type ConnectionTracer interface {
|
||||
ReceivedTransportParameters(*TransportParameters)
|
||||
RestoredTransportParameters(parameters *TransportParameters) // for 0-RTT
|
||||
SentPacket(hdr *ExtendedHeader, size ByteCount, ack *AckFrame, frames []Frame)
|
||||
ReceivedVersionNegotiationPacket(*Header, []VersionNumber)
|
||||
ReceivedVersionNegotiationPacket(dest, src ArbitraryLenConnectionID, _ []VersionNumber)
|
||||
ReceivedRetry(*Header)
|
||||
ReceivedPacket(hdr *ExtendedHeader, size ByteCount, frames []Frame)
|
||||
BufferedPacket(PacketType)
|
||||
ReceivedLongHeaderPacket(hdr *ExtendedHeader, size ByteCount, frames []Frame)
|
||||
ReceivedShortHeaderPacket(hdr *ShortHeader, size ByteCount, frames []Frame)
|
||||
BufferedPacket(PacketType, ByteCount)
|
||||
DroppedPacket(PacketType, ByteCount, PacketDropReason)
|
||||
UpdatedMetrics(rttStats *RTTStats, cwnd, bytesInFlight ByteCount, packetsInFlight int)
|
||||
AcknowledgedPacket(EncryptionLevel, PacketNumber)
|
||||
|
24
vendor/github.com/lucas-clemente/quic-go/logging/multiplex.go
generated
vendored
24
vendor/github.com/lucas-clemente/quic-go/logging/multiplex.go
generated
vendored
@ -39,6 +39,12 @@ func (m *tracerMultiplexer) SentPacket(remote net.Addr, hdr *Header, size ByteCo
|
||||
}
|
||||
}
|
||||
|
||||
func (m *tracerMultiplexer) SentVersionNegotiationPacket(remote net.Addr, dest, src ArbitraryLenConnectionID, versions []VersionNumber) {
|
||||
for _, t := range m.tracers {
|
||||
t.SentVersionNegotiationPacket(remote, dest, src, versions)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *tracerMultiplexer) DroppedPacket(remote net.Addr, typ PacketType, size ByteCount, reason PacketDropReason) {
|
||||
for _, t := range m.tracers {
|
||||
t.DroppedPacket(remote, typ, size, reason)
|
||||
@ -104,9 +110,9 @@ func (m *connTracerMultiplexer) SentPacket(hdr *ExtendedHeader, size ByteCount,
|
||||
}
|
||||
}
|
||||
|
||||
func (m *connTracerMultiplexer) ReceivedVersionNegotiationPacket(hdr *Header, versions []VersionNumber) {
|
||||
func (m *connTracerMultiplexer) ReceivedVersionNegotiationPacket(dest, src ArbitraryLenConnectionID, versions []VersionNumber) {
|
||||
for _, t := range m.tracers {
|
||||
t.ReceivedVersionNegotiationPacket(hdr, versions)
|
||||
t.ReceivedVersionNegotiationPacket(dest, src, versions)
|
||||
}
|
||||
}
|
||||
|
||||
@ -116,15 +122,21 @@ func (m *connTracerMultiplexer) ReceivedRetry(hdr *Header) {
|
||||
}
|
||||
}
|
||||
|
||||
func (m *connTracerMultiplexer) ReceivedPacket(hdr *ExtendedHeader, size ByteCount, frames []Frame) {
|
||||
func (m *connTracerMultiplexer) ReceivedLongHeaderPacket(hdr *ExtendedHeader, size ByteCount, frames []Frame) {
|
||||
for _, t := range m.tracers {
|
||||
t.ReceivedPacket(hdr, size, frames)
|
||||
t.ReceivedLongHeaderPacket(hdr, size, frames)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *connTracerMultiplexer) BufferedPacket(typ PacketType) {
|
||||
func (m *connTracerMultiplexer) ReceivedShortHeaderPacket(hdr *ShortHeader, size ByteCount, frames []Frame) {
|
||||
for _, t := range m.tracers {
|
||||
t.BufferedPacket(typ)
|
||||
t.ReceivedShortHeaderPacket(hdr, size, frames)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *connTracerMultiplexer) BufferedPacket(typ PacketType, size ByteCount) {
|
||||
for _, t := range m.tracers {
|
||||
t.BufferedPacket(typ, size)
|
||||
}
|
||||
}
|
||||
|
||||
|
31
vendor/github.com/lucas-clemente/quic-go/logging/null_tracer.go
generated
vendored
31
vendor/github.com/lucas-clemente/quic-go/logging/null_tracer.go
generated
vendored
@ -10,31 +10,40 @@
|
||||
// It is useful for embedding.
|
||||
type NullTracer struct{}
|
||||
|
||||
var _ Tracer = &NullTracer{}
|
||||
|
||||
func (n NullTracer) TracerForConnection(context.Context, Perspective, ConnectionID) ConnectionTracer {
|
||||
return NullConnectionTracer{}
|
||||
}
|
||||
func (n NullTracer) SentPacket(net.Addr, *Header, ByteCount, []Frame) {}
|
||||
func (n NullTracer) SentPacket(net.Addr, *Header, ByteCount, []Frame) {}
|
||||
func (n NullTracer) SentVersionNegotiationPacket(_ net.Addr, dest, src ArbitraryLenConnectionID, _ []VersionNumber) {
|
||||
}
|
||||
func (n NullTracer) DroppedPacket(net.Addr, PacketType, ByteCount, PacketDropReason) {}
|
||||
|
||||
// The NullConnectionTracer is a ConnectionTracer that does nothing.
|
||||
// It is useful for embedding.
|
||||
type NullConnectionTracer struct{}
|
||||
|
||||
var _ ConnectionTracer = &NullConnectionTracer{}
|
||||
|
||||
func (n NullConnectionTracer) StartedConnection(local, remote net.Addr, srcConnID, destConnID ConnectionID) {
|
||||
}
|
||||
|
||||
func (n NullConnectionTracer) NegotiatedVersion(chosen VersionNumber, clientVersions, serverVersions []VersionNumber) {
|
||||
}
|
||||
func (n NullConnectionTracer) ClosedConnection(err error) {}
|
||||
func (n NullConnectionTracer) SentTransportParameters(*TransportParameters) {}
|
||||
func (n NullConnectionTracer) ReceivedTransportParameters(*TransportParameters) {}
|
||||
func (n NullConnectionTracer) RestoredTransportParameters(*TransportParameters) {}
|
||||
func (n NullConnectionTracer) SentPacket(*ExtendedHeader, ByteCount, *AckFrame, []Frame) {}
|
||||
func (n NullConnectionTracer) ReceivedVersionNegotiationPacket(*Header, []VersionNumber) {}
|
||||
func (n NullConnectionTracer) ReceivedRetry(*Header) {}
|
||||
func (n NullConnectionTracer) ReceivedPacket(hdr *ExtendedHeader, size ByteCount, frames []Frame) {}
|
||||
func (n NullConnectionTracer) BufferedPacket(PacketType) {}
|
||||
func (n NullConnectionTracer) DroppedPacket(PacketType, ByteCount, PacketDropReason) {}
|
||||
func (n NullConnectionTracer) ClosedConnection(err error) {}
|
||||
func (n NullConnectionTracer) SentTransportParameters(*TransportParameters) {}
|
||||
func (n NullConnectionTracer) ReceivedTransportParameters(*TransportParameters) {}
|
||||
func (n NullConnectionTracer) RestoredTransportParameters(*TransportParameters) {}
|
||||
func (n NullConnectionTracer) SentPacket(*ExtendedHeader, ByteCount, *AckFrame, []Frame) {}
|
||||
func (n NullConnectionTracer) ReceivedVersionNegotiationPacket(dest, src ArbitraryLenConnectionID, _ []VersionNumber) {
|
||||
}
|
||||
func (n NullConnectionTracer) ReceivedRetry(*Header) {}
|
||||
func (n NullConnectionTracer) ReceivedLongHeaderPacket(*ExtendedHeader, ByteCount, []Frame) {}
|
||||
func (n NullConnectionTracer) ReceivedShortHeaderPacket(*ShortHeader, ByteCount, []Frame) {}
|
||||
func (n NullConnectionTracer) BufferedPacket(PacketType, ByteCount) {}
|
||||
func (n NullConnectionTracer) DroppedPacket(PacketType, ByteCount, PacketDropReason) {}
|
||||
|
||||
func (n NullConnectionTracer) UpdatedMetrics(rttStats *RTTStats, cwnd, bytesInFlight ByteCount, packetsInFlight int) {
|
||||
}
|
||||
func (n NullConnectionTracer) AcknowledgedPacket(EncryptionLevel, PacketNumber) {}
|
||||
|
30
vendor/github.com/lucas-clemente/quic-go/packet_handler_map.go
generated
vendored
30
vendor/github.com/lucas-clemente/quic-go/packet_handler_map.go
generated
vendored
@ -48,7 +48,7 @@ type packetHandlerMap struct {
|
||||
|
||||
closeQueue chan closePacket
|
||||
|
||||
handlers map[string] /* string(ConnectionID)*/ packetHandler
|
||||
handlers map[protocol.ConnectionID]packetHandler
|
||||
resetTokens map[protocol.StatelessResetToken] /* stateless reset token */ packetHandler
|
||||
server unknownPacketHandler
|
||||
numZeroRTTEntries int
|
||||
@ -127,7 +127,7 @@ func newPacketHandlerMap(
|
||||
conn: conn,
|
||||
connIDLen: connIDLen,
|
||||
listening: make(chan struct{}),
|
||||
handlers: make(map[string]packetHandler),
|
||||
handlers: make(map[protocol.ConnectionID]packetHandler),
|
||||
resetTokens: make(map[protocol.StatelessResetToken]packetHandler),
|
||||
deleteRetiredConnsAfter: protocol.RetiredConnectionIDDeleteTimeout,
|
||||
zeroRTTQueueDuration: protocol.Max0RTTQueueingDuration,
|
||||
@ -176,11 +176,11 @@ func (h *packetHandlerMap) Add(id protocol.ConnectionID, handler packetHandler)
|
||||
h.mutex.Lock()
|
||||
defer h.mutex.Unlock()
|
||||
|
||||
if _, ok := h.handlers[string(id)]; ok {
|
||||
if _, ok := h.handlers[id]; ok {
|
||||
h.logger.Debugf("Not adding connection ID %s, as it already exists.", id)
|
||||
return false
|
||||
}
|
||||
h.handlers[string(id)] = handler
|
||||
h.handlers[id] = handler
|
||||
h.logger.Debugf("Adding connection ID %s.", id)
|
||||
return true
|
||||
}
|
||||
@ -190,7 +190,7 @@ func (h *packetHandlerMap) AddWithConnID(clientDestConnID, newConnID protocol.Co
|
||||
defer h.mutex.Unlock()
|
||||
|
||||
var q *zeroRTTQueue
|
||||
if handler, ok := h.handlers[string(clientDestConnID)]; ok {
|
||||
if handler, ok := h.handlers[clientDestConnID]; ok {
|
||||
q, ok = handler.(*zeroRTTQueue)
|
||||
if !ok {
|
||||
h.logger.Debugf("Not adding connection ID %s for a new connection, as it already exists.", clientDestConnID)
|
||||
@ -206,15 +206,15 @@ func (h *packetHandlerMap) AddWithConnID(clientDestConnID, newConnID protocol.Co
|
||||
if q != nil {
|
||||
q.EnqueueAll(conn)
|
||||
}
|
||||
h.handlers[string(clientDestConnID)] = conn
|
||||
h.handlers[string(newConnID)] = conn
|
||||
h.handlers[clientDestConnID] = conn
|
||||
h.handlers[newConnID] = conn
|
||||
h.logger.Debugf("Adding connection IDs %s and %s for a new connection.", clientDestConnID, newConnID)
|
||||
return true
|
||||
}
|
||||
|
||||
func (h *packetHandlerMap) Remove(id protocol.ConnectionID) {
|
||||
h.mutex.Lock()
|
||||
delete(h.handlers, string(id))
|
||||
delete(h.handlers, id)
|
||||
h.mutex.Unlock()
|
||||
h.logger.Debugf("Removing connection ID %s.", id)
|
||||
}
|
||||
@ -223,7 +223,7 @@ func (h *packetHandlerMap) Retire(id protocol.ConnectionID) {
|
||||
h.logger.Debugf("Retiring connection ID %s in %s.", id, h.deleteRetiredConnsAfter)
|
||||
time.AfterFunc(h.deleteRetiredConnsAfter, func() {
|
||||
h.mutex.Lock()
|
||||
delete(h.handlers, string(id))
|
||||
delete(h.handlers, id)
|
||||
h.mutex.Unlock()
|
||||
h.logger.Debugf("Removing connection ID %s after it has been retired.", id)
|
||||
})
|
||||
@ -254,7 +254,7 @@ func(addr net.Addr, info *packetInfo) {
|
||||
|
||||
h.mutex.Lock()
|
||||
for _, id := range ids {
|
||||
h.handlers[string(id)] = handler
|
||||
h.handlers[id] = handler
|
||||
}
|
||||
h.mutex.Unlock()
|
||||
h.logger.Debugf("Replacing connection for connection IDs %s with a closed connection.", ids)
|
||||
@ -263,7 +263,7 @@ func(addr net.Addr, info *packetInfo) {
|
||||
h.mutex.Lock()
|
||||
handler.shutdown()
|
||||
for _, id := range ids {
|
||||
delete(h.handlers, string(id))
|
||||
delete(h.handlers, id)
|
||||
}
|
||||
h.mutex.Unlock()
|
||||
h.logger.Debugf("Removing connection IDs %s for a closed connection after it has been retired.", ids)
|
||||
@ -394,7 +394,7 @@ func (h *packetHandlerMap) handlePacket(p *receivedPacket) {
|
||||
return
|
||||
}
|
||||
|
||||
if handler, ok := h.handlers[string(connID)]; ok {
|
||||
if handler, ok := h.handlers[connID]; ok {
|
||||
if ha, ok := handler.(*zeroRTTQueue); ok { // only enqueue 0-RTT packets in the 0-RTT queue
|
||||
if wire.Is0RTTPacket(p.data) {
|
||||
ha.handlePacket(p)
|
||||
@ -419,15 +419,15 @@ func (h *packetHandlerMap) handlePacket(p *receivedPacket) {
|
||||
}
|
||||
h.numZeroRTTEntries++
|
||||
queue := &zeroRTTQueue{queue: make([]*receivedPacket, 0, 8)}
|
||||
h.handlers[string(connID)] = queue
|
||||
h.handlers[connID] = queue
|
||||
queue.retireTimer = time.AfterFunc(h.zeroRTTQueueDuration, func() {
|
||||
h.mutex.Lock()
|
||||
defer h.mutex.Unlock()
|
||||
// The entry might have been replaced by an actual connection.
|
||||
// Only delete it if it's still a 0-RTT queue.
|
||||
if handler, ok := h.handlers[string(connID)]; ok {
|
||||
if handler, ok := h.handlers[connID]; ok {
|
||||
if q, ok := handler.(*zeroRTTQueue); ok {
|
||||
delete(h.handlers, string(connID))
|
||||
delete(h.handlers, connID)
|
||||
h.numZeroRTTEntries--
|
||||
if h.numZeroRTTEntries < 0 {
|
||||
panic("number of 0-RTT queues < 0")
|
||||
|
299
vendor/github.com/lucas-clemente/quic-go/packet_packer.go
generated
vendored
299
vendor/github.com/lucas-clemente/quic-go/packet_packer.go
generated
vendored
@ -16,10 +16,9 @@
|
||||
)
|
||||
|
||||
type packer interface {
|
||||
PackCoalescedPacket() (*coalescedPacket, error)
|
||||
PackPacket() (*packedPacket, error)
|
||||
PackCoalescedPacket(onlyAck bool) (*coalescedPacket, error)
|
||||
PackPacket(onlyAck bool) (*packedPacket, error)
|
||||
MaybePackProbePacket(protocol.EncryptionLevel) (*packedPacket, error)
|
||||
MaybePackAckPacket(handshakeConfirmed bool) (*packedPacket, error)
|
||||
PackConnectionClose(*qerr.TransportError) (*coalescedPacket, error)
|
||||
PackApplicationClose(*qerr.ApplicationError) (*coalescedPacket, error)
|
||||
|
||||
@ -100,15 +99,16 @@ func (p *packetContents) ToAckHandlerPacket(now time.Time, q *retransmissionQueu
|
||||
p.frames[i].OnLost = q.AddAppData
|
||||
}
|
||||
}
|
||||
return &ackhandler.Packet{
|
||||
PacketNumber: p.header.PacketNumber,
|
||||
LargestAcked: largestAcked,
|
||||
Frames: p.frames,
|
||||
Length: p.length,
|
||||
EncryptionLevel: encLevel,
|
||||
SendTime: now,
|
||||
IsPathMTUProbePacket: p.isMTUProbePacket,
|
||||
}
|
||||
|
||||
ap := ackhandler.GetPacket()
|
||||
ap.PacketNumber = p.header.PacketNumber
|
||||
ap.LargestAcked = largestAcked
|
||||
ap.Frames = p.frames
|
||||
ap.Length = p.length
|
||||
ap.EncryptionLevel = encLevel
|
||||
ap.SendTime = now
|
||||
ap.IsPathMTUProbePacket = p.isMTUProbePacket
|
||||
return ap
|
||||
}
|
||||
|
||||
func getMaxPacketSize(addr net.Addr) protocol.ByteCount {
|
||||
@ -319,39 +319,6 @@ func (p *packetPacker) packetLength(hdr *wire.ExtendedHeader, payload *payload)
|
||||
return hdr.GetLength(p.version) + payload.length + paddingLen
|
||||
}
|
||||
|
||||
func (p *packetPacker) MaybePackAckPacket(handshakeConfirmed bool) (*packedPacket, error) {
|
||||
var encLevel protocol.EncryptionLevel
|
||||
var ack *wire.AckFrame
|
||||
if !handshakeConfirmed {
|
||||
ack = p.acks.GetAckFrame(protocol.EncryptionInitial, true)
|
||||
if ack != nil {
|
||||
encLevel = protocol.EncryptionInitial
|
||||
} else {
|
||||
ack = p.acks.GetAckFrame(protocol.EncryptionHandshake, true)
|
||||
if ack != nil {
|
||||
encLevel = protocol.EncryptionHandshake
|
||||
}
|
||||
}
|
||||
}
|
||||
if ack == nil {
|
||||
ack = p.acks.GetAckFrame(protocol.Encryption1RTT, true)
|
||||
if ack == nil {
|
||||
return nil, nil
|
||||
}
|
||||
encLevel = protocol.Encryption1RTT
|
||||
}
|
||||
payload := &payload{
|
||||
ack: ack,
|
||||
length: ack.Length(p.version),
|
||||
}
|
||||
|
||||
sealer, hdr, err := p.getSealerAndHeader(encLevel)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return p.writeSinglePacket(hdr, payload, encLevel, sealer)
|
||||
}
|
||||
|
||||
// size is the expected size of the packet, if no padding was applied.
|
||||
func (p *packetPacker) initialPaddingLen(frames []ackhandler.Frame, size protocol.ByteCount) protocol.ByteCount {
|
||||
// For the server, only ack-eliciting Initial packets need to be padded.
|
||||
@ -367,7 +334,7 @@ func (p *packetPacker) initialPaddingLen(frames []ackhandler.Frame, size protoco
|
||||
// PackCoalescedPacket packs a new packet.
|
||||
// It packs an Initial / Handshake if there is data to send in these packet number spaces.
|
||||
// It should only be called before the handshake is confirmed.
|
||||
func (p *packetPacker) PackCoalescedPacket() (*coalescedPacket, error) {
|
||||
func (p *packetPacker) PackCoalescedPacket(onlyAck bool) (*coalescedPacket, error) {
|
||||
maxPacketSize := p.maxPacketSize
|
||||
if p.perspective == protocol.PerspectiveClient {
|
||||
maxPacketSize = protocol.MinInitialPacketSize
|
||||
@ -382,7 +349,7 @@ func (p *packetPacker) PackCoalescedPacket() (*coalescedPacket, error) {
|
||||
}
|
||||
var size protocol.ByteCount
|
||||
if initialSealer != nil {
|
||||
initialHdr, initialPayload = p.maybeGetCryptoPacket(maxPacketSize-protocol.ByteCount(initialSealer.Overhead()), size, protocol.EncryptionInitial)
|
||||
initialHdr, initialPayload = p.maybeGetCryptoPacket(maxPacketSize-protocol.ByteCount(initialSealer.Overhead()), protocol.EncryptionInitial, onlyAck, true)
|
||||
if initialPayload != nil {
|
||||
size += p.packetLength(initialHdr, initialPayload) + protocol.ByteCount(initialSealer.Overhead())
|
||||
numPackets++
|
||||
@ -391,14 +358,14 @@ func (p *packetPacker) PackCoalescedPacket() (*coalescedPacket, error) {
|
||||
|
||||
// Add a Handshake packet.
|
||||
var handshakeSealer sealer
|
||||
if size < maxPacketSize-protocol.MinCoalescedPacketSize {
|
||||
if (onlyAck && size == 0) || (!onlyAck && size < maxPacketSize-protocol.MinCoalescedPacketSize) {
|
||||
var err error
|
||||
handshakeSealer, err = p.cryptoSetup.GetHandshakeSealer()
|
||||
if err != nil && err != handshake.ErrKeysDropped && err != handshake.ErrKeysNotYetAvailable {
|
||||
return nil, err
|
||||
}
|
||||
if handshakeSealer != nil {
|
||||
handshakeHdr, handshakePayload = p.maybeGetCryptoPacket(maxPacketSize-size-protocol.ByteCount(handshakeSealer.Overhead()), size, protocol.EncryptionHandshake)
|
||||
handshakeHdr, handshakePayload = p.maybeGetCryptoPacket(maxPacketSize-size-protocol.ByteCount(handshakeSealer.Overhead()), protocol.EncryptionHandshake, onlyAck, size == 0)
|
||||
if handshakePayload != nil {
|
||||
s := p.packetLength(handshakeHdr, handshakePayload) + protocol.ByteCount(handshakeSealer.Overhead())
|
||||
size += s
|
||||
@ -410,17 +377,24 @@ func (p *packetPacker) PackCoalescedPacket() (*coalescedPacket, error) {
|
||||
// Add a 0-RTT / 1-RTT packet.
|
||||
var appDataSealer sealer
|
||||
appDataEncLevel := protocol.Encryption1RTT
|
||||
if size < maxPacketSize-protocol.MinCoalescedPacketSize {
|
||||
var err error
|
||||
appDataSealer, appDataHdr, appDataPayload = p.maybeGetAppDataPacket(maxPacketSize-size, size)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
if (onlyAck && size == 0) || (!onlyAck && size < maxPacketSize-protocol.MinCoalescedPacketSize) {
|
||||
var sErr error
|
||||
var oneRTTSealer handshake.ShortHeaderSealer
|
||||
oneRTTSealer, sErr = p.cryptoSetup.Get1RTTSealer()
|
||||
appDataSealer = oneRTTSealer
|
||||
if sErr != nil && p.perspective == protocol.PerspectiveClient {
|
||||
appDataSealer, sErr = p.cryptoSetup.Get0RTTSealer()
|
||||
appDataEncLevel = protocol.Encryption0RTT
|
||||
}
|
||||
if appDataHdr != nil {
|
||||
if appDataHdr.IsLongHeader {
|
||||
appDataEncLevel = protocol.Encryption0RTT
|
||||
if appDataSealer != nil && sErr == nil {
|
||||
//nolint:exhaustive // 0-RTT and 1-RTT are the only two application data encryption levels.
|
||||
switch appDataEncLevel {
|
||||
case protocol.Encryption0RTT:
|
||||
appDataHdr, appDataPayload = p.maybeGetAppDataPacketFor0RTT(appDataSealer, maxPacketSize-size)
|
||||
case protocol.Encryption1RTT:
|
||||
appDataHdr, appDataPayload = p.maybeGetShortHeaderPacket(oneRTTSealer, maxPacketSize-size, onlyAck, size == 0)
|
||||
}
|
||||
if appDataPayload != nil {
|
||||
if appDataHdr != nil && appDataPayload != nil {
|
||||
size += p.packetLength(appDataHdr, appDataPayload) + protocol.ByteCount(appDataSealer.Overhead())
|
||||
numPackets++
|
||||
}
|
||||
@ -463,17 +437,17 @@ func (p *packetPacker) PackCoalescedPacket() (*coalescedPacket, error) {
|
||||
|
||||
// PackPacket packs a packet in the application data packet number space.
|
||||
// It should be called after the handshake is confirmed.
|
||||
func (p *packetPacker) PackPacket() (*packedPacket, error) {
|
||||
sealer, hdr, payload := p.maybeGetAppDataPacket(p.maxPacketSize, 0)
|
||||
func (p *packetPacker) PackPacket(onlyAck bool) (*packedPacket, error) {
|
||||
sealer, err := p.cryptoSetup.Get1RTTSealer()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
hdr, payload := p.maybeGetShortHeaderPacket(sealer, p.maxPacketSize, onlyAck, true)
|
||||
if payload == nil {
|
||||
return nil, nil
|
||||
}
|
||||
buffer := getPacketBuffer()
|
||||
encLevel := protocol.Encryption1RTT
|
||||
if hdr.IsLongHeader {
|
||||
encLevel = protocol.Encryption0RTT
|
||||
}
|
||||
cont, err := p.appendPacket(buffer, hdr, payload, 0, encLevel, sealer, false)
|
||||
cont, err := p.appendPacket(buffer, hdr, payload, 0, protocol.Encryption1RTT, sealer, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -483,7 +457,17 @@ func (p *packetPacker) PackPacket() (*packedPacket, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (p *packetPacker) maybeGetCryptoPacket(maxPacketSize, currentSize protocol.ByteCount, encLevel protocol.EncryptionLevel) (*wire.ExtendedHeader, *payload) {
|
||||
func (p *packetPacker) maybeGetCryptoPacket(maxPacketSize protocol.ByteCount, encLevel protocol.EncryptionLevel, onlyAck, ackAllowed bool) (*wire.ExtendedHeader, *payload) {
|
||||
if onlyAck {
|
||||
if ack := p.acks.GetAckFrame(encLevel, true); ack != nil {
|
||||
var payload payload
|
||||
payload.ack = ack
|
||||
payload.length = ack.Length(p.version)
|
||||
return p.getLongHeader(encLevel), &payload
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
var s cryptoStream
|
||||
var hasRetransmission bool
|
||||
//nolint:exhaustive // Initial and Handshake are the only two encryption levels here.
|
||||
@ -498,7 +482,7 @@ func (p *packetPacker) maybeGetCryptoPacket(maxPacketSize, currentSize protocol.
|
||||
|
||||
hasData := s.HasData()
|
||||
var ack *wire.AckFrame
|
||||
if encLevel == protocol.EncryptionInitial || currentSize == 0 {
|
||||
if ackAllowed {
|
||||
ack = p.acks.GetAckFrame(encLevel, !hasRetransmission && !hasData)
|
||||
}
|
||||
if !hasData && !hasRetransmission && ack == nil {
|
||||
@ -540,35 +524,26 @@ func (p *packetPacker) maybeGetCryptoPacket(maxPacketSize, currentSize protocol.
|
||||
return hdr, &payload
|
||||
}
|
||||
|
||||
func (p *packetPacker) maybeGetAppDataPacket(maxPacketSize, currentSize protocol.ByteCount) (sealer, *wire.ExtendedHeader, *payload) {
|
||||
var sealer sealer
|
||||
var encLevel protocol.EncryptionLevel
|
||||
var hdr *wire.ExtendedHeader
|
||||
oneRTTSealer, err := p.cryptoSetup.Get1RTTSealer()
|
||||
if err == nil {
|
||||
encLevel = protocol.Encryption1RTT
|
||||
sealer = oneRTTSealer
|
||||
hdr = p.getShortHeader(oneRTTSealer.KeyPhase())
|
||||
} else {
|
||||
// 1-RTT sealer not yet available
|
||||
if p.perspective != protocol.PerspectiveClient {
|
||||
return nil, nil, nil
|
||||
}
|
||||
sealer, err = p.cryptoSetup.Get0RTTSealer()
|
||||
if sealer == nil || err != nil {
|
||||
return nil, nil, nil
|
||||
}
|
||||
encLevel = protocol.Encryption0RTT
|
||||
hdr = p.getLongHeader(protocol.Encryption0RTT)
|
||||
func (p *packetPacker) maybeGetAppDataPacketFor0RTT(sealer sealer, maxPacketSize protocol.ByteCount) (*wire.ExtendedHeader, *payload) {
|
||||
if p.perspective != protocol.PerspectiveClient {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
hdr := p.getLongHeader(protocol.Encryption0RTT)
|
||||
maxPayloadSize := maxPacketSize - hdr.GetLength(p.version) - protocol.ByteCount(sealer.Overhead())
|
||||
payload := p.maybeGetAppDataPacketWithEncLevel(maxPayloadSize, encLevel == protocol.Encryption1RTT && currentSize == 0)
|
||||
return sealer, hdr, payload
|
||||
payload := p.maybeGetAppDataPacket(maxPayloadSize, false, false)
|
||||
return hdr, payload
|
||||
}
|
||||
|
||||
func (p *packetPacker) maybeGetAppDataPacketWithEncLevel(maxPayloadSize protocol.ByteCount, ackAllowed bool) *payload {
|
||||
payload := p.composeNextPacket(maxPayloadSize, ackAllowed)
|
||||
func (p *packetPacker) maybeGetShortHeaderPacket(sealer handshake.ShortHeaderSealer, maxPacketSize protocol.ByteCount, onlyAck, ackAllowed bool) (*wire.ExtendedHeader, *payload) {
|
||||
hdr := p.getShortHeader(sealer.KeyPhase())
|
||||
maxPayloadSize := maxPacketSize - hdr.GetLength(p.version) - protocol.ByteCount(sealer.Overhead())
|
||||
payload := p.maybeGetAppDataPacket(maxPayloadSize, onlyAck, ackAllowed)
|
||||
return hdr, payload
|
||||
}
|
||||
|
||||
func (p *packetPacker) maybeGetAppDataPacket(maxPayloadSize protocol.ByteCount, onlyAck, ackAllowed bool) *payload {
|
||||
payload := p.composeNextPacket(maxPayloadSize, onlyAck, ackAllowed)
|
||||
|
||||
// check if we have anything to send
|
||||
if len(payload.frames) == 0 {
|
||||
@ -591,35 +566,47 @@ func (p *packetPacker) maybeGetAppDataPacketWithEncLevel(maxPayloadSize protocol
|
||||
return payload
|
||||
}
|
||||
|
||||
func (p *packetPacker) composeNextPacket(maxFrameSize protocol.ByteCount, ackAllowed bool) *payload {
|
||||
payload := &payload{frames: make([]ackhandler.Frame, 0, 1)}
|
||||
|
||||
var hasDatagram bool
|
||||
if p.datagramQueue != nil {
|
||||
if datagram := p.datagramQueue.Get(); datagram != nil {
|
||||
payload.frames = append(payload.frames, ackhandler.Frame{
|
||||
Frame: datagram,
|
||||
// set it to a no-op. Then we won't set the default callback, which would retransmit the frame.
|
||||
OnLost: func(wire.Frame) {},
|
||||
})
|
||||
payload.length += datagram.Length(p.version)
|
||||
hasDatagram = true
|
||||
}
|
||||
}
|
||||
|
||||
var ack *wire.AckFrame
|
||||
hasData := p.framer.HasData()
|
||||
hasRetransmission := p.retransmissionQueue.HasAppData()
|
||||
// TODO: make sure ACKs are sent when a lot of DATAGRAMs are queued
|
||||
if !hasDatagram && ackAllowed {
|
||||
ack = p.acks.GetAckFrame(protocol.Encryption1RTT, !hasRetransmission && !hasData)
|
||||
if ack != nil {
|
||||
func (p *packetPacker) composeNextPacket(maxFrameSize protocol.ByteCount, onlyAck, ackAllowed bool) *payload {
|
||||
if onlyAck {
|
||||
if ack := p.acks.GetAckFrame(protocol.Encryption1RTT, true); ack != nil {
|
||||
payload := &payload{}
|
||||
payload.ack = ack
|
||||
payload.length += ack.Length(p.version)
|
||||
return payload
|
||||
}
|
||||
return &payload{}
|
||||
}
|
||||
|
||||
payload := &payload{frames: make([]ackhandler.Frame, 0, 1)}
|
||||
|
||||
hasData := p.framer.HasData()
|
||||
hasRetransmission := p.retransmissionQueue.HasAppData()
|
||||
|
||||
var hasAck bool
|
||||
if ackAllowed {
|
||||
if ack := p.acks.GetAckFrame(protocol.Encryption1RTT, !hasRetransmission && !hasData); ack != nil {
|
||||
payload.ack = ack
|
||||
payload.length += ack.Length(p.version)
|
||||
hasAck = true
|
||||
}
|
||||
}
|
||||
|
||||
if ack == nil && !hasData && !hasRetransmission {
|
||||
if p.datagramQueue != nil {
|
||||
if f := p.datagramQueue.Peek(); f != nil {
|
||||
size := f.Length(p.version)
|
||||
if size <= maxFrameSize-payload.length {
|
||||
payload.frames = append(payload.frames, ackhandler.Frame{
|
||||
Frame: f,
|
||||
// set it to a no-op. Then we won't set the default callback, which would retransmit the frame.
|
||||
OnLost: func(wire.Frame) {},
|
||||
})
|
||||
payload.length += size
|
||||
p.datagramQueue.Pop()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if hasAck && !hasData && !hasRetransmission {
|
||||
return payload
|
||||
}
|
||||
|
||||
@ -661,14 +648,14 @@ func (p *packetPacker) MaybePackProbePacket(encLevel protocol.EncryptionLevel) (
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
hdr, payload = p.maybeGetCryptoPacket(p.maxPacketSize-protocol.ByteCount(sealer.Overhead()), 0, protocol.EncryptionInitial)
|
||||
hdr, payload = p.maybeGetCryptoPacket(p.maxPacketSize-protocol.ByteCount(sealer.Overhead()), protocol.EncryptionInitial, false, true)
|
||||
case protocol.EncryptionHandshake:
|
||||
var err error
|
||||
sealer, err = p.cryptoSetup.GetHandshakeSealer()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
hdr, payload = p.maybeGetCryptoPacket(p.maxPacketSize-protocol.ByteCount(sealer.Overhead()), 0, protocol.EncryptionHandshake)
|
||||
hdr, payload = p.maybeGetCryptoPacket(p.maxPacketSize-protocol.ByteCount(sealer.Overhead()), protocol.EncryptionHandshake, false, true)
|
||||
case protocol.Encryption1RTT:
|
||||
oneRTTSealer, err := p.cryptoSetup.Get1RTTSealer()
|
||||
if err != nil {
|
||||
@ -676,7 +663,7 @@ func (p *packetPacker) MaybePackProbePacket(encLevel protocol.EncryptionLevel) (
|
||||
}
|
||||
sealer = oneRTTSealer
|
||||
hdr = p.getShortHeader(oneRTTSealer.KeyPhase())
|
||||
payload = p.maybeGetAppDataPacketWithEncLevel(p.maxPacketSize-protocol.ByteCount(sealer.Overhead())-hdr.GetLength(p.version), true)
|
||||
payload = p.maybeGetAppDataPacket(p.maxPacketSize-protocol.ByteCount(sealer.Overhead())-hdr.GetLength(p.version), false, true)
|
||||
default:
|
||||
panic("unknown encryption level")
|
||||
}
|
||||
@ -722,41 +709,6 @@ func (p *packetPacker) PackMTUProbePacket(ping ackhandler.Frame, size protocol.B
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (p *packetPacker) getSealerAndHeader(encLevel protocol.EncryptionLevel) (sealer, *wire.ExtendedHeader, error) {
|
||||
switch encLevel {
|
||||
case protocol.EncryptionInitial:
|
||||
sealer, err := p.cryptoSetup.GetInitialSealer()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
hdr := p.getLongHeader(protocol.EncryptionInitial)
|
||||
return sealer, hdr, nil
|
||||
case protocol.Encryption0RTT:
|
||||
sealer, err := p.cryptoSetup.Get0RTTSealer()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
hdr := p.getLongHeader(protocol.Encryption0RTT)
|
||||
return sealer, hdr, nil
|
||||
case protocol.EncryptionHandshake:
|
||||
sealer, err := p.cryptoSetup.GetHandshakeSealer()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
hdr := p.getLongHeader(protocol.EncryptionHandshake)
|
||||
return sealer, hdr, nil
|
||||
case protocol.Encryption1RTT:
|
||||
sealer, err := p.cryptoSetup.Get1RTTSealer()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
hdr := p.getShortHeader(sealer.KeyPhase())
|
||||
return sealer, hdr, nil
|
||||
default:
|
||||
return nil, nil, fmt.Errorf("unexpected encryption level: %s", encLevel)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *packetPacker) getShortHeader(kp protocol.KeyPhaseBit) *wire.ExtendedHeader {
|
||||
pn, pnLen := p.pnManager.PeekPacketNumber(protocol.Encryption1RTT)
|
||||
hdr := &wire.ExtendedHeader{}
|
||||
@ -791,28 +743,6 @@ func (p *packetPacker) getLongHeader(encLevel protocol.EncryptionLevel) *wire.Ex
|
||||
return hdr
|
||||
}
|
||||
|
||||
// writeSinglePacket packs a single packet.
|
||||
func (p *packetPacker) writeSinglePacket(
|
||||
hdr *wire.ExtendedHeader,
|
||||
payload *payload,
|
||||
encLevel protocol.EncryptionLevel,
|
||||
sealer sealer,
|
||||
) (*packedPacket, error) {
|
||||
buffer := getPacketBuffer()
|
||||
var paddingLen protocol.ByteCount
|
||||
if encLevel == protocol.EncryptionInitial {
|
||||
paddingLen = p.initialPaddingLen(payload.frames, hdr.GetLength(p.version)+payload.length+protocol.ByteCount(sealer.Overhead()))
|
||||
}
|
||||
contents, err := p.appendPacket(buffer, hdr, payload, paddingLen, encLevel, sealer, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &packedPacket{
|
||||
buffer: buffer,
|
||||
packetContents: contents,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (p *packetPacker) appendPacket(buffer *packetBuffer, header *wire.ExtendedHeader, payload *payload, padding protocol.ByteCount, encLevel protocol.EncryptionLevel, sealer sealer, isMTUProbePacket bool) (*packetContents, error) {
|
||||
var paddingLen protocol.ByteCount
|
||||
pnLen := protocol.ByteCount(header.PacketNumberLen)
|
||||
@ -830,35 +760,38 @@ func (p *packetPacker) appendPacket(buffer *packetBuffer, header *wire.ExtendedH
|
||||
return nil, err
|
||||
}
|
||||
payloadOffset := buf.Len()
|
||||
raw := buffer.Data[:payloadOffset]
|
||||
|
||||
if payload.ack != nil {
|
||||
if err := payload.ack.Write(buf, p.version); err != nil {
|
||||
var err error
|
||||
raw, err = payload.ack.Append(raw, p.version)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if paddingLen > 0 {
|
||||
buf.Write(make([]byte, paddingLen))
|
||||
raw = append(raw, make([]byte, paddingLen)...)
|
||||
}
|
||||
for _, frame := range payload.frames {
|
||||
if err := frame.Write(buf, p.version); err != nil {
|
||||
var err error
|
||||
raw, err = frame.Append(raw, p.version)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if payloadSize := protocol.ByteCount(buf.Len()-payloadOffset) - paddingLen; payloadSize != payload.length {
|
||||
if payloadSize := protocol.ByteCount(len(raw)-payloadOffset) - paddingLen; payloadSize != payload.length {
|
||||
return nil, fmt.Errorf("PacketPacker BUG: payload size inconsistent (expected %d, got %d bytes)", payload.length, payloadSize)
|
||||
}
|
||||
if !isMTUProbePacket {
|
||||
if size := protocol.ByteCount(buf.Len() + sealer.Overhead()); size > p.maxPacketSize {
|
||||
if size := protocol.ByteCount(len(raw) + sealer.Overhead()); size > p.maxPacketSize {
|
||||
return nil, fmt.Errorf("PacketPacker BUG: packet too large (%d bytes, allowed %d bytes)", size, p.maxPacketSize)
|
||||
}
|
||||
}
|
||||
|
||||
raw := buffer.Data
|
||||
// encrypt the packet
|
||||
raw = raw[:buf.Len()]
|
||||
_ = sealer.Seal(raw[payloadOffset:payloadOffset], raw[payloadOffset:], header.PacketNumber, raw[hdrOffset:payloadOffset])
|
||||
raw = raw[0 : buf.Len()+sealer.Overhead()]
|
||||
raw = raw[0 : len(raw)+sealer.Overhead()]
|
||||
// apply header protection
|
||||
pnOffset := payloadOffset - int(header.PacketNumberLen)
|
||||
sealer.EncryptHeader(raw[pnOffset+4:pnOffset+4+16], &raw[hdrOffset], raw[pnOffset:payloadOffset])
|
||||
|
106
vendor/github.com/lucas-clemente/quic-go/packet_unpacker.go
generated
vendored
106
vendor/github.com/lucas-clemente/quic-go/packet_unpacker.go
generated
vendored
@ -7,6 +7,7 @@
|
||||
|
||||
"github.com/lucas-clemente/quic-go/internal/handshake"
|
||||
"github.com/lucas-clemente/quic-go/internal/protocol"
|
||||
"github.com/lucas-clemente/quic-go/internal/qerr"
|
||||
"github.com/lucas-clemente/quic-go/internal/wire"
|
||||
)
|
||||
|
||||
@ -27,7 +28,6 @@ func (e *headerParseError) Error() string {
|
||||
}
|
||||
|
||||
type unpackedPacket struct {
|
||||
packetNumber protocol.PacketNumber // the decoded packet number
|
||||
hdr *wire.ExtendedHeader
|
||||
encryptionLevel protocol.EncryptionLevel
|
||||
data []byte
|
||||
@ -37,22 +37,25 @@ type unpackedPacket struct {
|
||||
type packetUnpacker struct {
|
||||
cs handshake.CryptoSetup
|
||||
|
||||
version protocol.VersionNumber
|
||||
shortHdrConnIDLen int
|
||||
version protocol.VersionNumber
|
||||
}
|
||||
|
||||
var _ unpacker = &packetUnpacker{}
|
||||
|
||||
func newPacketUnpacker(cs handshake.CryptoSetup, version protocol.VersionNumber) unpacker {
|
||||
func newPacketUnpacker(cs handshake.CryptoSetup, shortHdrConnIDLen int, version protocol.VersionNumber) unpacker {
|
||||
return &packetUnpacker{
|
||||
cs: cs,
|
||||
version: version,
|
||||
cs: cs,
|
||||
shortHdrConnIDLen: shortHdrConnIDLen,
|
||||
version: version,
|
||||
}
|
||||
}
|
||||
|
||||
// UnpackLongHeader unpacks a Long Header packet.
|
||||
// If the reserved bits are invalid, the error is wire.ErrInvalidReservedBits.
|
||||
// If any other error occurred when parsing the header, the error is of type headerParseError.
|
||||
// If decrypting the payload fails for any reason, the error is the error returned by the AEAD.
|
||||
func (u *packetUnpacker) Unpack(hdr *wire.Header, rcvTime time.Time, data []byte) (*unpackedPacket, error) {
|
||||
func (u *packetUnpacker) UnpackLongHeader(hdr *wire.Header, rcvTime time.Time, data []byte) (*unpackedPacket, error) {
|
||||
var encLevel protocol.EncryptionLevel
|
||||
var extHdr *wire.ExtendedHeader
|
||||
var decrypted []byte
|
||||
@ -89,30 +92,43 @@ func (u *packetUnpacker) Unpack(hdr *wire.Header, rcvTime time.Time, data []byte
|
||||
return nil, err
|
||||
}
|
||||
default:
|
||||
if hdr.IsLongHeader {
|
||||
return nil, fmt.Errorf("unknown packet type: %s", hdr.Type)
|
||||
}
|
||||
encLevel = protocol.Encryption1RTT
|
||||
opener, err := u.cs.Get1RTTOpener()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
extHdr, decrypted, err = u.unpackShortHeaderPacket(opener, hdr, rcvTime, data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("unknown packet type: %s", hdr.Type)
|
||||
}
|
||||
|
||||
if len(decrypted) == 0 {
|
||||
return nil, &qerr.TransportError{
|
||||
ErrorCode: qerr.ProtocolViolation,
|
||||
ErrorMessage: "empty packet",
|
||||
}
|
||||
}
|
||||
|
||||
return &unpackedPacket{
|
||||
hdr: extHdr,
|
||||
packetNumber: extHdr.PacketNumber,
|
||||
encryptionLevel: encLevel,
|
||||
data: decrypted,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (u *packetUnpacker) UnpackShortHeader(rcvTime time.Time, data []byte) (protocol.PacketNumber, protocol.PacketNumberLen, protocol.KeyPhaseBit, []byte, error) {
|
||||
opener, err := u.cs.Get1RTTOpener()
|
||||
if err != nil {
|
||||
return 0, 0, 0, nil, err
|
||||
}
|
||||
pn, pnLen, kp, decrypted, err := u.unpackShortHeaderPacket(opener, rcvTime, data)
|
||||
if err != nil {
|
||||
return 0, 0, 0, nil, err
|
||||
}
|
||||
if len(decrypted) == 0 {
|
||||
return 0, 0, 0, nil, &qerr.TransportError{
|
||||
ErrorCode: qerr.ProtocolViolation,
|
||||
ErrorMessage: "empty packet",
|
||||
}
|
||||
}
|
||||
return pn, pnLen, kp, decrypted, nil
|
||||
}
|
||||
|
||||
func (u *packetUnpacker) unpackLongHeaderPacket(opener handshake.LongHeaderOpener, hdr *wire.Header, data []byte) (*wire.ExtendedHeader, []byte, error) {
|
||||
extHdr, parseErr := u.unpackHeader(opener, hdr, data)
|
||||
extHdr, parseErr := u.unpackLongHeader(opener, hdr, data)
|
||||
// If the reserved bits are set incorrectly, we still need to continue unpacking.
|
||||
// This avoids a timing side-channel, which otherwise might allow an attacker
|
||||
// to gain information about the header encryption.
|
||||
@ -131,41 +147,57 @@ func (u *packetUnpacker) unpackLongHeaderPacket(opener handshake.LongHeaderOpene
|
||||
return extHdr, decrypted, nil
|
||||
}
|
||||
|
||||
func (u *packetUnpacker) unpackShortHeaderPacket(
|
||||
opener handshake.ShortHeaderOpener,
|
||||
hdr *wire.Header,
|
||||
rcvTime time.Time,
|
||||
data []byte,
|
||||
) (*wire.ExtendedHeader, []byte, error) {
|
||||
extHdr, parseErr := u.unpackHeader(opener, hdr, data)
|
||||
func (u *packetUnpacker) unpackShortHeaderPacket(opener handshake.ShortHeaderOpener, rcvTime time.Time, data []byte) (protocol.PacketNumber, protocol.PacketNumberLen, protocol.KeyPhaseBit, []byte, error) {
|
||||
l, pn, pnLen, kp, parseErr := u.unpackShortHeader(opener, data)
|
||||
// If the reserved bits are set incorrectly, we still need to continue unpacking.
|
||||
// This avoids a timing side-channel, which otherwise might allow an attacker
|
||||
// to gain information about the header encryption.
|
||||
if parseErr != nil && parseErr != wire.ErrInvalidReservedBits {
|
||||
return nil, nil, parseErr
|
||||
return 0, 0, 0, nil, &headerParseError{parseErr}
|
||||
}
|
||||
extHdr.PacketNumber = opener.DecodePacketNumber(extHdr.PacketNumber, extHdr.PacketNumberLen)
|
||||
extHdrLen := extHdr.ParsedLen()
|
||||
decrypted, err := opener.Open(data[extHdrLen:extHdrLen], data[extHdrLen:], rcvTime, extHdr.PacketNumber, extHdr.KeyPhase, data[:extHdrLen])
|
||||
pn = opener.DecodePacketNumber(pn, pnLen)
|
||||
decrypted, err := opener.Open(data[l:l], data[l:], rcvTime, pn, kp, data[:l])
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return 0, 0, 0, nil, err
|
||||
}
|
||||
if parseErr != nil {
|
||||
return nil, nil, parseErr
|
||||
return pn, pnLen, kp, decrypted, parseErr
|
||||
}
|
||||
|
||||
func (u *packetUnpacker) unpackShortHeader(hd headerDecryptor, data []byte) (int, protocol.PacketNumber, protocol.PacketNumberLen, protocol.KeyPhaseBit, error) {
|
||||
hdrLen := 1 /* first header byte */ + u.shortHdrConnIDLen
|
||||
if len(data) < hdrLen+4+16 {
|
||||
return 0, 0, 0, 0, fmt.Errorf("packet too small, expected at least 20 bytes after the header, got %d", len(data)-hdrLen)
|
||||
}
|
||||
return extHdr, decrypted, nil
|
||||
origPNBytes := make([]byte, 4)
|
||||
copy(origPNBytes, data[hdrLen:hdrLen+4])
|
||||
// 2. decrypt the header, assuming a 4 byte packet number
|
||||
hd.DecryptHeader(
|
||||
data[hdrLen+4:hdrLen+4+16],
|
||||
&data[0],
|
||||
data[hdrLen:hdrLen+4],
|
||||
)
|
||||
// 3. parse the header (and learn the actual length of the packet number)
|
||||
l, pn, pnLen, kp, parseErr := wire.ParseShortHeader(data, u.shortHdrConnIDLen)
|
||||
if parseErr != nil && parseErr != wire.ErrInvalidReservedBits {
|
||||
return l, pn, pnLen, kp, parseErr
|
||||
}
|
||||
// 4. if the packet number is shorter than 4 bytes, replace the remaining bytes with the copy we saved earlier
|
||||
if pnLen != protocol.PacketNumberLen4 {
|
||||
copy(data[hdrLen+int(pnLen):hdrLen+4], origPNBytes[int(pnLen):])
|
||||
}
|
||||
return l, pn, pnLen, kp, parseErr
|
||||
}
|
||||
|
||||
// The error is either nil, a wire.ErrInvalidReservedBits or of type headerParseError.
|
||||
func (u *packetUnpacker) unpackHeader(hd headerDecryptor, hdr *wire.Header, data []byte) (*wire.ExtendedHeader, error) {
|
||||
extHdr, err := unpackHeader(hd, hdr, data, u.version)
|
||||
func (u *packetUnpacker) unpackLongHeader(hd headerDecryptor, hdr *wire.Header, data []byte) (*wire.ExtendedHeader, error) {
|
||||
extHdr, err := unpackLongHeader(hd, hdr, data, u.version)
|
||||
if err != nil && err != wire.ErrInvalidReservedBits {
|
||||
return nil, &headerParseError{err: err}
|
||||
}
|
||||
return extHdr, err
|
||||
}
|
||||
|
||||
func unpackHeader(hd headerDecryptor, hdr *wire.Header, data []byte, version protocol.VersionNumber) (*wire.ExtendedHeader, error) {
|
||||
func unpackLongHeader(hd headerDecryptor, hdr *wire.Header, data []byte, version protocol.VersionNumber) (*wire.ExtendedHeader, error) {
|
||||
r := bytes.NewReader(data)
|
||||
|
||||
hdrLen := hdr.ParsedLen()
|
||||
|
19
vendor/github.com/lucas-clemente/quic-go/quicvarint/varint.go
generated
vendored
19
vendor/github.com/lucas-clemente/quic-go/quicvarint/varint.go
generated
vendored
@ -88,6 +88,25 @@ func Write(w Writer, i uint64) {
|
||||
}
|
||||
}
|
||||
|
||||
func Append(b []byte, i uint64) []byte {
|
||||
if i <= maxVarInt1 {
|
||||
return append(b, uint8(i))
|
||||
}
|
||||
if i <= maxVarInt2 {
|
||||
return append(b, []byte{uint8(i>>8) | 0x40, uint8(i)}...)
|
||||
}
|
||||
if i <= maxVarInt4 {
|
||||
return append(b, []byte{uint8(i>>24) | 0x80, uint8(i >> 16), uint8(i >> 8), uint8(i)}...)
|
||||
}
|
||||
if i <= maxVarInt8 {
|
||||
return append(b, []byte{
|
||||
uint8(i>>56) | 0xc0, uint8(i >> 48), uint8(i >> 40), uint8(i >> 32),
|
||||
uint8(i >> 24), uint8(i >> 16), uint8(i >> 8), uint8(i),
|
||||
}...)
|
||||
}
|
||||
panic(fmt.Sprintf("%#x doesn't fit into 62 bits", i))
|
||||
}
|
||||
|
||||
// WriteWithLen writes i in the QUIC varint format with the desired length to w.
|
||||
func WriteWithLen(w Writer, i uint64, length protocol.ByteCount) {
|
||||
if length != 1 && length != 2 && length != 4 && length != 8 {
|
||||
|
7
vendor/github.com/lucas-clemente/quic-go/send_queue.go
generated
vendored
7
vendor/github.com/lucas-clemente/quic-go/send_queue.go
generated
vendored
@ -36,6 +36,13 @@ func newSendQueue(conn sendConn) sender {
|
||||
func (h *sendQueue) Send(p *packetBuffer) {
|
||||
select {
|
||||
case h.queue <- p:
|
||||
// clear available channel if we've reached capacity
|
||||
if len(h.queue) == sendQueueCapacity {
|
||||
select {
|
||||
case <-h.available:
|
||||
default:
|
||||
}
|
||||
}
|
||||
case <-h.runStopped:
|
||||
default:
|
||||
panic("sendQueue.Send would have blocked")
|
||||
|
83
vendor/github.com/lucas-clemente/quic-go/server.go
generated
vendored
83
vendor/github.com/lucas-clemente/quic-go/server.go
generated
vendored
@ -320,20 +320,43 @@ func (s *baseServer) handlePacketImpl(p *receivedPacket) bool /* is the buffer s
|
||||
}
|
||||
return false
|
||||
}
|
||||
// Short header packets should never end up here in the first place
|
||||
if !wire.IsLongHeaderPacket(p.data[0]) {
|
||||
panic(fmt.Sprintf("misrouted packet: %#v", p.data))
|
||||
}
|
||||
v, err := wire.ParseVersion(p.data)
|
||||
// send a Version Negotiation Packet if the client is speaking a different protocol version
|
||||
if err != nil || !protocol.IsSupportedVersion(s.config.Versions, v) {
|
||||
if err != nil || p.Size() < protocol.MinUnknownVersionPacketSize {
|
||||
s.logger.Debugf("Dropping a packet with an unknown version that is too small (%d bytes)", p.Size())
|
||||
if s.config.Tracer != nil {
|
||||
s.config.Tracer.DroppedPacket(p.remoteAddr, logging.PacketTypeNotDetermined, p.Size(), logging.PacketDropUnexpectedPacket)
|
||||
}
|
||||
return false
|
||||
}
|
||||
_, src, dest, err := wire.ParseArbitraryLenConnectionIDs(p.data)
|
||||
if err != nil { // should never happen
|
||||
s.logger.Debugf("Dropping a packet with an unknown version for which we failed to parse connection IDs")
|
||||
if s.config.Tracer != nil {
|
||||
s.config.Tracer.DroppedPacket(p.remoteAddr, logging.PacketTypeNotDetermined, p.Size(), logging.PacketDropUnexpectedPacket)
|
||||
}
|
||||
return false
|
||||
}
|
||||
if !s.config.DisableVersionNegotiationPackets {
|
||||
go s.sendVersionNegotiationPacket(p.remoteAddr, src, dest, p.info.OOB())
|
||||
}
|
||||
return false
|
||||
}
|
||||
// If we're creating a new connection, the packet will be passed to the connection.
|
||||
// The header will then be parsed again.
|
||||
hdr, _, _, err := wire.ParsePacket(p.data, s.config.ConnectionIDGenerator.ConnectionIDLen())
|
||||
if err != nil && err != wire.ErrUnsupportedVersion {
|
||||
if err != nil {
|
||||
if s.config.Tracer != nil {
|
||||
s.config.Tracer.DroppedPacket(p.remoteAddr, logging.PacketTypeNotDetermined, p.Size(), logging.PacketDropHeaderParseError)
|
||||
}
|
||||
s.logger.Debugf("Error parsing packet: %s", err)
|
||||
return false
|
||||
}
|
||||
// Short header packets should never end up here in the first place
|
||||
if !hdr.IsLongHeader {
|
||||
panic(fmt.Sprintf("misrouted packet: %#v", hdr))
|
||||
}
|
||||
if hdr.Type == protocol.PacketTypeInitial && p.Size() < protocol.MinInitialPacketSize {
|
||||
s.logger.Debugf("Dropping a packet that is too small to be a valid Initial (%d bytes)", p.Size())
|
||||
if s.config.Tracer != nil {
|
||||
@ -341,20 +364,7 @@ func (s *baseServer) handlePacketImpl(p *receivedPacket) bool /* is the buffer s
|
||||
}
|
||||
return false
|
||||
}
|
||||
// send a Version Negotiation Packet if the client is speaking a different protocol version
|
||||
if !protocol.IsSupportedVersion(s.config.Versions, hdr.Version) {
|
||||
if p.Size() < protocol.MinUnknownVersionPacketSize {
|
||||
s.logger.Debugf("Dropping a packet with an unknown version that is too small (%d bytes)", p.Size())
|
||||
if s.config.Tracer != nil {
|
||||
s.config.Tracer.DroppedPacket(p.remoteAddr, logging.PacketTypeNotDetermined, p.Size(), logging.PacketDropUnexpectedPacket)
|
||||
}
|
||||
return false
|
||||
}
|
||||
if !s.config.DisableVersionNegotiationPackets {
|
||||
go s.sendVersionNegotiationPacket(p, hdr)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
if hdr.IsLongHeader && hdr.Type != protocol.PacketTypeInitial {
|
||||
// Drop long header packets.
|
||||
// There's little point in sending a Stateless Reset, since the client
|
||||
@ -467,7 +477,7 @@ func (s *baseServer) handleInitialImpl(p *receivedPacket, hdr *wire.Header) erro
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.logger.Debugf("Changing connection ID to %s.", protocol.ConnectionID(connID))
|
||||
s.logger.Debugf("Changing connection ID to %s.", connID)
|
||||
var conn quicConn
|
||||
tracingID := nextConnTracingID()
|
||||
if added := s.connHandler.AddWithConnID(hdr.DestConnectionID, connID, func() packetHandler {
|
||||
@ -565,7 +575,7 @@ func (s *baseServer) sendRetry(remoteAddr net.Addr, hdr *wire.Header, info *pack
|
||||
replyHdr.DestConnectionID = hdr.SrcConnectionID
|
||||
replyHdr.Token = token
|
||||
if s.logger.Debug() {
|
||||
s.logger.Debugf("Changing connection ID to %s.", protocol.ConnectionID(srcConnID))
|
||||
s.logger.Debugf("Changing connection ID to %s.", srcConnID)
|
||||
s.logger.Debugf("-> Sending Retry")
|
||||
replyHdr.Log(s.logger)
|
||||
}
|
||||
@ -591,7 +601,7 @@ func (s *baseServer) maybeSendInvalidToken(p *receivedPacket, hdr *wire.Header)
|
||||
// This makes sure that we won't send it for packets that were corrupted.
|
||||
sealer, opener := handshake.NewInitialAEAD(hdr.DestConnectionID, protocol.PerspectiveServer, hdr.Version)
|
||||
data := p.data[:hdr.ParsedLen()+hdr.Length]
|
||||
extHdr, err := unpackHeader(opener, hdr, data, hdr.Version)
|
||||
extHdr, err := unpackLongHeader(opener, hdr, data, hdr.Version)
|
||||
if err != nil {
|
||||
if s.config.Tracer != nil {
|
||||
s.config.Tracer.DroppedPacket(p.remoteAddr, logging.PacketTypeInitial, p.Size(), logging.PacketDropHeaderParseError)
|
||||
@ -639,13 +649,14 @@ func (s *baseServer) sendError(remoteAddr net.Addr, hdr *wire.Header, sealer han
|
||||
}
|
||||
payloadOffset := buf.Len()
|
||||
|
||||
if err := ccf.Write(buf, hdr.Version); err != nil {
|
||||
raw := buf.Bytes()
|
||||
raw, err := ccf.Append(raw, hdr.Version)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
raw := buf.Bytes()
|
||||
_ = sealer.Seal(raw[payloadOffset:payloadOffset], raw[payloadOffset:], replyHdr.PacketNumber, raw[:payloadOffset])
|
||||
raw = raw[0 : buf.Len()+sealer.Overhead()]
|
||||
raw = raw[0 : len(raw)+sealer.Overhead()]
|
||||
|
||||
pnOffset := payloadOffset - int(replyHdr.PacketNumberLen)
|
||||
sealer.EncryptHeader(
|
||||
@ -659,26 +670,18 @@ func (s *baseServer) sendError(remoteAddr net.Addr, hdr *wire.Header, sealer han
|
||||
if s.config.Tracer != nil {
|
||||
s.config.Tracer.SentPacket(remoteAddr, &replyHdr.Header, protocol.ByteCount(len(raw)), []logging.Frame{ccf})
|
||||
}
|
||||
_, err := s.conn.WritePacket(raw, remoteAddr, info.OOB())
|
||||
_, err = s.conn.WritePacket(raw, remoteAddr, info.OOB())
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *baseServer) sendVersionNegotiationPacket(p *receivedPacket, hdr *wire.Header) {
|
||||
s.logger.Debugf("Client offered version %s, sending Version Negotiation", hdr.Version)
|
||||
data := wire.ComposeVersionNegotiation(hdr.SrcConnectionID, hdr.DestConnectionID, s.config.Versions)
|
||||
func (s *baseServer) sendVersionNegotiationPacket(remote net.Addr, src, dest protocol.ArbitraryLenConnectionID, oob []byte) {
|
||||
s.logger.Debugf("Client offered version %s, sending Version Negotiation")
|
||||
|
||||
data := wire.ComposeVersionNegotiation(dest, src, s.config.Versions)
|
||||
if s.config.Tracer != nil {
|
||||
s.config.Tracer.SentPacket(
|
||||
p.remoteAddr,
|
||||
&wire.Header{
|
||||
IsLongHeader: true,
|
||||
DestConnectionID: hdr.SrcConnectionID,
|
||||
SrcConnectionID: hdr.DestConnectionID,
|
||||
},
|
||||
protocol.ByteCount(len(data)),
|
||||
nil,
|
||||
)
|
||||
s.config.Tracer.SentVersionNegotiationPacket(remote, src, dest, s.config.Versions)
|
||||
}
|
||||
if _, err := s.conn.WritePacket(data, p.remoteAddr, p.info.OOB()); err != nil {
|
||||
if _, err := s.conn.WritePacket(data, remote, oob); err != nil {
|
||||
s.logger.Debugf("Error sending Version Negotiation: %s", err)
|
||||
}
|
||||
}
|
||||
|
9
vendor/github.com/lucas-clemente/quic-go/sys_conn_oob.go
generated
vendored
9
vendor/github.com/lucas-clemente/quic-go/sys_conn_oob.go
generated
vendored
@ -122,10 +122,15 @@ func newConn(c OOBCapablePacketConn) (*oobConn, error) {
|
||||
bc = ipv4.NewPacketConn(c)
|
||||
}
|
||||
|
||||
msgs := make([]ipv4.Message, batchSize)
|
||||
for i := range msgs {
|
||||
// preallocate the [][]byte
|
||||
msgs[i].Buffers = make([][]byte, 1)
|
||||
}
|
||||
oobConn := &oobConn{
|
||||
OOBCapablePacketConn: c,
|
||||
batchConn: bc,
|
||||
messages: make([]ipv4.Message, batchSize),
|
||||
messages: msgs,
|
||||
readPos: batchSize,
|
||||
}
|
||||
for i := 0; i < batchSize; i++ {
|
||||
@ -142,7 +147,7 @@ func (c *oobConn) ReadPacket() (*receivedPacket, error) {
|
||||
buffer := getPacketBuffer()
|
||||
buffer.Data = buffer.Data[:protocol.MaxPacketBufferSize]
|
||||
c.buffers[i] = buffer
|
||||
c.messages[i].Buffers = [][]byte{c.buffers[i].Data}
|
||||
c.messages[i].Buffers[0] = c.buffers[i].Data
|
||||
}
|
||||
c.readPos = 0
|
||||
|
||||
|
2
vendor/github.com/lucas-clemente/quic-go/tools.go
generated
vendored
2
vendor/github.com/lucas-clemente/quic-go/tools.go
generated
vendored
@ -4,5 +4,5 @@
|
||||
|
||||
import (
|
||||
_ "github.com/golang/mock/mockgen"
|
||||
_ "github.com/onsi/ginkgo/ginkgo"
|
||||
_ "github.com/onsi/ginkgo/v2/ginkgo"
|
||||
)
|
||||
|
3
vendor/github.com/marten-seemann/qpack/README.md
generated
vendored
3
vendor/github.com/marten-seemann/qpack/README.md
generated
vendored
@ -1,10 +1,9 @@
|
||||
# QPACK
|
||||
|
||||
[![Godoc Reference](https://img.shields.io/badge/godoc-reference-blue.svg?style=flat-square)](https://godoc.org/github.com/marten-seemann/qpack)
|
||||
[![CircleCI Build Status](https://img.shields.io/circleci/project/github/marten-seemann/qpack.svg?style=flat-square&label=CircleCI+build)](https://circleci.com/gh/marten-seemann/qpack)
|
||||
[![Code Coverage](https://img.shields.io/codecov/c/github/marten-seemann/qpack/master.svg?style=flat-square)](https://codecov.io/gh/marten-seemann/qpack)
|
||||
|
||||
This is a minimal QPACK implementation in Go. It is minimal in the sense that it doesn't use the dynamic table at all, but just the static table and (Huffman encoded) string literals. Wherever possible, it reuses code from the [HPACK implementation in the Go standard library](https://github.com/golang/net/tree/master/http2/hpack).
|
||||
This is a minimal QPACK ([RFC 9204](https://datatracker.ietf.org/doc/html/rfc9204)) implementation in Go. It is minimal in the sense that it doesn't use the dynamic table at all, but just the static table and (Huffman encoded) string literals. Wherever possible, it reuses code from the [HPACK implementation in the Go standard library](https://github.com/golang/net/tree/master/http2/hpack).
|
||||
|
||||
It should be able to interoperate with other QPACK implemetations (both encoders and decoders), however it won't achieve a high compression efficiency.
|
||||
|
||||
|
4
vendor/github.com/marten-seemann/qpack/encoder.go
generated
vendored
4
vendor/github.com/marten-seemann/qpack/encoder.go
generated
vendored
@ -51,9 +51,9 @@ func (e *Encoder) WriteField(f HeaderField) error {
|
||||
e.writeLiteralFieldWithoutNameReference(f)
|
||||
}
|
||||
|
||||
e.w.Write(e.buf)
|
||||
_, err := e.w.Write(e.buf)
|
||||
e.buf = e.buf[:0]
|
||||
return nil
|
||||
return err
|
||||
}
|
||||
|
||||
// Close declares that the encoding is complete and resets the Encoder
|
||||
|
1
vendor/github.com/marten-seemann/qpack/static_table.go
generated
vendored
1
vendor/github.com/marten-seemann/qpack/static_table.go
generated
vendored
@ -104,6 +104,7 @@
|
||||
|
||||
// Only needed for tests.
|
||||
// use go:linkname to retrieve the static table.
|
||||
//
|
||||
//nolint:deadcode,unused
|
||||
func getStaticTable() []HeaderField {
|
||||
return staticTableEntries[:]
|
||||
|
3
vendor/github.com/nxadm/tail/.gitignore
generated
vendored
3
vendor/github.com/nxadm/tail/.gitignore
generated
vendored
@ -1,3 +0,0 @@
|
||||
.idea/
|
||||
.test/
|
||||
examples/_*
|
56
vendor/github.com/nxadm/tail/CHANGES.md
generated
vendored
56
vendor/github.com/nxadm/tail/CHANGES.md
generated
vendored
@ -1,56 +0,0 @@
|
||||
# Version v1.4.7-v1.4.8
|
||||
* Documentation updates.
|
||||
* Small linter cleanups.
|
||||
* Added example in test.
|
||||
|
||||
# Version v1.4.6
|
||||
|
||||
* Document the usage of Cleanup when re-reading a file (thanks to @lesovsky) for issue #18.
|
||||
* Add example directories with example and tests for issues.
|
||||
|
||||
# Version v1.4.4-v1.4.5
|
||||
|
||||
* Fix of checksum problem because of forced tag. No changes to the code.
|
||||
|
||||
# Version v1.4.1
|
||||
|
||||
* Incorporated PR 162 by by Mohammed902: "Simplify non-Windows build tag".
|
||||
|
||||
# Version v1.4.0
|
||||
|
||||
* Incorporated PR 9 by mschneider82: "Added seekinfo to Tail".
|
||||
|
||||
# Version v1.3.1
|
||||
|
||||
* Incorporated PR 7: "Fix deadlock when stopping on non-empty file/buffer",
|
||||
fixes upstream issue 93.
|
||||
|
||||
|
||||
# Version v1.3.0
|
||||
|
||||
* Incorporated changes of unmerged upstream PR 149 by mezzi: "added line num
|
||||
to Line struct".
|
||||
|
||||
# Version v1.2.1
|
||||
|
||||
* Incorporated changes of unmerged upstream PR 128 by jadekler: "Compile-able
|
||||
code in readme".
|
||||
* Incorporated changes of unmerged upstream PR 130 by fgeller: "small change
|
||||
to comment wording".
|
||||
* Incorporated changes of unmerged upstream PR 133 by sm3142: "removed
|
||||
spurious newlines from log messages".
|
||||
|
||||
# Version v1.2.0
|
||||
|
||||
* Incorporated changes of unmerged upstream PR 126 by Code-Hex: "Solved the
|
||||
problem for never return the last line if it's not followed by a newline".
|
||||
* Incorporated changes of unmerged upstream PR 131 by StoicPerlman: "Remove
|
||||
deprecated os.SEEK consts". The changes bumped the minimal supported Go
|
||||
release to 1.9.
|
||||
|
||||
# Version v1.1.0
|
||||
|
||||
* migration to go modules.
|
||||
* release of master branch of the dormant upstream, because it contains
|
||||
fixes and improvement no present in the tagged release.
|
||||
|
19
vendor/github.com/nxadm/tail/Dockerfile
generated
vendored
19
vendor/github.com/nxadm/tail/Dockerfile
generated
vendored
@ -1,19 +0,0 @@
|
||||
FROM golang
|
||||
|
||||
RUN mkdir -p $GOPATH/src/github.com/nxadm/tail/
|
||||
ADD . $GOPATH/src/github.com/nxadm/tail/
|
||||
|
||||
# expecting to fetch dependencies successfully.
|
||||
RUN go get -v github.com/nxadm/tail
|
||||
|
||||
# expecting to run the test successfully.
|
||||
RUN go test -v github.com/nxadm/tail
|
||||
|
||||
# expecting to install successfully
|
||||
RUN go install -v github.com/nxadm/tail
|
||||
RUN go install -v github.com/nxadm/tail/cmd/gotail
|
||||
|
||||
RUN $GOPATH/bin/gotail -h || true
|
||||
|
||||
ENV PATH $GOPATH/bin:$PATH
|
||||
CMD ["gotail"]
|
21
vendor/github.com/nxadm/tail/LICENSE
generated
vendored
21
vendor/github.com/nxadm/tail/LICENSE
generated
vendored
@ -1,21 +0,0 @@
|
||||
# The MIT License (MIT)
|
||||
|
||||
# © Copyright 2015 Hewlett Packard Enterprise Development LP
|
||||
Copyright (c) 2014 ActiveState
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
44
vendor/github.com/nxadm/tail/README.md
generated
vendored
44
vendor/github.com/nxadm/tail/README.md
generated
vendored
@ -1,44 +0,0 @@
|
||||
![ci](https://github.com/nxadm/tail/workflows/ci/badge.svg)[![Go Reference](https://pkg.go.dev/badge/github.com/nxadm/tail.svg)](https://pkg.go.dev/github.com/nxadm/tail)
|
||||
|
||||
# tail functionality in Go
|
||||
|
||||
nxadm/tail provides a Go library that emulates the features of the BSD `tail`
|
||||
program. The library comes with full support for truncation/move detection as
|
||||
it is designed to work with log rotation tools. The library works on all
|
||||
operating systems supported by Go, including POSIX systems like Linux and
|
||||
*BSD, and MS Windows. Go 1.9 is the oldest compiler release supported.
|
||||
|
||||
A simple example:
|
||||
|
||||
```Go
|
||||
// Create a tail
|
||||
t, err := tail.TailFile(
|
||||
"/var/log/nginx.log", tail.Config{Follow: true, ReOpen: true})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Print the text of each received line
|
||||
for line := range t.Lines {
|
||||
fmt.Println(line.Text)
|
||||
}
|
||||
```
|
||||
|
||||
See [API documentation](https://pkg.go.dev/github.com/nxadm/tail).
|
||||
|
||||
## Installing
|
||||
|
||||
go get github.com/nxadm/tail/...
|
||||
|
||||
## History
|
||||
|
||||
This project is an active, drop-in replacement for the
|
||||
[abandoned](https://en.wikipedia.org/wiki/HPE_Helion) Go tail library at
|
||||
[hpcloud](https://github.com/hpcloud/tail). Next to
|
||||
[addressing open issues/PRs of the original project](https://github.com/nxadm/tail/issues/6),
|
||||
nxadm/tail continues the development by keeping up to date with the Go toolchain
|
||||
(e.g. go modules) and dependencies, completing the documentation, adding features
|
||||
and fixing bugs.
|
||||
|
||||
## Examples
|
||||
Examples, e.g. used to debug an issue, are kept in the [examples directory](/examples).
|
7
vendor/github.com/nxadm/tail/ratelimiter/Licence
generated
vendored
7
vendor/github.com/nxadm/tail/ratelimiter/Licence
generated
vendored
@ -1,7 +0,0 @@
|
||||
Copyright (C) 2013 99designs
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
97
vendor/github.com/nxadm/tail/ratelimiter/leakybucket.go
generated
vendored
97
vendor/github.com/nxadm/tail/ratelimiter/leakybucket.go
generated
vendored
@ -1,97 +0,0 @@
|
||||
// Package ratelimiter implements the Leaky Bucket ratelimiting algorithm with memcached and in-memory backends.
|
||||
package ratelimiter
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
type LeakyBucket struct {
|
||||
Size uint16
|
||||
Fill float64
|
||||
LeakInterval time.Duration // time.Duration for 1 unit of size to leak
|
||||
Lastupdate time.Time
|
||||
Now func() time.Time
|
||||
}
|
||||
|
||||
func NewLeakyBucket(size uint16, leakInterval time.Duration) *LeakyBucket {
|
||||
bucket := LeakyBucket{
|
||||
Size: size,
|
||||
Fill: 0,
|
||||
LeakInterval: leakInterval,
|
||||
Now: time.Now,
|
||||
Lastupdate: time.Now(),
|
||||
}
|
||||
|
||||
return &bucket
|
||||
}
|
||||
|
||||
func (b *LeakyBucket) updateFill() {
|
||||
now := b.Now()
|
||||
if b.Fill > 0 {
|
||||
elapsed := now.Sub(b.Lastupdate)
|
||||
|
||||
b.Fill -= float64(elapsed) / float64(b.LeakInterval)
|
||||
if b.Fill < 0 {
|
||||
b.Fill = 0
|
||||
}
|
||||
}
|
||||
b.Lastupdate = now
|
||||
}
|
||||
|
||||
func (b *LeakyBucket) Pour(amount uint16) bool {
|
||||
b.updateFill()
|
||||
|
||||
var newfill float64 = b.Fill + float64(amount)
|
||||
|
||||
if newfill > float64(b.Size) {
|
||||
return false
|
||||
}
|
||||
|
||||
b.Fill = newfill
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// The time at which this bucket will be completely drained
|
||||
func (b *LeakyBucket) DrainedAt() time.Time {
|
||||
return b.Lastupdate.Add(time.Duration(b.Fill * float64(b.LeakInterval)))
|
||||
}
|
||||
|
||||
// The duration until this bucket is completely drained
|
||||
func (b *LeakyBucket) TimeToDrain() time.Duration {
|
||||
return b.DrainedAt().Sub(b.Now())
|
||||
}
|
||||
|
||||
func (b *LeakyBucket) TimeSinceLastUpdate() time.Duration {
|
||||
return b.Now().Sub(b.Lastupdate)
|
||||
}
|
||||
|
||||
type LeakyBucketSer struct {
|
||||
Size uint16
|
||||
Fill float64
|
||||
LeakInterval time.Duration // time.Duration for 1 unit of size to leak
|
||||
Lastupdate time.Time
|
||||
}
|
||||
|
||||
func (b *LeakyBucket) Serialise() *LeakyBucketSer {
|
||||
bucket := LeakyBucketSer{
|
||||
Size: b.Size,
|
||||
Fill: b.Fill,
|
||||
LeakInterval: b.LeakInterval,
|
||||
Lastupdate: b.Lastupdate,
|
||||
}
|
||||
|
||||
return &bucket
|
||||
}
|
||||
|
||||
func (b *LeakyBucketSer) DeSerialise() *LeakyBucket {
|
||||
bucket := LeakyBucket{
|
||||
Size: b.Size,
|
||||
Fill: b.Fill,
|
||||
LeakInterval: b.LeakInterval,
|
||||
Lastupdate: b.Lastupdate,
|
||||
Now: time.Now,
|
||||
}
|
||||
|
||||
return &bucket
|
||||
}
|
60
vendor/github.com/nxadm/tail/ratelimiter/memory.go
generated
vendored
60
vendor/github.com/nxadm/tail/ratelimiter/memory.go
generated
vendored
@ -1,60 +0,0 @@
|
||||
package ratelimiter
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
GC_SIZE int = 100
|
||||
GC_PERIOD time.Duration = 60 * time.Second
|
||||
)
|
||||
|
||||
type Memory struct {
|
||||
store map[string]LeakyBucket
|
||||
lastGCCollected time.Time
|
||||
}
|
||||
|
||||
func NewMemory() *Memory {
|
||||
m := new(Memory)
|
||||
m.store = make(map[string]LeakyBucket)
|
||||
m.lastGCCollected = time.Now()
|
||||
return m
|
||||
}
|
||||
|
||||
func (m *Memory) GetBucketFor(key string) (*LeakyBucket, error) {
|
||||
|
||||
bucket, ok := m.store[key]
|
||||
if !ok {
|
||||
return nil, errors.New("miss")
|
||||
}
|
||||
|
||||
return &bucket, nil
|
||||
}
|
||||
|
||||
func (m *Memory) SetBucketFor(key string, bucket LeakyBucket) error {
|
||||
|
||||
if len(m.store) > GC_SIZE {
|
||||
m.GarbageCollect()
|
||||
}
|
||||
|
||||
m.store[key] = bucket
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Memory) GarbageCollect() {
|
||||
now := time.Now()
|
||||
|
||||
// rate limit GC to once per minute
|
||||
if now.Unix() >= m.lastGCCollected.Add(GC_PERIOD).Unix() {
|
||||
for key, bucket := range m.store {
|
||||
// if the bucket is drained, then GC
|
||||
if bucket.DrainedAt().Unix() < now.Unix() {
|
||||
delete(m.store, key)
|
||||
}
|
||||
}
|
||||
|
||||
m.lastGCCollected = now
|
||||
}
|
||||
}
|
6
vendor/github.com/nxadm/tail/ratelimiter/storage.go
generated
vendored
6
vendor/github.com/nxadm/tail/ratelimiter/storage.go
generated
vendored
@ -1,6 +0,0 @@
|
||||
package ratelimiter
|
||||
|
||||
type Storage interface {
|
||||
GetBucketFor(string) (*LeakyBucket, error)
|
||||
SetBucketFor(string, LeakyBucket) error
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user