diff --git a/cmd/pggat/pgbouncer.go b/cmd/pggat/pgbouncer.go index 4fe2f957a4c5b74a0040857b730b2c0720245d11..52dcf980bd7379b09a877e5ff1371d542debc612 100644 --- a/cmd/pggat/pgbouncer.go +++ b/cmd/pggat/pgbouncer.go @@ -6,7 +6,8 @@ import ( "github.com/caddyserver/caddy/v2" "github.com/caddyserver/caddy/v2/caddyconfig" - caddycmd "github.com/caddyserver/caddy/v2/cmd" + + caddycmd "gfx.cafe/gfx/pggat/cmd" "gfx.cafe/gfx/pggat/lib/gat" "gfx.cafe/gfx/pggat/lib/gat/handlers/pgbouncer" diff --git a/go.mod b/go.mod index 706ee3ef0a02205ea95d65c8de93efd4799b8496..074e963d7513bedf790fdb2c1ad7bffd8ae2668c 100644 --- a/go.mod +++ b/go.mod @@ -17,6 +17,10 @@ require ( require ( cloud.google.com/go/compute v1.20.1 // indirect cloud.google.com/go/compute/metadata v0.2.3 // indirect + gfx.cafe/util/temple v0.0.0-20230312041217-0882540e78eb // indirect + github.com/Masterminds/goutils v1.1.1 // indirect + github.com/Masterminds/semver/v3 v3.2.0 // indirect + github.com/Masterminds/sprig/v3 v3.2.3 // indirect github.com/aryann/difflib v0.0.0-20210328193216-ff5ff6dc229b // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/caddyserver/certmagic v0.19.2 // indirect @@ -43,6 +47,8 @@ require ( github.com/googleapis/gax-go/v2 v2.11.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-retryablehttp v0.7.4 // indirect + github.com/huandu/xstrings v1.3.3 // indirect + github.com/iancoleman/strcase v0.2.0 // indirect github.com/imdario/mergo v0.3.12 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/josharian/intern v1.0.0 // indirect @@ -54,6 +60,8 @@ require ( github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect github.com/mholt/acmez v1.2.0 // indirect github.com/miekg/dns v1.1.55 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/motomux/pretty v0.0.0-20161209205251-b2aad2c9a95d // indirect @@ -67,7 +75,10 @@ require ( github.com/quic-go/qtls-go1-20 v0.3.1 // indirect github.com/quic-go/quic-go v0.37.5 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect + github.com/shopspring/decimal v1.2.0 // indirect github.com/sirupsen/logrus v1.9.3 // indirect + github.com/spf13/afero v1.9.3 // indirect + github.com/spf13/cast v1.4.1 // indirect github.com/spf13/cobra v1.7.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/xdg-go/stringprep v1.0.4 // indirect diff --git a/go.sum b/go.sum index 91e67319bb9289efbb9802a3f740a5306fbb6e00..d055e4f6894991cb9266b8f653fdc34f6c1e2e62 100644 --- a/go.sum +++ b/go.sum @@ -3,6 +3,7 @@ cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMT cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= @@ -13,6 +14,9 @@ cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKV cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= +cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= +cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= @@ -34,11 +38,20 @@ cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0Zeo cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= gfx.cafe/ghalliday1/scram v0.0.2 h1:uuScaL7DUEP/lKWJnA5kKHq5RJev26q8DMbP3gKviAg= gfx.cafe/ghalliday1/scram v0.0.2/go.mod h1:qt6+WJoFcX2id67G5w+/dktBJ56Se0sZAa7WjqfNNu0= +gfx.cafe/util/temple v0.0.0-20230312041217-0882540e78eb h1:E6gfSdAD5eBWHD5cLktd/umyivQlFTvEzoadoM33g3M= +gfx.cafe/util/temple v0.0.0-20230312041217-0882540e78eb/go.mod h1:rDv4JeaN6NFCUXiNiewrmQnvm7npR7XbJ1jsturNDhc= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= +github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= +github.com/Masterminds/semver/v3 v3.2.0 h1:3MEsd0SM6jqZojhjLWWeBY+Kcjy9i6MQAeY7YgDP83g= +github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= +github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj9n6YA= +github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= @@ -66,6 +79,7 @@ github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5P github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= @@ -85,6 +99,7 @@ github.com/emicklei/go-restful/v3 v3.9.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= @@ -172,6 +187,7 @@ github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= @@ -179,11 +195,15 @@ 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-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/s2a-go v0.1.4 h1:1kZ/sQM3srePvKs3tXAvQzo66XfcReoqFpIpIccE7Oc= github.com/google/s2a-go v0.1.4/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -193,6 +213,7 @@ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gax-go/v2 v2.11.0 h1:9V9PWXEsWnPpQhu/PeQIkS4eGzMlTLGgt80cUUI8Ki4= github.com/googleapis/gax-go/v2 v2.11.0/go.mod h1:DxmR61SGKkGLa2xigwuZIQpkCI2S5iydzRfb3peWZJI= +github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= @@ -202,8 +223,13 @@ github.com/hashicorp/go-retryablehttp v0.7.4 h1:ZQgVdpTdAL7WpMIwLzCfbalOcSUdkDZn github.com/hashicorp/go-retryablehttp v0.7.4/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/huandu/xstrings v1.3.3 h1:/Gcsuc1x8JVbJ9/rlye4xZnVAbEkGauT8lbebqcQws4= +github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= +github.com/iancoleman/strcase v0.2.0 h1:05I4QRnGpI0m37iZQRuskXh+w77mr6Z41lwQzuHLwW0= +github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= @@ -227,6 +253,7 @@ github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/q github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= @@ -246,6 +273,12 @@ github.com/mholt/acmez v1.2.0 h1:1hhLxSgY5FvH5HCnGUuwbKY2VQVo8IU7rxXKSnZ7F30= github.com/mholt/acmez v1.2.0/go.mod h1:VT9YwH1xgNX1kmYY89gY8xPJC84BFAisjo8Egigt4kE= github.com/miekg/dns v1.1.55 h1:GoQ4hpsj0nFLYe+bWiCToyrBEJXkQfOOIvFGFy0lEgo= github.com/miekg/dns v1.1.55/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY= +github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -265,6 +298,7 @@ github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= @@ -304,11 +338,18 @@ github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= +github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/spf13/afero v1.9.3 h1:41FoI0fD7OR7mGcKE/aOiLkGreyf8ifIOQmJANWogMk= +github.com/spf13/afero v1.9.3/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= +github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cast v1.4.1 h1:s0hze+J0196ZfEMTs80N7UlFt0BDuQ7Q+JDnHiMWKdA= +github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= @@ -349,6 +390,7 @@ go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= @@ -363,8 +405,11 @@ golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 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-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220314234659-1baeb1ce4c0b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk= golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -391,6 +436,7 @@ golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= @@ -399,6 +445,8 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 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.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU= @@ -432,7 +480,10 @@ golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81R 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-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 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-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= @@ -440,6 +491,7 @@ golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14= golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -447,6 +499,10 @@ golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4Iltr golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= golang.org/x/oauth2 v0.8.0 h1:6dkIjl3j3LtZ/O3sTgZTMsLKSftL/B8Zgq4huOIIUu8= @@ -495,11 +551,17 @@ golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -508,11 +570,13 @@ golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.11.0 h1:F9tnn/DA/Im8nCwm+fX+1/eBwi4qFjRT++MhtVC4ZX0= golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -520,9 +584,11 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 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.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -571,7 +637,14 @@ golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= +golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.10.0 h1:tvDr/iQoUqNdohiYm0LmmKcBk+q86lb9EprIUFhHHGg= @@ -596,6 +669,9 @@ google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0M google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= +google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= +google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= google.golang.org/api v0.126.0 h1:q4GJq+cAdMAC7XP7njvQ4tvohGLiSlytuL4BQxbIZ+o= google.golang.org/api v0.126.0/go.mod h1:mBwVAtz+87bEN6CbA1GtZPDOqY2R5ONPqJeIlvyo4Aw= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= @@ -636,7 +712,14 @@ google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7Fc google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20230706204954-ccb25ca9f130 h1:Au6te5hbKUV8pIYWHqOUZ1pva5qK/rwbIhoXEUB9Lu8= google.golang.org/genproto/googleapis/api v0.0.0-20230706204954-ccb25ca9f130 h1:XVeBY8d/FaK4848myy41HBqnDwvxeV3zMZhwN1TvAMU= google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 h1:bVf09lpb+OJbByTj913DRJioFFAjf/ZGxEz7MajTp2U= @@ -653,8 +736,11 @@ google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKa google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= +google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= google.golang.org/grpc v1.56.2 h1:fVRFRnXvU+x6C4IlHZewvJOVHoOv1TUuQyoRsYnB4bI= diff --git a/hack/packetgen/main.go b/hack/packetgen/main.go new file mode 100644 index 0000000000000000000000000000000000000000..c6d4f14eb0b353b75bc067c5acce5997a5cea701 --- /dev/null +++ b/hack/packetgen/main.go @@ -0,0 +1,29 @@ +package main + +import ( + _ "embed" + "fmt" + + "gfx.cafe/util/temple" + "gfx.cafe/util/temple/lib/prayer" +) + +func main() { + var idx int + var obj any + temple.RegisterTemplateDir("templates") + temple.ReadObjectFile(&obj, "protocol.yaml") + temple.RegisterFunc("temp", func() string { + idx++ + return fmt.Sprintf("temp%d", idx) + }) + temple.Prepare(&prayer.Go{ + Input: "packets", + Obj: obj, + Package: "packets", + Output: "out/packets.go", + }) + if err := temple.Pray(); err != nil { + panic(err) + } +} diff --git a/hack/packetgen/protocol.yaml b/hack/packetgen/protocol.yaml new file mode 100644 index 0000000000000000000000000000000000000000..85ccc00cec583acfbe6cc213fed2bb7f0560d142 --- /dev/null +++ b/hack/packetgen/protocol.yaml @@ -0,0 +1,382 @@ +Packets: + Startup: + Struct: + Name: Payload + Fields: + - Name: Mode + Map: + Name: Mode + Prefix: + Basic: int16 + Items: + Version3: + Type: 3 + Struct: + Name: Payload + Fields: + - Name: MinorVersion + Basic: int16 + - Name: Parameters + ZeroTerminatedSlice: + Name: Parameter + Fields: + - Name: Key + Basic: string + - Name: Value + Basic: string + Control: + Type: 1234 + Struct: + Name: Payload + Fields: + - Name: Mode + Map: + Name: Mode + Prefix: + Basic: int16 + Items: + Cancel: + Type: 5678 + Struct: + Name: Key + Fields: + - Name: ProcessID + Basic: int32 + - Name: SecretKey + Basic: int32 + SSL: + Type: 5679 + GSSAPI: + Type: 5680 + Authentication: + Type: 'R' + Struct: + Name: Payload + Fields: + - Name: Mode + Map: + Name: Mode + Prefix: + Basic: int32 + Items: + Ok: + Type: 0 + KerberosV5: + Type: 2 + CleartextPassword: + Type: 3 + MD5Password: + Type: 5 + Array: + Length: 4 + Basic: uint8 + GSS: + Type: 7 + GSSContinue: + Type: 8 + Remaining: + Basic: uint8 + SSPI: + Type: 9 + SASL: + Type: 10 + ZeroTerminatedSlice: + Name: Method + Fields: + - Name: Method + Basic: string + SASLContinue: + Type: 11 + Remaining: + Basic: uint8 + SASLFinal: + Type: 12 + Remaining: + Basic: uint8 + GSSResponse: + Type: 'p' + Remaining: + Basic: uint8 + PasswordMessage: + Type: 'p' + Basic: string + SASLInitialResponse: + Type: 'p' + Struct: + Name: Payload + Fields: + - Name: Mechanism + Basic: string + - Name: InitialClientResponse + NullableLengthPrefixedSlice: + Prefix: + Basic: int32 + Basic: uint8 + SASLResponse: + Type: 'p' + Remaining: + Basic: uint8 + BackendKeyData: + Type: 'K' + Struct: + Name: Payload + Fields: + - Name: ProcessID + Basic: int32 + - Name: SecretKey + Basic: int32 + Bind: + Type: 'B' + Struct: + Name: Payload + Fields: + - Name: Destination + Basic: string + - Name: Source + Basic: string + - Name: FormatCodes + LengthPrefixedSlice: + Prefix: + Basic: uint16 + Basic: int16 + - Name: Parameters + LengthPrefixedSlice: + Prefix: + Basic: uint16 + NullableLengthPrefixedSlice: + Prefix: + Basic: int32 + Basic: uint8 + - Name: ResultFormatCodes + LengthPrefixedSlice: + Prefix: + Basic: uint16 + Basic: int16 + BindComplete: + Type: '2' + Close: + Type: 'C' + Struct: + Name: Payload + Fields: + - Name: Which + Basic: uint8 + - Name: Name + Basic: string + CloseComplete: + Type: '3' + CommandComplete: + Type: 'C' + Basic: string + CopyData: + Type: 'd' + Remaining: + Basic: uint8 + CopyDone: + Type: 'c' + CopyFail: + Type: 'f' + Basic: string + CopyInResponse: + Type: 'G' + Struct: + Name: Payload + Fields: + - Name: Mode + Basic: int8 + - Name: ColumnFormatCodes + LengthPrefixedSlice: + Prefix: + Basic: uint16 + Basic: int16 + CopyOutResponse: + Type: 'H' + Struct: + Name: Payload + Fields: + - Name: Mode + Basic: int8 + - Name: ColumnFormatCodes + LengthPrefixedSlice: + Prefix: + Basic: uint16 + Basic: int16 + CopyBothResponse: + Type: 'W' + Struct: + Name: Payload + Fields: + - Name: Mode + Basic: int8 + - Name: ColumnFormatCodes + LengthPrefixedSlice: + Prefix: + Basic: uint16 + Basic: int16 + DataRow: + Type: 'D' + LengthPrefixedSlice: + Prefix: + Basic: uint16 + NullableLengthPrefixedSlice: + Prefix: + Basic: int32 + Basic: uint8 + Describe: + Type: 'D' + Struct: + Name: Payload + Fields: + - Name: Which + Basic: uint8 + - Name: Name + Basic: string + EmptyQueryResponse: + Type: 'I' + ErrorResponse: + Type: 'E' + ZeroTerminatedSlice: + Name: Field + Fields: + - Name: Code + Basic: uint8 + - Name: Value + Basic: string + Execute: + Type: 'E' + Struct: + Name: Payload + Fields: + - Name: Target + Basic: string + - Name: MaxRows + Basic: uint32 + Flush: + Type: 'H' + FunctionCall: + Type: 'F' + Struct: + Name: Payload + Fields: + - Name: ObjectID + Basic: int32 + - Name: ArgumentFormatCodes + LengthPrefixedSlice: + Prefix: + Basic: uint16 + Basic: int16 + - Name: Arguments + LengthPrefixedSlice: + Prefix: + Basic: uint16 + NullableLengthPrefixedSlice: + Prefix: + Basic: int32 + Basic: uint8 + - Name: ResultFormatCode + Basic: int16 + FunctionCallResponse: + Type: 'V' + NullableLengthPrefixedSlice: + Prefix: + Basic: int32 + Basic: uint8 + NegotiateProtocolVersion: + Type: 'v' + Struct: + Name: Payload + Fields: + - Name: MinorProtocolVersion + Basic: int32 + - Name: UnrecognizedProtocolOptions + LengthPrefixedSlice: + Prefix: + Basic: uint32 + Basic: string + NoData: + Type: 'n' + NoticeResponse: + Type: 'N' + ZeroTerminatedSlice: + Name: Field + Fields: + - Name: Code + Basic: uint8 + - Name: Value + Basic: string + NotificationResponse: + Type: 'A' + Struct: + Name: Payload + Fields: + - Name: ProcessID + Basic: int32 + - Name: Channel + Basic: string + - Name: Payload + Basic: string + ParameterDescription: + Type: 't' + LengthPrefixedSlice: + Prefix: + Basic: uint16 + Basic: int32 + ParameterStatus: + Type: 'S' + Struct: + Name: Payload + Fields: + - Name: Key + Basic: string + - Name: Value + Basic: string + Parse: + Type: 'P' + Struct: + Name: Payload + Fields: + - Name: Destination + Basic: string + - Name: Query + Basic: string + - Name: ParameterDataTypes + LengthPrefixedSlice: + Prefix: + Basic: uint16 + Basic: int32 + ParseComplete: + Type: '1' + PortalSuspended: + Type: 's' + Query: + Type: 'Q' + Basic: string + ReadyForQuery: + Type: 'Z' + Basic: uint8 + RowDescription: + Type: 'T' + LengthPrefixedSlice: + Prefix: + Basic: uint16 + Struct: + Name: Row + Fields: + - Name: Name + Basic: string + - Name: TableID + Basic: int32 + - Name: ColumnAttributeNumber + Basic: int16 + - Name: FieldDataType + Basic: int32 + - Name: DataTypeSize + Basic: int16 + - Name: TypeModifier + Basic: int32 + - Name: FormatCode + Basic: int16 + Sync: + Type: 'S' + Terminate: + Type: 'X' diff --git a/hack/packetgen/templates/decode.tmpl b/hack/packetgen/templates/decode.tmpl new file mode 100644 index 0000000000000000000000000000000000000000..cdfd7d424ba769ed18a39595cf2e968adad21917 --- /dev/null +++ b/hack/packetgen/templates/decode.tmpl @@ -0,0 +1,126 @@ +{{$name := index . 0 -}} +{{$pointer := index . 1 -}} +{{$value := index . 2 -}} + +{{if some $value.Map -}} + {{$prefixPointer := temp -}} + + var {{$prefixPointer}} {{template "type" (list $name $value.Map.Prefix)}} + + {{template "decode" (list $name $prefixPointer $value.Map.Prefix)}} + + switch {{$prefixPointer}} { + {{range $n, $item := $value.Map.Items -}} + {{$itemName := printf "%s%s" $name $n -}} + + case {{$item.Type}}: + {{$pointer}} = new({{$itemName}}) + {{end -}} + default: + err = ErrInvalidFormat + return + } + + err = {{$pointer}}.ReadFrom(decoder) + if err != nil { + return + } +{{else if some $value.Remaining -}} + {{$pointer}} = {{$pointer}}[:0] + + for { + if decoder.Position() >= decoder.Length() { + break + } + + {{$pointer}} = slices.Resize({{$pointer}}, len({{$pointer}})+1) + + {{$targetPointer := printf "%s[len(%s)-1]" $pointer $pointer -}} + + {{template "decode" (list $name $targetPointer $value.Remaining)}} + } +{{else if some $value.Basic -}} + *(*{{$value.Basic}})(&({{$pointer}})), err = decoder.{{upperCamel $value.Basic}}() + if err != nil { + return + } +{{else if some $value.Array -}} + {{$indexPointer := temp -}} + + for {{$indexPointer}} := 0; {{$indexPointer}} < {{$value.Array.Length}}; {{$indexPointer}}++ { + {{$targetPointer := printf "%s[%s]" $pointer $indexPointer -}} + + {{template "decode" (list $name $targetPointer $value.Array)}} + } +{{else if some $value.Struct -}} + {{$structName := printf "%s%s" $name $value.Struct.Name -}} + + {{range $field := $value.Struct.Fields -}} + {{$fieldPointer := printf "%s.%s" $pointer $field.Name -}} + + {{template "decode" (list $structName $fieldPointer $field) -}} + {{end -}} +{{else if some $value.LengthPrefixedSlice -}} + {{$lengthPointer := temp -}} + + var {{$lengthPointer}} {{template "type" (list $name $value.LengthPrefixedSlice.Prefix)}} + {{template "decode" (list $name $lengthPointer $value.LengthPrefixedSlice.Prefix)}} + + {{$pointer}} = slices.Resize({{$pointer}}, int({{$lengthPointer}})) + + {{$indexPointer := temp -}} + + for {{$indexPointer}} := 0; {{$indexPointer}} < int({{$lengthPointer}}); {{$indexPointer}}++ { + {{$targetPointer := printf "%s[%s]" $pointer $indexPointer -}} + + {{template "decode" (list $name $targetPointer $value.LengthPrefixedSlice)}} + } + +{{else if some $value.NullableLengthPrefixedSlice -}} + {{$lengthPointer := temp -}} + + var {{$lengthPointer}} {{template "type" (list $name $value.NullableLengthPrefixedSlice.Prefix)}} + {{template "decode" (list $name $lengthPointer $value.NullableLengthPrefixedSlice.Prefix)}} + + if {{$lengthPointer}} == -1 { + {{$pointer}} = nil + } else { + if {{$pointer}} == nil { + {{$pointer}} = make([]{{template "type" (list $name $value.NullableLengthPrefixedSlice)}}, int({{$lengthPointer}})) + } else { + {{$pointer}} = slices.Resize({{$pointer}}, int({{$lengthPointer}})) + } + + {{$indexPointer := temp -}} + + for {{$indexPointer}} := 0; {{$indexPointer}} < int({{$lengthPointer}}); {{$indexPointer}}++ { + {{$targetPointer := printf "%s[%s]" $pointer $indexPointer -}} + + {{template "decode" (list $name $targetPointer $value.NullableLengthPrefixedSlice)}} + } + } + +{{else if some $value.ZeroTerminatedSlice -}} + {{$structName := printf "%s%s" $name $value.ZeroTerminatedSlice.Name -}} + + {{$pointer}} = {{$pointer}}[:0] + + for { + {{$pointer}} = slices.Resize({{$pointer}}, len({{$pointer}})+1) + + {{$targetPointer := printf "%s[len(%s)-1]" $pointer $pointer -}} + + {{range $i, $field := $value.ZeroTerminatedSlice.Fields -}} + {{$fieldPointer := printf "%s.%s" $targetPointer $field.Name -}} + + {{template "decode" (list $structName $fieldPointer $field) -}} + + {{if eq $i 0 -}} + if {{$fieldPointer}} == *new({{template "type" (list $structName $field)}}) { + {{$pointer}} = {{$pointer}}[:len({{$pointer}})-1] + break + } + {{end -}} + {{end -}} + } +{{end -}} diff --git a/hack/packetgen/templates/encode.tmpl b/hack/packetgen/templates/encode.tmpl new file mode 100644 index 0000000000000000000000000000000000000000..9d6532f2583e5cf2a0267a9561156b2d4265bffc --- /dev/null +++ b/hack/packetgen/templates/encode.tmpl @@ -0,0 +1,87 @@ +{{$name := index . 0 -}} +{{$pointer := index . 1 -}} +{{$value := index . 2 -}} + +{{if some $value.Map -}} + {{$ifaceName := printf "%s%s" $name $value.Map.Name -}} + + {{$prefixPointer := printf "%s.%s()" $pointer $ifaceName -}} + + {{template "encode" (list $name $prefixPointer $value.Map.Prefix)}} + + err = {{$pointer}}.WriteTo(encoder) + if err != nil { + return + } +{{else if some $value.Remaining -}} + {{$itemPointer := temp -}} + + for _, {{$itemPointer}} := range {{$pointer}} { + {{template "encode" (list $name $itemPointer $value.Remaining)}} + } +{{else if some $value.Basic -}} + err = encoder.{{upperCamel $value.Basic}}({{$value.Basic}}({{$pointer}})) + if err != nil { + return + } +{{else if some $value.Array -}} + {{$itemPointer := temp -}} + + for _, {{$itemPointer}} := range {{$pointer}} { + {{template "encode" (list $name $itemPointer $value.Array)}} + } +{{else if some $value.Struct -}} + {{$structName := printf "%s%s" $name $value.Struct.Name -}} + + {{range $field := $value.Struct.Fields -}} + {{$fieldPointer := printf "%s.%s" $pointer $field.Name -}} + + {{template "encode" (list $structName $fieldPointer $field)}} + {{end -}} +{{else if some $value.LengthPrefixedSlice -}} + {{$lengthPointer := temp -}} + + {{$lengthPointer}} := {{template "type" (list $name $value.LengthPrefixedSlice.Prefix)}}(len({{$pointer}})) + + {{template "encode" (list $name $lengthPointer $value.LengthPrefixedSlice.Prefix)}} + + {{$itemPointer := temp -}} + + for _, {{$itemPointer}} := range {{$pointer}} { + {{template "encode" (list $name $itemPointer $value.LengthPrefixedSlice)}} + } +{{else if some $value.NullableLengthPrefixedSlice -}} + {{$lengthPointer := temp -}} + + {{$lengthPointer}} := {{template "type" (list $name $value.NullableLengthPrefixedSlice.Prefix)}}(len({{$pointer}})) + + if {{$pointer}} == nil { + {{$lengthPointer}} = -1 + } + + {{template "encode" (list $name $lengthPointer $value.NullableLengthPrefixedSlice.Prefix)}} + + {{$itemPointer := temp -}} + + for _, {{$itemPointer}} := range {{$pointer}} { + {{template "encode" (list $name $itemPointer $value.NullableLengthPrefixedSlice)}} + } +{{else if some $value.ZeroTerminatedSlice -}} + {{$structName := printf "%s%s" $name $value.ZeroTerminatedSlice.Name -}} + + {{$itemPointer := temp -}} + + for _, {{$itemPointer}} := range {{$pointer}} { + {{range $field := $value.ZeroTerminatedSlice.Fields -}} + {{$fieldPointer := printf "%s.%s" $itemPointer $field.Name -}} + + {{template "encode" (list $structName $fieldPointer $field)}} + {{end -}} + } + + {{$donePointer := temp -}} + + var {{$donePointer}} {{template "type" (list $structName (index $value.ZeroTerminatedSlice.Fields 0))}} + + {{template "encode" (list $structName $donePointer (index $value.ZeroTerminatedSlice.Fields 0))}} +{{end -}} diff --git a/hack/packetgen/templates/length.tmpl b/hack/packetgen/templates/length.tmpl new file mode 100644 index 0000000000000000000000000000000000000000..49bdf45401d17f50f4d731cd102a1f546c9151f0 --- /dev/null +++ b/hack/packetgen/templates/length.tmpl @@ -0,0 +1,112 @@ +{{$name := index . 0 -}} +{{$pointer := index . 1 -}} +{{$value := index . 2 -}} + +{{if some $value.Map -}} + {{$ifaceName := printf "%s%s" $name $value.Map.Name -}} + + {{$prefixPointer := printf "%s.%s()" $pointer $ifaceName -}} + + {{template "length" (list $name $prefixPointer $value.Map.Prefix)}} + + length += {{$pointer}}.Length() +{{else if some $value.Remaining -}} + {{$itemPointer := temp -}} + + for _, {{$itemPointer}} := range {{$pointer}} { + _ = {{$itemPointer}} + + {{template "length" (list $name $itemPointer $value.Remaining)}} + } +{{else if some $value.Basic -}} + {{if eq $value.Basic "uint8" -}} + length += 1 + {{else if eq $value.Basic "uint16" -}} + length += 2 + {{else if eq $value.Basic "uint32" -}} + length += 4 + {{else if eq $value.Basic "uint64" -}} + length += 8 + {{else if eq $value.Basic "int8" -}} + length += 1 + {{else if eq $value.Basic "int16" -}} + length += 2 + {{else if eq $value.Basic "int32" -}} + length += 4 + {{else if eq $value.Basic "int64" -}} + length += 8 + {{else if eq $value.Basic "float32" -}} + length += 4 + {{else if eq $value.Basic "float64" -}} + length += 8 + {{else if eq $value.Basic "string" -}} + length += len({{$pointer}}) + 1 + {{end -}} +{{else if some $value.Array -}} + {{$itemPointer := temp -}} + + for _, {{$itemPointer}} := range {{$pointer}} { + _ = {{$itemPointer}} + + {{template "length" (list $name $itemPointer $value.Array)}} + } +{{else if some $value.Struct -}} + {{$structName := printf "%s%s" $name $value.Struct.Name -}} + + {{range $field := $value.Struct.Fields -}} + {{$fieldPointer := printf "%s.%s" $pointer $field.Name -}} + + {{template "length" (list $structName $fieldPointer $field)}} + {{end -}} +{{else if some $value.LengthPrefixedSlice -}} + {{$lengthPointer := temp -}} + + {{$lengthPointer}} := {{template "type" (list $name $value.LengthPrefixedSlice.Prefix)}}(len({{$pointer}})) + _ = {{$lengthPointer}} + + {{template "length" (list $name $lengthPointer $value.LengthPrefixedSlice.Prefix)}} + + {{$itemPointer := temp -}} + + for _, {{$itemPointer}} := range {{$pointer}} { + _ = {{$itemPointer}} + + {{template "length" (list $name $itemPointer $value.LengthPrefixedSlice)}} + } +{{else if some $value.NullableLengthPrefixedSlice -}} + {{$lengthPointer := temp -}} + + {{$lengthPointer}} := {{template "type" (list $name $value.NullableLengthPrefixedSlice.Prefix)}}(len({{$pointer}})) + _ = {{$lengthPointer}} + + {{template "length" (list $name $lengthPointer $value.NullableLengthPrefixedSlice.Prefix)}} + + {{$itemPointer := temp -}} + + for _, {{$itemPointer}} := range {{$pointer}} { + _ = {{$itemPointer}} + + {{template "length" (list $name $itemPointer $value.NullableLengthPrefixedSlice)}} + } +{{else if some $value.ZeroTerminatedSlice -}} + {{$structName := printf "%s%s" $name $value.ZeroTerminatedSlice.Name -}} + + {{$itemPointer := temp -}} + + for _, {{$itemPointer}} := range {{$pointer}} { + _ = {{$itemPointer}} + + {{range $field := $value.ZeroTerminatedSlice.Fields -}} + {{$fieldPointer := printf "%s.%s" $itemPointer $field.Name -}} + + {{template "length" (list $structName $fieldPointer $field)}} + {{end -}} + } + + {{$donePointer := temp -}} + + var {{$donePointer}} {{template "type" (list $structName (index $value.ZeroTerminatedSlice.Fields 0))}} + _ = {{$donePointer}} + + {{template "length" (list $name $donePointer (index $value.ZeroTerminatedSlice.Fields 0))}} +{{end -}} diff --git a/hack/packetgen/templates/packets.tmpl b/hack/packetgen/templates/packets.tmpl new file mode 100644 index 0000000000000000000000000000000000000000..3b095d6fdd37cd543c6f5223f23462b43c8a9d88 --- /dev/null +++ b/hack/packetgen/templates/packets.tmpl @@ -0,0 +1,60 @@ +// automatically generated. do not edit + +import ( + "gfx.cafe/gfx/pggat/lib/fed" + "gfx.cafe/gfx/pggat/lib/util/slices" + + "errors" +) + +var ( + ErrUnexpectedPacket = errors.New("unexpected packet") + ErrInvalidFormat = errors.New("invalid packet format") +) + +const ( + {{range $name, $packet := .Packets -}} + {{if some $packet.Type -}} + Type{{$name}} = '{{$packet.Type}}' + {{end -}} + {{end -}} +) + +{{range $name, $packet := .Packets -}} + {{template "preType" (list $name $packet)}} + + type {{$name}} {{template "type" (list $name $packet)}} + + func (T *{{$name}}) Type() fed.Type { + {{if some $packet.Type -}} + return Type{{$name}} + {{else -}} + return 0 + {{end -}} + } + + func (T *{{$name}}) Length() (length int) { + {{template "length" (list $name "(*T)" $packet)}} + + return + } + + func (T *{{$name}}) ReadFrom(decoder *fed.Decoder) (err error) { + if decoder.Type() != T.Type() { + return ErrUnexpectedPacket + } + + {{template "decode" (list $name "(*T)" $packet)}} + + return + } + + func (T *{{$name}}) WriteTo(encoder *fed.Encoder) (err error) { + {{template "encode" (list $name "(*T)" $packet)}} + + return + } + + var _ fed.Packet = (*{{$name}})(nil) + +{{end}} diff --git a/hack/packetgen/templates/preType.tmpl b/hack/packetgen/templates/preType.tmpl new file mode 100644 index 0000000000000000000000000000000000000000..5bd8ba06118c6d4c0079f1621b593b849e859464 --- /dev/null +++ b/hack/packetgen/templates/preType.tmpl @@ -0,0 +1,75 @@ +{{$name := index . 0 -}} +{{$value := index . 1 -}} + +{{if some $value.Map -}} + {{$ifaceName := printf "%s%s" $name $value.Map.Name -}} + + {{range $n, $item := $value.Map.Items -}} + {{$itemName := printf "%s%s" $name $n -}} + + {{template "preType" (list $itemName $item) -}} + + type {{$itemName}} {{template "type" (list $itemName $item)}} + + func (*{{$itemName}}) {{$ifaceName}}() {{template "type" (list $name $value.Map.Prefix)}} { + return {{$item.Type}} + } + + func (T *{{$itemName}}) Length() (length int) { + {{template "length" (list $name "(*T)" $item)}} + + return + } + + func (T *{{$itemName}}) ReadFrom(decoder *fed.Decoder) (err error) { + {{template "decode" (list $itemName "(*T)" $item)}} + + return + } + + func (T *{{$itemName}}) WriteTo(encoder *fed.Encoder) (err error) { + {{template "encode" (list $itemName "(*T)" $item)}} + + return + } + + {{end -}} + + type {{$ifaceName}} interface{ + {{$ifaceName}}() {{template "type" (list $name $value.Map.Prefix)}} + + Length() int + ReadFrom(decoder *fed.Decoder) error + WriteTo(encoder *fed.Encoder) error + } +{{else if some $value.Struct -}} + {{$structName := printf "%s%s" $name $value.Struct.Name -}} + + {{range $field := $value.Struct.Fields -}} + {{template "preType" (list $structName $field) -}} + {{end -}} + + type {{$structName}} struct{ + {{range $field := $value.Struct.Fields -}} + {{$field.Name}} {{template "type" (list $structName $field)}} + {{end -}} + } + +{{else if some $value.LengthPrefixedSlice -}} + {{template "preType" (list $name $value.LengthPrefixedSlice) -}} +{{else if some $value.NullableLengthPrefixedSlice -}} + {{template "preType" (list $name $value.NullableLengthPrefixedSlice) -}} +{{else if some $value.ZeroTerminatedSlice -}} + {{$structName := printf "%s%s" $name $value.ZeroTerminatedSlice.Name -}} + + {{range $field := $value.ZeroTerminatedSlice.Fields -}} + {{template "preType" (list $structName $field) -}} + {{end -}} + + type {{$structName}} struct{ + {{range $field := $value.ZeroTerminatedSlice.Fields -}} + {{$field.Name}} {{template "type" (list $structName $field)}} + {{end -}} + } + +{{end -}} \ No newline at end of file diff --git a/hack/packetgen/templates/type.tmpl b/hack/packetgen/templates/type.tmpl new file mode 100644 index 0000000000000000000000000000000000000000..22f154a085e5cbf67941e419f72fc495ecea1d5d --- /dev/null +++ b/hack/packetgen/templates/type.tmpl @@ -0,0 +1,22 @@ +{{- $name := index . 0 -}} +{{- $value := index . 1 -}} + +{{- if some $value.Map -}} + {{printf "%s%s" $name $value.Map.Name}} +{{- else if some $value.Remaining -}} + []{{template "type" (list $name $value.Remaining)}} +{{- else if some $value.Basic -}} + {{$value.Basic}} +{{- else if some $value.Array -}} + [{{$value.Array.Length}}]{{template "type" (list $name $value.Array)}} +{{- else if some $value.Struct -}} + {{printf "%s%s" $name $value.Struct.Name}} +{{- else if some $value.LengthPrefixedSlice -}} + []{{template "type" (list $name $value.LengthPrefixedSlice)}} +{{- else if some $value.NullableLengthPrefixedSlice -}} + []{{template "type" (list $name $value.NullableLengthPrefixedSlice)}} +{{- else if some $value.ZeroTerminatedSlice -}} + []{{printf "%s%s" $name $value.ZeroTerminatedSlice.Name}} +{{- else -}} + struct{} +{{- end -}} \ No newline at end of file diff --git a/lib/bouncer/backends/v0/accept.go b/lib/bouncer/backends/v0/accept.go index d094f2f19f5f39bf5b38ca68f71a7a589ba7c5c9..6fe9254b8cc8184cc7889f48cf61c2a2757884e8 100644 --- a/lib/bouncer/backends/v0/accept.go +++ b/lib/bouncer/backends/v0/accept.go @@ -9,39 +9,43 @@ import ( "gfx.cafe/gfx/pggat/lib/bouncer" "gfx.cafe/gfx/pggat/lib/fed" packets "gfx.cafe/gfx/pggat/lib/fed/packets/v3.0" + "gfx.cafe/gfx/pggat/lib/perror" "gfx.cafe/gfx/pggat/lib/util/strutil" ) func authenticationSASLChallenge(ctx *acceptContext, encoder auth.SASLEncoder) (done bool, err error) { - ctx.Packet, err = ctx.Conn.ReadPacket(true, ctx.Packet) + var packet fed.Packet + packet, err = ctx.Conn.ReadPacket(true) if err != nil { return } - if ctx.Packet.Type() != packets.TypeAuthentication { + if packet.Type() != packets.TypeAuthentication { err = ErrUnexpectedPacket return } - var method int32 - p := ctx.Packet.ReadInt32(&method) + var p packets.Authentication + err = fed.ToConcrete(&p, packet) + if err != nil { + return + } - switch method { - case 11: + switch mode := p.Mode.(type) { + case *packets.AuthenticationPayloadSASLContinue: // challenge var response []byte - response, err = encoder.Write(p) + response, err = encoder.Write(*mode) if err != nil { return } - resp := packets.AuthenticationResponse(response) - ctx.Packet = resp.IntoPacket(ctx.Packet) - err = ctx.Conn.WritePacket(ctx.Packet) + resp := packets.SASLResponse(response) + err = ctx.Conn.WritePacket(&resp) return - case 12: + case *packets.AuthenticationPayloadSASLFinal: // finish - _, err = encoder.Write(p) + _, err = encoder.Write(*mode) if err != io.EOF { if err == nil { err = errors.New("expected EOF") @@ -67,11 +71,10 @@ func authenticationSASL(ctx *acceptContext, mechanisms []string, creds auth.SASL } saslInitialResponse := packets.SASLInitialResponse{ - Mechanism: mechanism, - InitialResponse: initialResponse, + Mechanism: mechanism, + InitialClientResponse: initialResponse, } - ctx.Packet = saslInitialResponse.IntoPacket(ctx.Packet) - err = ctx.Conn.WritePacket(ctx.Packet) + err = ctx.Conn.WritePacket(&saslInitialResponse) if err != nil { return err } @@ -92,11 +95,8 @@ func authenticationSASL(ctx *acceptContext, mechanisms []string, creds auth.SASL } func authenticationMD5(ctx *acceptContext, salt [4]byte, creds auth.MD5Client) error { - pw := packets.PasswordMessage{ - Password: creds.EncodeMD5(salt), - } - ctx.Packet = pw.IntoPacket(ctx.Packet) - err := ctx.Conn.WritePacket(ctx.Packet) + pw := packets.PasswordMessage(creds.EncodeMD5(salt)) + err := ctx.Conn.WritePacket(&pw) if err != nil { return err } @@ -104,69 +104,54 @@ func authenticationMD5(ctx *acceptContext, salt [4]byte, creds auth.MD5Client) e } func authenticationCleartext(ctx *acceptContext, creds auth.CleartextClient) error { - pw := packets.PasswordMessage{ - Password: creds.EncodeCleartext(), - } - ctx.Packet = pw.IntoPacket(ctx.Packet) - err := ctx.Conn.WritePacket(ctx.Packet) + pw := packets.PasswordMessage(creds.EncodeCleartext()) + err := ctx.Conn.WritePacket(&pw) if err != nil { return err } return nil } -func authentication(ctx *acceptContext) (done bool, err error) { - var method int32 - ctx.Packet.ReadInt32(&method) +func authentication(ctx *acceptContext, p *packets.Authentication) (done bool, err error) { // they have more authentication methods than there are pokemon - switch method { - case 0: + switch mode := p.Mode.(type) { + case *packets.AuthenticationPayloadOk: // we're good to go, that was easy ctx.Conn.Authenticated = true return true, nil - case 2: + case *packets.AuthenticationPayloadKerberosV5: err = errors.New("kerberos v5 is not supported") return - case 3: + case *packets.AuthenticationPayloadCleartextPassword: c, ok := ctx.Options.Credentials.(auth.CleartextClient) if !ok { return false, auth.ErrMethodNotSupported } return false, authenticationCleartext(ctx, c) - case 5: - var md5 packets.AuthenticationMD5 - if !md5.ReadFromPacket(ctx.Packet) { - err = ErrBadFormat - return - } - + case *packets.AuthenticationPayloadMD5Password: c, ok := ctx.Options.Credentials.(auth.MD5Client) if !ok { return false, auth.ErrMethodNotSupported } - return false, authenticationMD5(ctx, md5.Salt, c) - case 6: - err = errors.New("scm credential is not supported") - return - case 7: + return false, authenticationMD5(ctx, *mode, c) + case *packets.AuthenticationPayloadGSS: err = errors.New("gss is not supported") return - case 9: + case *packets.AuthenticationPayloadSSPI: err = errors.New("sspi is not supported") return - case 10: - // read list of mechanisms - var sasl packets.AuthenticationSASL - if !sasl.ReadFromPacket(ctx.Packet) { - err = ErrBadFormat - return - } - + case *packets.AuthenticationPayloadSASL: c, ok := ctx.Options.Credentials.(auth.SASLClient) if !ok { return false, auth.ErrMethodNotSupported } - return false, authenticationSASL(ctx, sasl.Mechanisms, c) + + var mechanisms = make([]string, 0, len(*mode)) + for _, m := range *mode { + mechanisms = append(mechanisms, m.Method) + } + + return false, authenticationSASL(ctx, mechanisms, c) default: err = errors.New("unknown authentication method") return @@ -174,22 +159,28 @@ func authentication(ctx *acceptContext) (done bool, err error) { } func startup0(ctx *acceptContext) (done bool, err error) { - ctx.Packet, err = ctx.Conn.ReadPacket(true, ctx.Packet) + var packet fed.Packet + packet, err = ctx.Conn.ReadPacket(true) if err != nil { return } - switch ctx.Packet.Type() { + switch packet.Type() { case packets.TypeErrorResponse: - var err2 packets.ErrorResponse - if !err2.ReadFromPacket(ctx.Packet) { - err = ErrBadFormat - } else { - err = errors.New(err2.Error.String()) + var p packets.ErrorResponse + err = fed.ToConcrete(&p, packet) + if err != nil { + return } + err = perror.FromPacket(&p) return case packets.TypeAuthentication: - return authentication(ctx) + var p packets.Authentication + err = fed.ToConcrete(&p, packet) + if err != nil { + return + } + return authentication(ctx, &p) case packets.TypeNegotiateProtocolVersion: // we only support protocol 3.0 for now err = errors.New("server wanted to negotiate protocol version") @@ -201,36 +192,44 @@ func startup0(ctx *acceptContext) (done bool, err error) { } func startup1(ctx *acceptContext) (done bool, err error) { - ctx.Packet, err = ctx.Conn.ReadPacket(true, ctx.Packet) + var packet fed.Packet + packet, err = ctx.Conn.ReadPacket(true) if err != nil { return } - switch ctx.Packet.Type() { + switch packet.Type() { case packets.TypeBackendKeyData: - ctx.Packet.ReadBytes(ctx.Conn.BackendKey[:]) + var p packets.BackendKeyData + err = fed.ToConcrete(&p, packet) + if err != nil { + return + } + ctx.Conn.BackendKey.SecretKey = p.SecretKey + ctx.Conn.BackendKey.ProcessID = p.ProcessID + return false, nil case packets.TypeParameterStatus: - var ps packets.ParameterStatus - if !ps.ReadFromPacket(ctx.Packet) { - err = ErrBadFormat + var p packets.ParameterStatus + err = fed.ToConcrete(&p, packet) + if err != nil { return } - ikey := strutil.MakeCIString(ps.Key) + ikey := strutil.MakeCIString(p.Key) if ctx.Conn.InitialParameters == nil { ctx.Conn.InitialParameters = make(map[strutil.CIString]string) } - ctx.Conn.InitialParameters[ikey] = ps.Value + ctx.Conn.InitialParameters[ikey] = p.Value return false, nil case packets.TypeReadyForQuery: return true, nil case packets.TypeErrorResponse: - var err2 packets.ErrorResponse - if !err2.ReadFromPacket(ctx.Packet) { - err = ErrBadFormat - } else { - err = errors.New(err2.Error.String()) + var p packets.ErrorResponse + err = fed.ToConcrete(&p, packet) + if err != nil { + return } + err = perror.FromPacket(&p) return case packets.TypeNoticeResponse: // TODO(garet) do something with notice @@ -242,20 +241,18 @@ func startup1(ctx *acceptContext) (done bool, err error) { } func enableSSL(ctx *acceptContext) (bool, error) { - ctx.Packet = ctx.Packet.Reset(0, 4) - ctx.Packet = ctx.Packet.AppendUint16(1234) - ctx.Packet = ctx.Packet.AppendUint16(5679) - if err := ctx.Conn.WritePacket(ctx.Packet); err != nil { - return false, err + p := packets.Startup{ + Mode: &packets.StartupPayloadControl{ + Mode: &packets.StartupPayloadControlPayloadSSL{}, + }, } - byteReader, ok := ctx.Conn.ReadWriteCloser.(io.ByteReader) - if !ok { - return false, errors.New("server must be io.ByteReader to enable ssl") + if err := ctx.Conn.WritePacket(&p); err != nil { + return false, err } // read byte to see if ssl is allowed - yn, err := byteReader.ReadByte() + yn, err := ctx.Conn.ReadByte() if err != nil { return false, err } @@ -265,12 +262,7 @@ func enableSSL(ctx *acceptContext) (bool, error) { return false, nil } - sslClient, ok := ctx.Conn.ReadWriteCloser.(fed.SSLClient) - if !ok { - return false, errors.New("server must be fed.SSLClient to enable ssl") - } - - if err = sslClient.EnableSSLClient(ctx.Options.SSLConfig); err != nil { + if err = ctx.Conn.EnableSSL(ctx.Options.SSLConfig, true); err != nil { return false, err } @@ -294,26 +286,32 @@ func accept(ctx *acceptContext) error { } } - size := 4 + len("user") + 1 + len(username) + 1 + len("database") + 1 + len(ctx.Options.Database) + 1 - for key, value := range ctx.Options.StartupParameters { - size += len(key.String()) + len(value) + 2 + m := packets.StartupPayloadVersion3{ + MinorVersion: 0, + Parameters: []packets.StartupPayloadVersion3PayloadParameter{ + { + Key: "user", + Value: username, + }, + { + Key: "database", + Value: ctx.Options.Database, + }, + }, } - size += 1 - - ctx.Packet = ctx.Packet.Reset(0, size) - ctx.Packet = ctx.Packet.AppendUint16(3) - ctx.Packet = ctx.Packet.AppendUint16(0) - ctx.Packet = ctx.Packet.AppendString("user") - ctx.Packet = ctx.Packet.AppendString(username) - ctx.Packet = ctx.Packet.AppendString("database") - ctx.Packet = ctx.Packet.AppendString(ctx.Options.Database) + for key, value := range ctx.Options.StartupParameters { - ctx.Packet = ctx.Packet.AppendString(key.String()) - ctx.Packet = ctx.Packet.AppendString(value) + m.Parameters = append(m.Parameters, packets.StartupPayloadVersion3PayloadParameter{ + Key: key.String(), + Value: value, + }) + } + + p := packets.Startup{ + Mode: &m, } - ctx.Packet = ctx.Packet.AppendUint8(0) - err := ctx.Conn.WritePacket(ctx.Packet) + err := ctx.Conn.WritePacket(&p) if err != nil { return err } diff --git a/lib/bouncer/backends/v0/cancel.go b/lib/bouncer/backends/v0/cancel.go index 23769b8dbed161c791b0e64ee450820a24d8bb9d..48ee2b66461df144c76de97208c8b00bd642d2bf 100644 --- a/lib/bouncer/backends/v0/cancel.go +++ b/lib/bouncer/backends/v0/cancel.go @@ -1,11 +1,18 @@ package backends -import "gfx.cafe/gfx/pggat/lib/fed" +import ( + "gfx.cafe/gfx/pggat/lib/fed" + packets "gfx.cafe/gfx/pggat/lib/fed/packets/v3.0" +) -func Cancel(server *fed.Conn, key [8]byte) error { - packet := fed.NewPacket(0, 12) - packet = packet.AppendUint16(1234) - packet = packet.AppendUint16(5678) - packet = packet.AppendBytes(key[:]) - return server.WritePacket(packet) +func Cancel(server *fed.Conn, key fed.BackendKey) error { + p := packets.Startup{ + Mode: &packets.StartupPayloadControl{ + Mode: &packets.StartupPayloadControlPayloadCancel{ + ProcessID: key.ProcessID, + SecretKey: key.SecretKey, + }, + }, + } + return server.WritePacket(&p) } diff --git a/lib/bouncer/backends/v0/context.go b/lib/bouncer/backends/v0/context.go index 01945b65e47630a4bdfa299abf446d1bbdc7f05c..3554fc2bbbb9be1721fd4a233611dc9de63f0807 100644 --- a/lib/bouncer/backends/v0/context.go +++ b/lib/bouncer/backends/v0/context.go @@ -5,7 +5,6 @@ import ( ) type acceptContext struct { - Packet fed.Packet Conn *fed.Conn Options acceptOptions } @@ -20,7 +19,7 @@ type context struct { func (T *context) ServerRead() error { var err error - T.Packet, err = T.Server.ReadPacket(true, T.Packet) + T.Packet, err = T.Server.ReadPacket(true) return err } @@ -51,7 +50,7 @@ func (T *context) PeerRead() bool { return false } var err error - T.Packet, err = T.Peer.ReadPacket(true, T.Packet) + T.Packet, err = T.Peer.ReadPacket(true) if err != nil { T.PeerFail(err) return false diff --git a/lib/bouncer/backends/v0/query.go b/lib/bouncer/backends/v0/query.go index 89a8bd3f82d758a7f924f14d7944e0285e4376ef..d86b46c19faec8c64321c1dc02b44849f6e9ab66 100644 --- a/lib/bouncer/backends/v0/query.go +++ b/lib/bouncer/backends/v0/query.go @@ -1,7 +1,7 @@ package backends import ( - "fmt" + "strings" "gfx.cafe/gfx/pggat/lib/fed" packets "gfx.cafe/gfx/pggat/lib/fed/packets/v3.0" @@ -13,10 +13,8 @@ func copyIn(ctx *context) error { for { if !ctx.PeerRead() { - copyFail := packets.CopyFail{ - Reason: "peer failed", - } - ctx.Packet = copyFail.IntoPacket(ctx.Packet) + copyFail := packets.CopyFail("peer failed") + ctx.Packet = ©Fail return ctx.ServerWrite() } @@ -87,11 +85,13 @@ func query(ctx *context) error { return err } case packets.TypeReadyForQuery: - var txState packets.ReadyForQuery - if !txState.ReadFromPacket(ctx.Packet) { - return ErrBadFormat + var p packets.ReadyForQuery + err = fed.ToConcrete(&p, ctx.Packet) + if err != nil { + return err } - ctx.TxState = byte(txState) + ctx.Packet = &p + ctx.TxState = byte(p) ctx.PeerWrite() return nil default: @@ -102,28 +102,35 @@ func query(ctx *context) error { func queryString(ctx *context, q string) error { qq := packets.Query(q) - ctx.Packet = qq.IntoPacket(ctx.Packet) + ctx.Packet = &qq return query(ctx) } -func QueryString(server, peer *fed.Conn, buffer fed.Packet, query string) (err, peerError error, packet fed.Packet) { +func QueryString(server, peer *fed.Conn, query string) (err, peerError error) { ctx := context{ Server: server, Peer: peer, - Packet: buffer, } err = queryString(&ctx, query) peerError = ctx.PeerError - packet = ctx.Packet return } -func SetParameter(server, peer *fed.Conn, buffer fed.Packet, name strutil.CIString, value string) (err, peerError error, packet fed.Packet) { +func SetParameter(server, peer *fed.Conn, name strutil.CIString, value string) (err, peerError error) { + var q strings.Builder + escapedName := strutil.Escape(name.String(), '"') + escapedValue := strutil.Escape(value, '\'') + q.Grow(len(`SET "" = ''`) + len(escapedName) + len(escapedValue)) + q.WriteString(`SET "`) + q.WriteString(escapedName) + q.WriteString(`" = '`) + q.WriteString(escapedValue) + q.WriteString(`'`) + return QueryString( server, peer, - buffer, - fmt.Sprintf(`SET "%s" = '%s'`, strutil.Escape(name.String(), '"'), strutil.Escape(value, '\'')), + q.String(), ) } @@ -146,11 +153,13 @@ func functionCall(ctx *context) error { packets.TypeNotificationResponse: ctx.PeerWrite() case packets.TypeReadyForQuery: - var txState packets.ReadyForQuery - if !txState.ReadFromPacket(ctx.Packet) { - return ErrBadFormat + var p packets.ReadyForQuery + err = fed.ToConcrete(&p, ctx.Packet) + if err != nil { + return err } - ctx.TxState = byte(txState) + ctx.Packet = &p + ctx.TxState = byte(p) ctx.PeerWrite() return nil default: @@ -160,7 +169,6 @@ func functionCall(ctx *context) error { } func sync(ctx *context) (bool, error) { - ctx.Packet = ctx.Packet.Reset(packets.TypeSync) if err := ctx.ServerWrite(); err != nil { return false, err } @@ -200,11 +208,13 @@ func sync(ctx *context) (bool, error) { return false, err } case packets.TypeReadyForQuery: - var txState packets.ReadyForQuery - if !txState.ReadFromPacket(ctx.Packet) { - return false, ErrBadFormat + var p packets.ReadyForQuery + err = fed.ToConcrete(&p, ctx.Packet) + if err != nil { + return false, err } - ctx.TxState = byte(txState) + ctx.Packet = &p + ctx.TxState = byte(p) ctx.PeerWrite() return true, nil default: @@ -213,15 +223,14 @@ func sync(ctx *context) (bool, error) { } } -func Sync(server, peer *fed.Conn, buffer fed.Packet) (err, peerErr error, packet fed.Packet) { +func Sync(server, peer *fed.Conn) (err, peerErr error) { ctx := context{ Server: server, Peer: peer, - Packet: buffer, + Packet: &packets.Sync{}, } _, err = sync(&ctx) peerErr = ctx.PeerError - packet = ctx.Packet return } @@ -233,6 +242,7 @@ func eqp(ctx *context) error { for { if !ctx.PeerRead() { for { + ctx.Packet = &packets.Sync{} ok, err := sync(ctx) if err != nil { return err @@ -276,7 +286,7 @@ func transaction(ctx *context) error { case packets.TypeSync: // phony sync call, we can just reply with a fake ReadyForQuery(TxState) rfq := packets.ReadyForQuery(ctx.TxState) - ctx.Packet = rfq.IntoPacket(ctx.Packet) + ctx.Packet = &rfq ctx.PeerWrite() case packets.TypeParse, packets.TypeBind, packets.TypeClose, packets.TypeDescribe, packets.TypeExecute, packets.TypeFlush: if err := eqp(ctx); err != nil { @@ -305,7 +315,7 @@ func transaction(ctx *context) error { } } -func Transaction(server, peer *fed.Conn, initialPacket fed.Packet) (err, peerError error, packet fed.Packet) { +func Transaction(server, peer *fed.Conn, initialPacket fed.Packet) (err, peerError error) { ctx := context{ Server: server, Peer: peer, @@ -313,6 +323,5 @@ func Transaction(server, peer *fed.Conn, initialPacket fed.Packet) (err, peerErr } err = transaction(&ctx) peerError = ctx.PeerError - packet = ctx.Packet return } diff --git a/lib/bouncer/bouncers/v2/bouncer.go b/lib/bouncer/bouncers/v2/bouncer.go index 573b8cc28a3ac92de6dcf1c5a03cfa5ace827877..946c66b29e11f4739a51a662743d28f37a1c1228 100644 --- a/lib/bouncer/bouncers/v2/bouncer.go +++ b/lib/bouncer/bouncers/v2/bouncer.go @@ -3,27 +3,22 @@ package bouncers import ( "gfx.cafe/gfx/pggat/lib/bouncer/backends/v0" "gfx.cafe/gfx/pggat/lib/fed" - packets "gfx.cafe/gfx/pggat/lib/fed/packets/v3.0" "gfx.cafe/gfx/pggat/lib/perror" ) -func clientFail(packet fed.Packet, client *fed.Conn, err perror.Error) fed.Packet { +func clientFail(client *fed.Conn, err perror.Error) { // send fatal error to client - resp := packets.ErrorResponse{ - Error: err, - } - packet = resp.IntoPacket(packet) - _ = client.WritePacket(packet) - return packet + resp := perror.ToPacket(err) + _ = client.WritePacket(resp) } -func Bounce(client, server *fed.Conn, initialPacket fed.Packet) (packet fed.Packet, clientError error, serverError error) { - serverError, clientError, packet = backends.Transaction(server, client, initialPacket) +func Bounce(client, server *fed.Conn, initialPacket fed.Packet) (clientError error, serverError error) { + serverError, clientError = backends.Transaction(server, client, initialPacket) if clientError != nil { - packet = clientFail(packet, client, perror.Wrap(clientError)) + clientFail(client, perror.Wrap(clientError)) } else if serverError != nil { - packet = clientFail(packet, client, perror.Wrap(serverError)) + clientFail(client, perror.Wrap(serverError)) } return diff --git a/lib/bouncer/frontends/v0/accept.go b/lib/bouncer/frontends/v0/accept.go index 5fadb9e3e51ba004a9e06fa86f103944bb7b09fd..00036e1abc5a8672eac16afe582f83d69b29b431 100644 --- a/lib/bouncer/frontends/v0/accept.go +++ b/lib/bouncer/frontends/v0/accept.go @@ -2,7 +2,6 @@ package frontends import ( "crypto/tls" - "io" "strings" "gfx.cafe/gfx/pggat/lib/fed" @@ -14,72 +13,47 @@ import ( func startup0( ctx *acceptContext, params *acceptParams, -) (cancelling bool, done bool, err perror.Error) { - var err2 error - ctx.Packet, err2 = ctx.Conn.ReadPacket(false, ctx.Packet) - if err2 != nil { - err = perror.Wrap(err2) +) (cancelling bool, done bool, err error) { + var packet fed.Packet + packet, err = ctx.Conn.ReadPacket(false) + if err != nil { return } - var majorVersion uint16 - var minorVersion uint16 - p := ctx.Packet.ReadUint16(&majorVersion) - p = p.ReadUint16(&minorVersion) + var p packets.Startup + err = fed.ToConcrete(&p, packet) + if err != nil { + return + } - if majorVersion == 1234 { - // Cancel or SSL - switch minorVersion { - case 5678: + switch mode := p.Mode.(type) { + case *packets.StartupPayloadControl: + switch control := mode.Mode.(type) { + case *packets.StartupPayloadControlPayloadCancel: // Cancel - p.ReadBytes(params.CancelKey[:]) + params.CancelKey.ProcessID = control.ProcessID + params.CancelKey.SecretKey = control.SecretKey cancelling = true done = true return - case 5679: - byteWriter, ok := ctx.Conn.ReadWriteCloser.(io.ByteWriter) - if !ok { - err = perror.New( - perror.FATAL, - perror.FeatureNotSupported, - "SSL is not supported", - ) - return - } - + case *packets.StartupPayloadControlPayloadSSL: // ssl is not enabled if ctx.Options.SSLConfig == nil { - err = perror.Wrap(byteWriter.WriteByte('N')) - return - } - - sslServer, ok := ctx.Conn.ReadWriteCloser.(fed.SSLServer) - if !ok { - err = perror.Wrap(byteWriter.WriteByte('N')) + err = ctx.Conn.WriteByte('N') return } // do ssl - if err = perror.Wrap(byteWriter.WriteByte('S')); err != nil { + if err = ctx.Conn.WriteByte('S'); err != nil { return } - if err = perror.Wrap(sslServer.EnableSSLServer(ctx.Options.SSLConfig)); err != nil { + if err = ctx.Conn.EnableSSL(ctx.Options.SSLConfig, false); err != nil { return } return - case 5680: - byteWriter, ok := ctx.Conn.ReadWriteCloser.(io.ByteWriter) - if !ok { - err = perror.New( - perror.FATAL, - perror.FeatureNotSupported, - "GSSAPI is not supported", - ) - return - } - + case *packets.StartupPayloadControlPayloadGSSAPI: // GSSAPI is not supported yet - err = perror.Wrap(byteWriter.WriteByte('N')) + err = ctx.Conn.WriteByte('N') return default: err = perror.New( @@ -89,121 +63,108 @@ func startup0( ) return } - } - - if majorVersion != 3 { - err = perror.New( - perror.FATAL, - perror.ProtocolViolation, - "Unsupported protocol version", - ) - return - } - - var unsupportedOptions []string - - for { - var key string - p = p.ReadString(&key) - if key == "" { - break - } - - var value string - p = p.ReadString(&value) - - switch key { - case "user": - ctx.Conn.User = value - case "database": - ctx.Conn.Database = value - case "options": - fields := strings.Fields(value) - for i := 0; i < len(fields); i++ { - switch fields[i] { - case "-c": - i++ - set := fields[i] - var ok bool - key, value, ok = strings.Cut(set, "=") - if !ok { + case *packets.StartupPayloadVersion3: + var unsupportedOptions []string + + for _, parameter := range mode.Parameters { + switch parameter.Key { + case "user": + ctx.Conn.User = parameter.Value + case "database": + ctx.Conn.Database = parameter.Value + case "options": + fields := strings.Fields(parameter.Value) + for i := 0; i < len(fields); i++ { + switch fields[i] { + case "-c": + i++ + set := fields[i] + key, value, ok := strings.Cut(set, "=") + if !ok { + err = perror.New( + perror.FATAL, + perror.ProtocolViolation, + "Expected key=value", + ) + return + } + + ikey := strutil.MakeCIString(key) + + if ctx.Conn.InitialParameters == nil { + ctx.Conn.InitialParameters = make(map[strutil.CIString]string) + } + ctx.Conn.InitialParameters[ikey] = value + default: err = perror.New( perror.FATAL, - perror.ProtocolViolation, - "Expected key=value", + perror.FeatureNotSupported, + "Flag not supported, sorry", ) return } - - ikey := strutil.MakeCIString(key) + } + case "replication": + err = perror.New( + perror.FATAL, + perror.FeatureNotSupported, + "Replication mode is not supported yet", + ) + return + default: + if strings.HasPrefix(parameter.Key, "_pq_.") { + // we don't support protocol extensions at the moment + unsupportedOptions = append(unsupportedOptions, parameter.Key) + } else { + ikey := strutil.MakeCIString(parameter.Key) if ctx.Conn.InitialParameters == nil { ctx.Conn.InitialParameters = make(map[strutil.CIString]string) } - ctx.Conn.InitialParameters[ikey] = value - default: - err = perror.New( - perror.FATAL, - perror.FeatureNotSupported, - "Flag not supported, sorry", - ) - return + ctx.Conn.InitialParameters[ikey] = parameter.Value } } - case "replication": + } + + if mode.MinorVersion != 0 || len(unsupportedOptions) > 0 { + // negotiate protocol + uopts := packets.NegotiateProtocolVersion{ + MinorProtocolVersion: 0, + UnrecognizedProtocolOptions: unsupportedOptions, + } + err = ctx.Conn.WritePacket(&uopts) + if err != nil { + return + } + } + + if ctx.Conn.User == "" { err = perror.New( perror.FATAL, - perror.FeatureNotSupported, - "Replication mode is not supported yet", + perror.InvalidAuthorizationSpecification, + "User is required", ) return - default: - if strings.HasPrefix(key, "_pq_.") { - // we don't support protocol extensions at the moment - unsupportedOptions = append(unsupportedOptions, key) - } else { - ikey := strutil.MakeCIString(key) - - if ctx.Conn.InitialParameters == nil { - ctx.Conn.InitialParameters = make(map[strutil.CIString]string) - } - ctx.Conn.InitialParameters[ikey] = value - } - } - } - - if minorVersion != 0 || len(unsupportedOptions) > 0 { - // negotiate protocol - uopts := packets.NegotiateProtocolVersion{ - MinorProtocolVersion: 0, - UnrecognizedOptions: unsupportedOptions, } - ctx.Packet = uopts.IntoPacket(ctx.Packet) - err = perror.Wrap(ctx.Conn.WritePacket(ctx.Packet)) - if err != nil { - return + if ctx.Conn.Database == "" { + ctx.Conn.Database = ctx.Conn.User } - } - if ctx.Conn.User == "" { + done = true + return + default: err = perror.New( perror.FATAL, - perror.InvalidAuthorizationSpecification, - "User is required", + perror.ProtocolViolation, + "Unsupported protocol version", ) return } - if ctx.Conn.Database == "" { - ctx.Conn.Database = ctx.Conn.User - } - - done = true - return } func accept0( ctx *acceptContext, -) (params acceptParams, err perror.Error) { +) (params acceptParams, err error) { for { var done bool params.IsCanceling, done, err = startup0(ctx, ¶ms) @@ -218,27 +179,24 @@ func accept0( return } -func fail(packet fed.Packet, client fed.ReadWriter, err perror.Error) { - resp := packets.ErrorResponse{ - Error: err, - } - packet = resp.IntoPacket(packet) - _ = client.WritePacket(packet) +func fail(client *fed.Conn, err error) { + resp := perror.ToPacket(perror.Wrap(err)) + _ = client.WritePacket(resp) } -func accept(ctx *acceptContext) (acceptParams, perror.Error) { +func accept(ctx *acceptContext) (acceptParams, error) { params, err := accept0(ctx) if err != nil { - fail(ctx.Packet, ctx.Conn, err) + fail(ctx.Conn, err) return acceptParams{}, err } return params, nil } func Accept(conn *fed.Conn, tlsConfig *tls.Config) ( - cancelKey [8]byte, + cancelKey fed.BackendKey, isCanceling bool, - err perror.Error, + err error, ) { ctx := acceptContext{ Conn: conn, diff --git a/lib/bouncer/frontends/v0/authenticate.go b/lib/bouncer/frontends/v0/authenticate.go index c22f4e3920af9877f2bceb6ca3d56dc49e4532ac..4c534ee24599dae1267b793998d9b20e25a5a95c 100644 --- a/lib/bouncer/frontends/v0/authenticate.go +++ b/lib/bouncer/frontends/v0/authenticate.go @@ -2,6 +2,7 @@ package frontends import ( "crypto/rand" + "encoding/binary" "errors" "io" @@ -11,69 +12,73 @@ import ( "gfx.cafe/gfx/pggat/lib/perror" ) -func authenticationSASLInitial(ctx *authenticateContext, creds auth.SASLServer) (tool auth.SASLVerifier, resp []byte, done bool, err perror.Error) { +func authenticationSASLInitial(ctx *authenticateContext, creds auth.SASLServer) (tool auth.SASLVerifier, resp []byte, done bool, err error) { // check which authentication method the client wants - var err2 error - ctx.Packet, err2 = ctx.Conn.ReadPacket(true, ctx.Packet) - if err2 != nil { - err = perror.Wrap(err2) + var packet fed.Packet + packet, err = ctx.Conn.ReadPacket(true) + if err != nil { return } - var initialResponse packets.SASLInitialResponse - if !initialResponse.ReadFromPacket(ctx.Packet) { - err = packets.ErrBadFormat + var p packets.SASLInitialResponse + err = fed.ToConcrete(&p, packet) + if err != nil { return } - tool, err2 = creds.VerifySASL(initialResponse.Mechanism) - if err2 != nil { - err = perror.Wrap(err2) + tool, err = creds.VerifySASL(p.Mechanism) + if err != nil { return } - resp, err2 = tool.Write(initialResponse.InitialResponse) - if err2 != nil { - if errors.Is(err2, io.EOF) { + resp, err = tool.Write(p.InitialClientResponse) + if err != nil { + if errors.Is(err, io.EOF) { done = true + err = nil return } - err = perror.Wrap(err2) return } return } -func authenticationSASLContinue(ctx *authenticateContext, tool auth.SASLVerifier) (resp []byte, done bool, err perror.Error) { - var err2 error - ctx.Packet, err2 = ctx.Conn.ReadPacket(true, ctx.Packet) - if err2 != nil { - err = perror.Wrap(err2) +func authenticationSASLContinue(ctx *authenticateContext, tool auth.SASLVerifier) (resp []byte, done bool, err error) { + var packet fed.Packet + packet, err = ctx.Conn.ReadPacket(true) + if err != nil { return } - var authResp packets.AuthenticationResponse - if !authResp.ReadFromPacket(ctx.Packet) { - err = packets.ErrBadFormat + var p packets.SASLResponse + err = fed.ToConcrete(&p, packet) + if err != nil { return } - resp, err2 = tool.Write(authResp) - if err2 != nil { - if errors.Is(err2, io.EOF) { + resp, err = tool.Write(p) + if err != nil { + if errors.Is(err, io.EOF) { done = true + err = nil return } - err = perror.Wrap(err2) return } return } -func authenticationSASL(ctx *authenticateContext, creds auth.SASLServer) perror.Error { - saslInitial := packets.AuthenticationSASL{ - Mechanisms: creds.SupportedSASLMechanisms(), +func authenticationSASL(ctx *authenticateContext, creds auth.SASLServer) error { + var mode packets.AuthenticationPayloadSASL + mechanisms := creds.SupportedSASLMechanisms() + for _, mechanism := range mechanisms { + mode = append(mode, packets.AuthenticationPayloadSASLMethod{ + Method: mechanism, + }) + } + + saslInitial := packets.Authentication{ + Mode: &mode, } - ctx.Packet = saslInitial.IntoPacket(ctx.Packet) - err := perror.Wrap(ctx.Conn.WritePacket(ctx.Packet)) + err := ctx.Conn.WritePacket(&saslInitial) if err != nil { return err } @@ -85,17 +90,21 @@ func authenticationSASL(ctx *authenticateContext, creds auth.SASLServer) perror. for { if done { - final := packets.AuthenticationSASLFinal(resp) - ctx.Packet = final.IntoPacket(ctx.Packet) - err = perror.Wrap(ctx.Conn.WritePacket(ctx.Packet)) + m := packets.AuthenticationPayloadSASLFinal(resp) + final := packets.Authentication{ + Mode: &m, + } + err = ctx.Conn.WritePacket(&final) if err != nil { return err } break } else { - cont := packets.AuthenticationSASLContinue(resp) - ctx.Packet = cont.IntoPacket(ctx.Packet) - err = perror.Wrap(ctx.Conn.WritePacket(ctx.Packet)) + m := packets.AuthenticationPayloadSASLContinue(resp) + cont := packets.Authentication{ + Mode: &m, + } + err = ctx.Conn.WritePacket(&cont) if err != nil { return err } @@ -110,39 +119,41 @@ func authenticationSASL(ctx *authenticateContext, creds auth.SASLServer) perror. return nil } -func authenticationMD5(ctx *authenticateContext, creds auth.MD5Server) perror.Error { +func authenticationMD5(ctx *authenticateContext, creds auth.MD5Server) error { var salt [4]byte _, err := rand.Read(salt[:]) if err != nil { - return perror.Wrap(err) + return err } - md5Initial := packets.AuthenticationMD5{ - Salt: salt, + mode := packets.AuthenticationPayloadMD5Password(salt) + md5Initial := packets.Authentication{ + Mode: &mode, } - ctx.Packet = md5Initial.IntoPacket(ctx.Packet) - err = ctx.Conn.WritePacket(ctx.Packet) + err = ctx.Conn.WritePacket(&md5Initial) if err != nil { - return perror.Wrap(err) + return err } - ctx.Packet, err = ctx.Conn.ReadPacket(true, ctx.Packet) + var packet fed.Packet + packet, err = ctx.Conn.ReadPacket(true) if err != nil { - return perror.Wrap(err) + return err } var pw packets.PasswordMessage - if !pw.ReadFromPacket(ctx.Packet) { - return packets.ErrUnexpectedPacket + err = fed.ToConcrete(&pw, packet) + if err != nil { + return err } - if err = creds.VerifyMD5(salt, pw.Password); err != nil { - return perror.Wrap(err) + if err = creds.VerifyMD5(salt, string(pw)); err != nil { + return err } return nil } -func authenticate(ctx *authenticateContext) (err perror.Error) { +func authenticate(ctx *authenticateContext) (err error) { if ctx.Options.Credentials != nil { if credsSASL, ok := ctx.Options.Credentials.(auth.SASLServer); ok { err = authenticationSASL(ctx, credsSASL) @@ -161,32 +172,40 @@ func authenticate(ctx *authenticateContext) (err perror.Error) { } // send auth Ok - authOk := packets.AuthenticationOk{} - ctx.Packet = authOk.IntoPacket(ctx.Packet) - if err = perror.Wrap(ctx.Conn.WritePacket(ctx.Packet)); err != nil { + authOk := packets.Authentication{ + Mode: &packets.AuthenticationPayloadOk{}, + } + if err = ctx.Conn.WritePacket(&authOk); err != nil { return } ctx.Conn.Authenticated = true // send backend key data - _, err2 := rand.Read(ctx.Conn.BackendKey[:]) - if err2 != nil { - err = perror.Wrap(err2) + var processID [4]byte + if _, err = rand.Reader.Read(processID[:]); err != nil { return } + var backendKey [4]byte + if _, err = rand.Reader.Read(backendKey[:]); err != nil { + return + } + ctx.Conn.BackendKey = fed.BackendKey{ + ProcessID: int32(binary.BigEndian.Uint32(processID[:])), + SecretKey: int32(binary.BigEndian.Uint32(backendKey[:])), + } keyData := packets.BackendKeyData{ - CancellationKey: ctx.Conn.BackendKey, + ProcessID: ctx.Conn.BackendKey.ProcessID, + SecretKey: ctx.Conn.BackendKey.SecretKey, } - ctx.Packet = keyData.IntoPacket(ctx.Packet) - if err = perror.Wrap(ctx.Conn.WritePacket(ctx.Packet)); err != nil { + if err = ctx.Conn.WritePacket(&keyData); err != nil { return } return } -func Authenticate(conn *fed.Conn, creds auth.Credentials) (err perror.Error) { +func Authenticate(conn *fed.Conn, creds auth.Credentials) (err error) { if conn.Authenticated { // already authenticated return diff --git a/lib/bouncer/frontends/v0/context.go b/lib/bouncer/frontends/v0/context.go index e0668cef9a24a5c7287da9562012e47f27cda543..993073ffab07b6d371176eff956b7627fa814a75 100644 --- a/lib/bouncer/frontends/v0/context.go +++ b/lib/bouncer/frontends/v0/context.go @@ -3,13 +3,11 @@ package frontends import "gfx.cafe/gfx/pggat/lib/fed" type acceptContext struct { - Packet fed.Packet Conn *fed.Conn Options acceptOptions } type authenticateContext struct { - Packet fed.Packet Conn *fed.Conn Options authenticateOptions } diff --git a/lib/bouncer/frontends/v0/params.go b/lib/bouncer/frontends/v0/params.go index 0d960dbf3edbad11e492c22e899dd71e08824172..4f28f8347cb111f03ade898b28fde91364420d3b 100644 --- a/lib/bouncer/frontends/v0/params.go +++ b/lib/bouncer/frontends/v0/params.go @@ -1,6 +1,8 @@ package frontends +import "gfx.cafe/gfx/pggat/lib/fed" + type acceptParams struct { - CancelKey [8]byte + CancelKey fed.BackendKey IsCanceling bool } diff --git a/lib/fed/backendkey.go b/lib/fed/backendkey.go new file mode 100644 index 0000000000000000000000000000000000000000..e611366bbcf9db31d64ddf330c0a0d455f9ec5ca --- /dev/null +++ b/lib/fed/backendkey.go @@ -0,0 +1,6 @@ +package fed + +type BackendKey struct { + ProcessID int32 + SecretKey int32 +} diff --git a/lib/fed/conn.go b/lib/fed/conn.go index c0b8e990d29292906f42356c127a0b1e7cce87db..547981adff48d7d564ff4b653fd9b05504b75b6d 100644 --- a/lib/fed/conn.go +++ b/lib/fed/conn.go @@ -1,6 +1,10 @@ package fed import ( + "crypto/tls" + "errors" + "net" + "gfx.cafe/gfx/pggat/lib/util/decorator" "gfx.cafe/gfx/pggat/lib/util/strutil" ) @@ -8,54 +12,128 @@ import ( type Conn struct { noCopy decorator.NoCopy - ReadWriteCloser + encoder Encoder + decoder Decoder + + NetConn net.Conn Middleware []Middleware + SSL bool User string Database string InitialParameters map[strutil.CIString]string Authenticated bool - BackendKey [8]byte + BackendKey BackendKey } -func NewConn(rw ReadWriteCloser) *Conn { - return &Conn{ - ReadWriteCloser: rw, +func NewConn(rw net.Conn) *Conn { + c := &Conn{ + NetConn: rw, } + c.encoder.Writer.Reset(rw) + c.decoder.Reader.Reset(rw) + return c +} + +func (T *Conn) Flush() error { + return T.encoder.Flush() } -func (T *Conn) ReadPacket(typed bool, buffer Packet) (packet Packet, err error) { - packet = buffer +func (T *Conn) ReadPacket(typed bool) (Packet, error) { + if err := T.Flush(); err != nil { + return nil, err + } + for { - packet, err = T.ReadWriteCloser.ReadPacket(typed, buffer) - if err != nil { - return + if err := T.decoder.Next(typed); err != nil { + return nil, err + } + var packet Packet + packet = PendingPacket{ + Decoder: &T.decoder, } for _, middleware := range T.Middleware { + var err error packet, err = middleware.ReadPacket(packet) if err != nil { - return + return nil, err } - if len(packet) == 0 { + if packet == nil { break } } - if len(packet) != 0 { - return + if packet != nil { + return packet, nil } } } -func (T *Conn) WritePacket(packet Packet) (err error) { +func (T *Conn) WritePacket(packet Packet) error { for _, middleware := range T.Middleware { + var err error packet, err = middleware.WritePacket(packet) - if err != nil || len(packet) == 0 { - return + if err != nil { + return err + } + if packet == nil { + break } } - err = T.ReadWriteCloser.WritePacket(packet) - return + if packet == nil { + return nil + } + + err := T.encoder.Next(packet.Type(), packet.Length()) + if err != nil { + return err + } + + return packet.WriteTo(&T.encoder) +} + +func (T *Conn) WriteByte(b byte) error { + return T.encoder.WriteByte(b) } -var _ ReadWriteCloser = (*Conn)(nil) +func (T *Conn) ReadByte() (byte, error) { + if err := T.Flush(); err != nil { + return 0, err + } + + return T.decoder.ReadByte() +} + +func (T *Conn) EnableSSL(config *tls.Config, isClient bool) error { + if T.SSL { + return errors.New("SSL is already enabled") + } + T.SSL = true + + // Flush buffers + if err := T.Flush(); err != nil { + return err + } + if T.decoder.Reader.Buffered() > 0 { + return errors.New("expected empty read buffer") + } + + var sslConn *tls.Conn + if isClient { + sslConn = tls.Client(T.NetConn, config) + } else { + sslConn = tls.Server(T.NetConn, config) + } + T.encoder.Writer.Reset(sslConn) + T.decoder.Reader.Reset(sslConn) + T.NetConn = sslConn + return sslConn.Handshake() +} + +func (T *Conn) Close() error { + if err := T.encoder.Flush(); err != nil { + return err + } + + return T.NetConn.Close() +} diff --git a/lib/fed/decoder.go b/lib/fed/decoder.go new file mode 100644 index 0000000000000000000000000000000000000000..df53acd30208adae54cedf22da2e6b99edbe73e0 --- /dev/null +++ b/lib/fed/decoder.go @@ -0,0 +1,156 @@ +package fed + +import ( + "bufio" + "encoding/binary" + "io" + "math" + + "gfx.cafe/gfx/pggat/lib/util/decorator" +) + +type Decoder struct { + noCopy decorator.NoCopy + + Reader bufio.Reader + + typ Type + len int + pos int + + buf [8]byte +} + +func NewDecoder(r io.Reader) *Decoder { + d := &Decoder{} + d.Reader.Reset(r) + return d +} + +func (T *Decoder) Read(b []byte) (n int, err error) { + rem := T.len - T.pos + if rem == 0 { + err = io.EOF + return + } + if len(b) > rem { + n, err = T.Reader.Read(b[:rem]) + } else { + n, err = T.Reader.Read(b) + } + T.pos += n + return +} + +func (T *Decoder) ReadByte() (byte, error) { + if T.pos != T.len { + _, err := T.Reader.Discard(T.len - T.pos) + if err != nil { + return 0, err + } + } + + T.typ = 0 + T.len = 0 + T.pos = 0 + return T.Reader.ReadByte() +} + +func (T *Decoder) Next(typed bool) error { + if T.pos != T.len { + _, err := T.Reader.Discard(T.len - T.pos) + if err != nil { + return err + } + } + + var err error + if typed { + _, err = io.ReadFull(&T.Reader, T.buf[:5]) + } else { + T.buf[0] = 0 + _, err = io.ReadFull(&T.Reader, T.buf[1:5]) + } + if err != nil { + return err + } + T.typ = Type(T.buf[0]) + T.len = int(binary.BigEndian.Uint32(T.buf[1:5])) - 4 + T.pos = 0 + return nil +} + +func (T *Decoder) Type() Type { + return T.typ +} + +func (T *Decoder) Length() int { + return T.len +} + +func (T *Decoder) Position() int { + return T.pos +} + +func (T *Decoder) Uint8() (uint8, error) { + v, err := T.Reader.ReadByte() + T.pos += 1 + return v, err +} + +func (T *Decoder) Uint16() (uint16, error) { + _, err := io.ReadFull(&T.Reader, T.buf[:2]) + T.pos += 2 + return binary.BigEndian.Uint16(T.buf[:2]), err +} + +func (T *Decoder) Uint32() (uint32, error) { + _, err := io.ReadFull(&T.Reader, T.buf[:4]) + T.pos += 4 + return binary.BigEndian.Uint32(T.buf[:4]), err +} + +func (T *Decoder) Uint64() (uint64, error) { + _, err := io.ReadFull(&T.Reader, T.buf[:8]) + T.pos += 8 + return binary.BigEndian.Uint64(T.buf[:8]), err +} + +func (T *Decoder) Int8() (int8, error) { + v, err := T.Uint8() + return int8(v), err +} + +func (T *Decoder) Int16() (int16, error) { + v, err := T.Uint16() + return int16(v), err +} + +func (T *Decoder) Int32() (int32, error) { + v, err := T.Uint32() + return int32(v), err +} + +func (T *Decoder) Int64() (int64, error) { + v, err := T.Uint64() + return int64(v), err +} + +func (T *Decoder) Float32() (float32, error) { + v, err := T.Uint32() + return math.Float32frombits(v), err +} + +func (T *Decoder) Float64() (float64, error) { + v, err := T.Uint64() + return math.Float64frombits(v), err +} + +func (T *Decoder) String() (string, error) { + s, err := T.Reader.ReadString(0) + if err != nil { + return "", err + } + T.pos += len(s) + return s[:len(s)-1], nil +} diff --git a/lib/fed/encoder.go b/lib/fed/encoder.go new file mode 100644 index 0000000000000000000000000000000000000000..0acf75053a46b3df37c806571d144e817dda13e8 --- /dev/null +++ b/lib/fed/encoder.go @@ -0,0 +1,137 @@ +package fed + +import ( + "bufio" + "encoding/binary" + "io" + "math" + + "gfx.cafe/gfx/pggat/lib/util/decorator" +) + +type Encoder struct { + noCopy decorator.NoCopy + + Writer bufio.Writer + + typ Type + len int + pos int + + buf [8]byte +} + +func NewEncoder(w io.Writer) *Encoder { + e := &Encoder{} + e.Writer.Reset(w) + return e +} + +func (T *Encoder) Flush() error { + return T.Writer.Flush() +} + +func (T *Encoder) WriteByte(b byte) error { + if T.pos != T.len { + panic("wrong number of bytes written") + } + + T.typ = 0 + T.len = 0 + T.pos = 0 + return T.Writer.WriteByte(b) +} + +func (T *Encoder) Next(typ Type, length int) error { + if T.pos != T.len { + panic("wrong number of bytes written") + } + + if typ != 0 { + if err := T.Writer.WriteByte(byte(typ)); err != nil { + return err + } + } + + binary.BigEndian.PutUint32(T.buf[:4], uint32(length+4)) + _, err := T.Writer.Write(T.buf[:4]) + + T.typ = typ + T.len = length + T.pos = 0 + + return err +} + +func (T *Encoder) Type() Type { + return T.typ +} + +func (T *Encoder) Length() int { + return T.len +} + +func (T *Encoder) Position() int { + return T.pos +} + +func (T *Encoder) Uint8(v uint8) error { + err := T.Writer.WriteByte(v) + T.pos += 1 + return err +} + +func (T *Encoder) Uint16(v uint16) error { + binary.BigEndian.PutUint16(T.buf[:2], v) + _, err := T.Writer.Write(T.buf[:2]) + T.pos += 2 + return err +} + +func (T *Encoder) Uint32(v uint32) error { + binary.BigEndian.PutUint32(T.buf[:4], v) + _, err := T.Writer.Write(T.buf[:4]) + T.pos += 4 + return err +} + +func (T *Encoder) Uint64(v uint64) error { + binary.BigEndian.PutUint64(T.buf[:8], v) + _, err := T.Writer.Write(T.buf[:8]) + T.pos += 8 + return err +} + +func (T *Encoder) Int8(v int8) error { + return T.Uint8(uint8(v)) +} + +func (T *Encoder) Int16(v int16) error { + return T.Uint16(uint16(v)) +} + +func (T *Encoder) Int32(v int32) error { + return T.Uint32(uint32(v)) +} + +func (T *Encoder) Int64(v int64) error { + return T.Uint64(uint64(v)) +} + +func (T *Encoder) Float32(v float32) error { + return T.Uint32(math.Float32bits(v)) +} + +func (T *Encoder) Float64(v float64) error { + return T.Uint64(math.Float64bits(v)) +} + +func (T *Encoder) String(v string) error { + n, err := T.Writer.WriteString(v) + if err != nil { + return err + } + err = T.Writer.WriteByte(0) + T.pos += n + 1 + return err +} diff --git a/lib/fed/middlewares/eqp/client.go b/lib/fed/middlewares/eqp/client.go index 47417442094ac0b94e8304be45c5fb1af67a8cbd..aeaab9e81db6b8ff2815286c581ab4177de5d103 100644 --- a/lib/fed/middlewares/eqp/client.go +++ b/lib/fed/middlewares/eqp/client.go @@ -13,13 +13,11 @@ func NewClient() *Client { } func (T *Client) ReadPacket(packet fed.Packet) (fed.Packet, error) { - T.state.C2S(packet) - return packet, nil + return T.state.C2S(packet) } func (T *Client) WritePacket(packet fed.Packet) (fed.Packet, error) { - T.state.S2C(packet) - return packet, nil + return T.state.S2C(packet) } var _ fed.Middleware = (*Client)(nil) diff --git a/lib/fed/middlewares/eqp/server.go b/lib/fed/middlewares/eqp/server.go index f1b9e7889ac2b5bf3fae74e07edf4e4c73080bcc..9b070d971dde21c1292e36e2788d64cf02d4087c 100644 --- a/lib/fed/middlewares/eqp/server.go +++ b/lib/fed/middlewares/eqp/server.go @@ -13,13 +13,11 @@ func NewServer() *Server { } func (T *Server) ReadPacket(packet fed.Packet) (fed.Packet, error) { - T.state.S2C(packet) - return packet, nil + return T.state.S2C(packet) } func (T *Server) WritePacket(packet fed.Packet) (fed.Packet, error) { - T.state.C2S(packet) - return packet, nil + return T.state.C2S(packet) } var _ fed.Middleware = (*Server)(nil) diff --git a/lib/fed/middlewares/eqp/state.go b/lib/fed/middlewares/eqp/state.go index a8e7507c655cce83282dc4d8f44eb75b3c989d87..f029e01d0bb26ebc510df7012404b891accad86d 100644 --- a/lib/fed/middlewares/eqp/state.go +++ b/lib/fed/middlewares/eqp/state.go @@ -1,53 +1,12 @@ package eqp import ( - "bytes" - "hash/maphash" - "gfx.cafe/gfx/pggat/lib/fed" packets "gfx.cafe/gfx/pggat/lib/fed/packets/v3.0" "gfx.cafe/gfx/pggat/lib/util/maps" "gfx.cafe/gfx/pggat/lib/util/ring" ) -var seed = maphash.MakeSeed() - -type PreparedStatement struct { - Packet fed.Packet - Target string - Hash uint64 -} - -func MakePreparedStatement(packet fed.Packet) PreparedStatement { - if packet.Type() != packets.TypeParse { - panic("unreachable") - } - - var res PreparedStatement - packet.ReadString(&res.Target) - res.Packet = bytes.Clone(packet) - res.Hash = maphash.Bytes(seed, packet.Payload()) - - return res -} - -type Portal struct { - Packet fed.Packet - Target string -} - -func MakePortal(packet fed.Packet) Portal { - if packet.Type() != packets.TypeBind { - panic("unreachable") - } - - var res Portal - packet.ReadString(&res.Target) - res.Packet = bytes.Clone(packet) - - return res -} - type CloseVariant int const ( @@ -61,65 +20,76 @@ type Close struct { } type State struct { - preparedStatements map[string]PreparedStatement - portals map[string]Portal + preparedStatements map[string]*packets.Parse + portals map[string]*packets.Bind - pendingPreparedStatements ring.Ring[PreparedStatement] - pendingPortals ring.Ring[Portal] + pendingPreparedStatements ring.Ring[*packets.Parse] + pendingPortals ring.Ring[*packets.Bind] pendingCloses ring.Ring[Close] } // C2S is client to server packets -func (T *State) C2S(packet fed.Packet) { +func (T *State) C2S(packet fed.Packet) (fed.Packet, error) { switch packet.Type() { case packets.TypeClose: - T.Close(packet) + return T.Close(packet) case packets.TypeParse: - T.Parse(packet) + return T.Parse(packet) case packets.TypeBind: - T.Bind(packet) + return T.Bind(packet) case packets.TypeQuery: T.Query() + return packet, nil + default: + return packet, nil } } // S2C is server to client packets -func (T *State) S2C(packet fed.Packet) { +func (T *State) S2C(packet fed.Packet) (fed.Packet, error) { switch packet.Type() { case packets.TypeCloseComplete: T.CloseComplete() + return packet, nil case packets.TypeParseComplete: T.ParseComplete() + return packet, nil case packets.TypeBindComplete: T.BindComplete() + return packet, nil case packets.TypeCommandComplete: - T.CommandComplete(packet) + return T.CommandComplete(packet) case packets.TypeReadyForQuery: - T.ReadyForQuery(packet) + return T.ReadyForQuery(packet) + default: + return packet, nil } } // Close is a pending close. Execute on Close C->S -func (T *State) Close(packet fed.Packet) { - var which byte - p := packet.ReadUint8(&which) - var target string - p.ReadString(&target) +func (T *State) Close(packet fed.Packet) (fed.Packet, error) { + var p packets.Close + err := fed.ToConcrete(&p, packet) + if err != nil { + return nil, err + } var variant CloseVariant - switch which { + switch p.Which { case 'S': variant = CloseVariantPreparedStatement case 'P': variant = CloseVariantPortal default: - return + return nil, packets.ErrInvalidFormat } T.pendingCloses.PushBack(Close{ Variant: variant, - Target: target, + Target: p.Name, }) + + return &p, nil } // CloseComplete notifies that a close was successful. Execute on CloseComplete S->C @@ -140,9 +110,14 @@ func (T *State) CloseComplete() { } // Parse is a pending prepared statement. Execute on Parse C->S -func (T *State) Parse(packet fed.Packet) { - preparedStatement := MakePreparedStatement(packet) - T.pendingPreparedStatements.PushBack(preparedStatement) +func (T *State) Parse(packet fed.Packet) (fed.Packet, error) { + var p packets.Parse + err := fed.ToConcrete(&p, packet) + if err != nil { + return nil, err + } + T.pendingPreparedStatements.PushBack(&p) + return &p, nil } // ParseComplete notifies that a parse was successful. Execute on ParseComplete S->C @@ -153,15 +128,20 @@ func (T *State) ParseComplete() { } if T.preparedStatements == nil { - T.preparedStatements = make(map[string]PreparedStatement) + T.preparedStatements = make(map[string]*packets.Parse) } - T.preparedStatements[preparedStatement.Target] = preparedStatement + T.preparedStatements[preparedStatement.Destination] = preparedStatement } // Bind is a pending portal. Execute on Bind C->S -func (T *State) Bind(packet fed.Packet) { - portal := MakePortal(packet) - T.pendingPortals.PushBack(portal) +func (T *State) Bind(packet fed.Packet) (fed.Packet, error) { + var p packets.Bind + err := fed.ToConcrete(&p, packet) + if err != nil { + return nil, err + } + T.pendingPortals.PushBack(&p) + return &p, nil } // BindComplete notifies that a bind was successful. Execute on BindComplete S->C @@ -172,9 +152,9 @@ func (T *State) BindComplete() { } if T.portals == nil { - T.portals = make(map[string]Portal) + T.portals = make(map[string]*packets.Bind) } - T.portals[portal.Target] = portal + T.portals[portal.Destination] = portal } // Query clobbers the unnamed portal and unnamed prepared statement. Execute on Query C->S @@ -184,27 +164,33 @@ func (T *State) Query() { } // CommandComplete clobbers everything if DISCARD ALL | DEALLOCATE | CLOSE -func (T *State) CommandComplete(packet fed.Packet) { - var commandComplete packets.CommandComplete - if !commandComplete.ReadFromPacket(packet) { - return +func (T *State) CommandComplete(packet fed.Packet) (fed.Packet, error) { + var p packets.CommandComplete + err := fed.ToConcrete(&p, packet) + if err != nil { + return nil, err } - if commandComplete == "DISCARD ALL" { + if p == "DISCARD ALL" { maps.Clear(T.preparedStatements) maps.Clear(T.portals) T.pendingPreparedStatements.Clear() T.pendingPortals.Clear() T.pendingCloses.Clear() } + + return &p, nil } // ReadyForQuery clobbers portals if state == 'I' and pending. Execute on ReadyForQuery S->C -func (T *State) ReadyForQuery(packet fed.Packet) { - var state byte - packet.ReadUint8(&state) +func (T *State) ReadyForQuery(packet fed.Packet) (fed.Packet, error) { + var p packets.ReadyForQuery + err := fed.ToConcrete(&p, packet) + if err != nil { + return nil, err + } - if state == 'I' { + if p == 'I' { // clobber all portals for name := range T.portals { delete(T.portals, name) @@ -215,4 +201,6 @@ func (T *State) ReadyForQuery(packet fed.Packet) { T.pendingPreparedStatements.Clear() T.pendingPortals.Clear() T.pendingCloses.Clear() + + return &p, nil } diff --git a/lib/fed/middlewares/eqp/sync.go b/lib/fed/middlewares/eqp/sync.go index 150d8e0d9ef2824a7cbbdc4f9029dc92d29abf7d..05fc56e53b2860c246faf1e5549f87a8ce9715dc 100644 --- a/lib/fed/middlewares/eqp/sync.go +++ b/lib/fed/middlewares/eqp/sync.go @@ -1,11 +1,25 @@ package eqp import ( + "slices" + "gfx.cafe/gfx/pggat/lib/bouncer/backends/v0" "gfx.cafe/gfx/pggat/lib/fed" packets "gfx.cafe/gfx/pggat/lib/fed/packets/v3.0" ) +func preparedStatementsEqual(a, b *packets.Parse) bool { + if a.Query != b.Query { + return false + } + + if !slices.Equal(a.ParameterDataTypes, b.ParameterDataTypes) { + return false + } + + return true +} + func Sync(c *Client, server *fed.Conn, s *Server) error { var needsBackendSync bool @@ -16,15 +30,12 @@ func Sync(c *Client, server *fed.Conn, s *Server) error { needsBackendSync = true } - var packet fed.Packet - for name := range s.state.portals { p := packets.Close{ - Which: 'P', - Target: name, + Which: 'P', + Name: name, } - packet = p.IntoPacket(packet) - if err := server.WritePacket(packet); err != nil { + if err := server.WritePacket(&p); err != nil { return err } } @@ -32,8 +43,7 @@ func Sync(c *Client, server *fed.Conn, s *Server) error { // close all prepared statements that don't match client for name, preparedStatement := range s.state.preparedStatements { if clientPreparedStatement, ok := c.state.preparedStatements[name]; ok { - if preparedStatement.Hash == clientPreparedStatement.Hash { - // the same + if preparedStatementsEqual(preparedStatement, clientPreparedStatement) { continue } @@ -44,11 +54,10 @@ func Sync(c *Client, server *fed.Conn, s *Server) error { } p := packets.Close{ - Which: 'S', - Target: name, + Which: 'S', + Name: name, } - packet = p.IntoPacket(packet) - if err := server.WritePacket(packet); err != nil { + if err := server.WritePacket(&p); err != nil { return err } @@ -58,13 +67,12 @@ func Sync(c *Client, server *fed.Conn, s *Server) error { // parse all prepared statements that aren't on server for name, preparedStatement := range c.state.preparedStatements { if serverPreparedStatement, ok := s.state.preparedStatements[name]; ok { - if preparedStatement.Hash == serverPreparedStatement.Hash { - // the same + if preparedStatementsEqual(preparedStatement, serverPreparedStatement) { continue } } - if err := server.WritePacket(preparedStatement.Packet); err != nil { + if err := server.WritePacket(preparedStatement); err != nil { return err } @@ -77,14 +85,14 @@ func Sync(c *Client, server *fed.Conn, s *Server) error { } for _, portal := range c.state.portals { - if err := server.WritePacket(portal.Packet); err != nil { + if err := server.WritePacket(portal); err != nil { return err } } if needsBackendSync { var err error - err, _, packet = backends.Sync(server, nil, packet) + err, _ = backends.Sync(server, nil) return err } diff --git a/lib/fed/middlewares/ps/client.go b/lib/fed/middlewares/ps/client.go index ecb819f992b19c47dbf313604db87df7e0f7b2d9..a0ca2278d4a028bdbf646b32e06384c1ea17ccb8 100644 --- a/lib/fed/middlewares/ps/client.go +++ b/lib/fed/middlewares/ps/client.go @@ -1,8 +1,6 @@ package ps import ( - "errors" - "gfx.cafe/gfx/pggat/lib/fed" packets "gfx.cafe/gfx/pggat/lib/fed/packets/v3.0" "gfx.cafe/gfx/pggat/lib/util/strutil" @@ -26,21 +24,24 @@ func (T *Client) ReadPacket(packet fed.Packet) (fed.Packet, error) { func (T *Client) WritePacket(packet fed.Packet) (fed.Packet, error) { switch packet.Type() { case packets.TypeParameterStatus: - var ps packets.ParameterStatus - if !ps.ReadFromPacket(packet) { - return packet, errors.New("bad packet format i") + var p packets.ParameterStatus + err := fed.ToConcrete(&p, packet) + if err != nil { + return nil, err } - ikey := strutil.MakeCIString(ps.Key) - if T.synced && T.parameters[ikey] == ps.Value { + ikey := strutil.MakeCIString(p.Key) + if T.synced && T.parameters[ikey] == p.Value { // already set - return packet[:0], nil + return nil, nil } if T.parameters == nil { T.parameters = make(map[strutil.CIString]string) } - T.parameters[ikey] = ps.Value + T.parameters[ikey] = p.Value + return &p, nil + default: + return packet, nil } - return packet, nil } var _ fed.Middleware = (*Client)(nil) diff --git a/lib/fed/middlewares/ps/server.go b/lib/fed/middlewares/ps/server.go index f74f4f0c8c2c15414a34524984b83d313cc53159..dcc8515662a8dcf94d568b55523c44e182237ef5 100644 --- a/lib/fed/middlewares/ps/server.go +++ b/lib/fed/middlewares/ps/server.go @@ -1,8 +1,6 @@ package ps import ( - "errors" - "gfx.cafe/gfx/pggat/lib/fed" packets "gfx.cafe/gfx/pggat/lib/fed/packets/v3.0" "gfx.cafe/gfx/pggat/lib/util/strutil" @@ -21,17 +19,20 @@ func NewServer(parameters map[strutil.CIString]string) *Server { func (T *Server) ReadPacket(packet fed.Packet) (fed.Packet, error) { switch packet.Type() { case packets.TypeParameterStatus: - var ps packets.ParameterStatus - if !ps.ReadFromPacket(packet) { - return packet, errors.New("bad packet format j") + var p packets.ParameterStatus + err := fed.ToConcrete(&p, packet) + if err != nil { + return nil, err } - ikey := strutil.MakeCIString(ps.Key) + ikey := strutil.MakeCIString(p.Key) if T.parameters == nil { T.parameters = make(map[strutil.CIString]string) } - T.parameters[ikey] = ps.Value + T.parameters[ikey] = p.Value + return &p, nil + default: + return packet, nil } - return packet, nil } func (T *Server) WritePacket(packet fed.Packet) (fed.Packet, error) { diff --git a/lib/fed/middlewares/ps/sync.go b/lib/fed/middlewares/ps/sync.go index be296b9c3421570d64d5d46460fdf623419c5325..8f9f19267e23c7918527a56c781338c06742a2be 100644 --- a/lib/fed/middlewares/ps/sync.go +++ b/lib/fed/middlewares/ps/sync.go @@ -12,16 +12,13 @@ func sync(tracking []strutil.CIString, client *fed.Conn, c *Client, server *fed. value, hasValue := c.parameters[name] expected, hasExpected := s.parameters[name] - var packet fed.Packet - if value == expected { if !c.synced { ps := packets.ParameterStatus{ Key: name.String(), Value: expected, } - packet = ps.IntoPacket(packet) - if err := client.WritePacket(packet); err != nil { + if err := client.WritePacket(&ps); err != nil { return err } } @@ -32,7 +29,7 @@ func sync(tracking []strutil.CIString, client *fed.Conn, c *Client, server *fed. if hasValue && slices.Contains(tracking, name) { var err error - if err, _, packet = backends.SetParameter(server, nil, packet, name, value); err != nil { + if err, _ = backends.SetParameter(server, nil, name, value); err != nil { return err } if s.parameters == nil { @@ -50,8 +47,7 @@ func sync(tracking []strutil.CIString, client *fed.Conn, c *Client, server *fed. Key: name.String(), Value: expected, } - packet = ps.IntoPacket(packet) - if err := client.WritePacket(packet); err != nil { + if err := client.WritePacket(&ps); err != nil { return err } } diff --git a/lib/fed/netconn.go b/lib/fed/netconn.go deleted file mode 100644 index 480edb12b2c66cca2eea13888daac31ca226c404..0000000000000000000000000000000000000000 --- a/lib/fed/netconn.go +++ /dev/null @@ -1,144 +0,0 @@ -package fed - -import ( - "bufio" - "crypto/tls" - "encoding/binary" - "errors" - "io" - "net" - - "gfx.cafe/gfx/pggat/lib/util/slices" -) - -type NetConn struct { - conn net.Conn - writer bufio.Writer - reader bufio.Reader - sslEnabled bool - - headerBuf [5]byte -} - -func NewNetConn(conn net.Conn) *NetConn { - c := &NetConn{ - conn: conn, - } - c.writer.Reset(conn) - c.reader.Reset(conn) - return c -} - -func (T *NetConn) LocalAddr() net.Addr { - return T.conn.LocalAddr() -} - -func (T *NetConn) RemoteAddr() net.Addr { - return T.conn.RemoteAddr() -} - -// SSL - -var errSSLAlreadyEnabled = errors.New("ssl is already enabled") - -func (T *NetConn) SSL() bool { - return T.sslEnabled -} - -func (T *NetConn) EnableSSLClient(config *tls.Config) error { - if T.sslEnabled { - return errSSLAlreadyEnabled - } - T.sslEnabled = true - - if err := T.writer.Flush(); err != nil { - return err - } - if T.reader.Buffered() > 0 { - return errors.New("expected empty read buffer") - } - sslConn := tls.Client(T.conn, config) - T.writer.Reset(sslConn) - T.reader.Reset(sslConn) - T.conn = sslConn - return sslConn.Handshake() -} - -func (T *NetConn) EnableSSLServer(config *tls.Config) error { - if T.sslEnabled { - return errSSLAlreadyEnabled - } - T.sslEnabled = true - - if err := T.writer.Flush(); err != nil { - return err - } - if T.reader.Buffered() > 0 { - return errors.New("expected empty read buffer") - } - sslConn := tls.Server(T.conn, config) - T.writer.Reset(sslConn) - T.reader.Reset(sslConn) - T.conn = sslConn - return sslConn.Handshake() -} - -func (T *NetConn) ReadByte() (byte, error) { - if err := T.writer.Flush(); err != nil { - return 0, err - } - return T.reader.ReadByte() -} - -func (T *NetConn) ReadPacket(typed bool, buffer Packet) (packet Packet, err error) { - packet = buffer - - if err = T.writer.Flush(); err != nil { - return - } - - if typed { - _, err = io.ReadFull(&T.reader, T.headerBuf[:]) - if err != nil { - return - } - } else { - _, err = io.ReadFull(&T.reader, T.headerBuf[1:]) - if err != nil { - return - } - } - - length := binary.BigEndian.Uint32(T.headerBuf[1:]) - - packet = slices.Resize(buffer, int(length)+1) - copy(packet, T.headerBuf[:]) - - _, err = io.ReadFull(&T.reader, packet.Payload()) - if err != nil { - return - } - return -} - -func (T *NetConn) WriteByte(b byte) error { - return T.writer.WriteByte(b) -} - -func (T *NetConn) WritePacket(packet Packet) error { - _, err := T.writer.Write(packet.Bytes()) - return err -} - -func (T *NetConn) Close() error { - if err := T.writer.Flush(); err != nil { - return err - } - return T.conn.Close() -} - -var _ ReadWriteCloser = (*NetConn)(nil) -var _ SSLServer = (*NetConn)(nil) -var _ SSLClient = (*NetConn)(nil) -var _ io.ByteReader = (*NetConn)(nil) -var _ io.ByteWriter = (*NetConn)(nil) diff --git a/lib/fed/packet.go b/lib/fed/packet.go index 2a87a27731df8216bf80f37cf462eb33095d1b9d..6da6f2bf682c0ad77fe192ae2fc078275d728519 100644 --- a/lib/fed/packet.go +++ b/lib/fed/packet.go @@ -1,247 +1,54 @@ package fed -import ( - "encoding/binary" - "math" +type Packet interface { + Type() Type + Length() int - "gfx.cafe/gfx/pggat/lib/util/slices" -) - -type Packet []byte - -func NewPacket(typ Type, size ...int) Packet { - return Packet(nil).Reset(typ, size...) -} - -func (T Packet) Reset(typ Type, size ...int) Packet { - packet := T - c := 5 - if len(size) > 0 { - c += size[0] - } - - if cap(packet) < c { - packet = make([]byte, 5, c) - } else { - packet = slices.Resize(packet, 5) - } - packet[0] = byte(typ) - packet[1] = 0 - packet[2] = 0 - packet[3] = 0 - packet[4] = 0 - return packet -} - -func (T Packet) Payload() PacketFragment { - return PacketFragment(T[5:]) -} - -func (T Packet) Bytes() []byte { - binary.BigEndian.PutUint32(T[1:], uint32(len(T)-1)) - - if T.Type() == 0 { - return T[1:] - } - return T -} - -func (T Packet) Type() Type { - return Type(T[0]) -} - -func (T Packet) AppendUint8(v uint8) Packet { - return append(T, v) + WriteTo(encoder *Encoder) error } -func (T Packet) AppendUint16(v uint16) Packet { - return binary.BigEndian.AppendUint16(T, v) -} - -func (T Packet) AppendUint32(v uint32) Packet { - return binary.BigEndian.AppendUint32(T, v) -} - -func (T Packet) AppendUint64(v uint64) Packet { - return binary.BigEndian.AppendUint64(T, v) -} +type ReadablePacket interface { + Packet -func (T Packet) AppendInt8(v int8) Packet { - return T.AppendUint8(uint8(v)) + ReadFrom(decoder *Decoder) error } -func (T Packet) AppendInt16(v int16) Packet { - return T.AppendUint16(uint16(v)) +type PendingPacket struct { + Decoder *Decoder } -func (T Packet) AppendInt32(v int32) Packet { - return T.AppendUint32(uint32(v)) +func (T PendingPacket) Type() Type { + return T.Decoder.Type() } -func (T Packet) AppendInt64(v int64) Packet { - return T.AppendUint64(uint64(v)) +func (T PendingPacket) Length() int { + return T.Decoder.Length() } -func (T Packet) AppendFloat32(v float32) Packet { - return T.AppendUint32(math.Float32bits(v)) -} - -func (T Packet) AppendFloat64(v float64) Packet { - return T.AppendUint64(math.Float64bits(v)) -} - -func (T Packet) AppendString(v string) Packet { - return append(append(T, v...), 0) -} - -func (T Packet) AppendBytes(v []byte) Packet { - return append(T, v...) -} - -func (T Packet) ReadUint8(v *uint8) PacketFragment { - return T.Payload().ReadUint8(v) -} - -func (T Packet) ReadUint16(v *uint16) PacketFragment { - return T.Payload().ReadUint16(v) -} - -func (T Packet) ReadUint32(v *uint32) PacketFragment { - return T.Payload().ReadUint32(v) -} - -func (T Packet) ReadUint64(v *uint64) PacketFragment { - return T.Payload().ReadUint64(v) -} - -func (T Packet) ReadInt8(v *int8) PacketFragment { - return T.Payload().ReadInt8(v) -} - -func (T Packet) ReadInt16(v *int16) PacketFragment { - return T.Payload().ReadInt16(v) -} - -func (T Packet) ReadInt32(v *int32) PacketFragment { - return T.Payload().ReadInt32(v) -} - -func (T Packet) ReadInt64(v *int64) PacketFragment { - return T.Payload().ReadInt64(v) -} - -func (T Packet) ReadFloat32(v *float32) PacketFragment { - return T.Payload().ReadFloat32(v) -} - -func (T Packet) ReadFloat64(v *float64) PacketFragment { - return T.Payload().ReadFloat64(v) -} - -func (T Packet) ReadString(v *string) PacketFragment { - return T.Payload().ReadString(v) -} - -func (T Packet) ReadBytes(v []byte) PacketFragment { - return T.Payload().ReadBytes(v) -} - -type PacketFragment []byte - -func (T PacketFragment) ReadUint8(v *uint8) PacketFragment { - if len(T) < 1 { - return T - } - - *v = T[0] - return T[1:] -} - -func (T PacketFragment) ReadUint16(v *uint16) PacketFragment { - if len(T) < 2 { - return T - } - - *v = binary.BigEndian.Uint16(T) - return T[2:] -} - -func (T PacketFragment) ReadUint32(v *uint32) PacketFragment { - if len(T) < 4 { - return T - } - - *v = binary.BigEndian.Uint32(T) - return T[4:] -} - -func (T PacketFragment) ReadUint64(v *uint64) PacketFragment { - if len(T) < 8 { - return T - } - - *v = binary.BigEndian.Uint64(T) - return T[8:] -} - -func (T PacketFragment) ReadInt8(v *int8) PacketFragment { - var vv uint8 - n := T.ReadUint8(&vv) - *v = int8(vv) - return n -} - -func (T PacketFragment) ReadInt16(v *int16) PacketFragment { - var vv uint16 - n := T.ReadUint16(&vv) - *v = int16(vv) - return n -} - -func (T PacketFragment) ReadInt32(v *int32) PacketFragment { - var vv uint32 - n := T.ReadUint32(&vv) - *v = int32(vv) - return n -} - -func (T PacketFragment) ReadInt64(v *int64) PacketFragment { - var vv uint64 - n := T.ReadUint64(&vv) - *v = int64(vv) - return n -} - -func (T PacketFragment) ReadFloat32(v *float32) PacketFragment { - var vv uint32 - n := T.ReadUint32(&vv) - *v = math.Float32frombits(vv) - return n -} - -func (T PacketFragment) ReadFloat64(v *float64) PacketFragment { - var vv uint64 - n := T.ReadUint64(&vv) - *v = math.Float64frombits(vv) - return n -} - -func (T PacketFragment) ReadString(v *string) PacketFragment { - for i, b := range T { - if b != '\x00' { - continue +func (T PendingPacket) WriteTo(encoder *Encoder) error { + count := T.Decoder.Length() - T.Decoder.Position() + for T.Decoder.Position() < T.Decoder.Length() { + if _, err := encoder.Writer.ReadFrom(T.Decoder); err != nil { + return err } - *v = string(T[:i]) - return T[i+1:] } - - return T + encoder.pos += count + return nil } -func (T PacketFragment) ReadBytes(v []byte) PacketFragment { - if len(T) < len(v) { - return T +var _ Packet = PendingPacket{} + +func ToConcrete[T any, PT interface { + ReadFrom(decoder *Decoder) error + *T +}](value PT, packet Packet) error { + switch p := packet.(type) { + case PT: + *value = *p + return nil + case PendingPacket: + return value.ReadFrom(p.Decoder) + default: + panic("incompatible packet types") } - copy(v, T) - return T[len(v):] } diff --git a/lib/fed/packets/v3.0/authenticationcleartext.go b/lib/fed/packets/v3.0/authenticationcleartext.go deleted file mode 100644 index 36cd0413b43e7e914207d645ddf75183e6ad397c..0000000000000000000000000000000000000000 --- a/lib/fed/packets/v3.0/authenticationcleartext.go +++ /dev/null @@ -1,23 +0,0 @@ -package packets - -import "gfx.cafe/gfx/pggat/lib/fed" - -type AuthenticationCleartext struct{} - -func (T *AuthenticationCleartext) ReadFromPacket(packet fed.Packet) bool { - if packet.Type() != TypeAuthentication { - return false - } - var method int32 - packet.ReadInt32(&method) - if method != 3 { - return false - } - return true -} - -func (T *AuthenticationCleartext) IntoPacket(packet fed.Packet) fed.Packet { - packet = packet.Reset(TypeAuthentication, 4) - packet = packet.AppendUint32(3) - return packet -} diff --git a/lib/fed/packets/v3.0/authenticationmd5.go b/lib/fed/packets/v3.0/authenticationmd5.go deleted file mode 100644 index 9a88902b653d111992e7ef1a750e3584129f1b44..0000000000000000000000000000000000000000 --- a/lib/fed/packets/v3.0/authenticationmd5.go +++ /dev/null @@ -1,27 +0,0 @@ -package packets - -import "gfx.cafe/gfx/pggat/lib/fed" - -type AuthenticationMD5 struct { - Salt [4]byte -} - -func (T *AuthenticationMD5) ReadFromPacket(packet fed.Packet) bool { - if packet.Type() != TypeAuthentication { - return false - } - var method int32 - p := packet.ReadInt32(&method) - if method != 5 { - return false - } - p = p.ReadBytes(T.Salt[:]) - return true -} - -func (T *AuthenticationMD5) IntoPacket(packet fed.Packet) fed.Packet { - packet = packet.Reset(TypeAuthentication, 8) - packet = packet.AppendUint32(5) - packet = packet.AppendBytes(T.Salt[:]) - return packet -} diff --git a/lib/fed/packets/v3.0/authenticationok.go b/lib/fed/packets/v3.0/authenticationok.go deleted file mode 100644 index 16dee6a21e8c8e411c8d48b2def9920e4ce2c705..0000000000000000000000000000000000000000 --- a/lib/fed/packets/v3.0/authenticationok.go +++ /dev/null @@ -1,23 +0,0 @@ -package packets - -import "gfx.cafe/gfx/pggat/lib/fed" - -type AuthenticationOk struct{} - -func (T *AuthenticationOk) ReadFromPacket(packet fed.Packet) bool { - if packet.Type() != TypeAuthentication { - return false - } - var method int32 - packet.ReadInt32(&method) - if method != 0 { - return false - } - return true -} - -func (T *AuthenticationOk) IntoPacket(packet fed.Packet) fed.Packet { - packet = packet.Reset(TypeAuthentication, 4) - packet = packet.AppendUint32(0) - return packet -} diff --git a/lib/fed/packets/v3.0/authenticationresponse.go b/lib/fed/packets/v3.0/authenticationresponse.go deleted file mode 100644 index 9c1be35fad8e41e1f0b21b6cdb8fcf2b511a3864..0000000000000000000000000000000000000000 --- a/lib/fed/packets/v3.0/authenticationresponse.go +++ /dev/null @@ -1,23 +0,0 @@ -package packets - -import ( - "gfx.cafe/gfx/pggat/lib/fed" - "gfx.cafe/gfx/pggat/lib/util/slices" -) - -type AuthenticationResponse []byte - -func (T *AuthenticationResponse) ReadFromPacket(packet fed.Packet) bool { - if packet.Type() != TypeAuthenticationResponse { - return false - } - *T = slices.Resize(*T, len(packet.Payload())) - packet.ReadBytes(*T) - return true -} - -func (T *AuthenticationResponse) IntoPacket(packet fed.Packet) fed.Packet { - packet = fed.NewPacket(TypeAuthenticationResponse, len(*T)) - packet = packet.AppendBytes(*T) - return packet -} diff --git a/lib/fed/packets/v3.0/authenticationsasl.go b/lib/fed/packets/v3.0/authenticationsasl.go deleted file mode 100644 index 0382b65ad1da6cdf90001b11fa492ea1255e6833..0000000000000000000000000000000000000000 --- a/lib/fed/packets/v3.0/authenticationsasl.go +++ /dev/null @@ -1,44 +0,0 @@ -package packets - -import "gfx.cafe/gfx/pggat/lib/fed" - -type AuthenticationSASL struct { - Mechanisms []string -} - -func (T *AuthenticationSASL) ReadFromPacket(packet fed.Packet) bool { - if packet.Type() != TypeAuthentication { - return false - } - var method int32 - p := packet.ReadInt32(&method) - if method != 10 { - return false - } - T.Mechanisms = T.Mechanisms[:0] - for { - var mechanism string - p = p.ReadString(&mechanism) - if mechanism == "" { - break - } - T.Mechanisms = append(T.Mechanisms, mechanism) - } - return true -} - -func (T *AuthenticationSASL) IntoPacket(packet fed.Packet) fed.Packet { - size := 5 - for _, mechanism := range T.Mechanisms { - size += len(mechanism) + 1 - } - - packet = packet.Reset(TypeAuthentication, size) - - packet = packet.AppendInt32(10) - for _, mechanism := range T.Mechanisms { - packet = packet.AppendString(mechanism) - } - packet = packet.AppendUint8(0) - return packet -} diff --git a/lib/fed/packets/v3.0/authenticationsaslcontinue.go b/lib/fed/packets/v3.0/authenticationsaslcontinue.go deleted file mode 100644 index 135d87ab8dc020e453b879dc689d520b436aeca8..0000000000000000000000000000000000000000 --- a/lib/fed/packets/v3.0/authenticationsaslcontinue.go +++ /dev/null @@ -1,29 +0,0 @@ -package packets - -import ( - "gfx.cafe/gfx/pggat/lib/fed" - "gfx.cafe/gfx/pggat/lib/util/slices" -) - -type AuthenticationSASLContinue []byte - -func (T *AuthenticationSASLContinue) ReadFromPacket(packet fed.Packet) bool { - if packet.Type() != TypeAuthentication { - return false - } - var method int32 - p := packet.ReadInt32(&method) - if method != 11 { - return false - } - *T = slices.Resize(*T, len(p)) - p.ReadBytes(*T) - return true -} - -func (T *AuthenticationSASLContinue) IntoPacket(packet fed.Packet) fed.Packet { - packet = packet.Reset(TypeAuthentication, 4+len(*T)) - packet = packet.AppendUint32(11) - packet = packet.AppendBytes(*T) - return packet -} diff --git a/lib/fed/packets/v3.0/authenticationsaslfinal.go b/lib/fed/packets/v3.0/authenticationsaslfinal.go deleted file mode 100644 index b5a191cafe8cfd3f9a39dcc763fecfea084d8d5f..0000000000000000000000000000000000000000 --- a/lib/fed/packets/v3.0/authenticationsaslfinal.go +++ /dev/null @@ -1,29 +0,0 @@ -package packets - -import ( - "gfx.cafe/gfx/pggat/lib/fed" - "gfx.cafe/gfx/pggat/lib/util/slices" -) - -type AuthenticationSASLFinal []byte - -func (T *AuthenticationSASLFinal) ReadFromPacket(packet fed.Packet) bool { - if packet.Type() != TypeAuthentication { - return false - } - var method int32 - p := packet.ReadInt32(&method) - if method != 12 { - return false - } - *T = slices.Resize(*T, len(p)) - p.ReadBytes(*T) - return true -} - -func (T *AuthenticationSASLFinal) IntoPacket(packet fed.Packet) fed.Packet { - packet = packet.Reset(TypeAuthentication, 4+len(*T)) - packet = packet.AppendUint32(12) - packet = packet.AppendBytes(*T) - return packet -} diff --git a/lib/fed/packets/v3.0/backendkeydata.go b/lib/fed/packets/v3.0/backendkeydata.go deleted file mode 100644 index e144b3ad19e42c814dc661ad3542d544ac875c86..0000000000000000000000000000000000000000 --- a/lib/fed/packets/v3.0/backendkeydata.go +++ /dev/null @@ -1,21 +0,0 @@ -package packets - -import "gfx.cafe/gfx/pggat/lib/fed" - -type BackendKeyData struct { - CancellationKey [8]byte -} - -func (T *BackendKeyData) ReadFromPacket(packet fed.Packet) bool { - if packet.Type() != TypeBackendKeyData { - return false - } - packet.ReadBytes(T.CancellationKey[:]) - return true -} - -func (T *BackendKeyData) IntoPacket(packet fed.Packet) fed.Packet { - packet = fed.NewPacket(TypeBackendKeyData, 8) - packet = packet.AppendBytes(T.CancellationKey[:]) - return packet -} diff --git a/lib/fed/packets/v3.0/bind.go b/lib/fed/packets/v3.0/bind.go deleted file mode 100644 index de1755e519369e5e57c2d3936007387be134f8df..0000000000000000000000000000000000000000 --- a/lib/fed/packets/v3.0/bind.go +++ /dev/null @@ -1,88 +0,0 @@ -package packets - -import ( - "gfx.cafe/gfx/pggat/lib/fed" - "gfx.cafe/gfx/pggat/lib/util/slices" -) - -type Bind struct { - Destination string - Source string - ParameterFormatCodes []int16 - ParameterValues [][]byte - ResultFormatCodes []int16 -} - -func (T *Bind) ReadFromPacket(packet fed.Packet) bool { - if packet.Type() != TypeBind { - return false - } - p := packet.ReadString(&T.Destination) - p = p.ReadString(&T.Source) - - var parameterFormatCodesLength uint16 - p = p.ReadUint16(¶meterFormatCodesLength) - T.ParameterFormatCodes = slices.Resize(T.ParameterFormatCodes, int(parameterFormatCodesLength)) - for i := 0; i < int(parameterFormatCodesLength); i++ { - p = p.ReadInt16(&T.ParameterFormatCodes[i]) - } - - var parameterValuesLength uint16 - p = p.ReadUint16(¶meterValuesLength) - T.ParameterValues = slices.Resize(T.ParameterValues, int(parameterValuesLength)) - for i := 0; i < int(parameterValuesLength); i++ { - var parameterValueLength int32 - p = p.ReadInt32(¶meterValueLength) - if parameterValueLength == -1 { - T.ParameterValues[i] = nil - continue - } - T.ParameterValues[i] = slices.Resize(T.ParameterValues[i], int(parameterValueLength)) - p = p.ReadBytes(T.ParameterValues[i]) - } - - var resultFormatCodesLength uint16 - p = p.ReadUint16(&resultFormatCodesLength) - T.ResultFormatCodes = slices.Resize(T.ResultFormatCodes, int(resultFormatCodesLength)) - for i := 0; i < int(resultFormatCodesLength); i++ { - p = p.ReadInt16(&T.ResultFormatCodes[i]) - } - - return true -} - -func (T *Bind) IntoPacket(packet fed.Packet) fed.Packet { - size := 0 - size += len(T.Destination) + 1 - size += len(T.Source) + 1 - size += 2 - size += len(T.ParameterFormatCodes) * 2 - size += 2 - for _, v := range T.ParameterValues { - size += 4 + len(v) - } - size += 2 - size += len(T.ResultFormatCodes) * 2 - - packet = packet.Reset(TypeBind, size) - packet = packet.AppendString(T.Destination) - packet = packet.AppendString(T.Source) - packet = packet.AppendUint16(uint16(len(T.ParameterFormatCodes))) - for _, v := range T.ParameterFormatCodes { - packet = packet.AppendInt16(v) - } - packet = packet.AppendUint16(uint16(len(T.ParameterValues))) - for _, v := range T.ParameterValues { - if v == nil { - packet = packet.AppendInt32(-1) - continue - } - packet = packet.AppendInt32(int32(len(v))) - packet = packet.AppendBytes(v) - } - packet = packet.AppendUint16(uint16(len(T.ResultFormatCodes))) - for _, v := range T.ResultFormatCodes { - packet = packet.AppendInt16(v) - } - return packet -} diff --git a/lib/fed/packets/v3.0/close.go b/lib/fed/packets/v3.0/close.go deleted file mode 100644 index 89221f91217347809832b29ce2760b0fc5a0711c..0000000000000000000000000000000000000000 --- a/lib/fed/packets/v3.0/close.go +++ /dev/null @@ -1,24 +0,0 @@ -package packets - -import "gfx.cafe/gfx/pggat/lib/fed" - -type Close struct { - Which byte - Target string -} - -func (T *Close) ReadFromPacket(packet fed.Packet) bool { - if packet.Type() != TypeClose { - return false - } - p := packet.ReadUint8(&T.Which) - p = p.ReadString(&T.Target) - return true -} - -func (T *Close) IntoPacket(packet fed.Packet) fed.Packet { - packet = packet.Reset(TypeClose, 2+len(T.Target)) - packet = packet.AppendUint8(T.Which) - packet = packet.AppendString(T.Target) - return packet -} diff --git a/lib/fed/packets/v3.0/commandcomplete.go b/lib/fed/packets/v3.0/commandcomplete.go deleted file mode 100644 index 647804d4ff54d755e6bee2fef6fc0ba65856b15a..0000000000000000000000000000000000000000 --- a/lib/fed/packets/v3.0/commandcomplete.go +++ /dev/null @@ -1,19 +0,0 @@ -package packets - -import "gfx.cafe/gfx/pggat/lib/fed" - -type CommandComplete string - -func (T *CommandComplete) ReadFromPacket(packet fed.Packet) bool { - if packet.Type() != TypeCommandComplete { - return false - } - packet.ReadString((*string)(T)) - return true -} - -func (T *CommandComplete) IntoPacket(packet fed.Packet) fed.Packet { - packet = packet.Reset(TypeCommandComplete, len(*T)+1) - packet = packet.AppendString(string(*T)) - return packet -} diff --git a/lib/fed/packets/v3.0/copydata.go b/lib/fed/packets/v3.0/copydata.go deleted file mode 100644 index 3043745bcbe0c5fdece8514e44dc242d5e8dae8e..0000000000000000000000000000000000000000 --- a/lib/fed/packets/v3.0/copydata.go +++ /dev/null @@ -1,24 +0,0 @@ -package packets - -import ( - "gfx.cafe/gfx/pggat/lib/fed" - "gfx.cafe/gfx/pggat/lib/util/slices" -) - -type CopyData []byte - -func (T *CopyData) ReadFromPacket(packet fed.Packet) bool { - if packet.Type() != TypeCopyData { - return false - } - - *T = slices.Resize(*T, len(packet.Payload())) - packet.ReadBytes(*T) - return true -} - -func (T *CopyData) IntoPacket(packet fed.Packet) fed.Packet { - packet = fed.NewPacket(TypeCopyData, len(*T)) - packet = packet.AppendBytes(*T) - return packet -} diff --git a/lib/fed/packets/v3.0/copyfail.go b/lib/fed/packets/v3.0/copyfail.go deleted file mode 100644 index 6f42d09721b867f64281b0158fc25d7543048494..0000000000000000000000000000000000000000 --- a/lib/fed/packets/v3.0/copyfail.go +++ /dev/null @@ -1,21 +0,0 @@ -package packets - -import "gfx.cafe/gfx/pggat/lib/fed" - -type CopyFail struct { - Reason string -} - -func (T *CopyFail) ReadFromPacket(packet fed.Packet) bool { - if packet.Type() != TypeCopyFail { - return false - } - packet.ReadString(&T.Reason) - return true -} - -func (T *CopyFail) IntoPacket(packet fed.Packet) fed.Packet { - packet = packet.Reset(TypeCopyFail, len(T.Reason)+1) - packet = packet.AppendString(T.Reason) - return packet -} diff --git a/lib/fed/packets/v3.0/datarow.go b/lib/fed/packets/v3.0/datarow.go deleted file mode 100644 index 31e2662266010779626a68835db14a6ae93dc43a..0000000000000000000000000000000000000000 --- a/lib/fed/packets/v3.0/datarow.go +++ /dev/null @@ -1,52 +0,0 @@ -package packets - -import ( - "gfx.cafe/gfx/pggat/lib/fed" - "gfx.cafe/gfx/pggat/lib/util/slices" -) - -type DataRow struct { - Columns [][]byte -} - -func (T *DataRow) ReadFromPacket(packet fed.Packet) bool { - if packet.Type() != TypeDataRow { - return false - } - - var columnCount uint16 - p := packet.ReadUint16(&columnCount) - T.Columns = slices.Resize(T.Columns, int(columnCount)) - for i := 0; i < int(columnCount); i++ { - var valueLength int32 - p = p.ReadInt32(&valueLength) - if valueLength == -1 { - continue - } - T.Columns[i] = slices.Resize(T.Columns[i], int(valueLength)) - p = p.ReadBytes(T.Columns[i]) - } - - return true -} - -func (T *DataRow) IntoPacket(packet fed.Packet) fed.Packet { - size := 2 - for _, v := range T.Columns { - size += len(v) + 4 - } - - packet = packet.Reset(TypeDataRow, size) - packet = packet.AppendUint16(uint16(len(T.Columns))) - for _, v := range T.Columns { - if v == nil { - packet = packet.AppendInt32(-1) - continue - } - - packet = packet.AppendInt32(int32(len(v))) - packet = packet.AppendBytes(v) - } - - return packet -} diff --git a/lib/fed/packets/v3.0/describe.go b/lib/fed/packets/v3.0/describe.go deleted file mode 100644 index e6510ffe49a5db52e503cfc7d6b781e6844f090c..0000000000000000000000000000000000000000 --- a/lib/fed/packets/v3.0/describe.go +++ /dev/null @@ -1,24 +0,0 @@ -package packets - -import "gfx.cafe/gfx/pggat/lib/fed" - -type Describe struct { - Which byte - Target string -} - -func (T *Describe) ReadFromPacket(packet fed.Packet) bool { - if packet.Type() != TypeDescribe { - return false - } - p := packet.ReadUint8(&T.Which) - p = p.ReadString(&T.Target) - return true -} - -func (T *Describe) IntoPacket(packet fed.Packet) fed.Packet { - packet = packet.Reset(TypeDescribe, len(T.Target)+2) - packet = packet.AppendUint8(T.Which) - packet = packet.AppendString(T.Target) - return packet -} diff --git a/lib/fed/packets/v3.0/errorresponse.go b/lib/fed/packets/v3.0/errorresponse.go deleted file mode 100644 index a97f46058cac2f83ab2d77d4aa5f475937a3f58e..0000000000000000000000000000000000000000 --- a/lib/fed/packets/v3.0/errorresponse.go +++ /dev/null @@ -1,86 +0,0 @@ -package packets - -import ( - "gfx.cafe/gfx/pggat/lib/fed" - "gfx.cafe/gfx/pggat/lib/perror" -) - -type ErrorResponse struct { - Error perror.Error -} - -func (T *ErrorResponse) ReadFromPacket(packet fed.Packet) bool { - if packet.Type() != TypeErrorResponse { - return false - } - - var severity perror.Severity - var code perror.Code - var message string - var extra []perror.ExtraField - - p := packet.Payload() - - for { - var typ uint8 - p = p.ReadUint8(&typ) - - if typ == 0 { - break - } - - var value string - p = p.ReadString(&value) - - switch typ { - case 'S': - severity = perror.Severity(value) - case 'C': - code = perror.Code(value) - case 'M': - message = value - default: - extra = append(extra, perror.ExtraField{ - Type: perror.Extra(typ), - Value: value, - }) - } - } - - T.Error = perror.New( - severity, - code, - message, - extra..., - ) - return true -} - -func (T *ErrorResponse) IntoPacket(packet fed.Packet) fed.Packet { - size := 1 - size += len(T.Error.Severity()) + 2 - size += len(T.Error.Code()) + 2 - size += len(T.Error.Message()) + 2 - for _, field := range T.Error.Extra() { - size += len(field.Value) + 2 - } - - packet = packet.Reset(TypeErrorResponse, size) - - packet = packet.AppendUint8('S') - packet = packet.AppendString(string(T.Error.Severity())) - - packet = packet.AppendUint8('C') - packet = packet.AppendString(string(T.Error.Code())) - - packet = packet.AppendUint8('M') - packet = packet.AppendString(T.Error.Message()) - - for _, field := range T.Error.Extra() { - packet = packet.AppendUint8(uint8(field.Type)) - packet = packet.AppendString(field.Value) - } - - packet = packet.AppendUint8(0) - return packet -} diff --git a/lib/fed/packets/v3.0/errors.go b/lib/fed/packets/v3.0/errors.go deleted file mode 100644 index b7bc928bb4bc9565be27eb54f1f8e18dc8ba4d9a..0000000000000000000000000000000000000000 --- a/lib/fed/packets/v3.0/errors.go +++ /dev/null @@ -1,16 +0,0 @@ -package packets - -import "gfx.cafe/gfx/pggat/lib/perror" - -var ( - ErrBadFormat = perror.New( - perror.FATAL, - perror.ProtocolViolation, - "Bad packet format", - ) - ErrUnexpectedPacket = perror.New( - perror.FATAL, - perror.ProtocolViolation, - "unexpected packet", - ) -) diff --git a/lib/fed/packets/v3.0/execute.go b/lib/fed/packets/v3.0/execute.go deleted file mode 100644 index 9d8c172d2d657dc6e0dae70037c0b3d59b762358..0000000000000000000000000000000000000000 --- a/lib/fed/packets/v3.0/execute.go +++ /dev/null @@ -1,24 +0,0 @@ -package packets - -import "gfx.cafe/gfx/pggat/lib/fed" - -type Execute struct { - Target string - MaxRows int32 -} - -func (T *Execute) ReadFromPacket(packet fed.Packet) bool { - if packet.Type() != TypeExecute { - return false - } - p := packet.ReadString(&T.Target) - p = p.ReadInt32(&T.MaxRows) - return true -} - -func (T *Execute) IntoPacket(packet fed.Packet) fed.Packet { - packet = packet.Reset(TypeExecute, len(T.Target)+5) - packet = packet.AppendString(T.Target) - packet = packet.AppendInt32(T.MaxRows) - return packet -} diff --git a/lib/fed/packets/v3.0/negotiateprotocolversion.go b/lib/fed/packets/v3.0/negotiateprotocolversion.go deleted file mode 100644 index aad5dfadb33ce7cfd82a18f8d0f6e1d39fa06894..0000000000000000000000000000000000000000 --- a/lib/fed/packets/v3.0/negotiateprotocolversion.go +++ /dev/null @@ -1,44 +0,0 @@ -package packets - -import ( - "gfx.cafe/gfx/pggat/lib/fed" - "gfx.cafe/gfx/pggat/lib/util/slices" -) - -type NegotiateProtocolVersion struct { - MinorProtocolVersion int32 - UnrecognizedOptions []string -} - -func (T *NegotiateProtocolVersion) ReadFromPacket(packet fed.Packet) bool { - if packet.Type() != TypeNegotiateProtocolVersion { - return false - } - p := packet.ReadInt32(&T.MinorProtocolVersion) - - var numUnrecognizedOptions int32 - p = p.ReadInt32(&numUnrecognizedOptions) - - T.UnrecognizedOptions = slices.Resize(T.UnrecognizedOptions, int(numUnrecognizedOptions)) - for i := 0; i < int(numUnrecognizedOptions); i++ { - p = p.ReadString(&T.UnrecognizedOptions[i]) - } - - return true -} - -func (T *NegotiateProtocolVersion) IntoPacket(packet fed.Packet) fed.Packet { - size := 8 - for _, v := range T.UnrecognizedOptions { - size += len(v) + 1 - } - - packet = packet.Reset(TypeNegotiateProtocolVersion, size) - packet = packet.AppendInt32(T.MinorProtocolVersion) - packet = packet.AppendInt32(int32(len(T.UnrecognizedOptions))) - for _, v := range T.UnrecognizedOptions { - packet = packet.AppendString(v) - } - - return packet -} diff --git a/lib/fed/packets/v3.0/packets.go b/lib/fed/packets/v3.0/packets.go new file mode 100644 index 0000000000000000000000000000000000000000..e8244ab5285c73c3ead171e19f6b06320effbe63 --- /dev/null +++ b/lib/fed/packets/v3.0/packets.go @@ -0,0 +1,3242 @@ +package packets + +// automatically generated. do not edit + +import ( + "gfx.cafe/gfx/pggat/lib/fed" + "gfx.cafe/gfx/pggat/lib/util/slices" + + "errors" +) + +var ( + ErrUnexpectedPacket = errors.New("unexpected packet") + ErrInvalidFormat = errors.New("invalid packet format") +) + +const ( + TypeAuthentication = 'R' + TypeBackendKeyData = 'K' + TypeBind = 'B' + TypeBindComplete = '2' + TypeClose = 'C' + TypeCloseComplete = '3' + TypeCommandComplete = 'C' + TypeCopyBothResponse = 'W' + TypeCopyData = 'd' + TypeCopyDone = 'c' + TypeCopyFail = 'f' + TypeCopyInResponse = 'G' + TypeCopyOutResponse = 'H' + TypeDataRow = 'D' + TypeDescribe = 'D' + TypeEmptyQueryResponse = 'I' + TypeErrorResponse = 'E' + TypeExecute = 'E' + TypeFlush = 'H' + TypeFunctionCall = 'F' + TypeFunctionCallResponse = 'V' + TypeGSSResponse = 'p' + TypeNegotiateProtocolVersion = 'v' + TypeNoData = 'n' + TypeNoticeResponse = 'N' + TypeNotificationResponse = 'A' + TypeParameterDescription = 't' + TypeParameterStatus = 'S' + TypeParse = 'P' + TypeParseComplete = '1' + TypePasswordMessage = 'p' + TypePortalSuspended = 's' + TypeQuery = 'Q' + TypeReadyForQuery = 'Z' + TypeRowDescription = 'T' + TypeSASLInitialResponse = 'p' + TypeSASLResponse = 'p' + TypeSync = 'S' + TypeTerminate = 'X' +) + +type AuthenticationPayloadCleartextPassword struct{} + +func (*AuthenticationPayloadCleartextPassword) AuthenticationPayloadMode() int32 { + return 3 +} + +func (T *AuthenticationPayloadCleartextPassword) Length() (length int) { + + return +} + +func (T *AuthenticationPayloadCleartextPassword) ReadFrom(decoder *fed.Decoder) (err error) { + + return +} + +func (T *AuthenticationPayloadCleartextPassword) WriteTo(encoder *fed.Encoder) (err error) { + + return +} + +type AuthenticationPayloadGSS struct{} + +func (*AuthenticationPayloadGSS) AuthenticationPayloadMode() int32 { + return 7 +} + +func (T *AuthenticationPayloadGSS) Length() (length int) { + + return +} + +func (T *AuthenticationPayloadGSS) ReadFrom(decoder *fed.Decoder) (err error) { + + return +} + +func (T *AuthenticationPayloadGSS) WriteTo(encoder *fed.Encoder) (err error) { + + return +} + +type AuthenticationPayloadGSSContinue []uint8 + +func (*AuthenticationPayloadGSSContinue) AuthenticationPayloadMode() int32 { + return 8 +} + +func (T *AuthenticationPayloadGSSContinue) Length() (length int) { + for _, temp1 := range *T { + _ = temp1 + + length += 1 + + } + + return +} + +func (T *AuthenticationPayloadGSSContinue) ReadFrom(decoder *fed.Decoder) (err error) { + (*T) = (*T)[:0] + + for { + if decoder.Position() >= decoder.Length() { + break + } + + (*T) = slices.Resize((*T), len((*T))+1) + + *(*uint8)(&((*T)[len((*T))-1])), err = decoder.Uint8() + if err != nil { + return + } + + } + + return +} + +func (T *AuthenticationPayloadGSSContinue) WriteTo(encoder *fed.Encoder) (err error) { + for _, temp2 := range *T { + err = encoder.Uint8(uint8(temp2)) + if err != nil { + return + } + + } + + return +} + +type AuthenticationPayloadKerberosV5 struct{} + +func (*AuthenticationPayloadKerberosV5) AuthenticationPayloadMode() int32 { + return 2 +} + +func (T *AuthenticationPayloadKerberosV5) Length() (length int) { + + return +} + +func (T *AuthenticationPayloadKerberosV5) ReadFrom(decoder *fed.Decoder) (err error) { + + return +} + +func (T *AuthenticationPayloadKerberosV5) WriteTo(encoder *fed.Encoder) (err error) { + + return +} + +type AuthenticationPayloadMD5Password [4]uint8 + +func (*AuthenticationPayloadMD5Password) AuthenticationPayloadMode() int32 { + return 5 +} + +func (T *AuthenticationPayloadMD5Password) Length() (length int) { + for _, temp3 := range *T { + _ = temp3 + + length += 1 + + } + + return +} + +func (T *AuthenticationPayloadMD5Password) ReadFrom(decoder *fed.Decoder) (err error) { + for temp4 := 0; temp4 < 4; temp4++ { + *(*uint8)(&((*T)[temp4])), err = decoder.Uint8() + if err != nil { + return + } + + } + + return +} + +func (T *AuthenticationPayloadMD5Password) WriteTo(encoder *fed.Encoder) (err error) { + for _, temp5 := range *T { + err = encoder.Uint8(uint8(temp5)) + if err != nil { + return + } + + } + + return +} + +type AuthenticationPayloadOk struct{} + +func (*AuthenticationPayloadOk) AuthenticationPayloadMode() int32 { + return 0 +} + +func (T *AuthenticationPayloadOk) Length() (length int) { + + return +} + +func (T *AuthenticationPayloadOk) ReadFrom(decoder *fed.Decoder) (err error) { + + return +} + +func (T *AuthenticationPayloadOk) WriteTo(encoder *fed.Encoder) (err error) { + + return +} + +type AuthenticationPayloadSASLMethod struct { + Method string +} + +type AuthenticationPayloadSASL []AuthenticationPayloadSASLMethod + +func (*AuthenticationPayloadSASL) AuthenticationPayloadMode() int32 { + return 10 +} + +func (T *AuthenticationPayloadSASL) Length() (length int) { + for _, temp6 := range *T { + _ = temp6 + + length += len(temp6.Method) + 1 + + } + + var temp7 string + _ = temp7 + + length += len(temp7) + 1 + + return +} + +func (T *AuthenticationPayloadSASL) ReadFrom(decoder *fed.Decoder) (err error) { + (*T) = (*T)[:0] + + for { + (*T) = slices.Resize((*T), len((*T))+1) + + *(*string)(&((*T)[len((*T))-1].Method)), err = decoder.String() + if err != nil { + return + } + if (*T)[len((*T))-1].Method == *new(string) { + (*T) = (*T)[:len((*T))-1] + break + } + } + + return +} + +func (T *AuthenticationPayloadSASL) WriteTo(encoder *fed.Encoder) (err error) { + for _, temp8 := range *T { + err = encoder.String(string(temp8.Method)) + if err != nil { + return + } + + } + + var temp9 string + + err = encoder.String(string(temp9)) + if err != nil { + return + } + + return +} + +type AuthenticationPayloadSASLContinue []uint8 + +func (*AuthenticationPayloadSASLContinue) AuthenticationPayloadMode() int32 { + return 11 +} + +func (T *AuthenticationPayloadSASLContinue) Length() (length int) { + for _, temp10 := range *T { + _ = temp10 + + length += 1 + + } + + return +} + +func (T *AuthenticationPayloadSASLContinue) ReadFrom(decoder *fed.Decoder) (err error) { + (*T) = (*T)[:0] + + for { + if decoder.Position() >= decoder.Length() { + break + } + + (*T) = slices.Resize((*T), len((*T))+1) + + *(*uint8)(&((*T)[len((*T))-1])), err = decoder.Uint8() + if err != nil { + return + } + + } + + return +} + +func (T *AuthenticationPayloadSASLContinue) WriteTo(encoder *fed.Encoder) (err error) { + for _, temp11 := range *T { + err = encoder.Uint8(uint8(temp11)) + if err != nil { + return + } + + } + + return +} + +type AuthenticationPayloadSASLFinal []uint8 + +func (*AuthenticationPayloadSASLFinal) AuthenticationPayloadMode() int32 { + return 12 +} + +func (T *AuthenticationPayloadSASLFinal) Length() (length int) { + for _, temp12 := range *T { + _ = temp12 + + length += 1 + + } + + return +} + +func (T *AuthenticationPayloadSASLFinal) ReadFrom(decoder *fed.Decoder) (err error) { + (*T) = (*T)[:0] + + for { + if decoder.Position() >= decoder.Length() { + break + } + + (*T) = slices.Resize((*T), len((*T))+1) + + *(*uint8)(&((*T)[len((*T))-1])), err = decoder.Uint8() + if err != nil { + return + } + + } + + return +} + +func (T *AuthenticationPayloadSASLFinal) WriteTo(encoder *fed.Encoder) (err error) { + for _, temp13 := range *T { + err = encoder.Uint8(uint8(temp13)) + if err != nil { + return + } + + } + + return +} + +type AuthenticationPayloadSSPI struct{} + +func (*AuthenticationPayloadSSPI) AuthenticationPayloadMode() int32 { + return 9 +} + +func (T *AuthenticationPayloadSSPI) Length() (length int) { + + return +} + +func (T *AuthenticationPayloadSSPI) ReadFrom(decoder *fed.Decoder) (err error) { + + return +} + +func (T *AuthenticationPayloadSSPI) WriteTo(encoder *fed.Encoder) (err error) { + + return +} + +type AuthenticationPayloadMode interface { + AuthenticationPayloadMode() int32 + + Length() int + ReadFrom(decoder *fed.Decoder) error + WriteTo(encoder *fed.Encoder) error +} +type AuthenticationPayload struct { + Mode AuthenticationPayloadMode +} + +type Authentication AuthenticationPayload + +func (T *Authentication) Type() fed.Type { + return TypeAuthentication +} + +func (T *Authentication) Length() (length int) { + length += 4 + + length += (*T).Mode.Length() + + return +} + +func (T *Authentication) ReadFrom(decoder *fed.Decoder) (err error) { + if decoder.Type() != T.Type() { + return ErrUnexpectedPacket + } + + var temp14 int32 + + *(*int32)(&(temp14)), err = decoder.Int32() + if err != nil { + return + } + + switch temp14 { + case 3: + (*T).Mode = new(AuthenticationPayloadCleartextPassword) + case 7: + (*T).Mode = new(AuthenticationPayloadGSS) + case 8: + (*T).Mode = new(AuthenticationPayloadGSSContinue) + case 2: + (*T).Mode = new(AuthenticationPayloadKerberosV5) + case 5: + (*T).Mode = new(AuthenticationPayloadMD5Password) + case 0: + (*T).Mode = new(AuthenticationPayloadOk) + case 10: + (*T).Mode = new(AuthenticationPayloadSASL) + case 11: + (*T).Mode = new(AuthenticationPayloadSASLContinue) + case 12: + (*T).Mode = new(AuthenticationPayloadSASLFinal) + case 9: + (*T).Mode = new(AuthenticationPayloadSSPI) + default: + err = ErrInvalidFormat + return + } + + err = (*T).Mode.ReadFrom(decoder) + if err != nil { + return + } + + return +} + +func (T *Authentication) WriteTo(encoder *fed.Encoder) (err error) { + err = encoder.Int32(int32((*T).Mode.AuthenticationPayloadMode())) + if err != nil { + return + } + + err = (*T).Mode.WriteTo(encoder) + if err != nil { + return + } + + return +} + +var _ fed.Packet = (*Authentication)(nil) + +type BackendKeyDataPayload struct { + ProcessID int32 + SecretKey int32 +} + +type BackendKeyData BackendKeyDataPayload + +func (T *BackendKeyData) Type() fed.Type { + return TypeBackendKeyData +} + +func (T *BackendKeyData) Length() (length int) { + length += 4 + + length += 4 + + return +} + +func (T *BackendKeyData) ReadFrom(decoder *fed.Decoder) (err error) { + if decoder.Type() != T.Type() { + return ErrUnexpectedPacket + } + + *(*int32)(&((*T).ProcessID)), err = decoder.Int32() + if err != nil { + return + } + *(*int32)(&((*T).SecretKey)), err = decoder.Int32() + if err != nil { + return + } + + return +} + +func (T *BackendKeyData) WriteTo(encoder *fed.Encoder) (err error) { + err = encoder.Int32(int32((*T).ProcessID)) + if err != nil { + return + } + + err = encoder.Int32(int32((*T).SecretKey)) + if err != nil { + return + } + + return +} + +var _ fed.Packet = (*BackendKeyData)(nil) + +type BindPayload struct { + Destination string + Source string + FormatCodes []int16 + Parameters [][]uint8 + ResultFormatCodes []int16 +} + +type Bind BindPayload + +func (T *Bind) Type() fed.Type { + return TypeBind +} + +func (T *Bind) Length() (length int) { + length += len((*T).Destination) + 1 + + length += len((*T).Source) + 1 + + temp15 := uint16(len((*T).FormatCodes)) + _ = temp15 + + length += 2 + + for _, temp16 := range (*T).FormatCodes { + _ = temp16 + + length += 2 + + } + + temp17 := uint16(len((*T).Parameters)) + _ = temp17 + + length += 2 + + for _, temp18 := range (*T).Parameters { + _ = temp18 + + temp19 := int32(len(temp18)) + _ = temp19 + + length += 4 + + for _, temp20 := range temp18 { + _ = temp20 + + length += 1 + + } + + } + + temp21 := uint16(len((*T).ResultFormatCodes)) + _ = temp21 + + length += 2 + + for _, temp22 := range (*T).ResultFormatCodes { + _ = temp22 + + length += 2 + + } + + return +} + +func (T *Bind) ReadFrom(decoder *fed.Decoder) (err error) { + if decoder.Type() != T.Type() { + return ErrUnexpectedPacket + } + + *(*string)(&((*T).Destination)), err = decoder.String() + if err != nil { + return + } + *(*string)(&((*T).Source)), err = decoder.String() + if err != nil { + return + } + var temp23 uint16 + *(*uint16)(&(temp23)), err = decoder.Uint16() + if err != nil { + return + } + + (*T).FormatCodes = slices.Resize((*T).FormatCodes, int(temp23)) + + for temp24 := 0; temp24 < int(temp23); temp24++ { + *(*int16)(&((*T).FormatCodes[temp24])), err = decoder.Int16() + if err != nil { + return + } + + } + + var temp25 uint16 + *(*uint16)(&(temp25)), err = decoder.Uint16() + if err != nil { + return + } + + (*T).Parameters = slices.Resize((*T).Parameters, int(temp25)) + + for temp26 := 0; temp26 < int(temp25); temp26++ { + var temp27 int32 + *(*int32)(&(temp27)), err = decoder.Int32() + if err != nil { + return + } + + if temp27 == -1 { + (*T).Parameters[temp26] = nil + } else { + if (*T).Parameters[temp26] == nil { + (*T).Parameters[temp26] = make([]uint8, int(temp27)) + } else { + (*T).Parameters[temp26] = slices.Resize((*T).Parameters[temp26], int(temp27)) + } + + for temp28 := 0; temp28 < int(temp27); temp28++ { + *(*uint8)(&((*T).Parameters[temp26][temp28])), err = decoder.Uint8() + if err != nil { + return + } + + } + } + + } + + var temp29 uint16 + *(*uint16)(&(temp29)), err = decoder.Uint16() + if err != nil { + return + } + + (*T).ResultFormatCodes = slices.Resize((*T).ResultFormatCodes, int(temp29)) + + for temp30 := 0; temp30 < int(temp29); temp30++ { + *(*int16)(&((*T).ResultFormatCodes[temp30])), err = decoder.Int16() + if err != nil { + return + } + + } + + return +} + +func (T *Bind) WriteTo(encoder *fed.Encoder) (err error) { + err = encoder.String(string((*T).Destination)) + if err != nil { + return + } + + err = encoder.String(string((*T).Source)) + if err != nil { + return + } + + temp31 := uint16(len((*T).FormatCodes)) + + err = encoder.Uint16(uint16(temp31)) + if err != nil { + return + } + + for _, temp32 := range (*T).FormatCodes { + err = encoder.Int16(int16(temp32)) + if err != nil { + return + } + + } + + temp33 := uint16(len((*T).Parameters)) + + err = encoder.Uint16(uint16(temp33)) + if err != nil { + return + } + + for _, temp34 := range (*T).Parameters { + temp35 := int32(len(temp34)) + + if temp34 == nil { + temp35 = -1 + } + + err = encoder.Int32(int32(temp35)) + if err != nil { + return + } + + for _, temp36 := range temp34 { + err = encoder.Uint8(uint8(temp36)) + if err != nil { + return + } + + } + + } + + temp37 := uint16(len((*T).ResultFormatCodes)) + + err = encoder.Uint16(uint16(temp37)) + if err != nil { + return + } + + for _, temp38 := range (*T).ResultFormatCodes { + err = encoder.Int16(int16(temp38)) + if err != nil { + return + } + + } + + return +} + +var _ fed.Packet = (*Bind)(nil) + +type BindComplete struct{} + +func (T *BindComplete) Type() fed.Type { + return TypeBindComplete +} + +func (T *BindComplete) Length() (length int) { + + return +} + +func (T *BindComplete) ReadFrom(decoder *fed.Decoder) (err error) { + if decoder.Type() != T.Type() { + return ErrUnexpectedPacket + } + + return +} + +func (T *BindComplete) WriteTo(encoder *fed.Encoder) (err error) { + + return +} + +var _ fed.Packet = (*BindComplete)(nil) + +type ClosePayload struct { + Which uint8 + Name string +} + +type Close ClosePayload + +func (T *Close) Type() fed.Type { + return TypeClose +} + +func (T *Close) Length() (length int) { + length += 1 + + length += len((*T).Name) + 1 + + return +} + +func (T *Close) ReadFrom(decoder *fed.Decoder) (err error) { + if decoder.Type() != T.Type() { + return ErrUnexpectedPacket + } + + *(*uint8)(&((*T).Which)), err = decoder.Uint8() + if err != nil { + return + } + *(*string)(&((*T).Name)), err = decoder.String() + if err != nil { + return + } + + return +} + +func (T *Close) WriteTo(encoder *fed.Encoder) (err error) { + err = encoder.Uint8(uint8((*T).Which)) + if err != nil { + return + } + + err = encoder.String(string((*T).Name)) + if err != nil { + return + } + + return +} + +var _ fed.Packet = (*Close)(nil) + +type CloseComplete struct{} + +func (T *CloseComplete) Type() fed.Type { + return TypeCloseComplete +} + +func (T *CloseComplete) Length() (length int) { + + return +} + +func (T *CloseComplete) ReadFrom(decoder *fed.Decoder) (err error) { + if decoder.Type() != T.Type() { + return ErrUnexpectedPacket + } + + return +} + +func (T *CloseComplete) WriteTo(encoder *fed.Encoder) (err error) { + + return +} + +var _ fed.Packet = (*CloseComplete)(nil) + +type CommandComplete string + +func (T *CommandComplete) Type() fed.Type { + return TypeCommandComplete +} + +func (T *CommandComplete) Length() (length int) { + length += len((*T)) + 1 + + return +} + +func (T *CommandComplete) ReadFrom(decoder *fed.Decoder) (err error) { + if decoder.Type() != T.Type() { + return ErrUnexpectedPacket + } + + *(*string)(&(*T)), err = decoder.String() + if err != nil { + return + } + + return +} + +func (T *CommandComplete) WriteTo(encoder *fed.Encoder) (err error) { + err = encoder.String(string((*T))) + if err != nil { + return + } + + return +} + +var _ fed.Packet = (*CommandComplete)(nil) + +type CopyBothResponsePayload struct { + Mode int8 + ColumnFormatCodes []int16 +} + +type CopyBothResponse CopyBothResponsePayload + +func (T *CopyBothResponse) Type() fed.Type { + return TypeCopyBothResponse +} + +func (T *CopyBothResponse) Length() (length int) { + length += 1 + + temp39 := uint16(len((*T).ColumnFormatCodes)) + _ = temp39 + + length += 2 + + for _, temp40 := range (*T).ColumnFormatCodes { + _ = temp40 + + length += 2 + + } + + return +} + +func (T *CopyBothResponse) ReadFrom(decoder *fed.Decoder) (err error) { + if decoder.Type() != T.Type() { + return ErrUnexpectedPacket + } + + *(*int8)(&((*T).Mode)), err = decoder.Int8() + if err != nil { + return + } + var temp41 uint16 + *(*uint16)(&(temp41)), err = decoder.Uint16() + if err != nil { + return + } + + (*T).ColumnFormatCodes = slices.Resize((*T).ColumnFormatCodes, int(temp41)) + + for temp42 := 0; temp42 < int(temp41); temp42++ { + *(*int16)(&((*T).ColumnFormatCodes[temp42])), err = decoder.Int16() + if err != nil { + return + } + + } + + return +} + +func (T *CopyBothResponse) WriteTo(encoder *fed.Encoder) (err error) { + err = encoder.Int8(int8((*T).Mode)) + if err != nil { + return + } + + temp43 := uint16(len((*T).ColumnFormatCodes)) + + err = encoder.Uint16(uint16(temp43)) + if err != nil { + return + } + + for _, temp44 := range (*T).ColumnFormatCodes { + err = encoder.Int16(int16(temp44)) + if err != nil { + return + } + + } + + return +} + +var _ fed.Packet = (*CopyBothResponse)(nil) + +type CopyData []uint8 + +func (T *CopyData) Type() fed.Type { + return TypeCopyData +} + +func (T *CopyData) Length() (length int) { + for _, temp45 := range *T { + _ = temp45 + + length += 1 + + } + + return +} + +func (T *CopyData) ReadFrom(decoder *fed.Decoder) (err error) { + if decoder.Type() != T.Type() { + return ErrUnexpectedPacket + } + + (*T) = (*T)[:0] + + for { + if decoder.Position() >= decoder.Length() { + break + } + + (*T) = slices.Resize((*T), len((*T))+1) + + *(*uint8)(&((*T)[len((*T))-1])), err = decoder.Uint8() + if err != nil { + return + } + + } + + return +} + +func (T *CopyData) WriteTo(encoder *fed.Encoder) (err error) { + for _, temp46 := range *T { + err = encoder.Uint8(uint8(temp46)) + if err != nil { + return + } + + } + + return +} + +var _ fed.Packet = (*CopyData)(nil) + +type CopyDone struct{} + +func (T *CopyDone) Type() fed.Type { + return TypeCopyDone +} + +func (T *CopyDone) Length() (length int) { + + return +} + +func (T *CopyDone) ReadFrom(decoder *fed.Decoder) (err error) { + if decoder.Type() != T.Type() { + return ErrUnexpectedPacket + } + + return +} + +func (T *CopyDone) WriteTo(encoder *fed.Encoder) (err error) { + + return +} + +var _ fed.Packet = (*CopyDone)(nil) + +type CopyFail string + +func (T *CopyFail) Type() fed.Type { + return TypeCopyFail +} + +func (T *CopyFail) Length() (length int) { + length += len((*T)) + 1 + + return +} + +func (T *CopyFail) ReadFrom(decoder *fed.Decoder) (err error) { + if decoder.Type() != T.Type() { + return ErrUnexpectedPacket + } + + *(*string)(&(*T)), err = decoder.String() + if err != nil { + return + } + + return +} + +func (T *CopyFail) WriteTo(encoder *fed.Encoder) (err error) { + err = encoder.String(string((*T))) + if err != nil { + return + } + + return +} + +var _ fed.Packet = (*CopyFail)(nil) + +type CopyInResponsePayload struct { + Mode int8 + ColumnFormatCodes []int16 +} + +type CopyInResponse CopyInResponsePayload + +func (T *CopyInResponse) Type() fed.Type { + return TypeCopyInResponse +} + +func (T *CopyInResponse) Length() (length int) { + length += 1 + + temp47 := uint16(len((*T).ColumnFormatCodes)) + _ = temp47 + + length += 2 + + for _, temp48 := range (*T).ColumnFormatCodes { + _ = temp48 + + length += 2 + + } + + return +} + +func (T *CopyInResponse) ReadFrom(decoder *fed.Decoder) (err error) { + if decoder.Type() != T.Type() { + return ErrUnexpectedPacket + } + + *(*int8)(&((*T).Mode)), err = decoder.Int8() + if err != nil { + return + } + var temp49 uint16 + *(*uint16)(&(temp49)), err = decoder.Uint16() + if err != nil { + return + } + + (*T).ColumnFormatCodes = slices.Resize((*T).ColumnFormatCodes, int(temp49)) + + for temp50 := 0; temp50 < int(temp49); temp50++ { + *(*int16)(&((*T).ColumnFormatCodes[temp50])), err = decoder.Int16() + if err != nil { + return + } + + } + + return +} + +func (T *CopyInResponse) WriteTo(encoder *fed.Encoder) (err error) { + err = encoder.Int8(int8((*T).Mode)) + if err != nil { + return + } + + temp51 := uint16(len((*T).ColumnFormatCodes)) + + err = encoder.Uint16(uint16(temp51)) + if err != nil { + return + } + + for _, temp52 := range (*T).ColumnFormatCodes { + err = encoder.Int16(int16(temp52)) + if err != nil { + return + } + + } + + return +} + +var _ fed.Packet = (*CopyInResponse)(nil) + +type CopyOutResponsePayload struct { + Mode int8 + ColumnFormatCodes []int16 +} + +type CopyOutResponse CopyOutResponsePayload + +func (T *CopyOutResponse) Type() fed.Type { + return TypeCopyOutResponse +} + +func (T *CopyOutResponse) Length() (length int) { + length += 1 + + temp53 := uint16(len((*T).ColumnFormatCodes)) + _ = temp53 + + length += 2 + + for _, temp54 := range (*T).ColumnFormatCodes { + _ = temp54 + + length += 2 + + } + + return +} + +func (T *CopyOutResponse) ReadFrom(decoder *fed.Decoder) (err error) { + if decoder.Type() != T.Type() { + return ErrUnexpectedPacket + } + + *(*int8)(&((*T).Mode)), err = decoder.Int8() + if err != nil { + return + } + var temp55 uint16 + *(*uint16)(&(temp55)), err = decoder.Uint16() + if err != nil { + return + } + + (*T).ColumnFormatCodes = slices.Resize((*T).ColumnFormatCodes, int(temp55)) + + for temp56 := 0; temp56 < int(temp55); temp56++ { + *(*int16)(&((*T).ColumnFormatCodes[temp56])), err = decoder.Int16() + if err != nil { + return + } + + } + + return +} + +func (T *CopyOutResponse) WriteTo(encoder *fed.Encoder) (err error) { + err = encoder.Int8(int8((*T).Mode)) + if err != nil { + return + } + + temp57 := uint16(len((*T).ColumnFormatCodes)) + + err = encoder.Uint16(uint16(temp57)) + if err != nil { + return + } + + for _, temp58 := range (*T).ColumnFormatCodes { + err = encoder.Int16(int16(temp58)) + if err != nil { + return + } + + } + + return +} + +var _ fed.Packet = (*CopyOutResponse)(nil) + +type DataRow [][]uint8 + +func (T *DataRow) Type() fed.Type { + return TypeDataRow +} + +func (T *DataRow) Length() (length int) { + temp59 := uint16(len((*T))) + _ = temp59 + + length += 2 + + for _, temp60 := range *T { + _ = temp60 + + temp61 := int32(len(temp60)) + _ = temp61 + + length += 4 + + for _, temp62 := range temp60 { + _ = temp62 + + length += 1 + + } + + } + + return +} + +func (T *DataRow) ReadFrom(decoder *fed.Decoder) (err error) { + if decoder.Type() != T.Type() { + return ErrUnexpectedPacket + } + + var temp63 uint16 + *(*uint16)(&(temp63)), err = decoder.Uint16() + if err != nil { + return + } + + (*T) = slices.Resize((*T), int(temp63)) + + for temp64 := 0; temp64 < int(temp63); temp64++ { + var temp65 int32 + *(*int32)(&(temp65)), err = decoder.Int32() + if err != nil { + return + } + + if temp65 == -1 { + (*T)[temp64] = nil + } else { + if (*T)[temp64] == nil { + (*T)[temp64] = make([]uint8, int(temp65)) + } else { + (*T)[temp64] = slices.Resize((*T)[temp64], int(temp65)) + } + + for temp66 := 0; temp66 < int(temp65); temp66++ { + *(*uint8)(&((*T)[temp64][temp66])), err = decoder.Uint8() + if err != nil { + return + } + + } + } + + } + + return +} + +func (T *DataRow) WriteTo(encoder *fed.Encoder) (err error) { + temp67 := uint16(len((*T))) + + err = encoder.Uint16(uint16(temp67)) + if err != nil { + return + } + + for _, temp68 := range *T { + temp69 := int32(len(temp68)) + + if temp68 == nil { + temp69 = -1 + } + + err = encoder.Int32(int32(temp69)) + if err != nil { + return + } + + for _, temp70 := range temp68 { + err = encoder.Uint8(uint8(temp70)) + if err != nil { + return + } + + } + + } + + return +} + +var _ fed.Packet = (*DataRow)(nil) + +type DescribePayload struct { + Which uint8 + Name string +} + +type Describe DescribePayload + +func (T *Describe) Type() fed.Type { + return TypeDescribe +} + +func (T *Describe) Length() (length int) { + length += 1 + + length += len((*T).Name) + 1 + + return +} + +func (T *Describe) ReadFrom(decoder *fed.Decoder) (err error) { + if decoder.Type() != T.Type() { + return ErrUnexpectedPacket + } + + *(*uint8)(&((*T).Which)), err = decoder.Uint8() + if err != nil { + return + } + *(*string)(&((*T).Name)), err = decoder.String() + if err != nil { + return + } + + return +} + +func (T *Describe) WriteTo(encoder *fed.Encoder) (err error) { + err = encoder.Uint8(uint8((*T).Which)) + if err != nil { + return + } + + err = encoder.String(string((*T).Name)) + if err != nil { + return + } + + return +} + +var _ fed.Packet = (*Describe)(nil) + +type EmptyQueryResponse struct{} + +func (T *EmptyQueryResponse) Type() fed.Type { + return TypeEmptyQueryResponse +} + +func (T *EmptyQueryResponse) Length() (length int) { + + return +} + +func (T *EmptyQueryResponse) ReadFrom(decoder *fed.Decoder) (err error) { + if decoder.Type() != T.Type() { + return ErrUnexpectedPacket + } + + return +} + +func (T *EmptyQueryResponse) WriteTo(encoder *fed.Encoder) (err error) { + + return +} + +var _ fed.Packet = (*EmptyQueryResponse)(nil) + +type ErrorResponseField struct { + Code uint8 + Value string +} + +type ErrorResponse []ErrorResponseField + +func (T *ErrorResponse) Type() fed.Type { + return TypeErrorResponse +} + +func (T *ErrorResponse) Length() (length int) { + for _, temp71 := range *T { + _ = temp71 + + length += 1 + + length += len(temp71.Value) + 1 + + } + + var temp72 uint8 + _ = temp72 + + length += 1 + + return +} + +func (T *ErrorResponse) ReadFrom(decoder *fed.Decoder) (err error) { + if decoder.Type() != T.Type() { + return ErrUnexpectedPacket + } + + (*T) = (*T)[:0] + + for { + (*T) = slices.Resize((*T), len((*T))+1) + + *(*uint8)(&((*T)[len((*T))-1].Code)), err = decoder.Uint8() + if err != nil { + return + } + if (*T)[len((*T))-1].Code == *new(uint8) { + (*T) = (*T)[:len((*T))-1] + break + } + *(*string)(&((*T)[len((*T))-1].Value)), err = decoder.String() + if err != nil { + return + } + } + + return +} + +func (T *ErrorResponse) WriteTo(encoder *fed.Encoder) (err error) { + for _, temp73 := range *T { + err = encoder.Uint8(uint8(temp73.Code)) + if err != nil { + return + } + + err = encoder.String(string(temp73.Value)) + if err != nil { + return + } + + } + + var temp74 uint8 + + err = encoder.Uint8(uint8(temp74)) + if err != nil { + return + } + + return +} + +var _ fed.Packet = (*ErrorResponse)(nil) + +type ExecutePayload struct { + Target string + MaxRows uint32 +} + +type Execute ExecutePayload + +func (T *Execute) Type() fed.Type { + return TypeExecute +} + +func (T *Execute) Length() (length int) { + length += len((*T).Target) + 1 + + length += 4 + + return +} + +func (T *Execute) ReadFrom(decoder *fed.Decoder) (err error) { + if decoder.Type() != T.Type() { + return ErrUnexpectedPacket + } + + *(*string)(&((*T).Target)), err = decoder.String() + if err != nil { + return + } + *(*uint32)(&((*T).MaxRows)), err = decoder.Uint32() + if err != nil { + return + } + + return +} + +func (T *Execute) WriteTo(encoder *fed.Encoder) (err error) { + err = encoder.String(string((*T).Target)) + if err != nil { + return + } + + err = encoder.Uint32(uint32((*T).MaxRows)) + if err != nil { + return + } + + return +} + +var _ fed.Packet = (*Execute)(nil) + +type Flush struct{} + +func (T *Flush) Type() fed.Type { + return TypeFlush +} + +func (T *Flush) Length() (length int) { + + return +} + +func (T *Flush) ReadFrom(decoder *fed.Decoder) (err error) { + if decoder.Type() != T.Type() { + return ErrUnexpectedPacket + } + + return +} + +func (T *Flush) WriteTo(encoder *fed.Encoder) (err error) { + + return +} + +var _ fed.Packet = (*Flush)(nil) + +type FunctionCallPayload struct { + ObjectID int32 + ArgumentFormatCodes []int16 + Arguments [][]uint8 + ResultFormatCode int16 +} + +type FunctionCall FunctionCallPayload + +func (T *FunctionCall) Type() fed.Type { + return TypeFunctionCall +} + +func (T *FunctionCall) Length() (length int) { + length += 4 + + temp75 := uint16(len((*T).ArgumentFormatCodes)) + _ = temp75 + + length += 2 + + for _, temp76 := range (*T).ArgumentFormatCodes { + _ = temp76 + + length += 2 + + } + + temp77 := uint16(len((*T).Arguments)) + _ = temp77 + + length += 2 + + for _, temp78 := range (*T).Arguments { + _ = temp78 + + temp79 := int32(len(temp78)) + _ = temp79 + + length += 4 + + for _, temp80 := range temp78 { + _ = temp80 + + length += 1 + + } + + } + + length += 2 + + return +} + +func (T *FunctionCall) ReadFrom(decoder *fed.Decoder) (err error) { + if decoder.Type() != T.Type() { + return ErrUnexpectedPacket + } + + *(*int32)(&((*T).ObjectID)), err = decoder.Int32() + if err != nil { + return + } + var temp81 uint16 + *(*uint16)(&(temp81)), err = decoder.Uint16() + if err != nil { + return + } + + (*T).ArgumentFormatCodes = slices.Resize((*T).ArgumentFormatCodes, int(temp81)) + + for temp82 := 0; temp82 < int(temp81); temp82++ { + *(*int16)(&((*T).ArgumentFormatCodes[temp82])), err = decoder.Int16() + if err != nil { + return + } + + } + + var temp83 uint16 + *(*uint16)(&(temp83)), err = decoder.Uint16() + if err != nil { + return + } + + (*T).Arguments = slices.Resize((*T).Arguments, int(temp83)) + + for temp84 := 0; temp84 < int(temp83); temp84++ { + var temp85 int32 + *(*int32)(&(temp85)), err = decoder.Int32() + if err != nil { + return + } + + if temp85 == -1 { + (*T).Arguments[temp84] = nil + } else { + if (*T).Arguments[temp84] == nil { + (*T).Arguments[temp84] = make([]uint8, int(temp85)) + } else { + (*T).Arguments[temp84] = slices.Resize((*T).Arguments[temp84], int(temp85)) + } + + for temp86 := 0; temp86 < int(temp85); temp86++ { + *(*uint8)(&((*T).Arguments[temp84][temp86])), err = decoder.Uint8() + if err != nil { + return + } + + } + } + + } + + *(*int16)(&((*T).ResultFormatCode)), err = decoder.Int16() + if err != nil { + return + } + + return +} + +func (T *FunctionCall) WriteTo(encoder *fed.Encoder) (err error) { + err = encoder.Int32(int32((*T).ObjectID)) + if err != nil { + return + } + + temp87 := uint16(len((*T).ArgumentFormatCodes)) + + err = encoder.Uint16(uint16(temp87)) + if err != nil { + return + } + + for _, temp88 := range (*T).ArgumentFormatCodes { + err = encoder.Int16(int16(temp88)) + if err != nil { + return + } + + } + + temp89 := uint16(len((*T).Arguments)) + + err = encoder.Uint16(uint16(temp89)) + if err != nil { + return + } + + for _, temp90 := range (*T).Arguments { + temp91 := int32(len(temp90)) + + if temp90 == nil { + temp91 = -1 + } + + err = encoder.Int32(int32(temp91)) + if err != nil { + return + } + + for _, temp92 := range temp90 { + err = encoder.Uint8(uint8(temp92)) + if err != nil { + return + } + + } + + } + + err = encoder.Int16(int16((*T).ResultFormatCode)) + if err != nil { + return + } + + return +} + +var _ fed.Packet = (*FunctionCall)(nil) + +type FunctionCallResponse []uint8 + +func (T *FunctionCallResponse) Type() fed.Type { + return TypeFunctionCallResponse +} + +func (T *FunctionCallResponse) Length() (length int) { + temp93 := int32(len((*T))) + _ = temp93 + + length += 4 + + for _, temp94 := range *T { + _ = temp94 + + length += 1 + + } + + return +} + +func (T *FunctionCallResponse) ReadFrom(decoder *fed.Decoder) (err error) { + if decoder.Type() != T.Type() { + return ErrUnexpectedPacket + } + + var temp95 int32 + *(*int32)(&(temp95)), err = decoder.Int32() + if err != nil { + return + } + + if temp95 == -1 { + (*T) = nil + } else { + if (*T) == nil { + (*T) = make([]uint8, int(temp95)) + } else { + (*T) = slices.Resize((*T), int(temp95)) + } + + for temp96 := 0; temp96 < int(temp95); temp96++ { + *(*uint8)(&((*T)[temp96])), err = decoder.Uint8() + if err != nil { + return + } + + } + } + + return +} + +func (T *FunctionCallResponse) WriteTo(encoder *fed.Encoder) (err error) { + temp97 := int32(len((*T))) + + if (*T) == nil { + temp97 = -1 + } + + err = encoder.Int32(int32(temp97)) + if err != nil { + return + } + + for _, temp98 := range *T { + err = encoder.Uint8(uint8(temp98)) + if err != nil { + return + } + + } + + return +} + +var _ fed.Packet = (*FunctionCallResponse)(nil) + +type GSSResponse []uint8 + +func (T *GSSResponse) Type() fed.Type { + return TypeGSSResponse +} + +func (T *GSSResponse) Length() (length int) { + for _, temp99 := range *T { + _ = temp99 + + length += 1 + + } + + return +} + +func (T *GSSResponse) ReadFrom(decoder *fed.Decoder) (err error) { + if decoder.Type() != T.Type() { + return ErrUnexpectedPacket + } + + (*T) = (*T)[:0] + + for { + if decoder.Position() >= decoder.Length() { + break + } + + (*T) = slices.Resize((*T), len((*T))+1) + + *(*uint8)(&((*T)[len((*T))-1])), err = decoder.Uint8() + if err != nil { + return + } + + } + + return +} + +func (T *GSSResponse) WriteTo(encoder *fed.Encoder) (err error) { + for _, temp100 := range *T { + err = encoder.Uint8(uint8(temp100)) + if err != nil { + return + } + + } + + return +} + +var _ fed.Packet = (*GSSResponse)(nil) + +type NegotiateProtocolVersionPayload struct { + MinorProtocolVersion int32 + UnrecognizedProtocolOptions []string +} + +type NegotiateProtocolVersion NegotiateProtocolVersionPayload + +func (T *NegotiateProtocolVersion) Type() fed.Type { + return TypeNegotiateProtocolVersion +} + +func (T *NegotiateProtocolVersion) Length() (length int) { + length += 4 + + temp101 := uint32(len((*T).UnrecognizedProtocolOptions)) + _ = temp101 + + length += 4 + + for _, temp102 := range (*T).UnrecognizedProtocolOptions { + _ = temp102 + + length += len(temp102) + 1 + + } + + return +} + +func (T *NegotiateProtocolVersion) ReadFrom(decoder *fed.Decoder) (err error) { + if decoder.Type() != T.Type() { + return ErrUnexpectedPacket + } + + *(*int32)(&((*T).MinorProtocolVersion)), err = decoder.Int32() + if err != nil { + return + } + var temp103 uint32 + *(*uint32)(&(temp103)), err = decoder.Uint32() + if err != nil { + return + } + + (*T).UnrecognizedProtocolOptions = slices.Resize((*T).UnrecognizedProtocolOptions, int(temp103)) + + for temp104 := 0; temp104 < int(temp103); temp104++ { + *(*string)(&((*T).UnrecognizedProtocolOptions[temp104])), err = decoder.String() + if err != nil { + return + } + + } + + return +} + +func (T *NegotiateProtocolVersion) WriteTo(encoder *fed.Encoder) (err error) { + err = encoder.Int32(int32((*T).MinorProtocolVersion)) + if err != nil { + return + } + + temp105 := uint32(len((*T).UnrecognizedProtocolOptions)) + + err = encoder.Uint32(uint32(temp105)) + if err != nil { + return + } + + for _, temp106 := range (*T).UnrecognizedProtocolOptions { + err = encoder.String(string(temp106)) + if err != nil { + return + } + + } + + return +} + +var _ fed.Packet = (*NegotiateProtocolVersion)(nil) + +type NoData struct{} + +func (T *NoData) Type() fed.Type { + return TypeNoData +} + +func (T *NoData) Length() (length int) { + + return +} + +func (T *NoData) ReadFrom(decoder *fed.Decoder) (err error) { + if decoder.Type() != T.Type() { + return ErrUnexpectedPacket + } + + return +} + +func (T *NoData) WriteTo(encoder *fed.Encoder) (err error) { + + return +} + +var _ fed.Packet = (*NoData)(nil) + +type NoticeResponseField struct { + Code uint8 + Value string +} + +type NoticeResponse []NoticeResponseField + +func (T *NoticeResponse) Type() fed.Type { + return TypeNoticeResponse +} + +func (T *NoticeResponse) Length() (length int) { + for _, temp107 := range *T { + _ = temp107 + + length += 1 + + length += len(temp107.Value) + 1 + + } + + var temp108 uint8 + _ = temp108 + + length += 1 + + return +} + +func (T *NoticeResponse) ReadFrom(decoder *fed.Decoder) (err error) { + if decoder.Type() != T.Type() { + return ErrUnexpectedPacket + } + + (*T) = (*T)[:0] + + for { + (*T) = slices.Resize((*T), len((*T))+1) + + *(*uint8)(&((*T)[len((*T))-1].Code)), err = decoder.Uint8() + if err != nil { + return + } + if (*T)[len((*T))-1].Code == *new(uint8) { + (*T) = (*T)[:len((*T))-1] + break + } + *(*string)(&((*T)[len((*T))-1].Value)), err = decoder.String() + if err != nil { + return + } + } + + return +} + +func (T *NoticeResponse) WriteTo(encoder *fed.Encoder) (err error) { + for _, temp109 := range *T { + err = encoder.Uint8(uint8(temp109.Code)) + if err != nil { + return + } + + err = encoder.String(string(temp109.Value)) + if err != nil { + return + } + + } + + var temp110 uint8 + + err = encoder.Uint8(uint8(temp110)) + if err != nil { + return + } + + return +} + +var _ fed.Packet = (*NoticeResponse)(nil) + +type NotificationResponsePayload struct { + ProcessID int32 + Channel string + Payload string +} + +type NotificationResponse NotificationResponsePayload + +func (T *NotificationResponse) Type() fed.Type { + return TypeNotificationResponse +} + +func (T *NotificationResponse) Length() (length int) { + length += 4 + + length += len((*T).Channel) + 1 + + length += len((*T).Payload) + 1 + + return +} + +func (T *NotificationResponse) ReadFrom(decoder *fed.Decoder) (err error) { + if decoder.Type() != T.Type() { + return ErrUnexpectedPacket + } + + *(*int32)(&((*T).ProcessID)), err = decoder.Int32() + if err != nil { + return + } + *(*string)(&((*T).Channel)), err = decoder.String() + if err != nil { + return + } + *(*string)(&((*T).Payload)), err = decoder.String() + if err != nil { + return + } + + return +} + +func (T *NotificationResponse) WriteTo(encoder *fed.Encoder) (err error) { + err = encoder.Int32(int32((*T).ProcessID)) + if err != nil { + return + } + + err = encoder.String(string((*T).Channel)) + if err != nil { + return + } + + err = encoder.String(string((*T).Payload)) + if err != nil { + return + } + + return +} + +var _ fed.Packet = (*NotificationResponse)(nil) + +type ParameterDescription []int32 + +func (T *ParameterDescription) Type() fed.Type { + return TypeParameterDescription +} + +func (T *ParameterDescription) Length() (length int) { + temp111 := uint16(len((*T))) + _ = temp111 + + length += 2 + + for _, temp112 := range *T { + _ = temp112 + + length += 4 + + } + + return +} + +func (T *ParameterDescription) ReadFrom(decoder *fed.Decoder) (err error) { + if decoder.Type() != T.Type() { + return ErrUnexpectedPacket + } + + var temp113 uint16 + *(*uint16)(&(temp113)), err = decoder.Uint16() + if err != nil { + return + } + + (*T) = slices.Resize((*T), int(temp113)) + + for temp114 := 0; temp114 < int(temp113); temp114++ { + *(*int32)(&((*T)[temp114])), err = decoder.Int32() + if err != nil { + return + } + + } + + return +} + +func (T *ParameterDescription) WriteTo(encoder *fed.Encoder) (err error) { + temp115 := uint16(len((*T))) + + err = encoder.Uint16(uint16(temp115)) + if err != nil { + return + } + + for _, temp116 := range *T { + err = encoder.Int32(int32(temp116)) + if err != nil { + return + } + + } + + return +} + +var _ fed.Packet = (*ParameterDescription)(nil) + +type ParameterStatusPayload struct { + Key string + Value string +} + +type ParameterStatus ParameterStatusPayload + +func (T *ParameterStatus) Type() fed.Type { + return TypeParameterStatus +} + +func (T *ParameterStatus) Length() (length int) { + length += len((*T).Key) + 1 + + length += len((*T).Value) + 1 + + return +} + +func (T *ParameterStatus) ReadFrom(decoder *fed.Decoder) (err error) { + if decoder.Type() != T.Type() { + return ErrUnexpectedPacket + } + + *(*string)(&((*T).Key)), err = decoder.String() + if err != nil { + return + } + *(*string)(&((*T).Value)), err = decoder.String() + if err != nil { + return + } + + return +} + +func (T *ParameterStatus) WriteTo(encoder *fed.Encoder) (err error) { + err = encoder.String(string((*T).Key)) + if err != nil { + return + } + + err = encoder.String(string((*T).Value)) + if err != nil { + return + } + + return +} + +var _ fed.Packet = (*ParameterStatus)(nil) + +type ParsePayload struct { + Destination string + Query string + ParameterDataTypes []int32 +} + +type Parse ParsePayload + +func (T *Parse) Type() fed.Type { + return TypeParse +} + +func (T *Parse) Length() (length int) { + length += len((*T).Destination) + 1 + + length += len((*T).Query) + 1 + + temp117 := uint16(len((*T).ParameterDataTypes)) + _ = temp117 + + length += 2 + + for _, temp118 := range (*T).ParameterDataTypes { + _ = temp118 + + length += 4 + + } + + return +} + +func (T *Parse) ReadFrom(decoder *fed.Decoder) (err error) { + if decoder.Type() != T.Type() { + return ErrUnexpectedPacket + } + + *(*string)(&((*T).Destination)), err = decoder.String() + if err != nil { + return + } + *(*string)(&((*T).Query)), err = decoder.String() + if err != nil { + return + } + var temp119 uint16 + *(*uint16)(&(temp119)), err = decoder.Uint16() + if err != nil { + return + } + + (*T).ParameterDataTypes = slices.Resize((*T).ParameterDataTypes, int(temp119)) + + for temp120 := 0; temp120 < int(temp119); temp120++ { + *(*int32)(&((*T).ParameterDataTypes[temp120])), err = decoder.Int32() + if err != nil { + return + } + + } + + return +} + +func (T *Parse) WriteTo(encoder *fed.Encoder) (err error) { + err = encoder.String(string((*T).Destination)) + if err != nil { + return + } + + err = encoder.String(string((*T).Query)) + if err != nil { + return + } + + temp121 := uint16(len((*T).ParameterDataTypes)) + + err = encoder.Uint16(uint16(temp121)) + if err != nil { + return + } + + for _, temp122 := range (*T).ParameterDataTypes { + err = encoder.Int32(int32(temp122)) + if err != nil { + return + } + + } + + return +} + +var _ fed.Packet = (*Parse)(nil) + +type ParseComplete struct{} + +func (T *ParseComplete) Type() fed.Type { + return TypeParseComplete +} + +func (T *ParseComplete) Length() (length int) { + + return +} + +func (T *ParseComplete) ReadFrom(decoder *fed.Decoder) (err error) { + if decoder.Type() != T.Type() { + return ErrUnexpectedPacket + } + + return +} + +func (T *ParseComplete) WriteTo(encoder *fed.Encoder) (err error) { + + return +} + +var _ fed.Packet = (*ParseComplete)(nil) + +type PasswordMessage string + +func (T *PasswordMessage) Type() fed.Type { + return TypePasswordMessage +} + +func (T *PasswordMessage) Length() (length int) { + length += len((*T)) + 1 + + return +} + +func (T *PasswordMessage) ReadFrom(decoder *fed.Decoder) (err error) { + if decoder.Type() != T.Type() { + return ErrUnexpectedPacket + } + + *(*string)(&(*T)), err = decoder.String() + if err != nil { + return + } + + return +} + +func (T *PasswordMessage) WriteTo(encoder *fed.Encoder) (err error) { + err = encoder.String(string((*T))) + if err != nil { + return + } + + return +} + +var _ fed.Packet = (*PasswordMessage)(nil) + +type PortalSuspended struct{} + +func (T *PortalSuspended) Type() fed.Type { + return TypePortalSuspended +} + +func (T *PortalSuspended) Length() (length int) { + + return +} + +func (T *PortalSuspended) ReadFrom(decoder *fed.Decoder) (err error) { + if decoder.Type() != T.Type() { + return ErrUnexpectedPacket + } + + return +} + +func (T *PortalSuspended) WriteTo(encoder *fed.Encoder) (err error) { + + return +} + +var _ fed.Packet = (*PortalSuspended)(nil) + +type Query string + +func (T *Query) Type() fed.Type { + return TypeQuery +} + +func (T *Query) Length() (length int) { + length += len((*T)) + 1 + + return +} + +func (T *Query) ReadFrom(decoder *fed.Decoder) (err error) { + if decoder.Type() != T.Type() { + return ErrUnexpectedPacket + } + + *(*string)(&(*T)), err = decoder.String() + if err != nil { + return + } + + return +} + +func (T *Query) WriteTo(encoder *fed.Encoder) (err error) { + err = encoder.String(string((*T))) + if err != nil { + return + } + + return +} + +var _ fed.Packet = (*Query)(nil) + +type ReadyForQuery uint8 + +func (T *ReadyForQuery) Type() fed.Type { + return TypeReadyForQuery +} + +func (T *ReadyForQuery) Length() (length int) { + length += 1 + + return +} + +func (T *ReadyForQuery) ReadFrom(decoder *fed.Decoder) (err error) { + if decoder.Type() != T.Type() { + return ErrUnexpectedPacket + } + + *(*uint8)(&(*T)), err = decoder.Uint8() + if err != nil { + return + } + + return +} + +func (T *ReadyForQuery) WriteTo(encoder *fed.Encoder) (err error) { + err = encoder.Uint8(uint8((*T))) + if err != nil { + return + } + + return +} + +var _ fed.Packet = (*ReadyForQuery)(nil) + +type RowDescriptionRow struct { + Name string + TableID int32 + ColumnAttributeNumber int16 + FieldDataType int32 + DataTypeSize int16 + TypeModifier int32 + FormatCode int16 +} + +type RowDescription []RowDescriptionRow + +func (T *RowDescription) Type() fed.Type { + return TypeRowDescription +} + +func (T *RowDescription) Length() (length int) { + temp123 := uint16(len((*T))) + _ = temp123 + + length += 2 + + for _, temp124 := range *T { + _ = temp124 + + length += len(temp124.Name) + 1 + + length += 4 + + length += 2 + + length += 4 + + length += 2 + + length += 4 + + length += 2 + + } + + return +} + +func (T *RowDescription) ReadFrom(decoder *fed.Decoder) (err error) { + if decoder.Type() != T.Type() { + return ErrUnexpectedPacket + } + + var temp125 uint16 + *(*uint16)(&(temp125)), err = decoder.Uint16() + if err != nil { + return + } + + (*T) = slices.Resize((*T), int(temp125)) + + for temp126 := 0; temp126 < int(temp125); temp126++ { + *(*string)(&((*T)[temp126].Name)), err = decoder.String() + if err != nil { + return + } + *(*int32)(&((*T)[temp126].TableID)), err = decoder.Int32() + if err != nil { + return + } + *(*int16)(&((*T)[temp126].ColumnAttributeNumber)), err = decoder.Int16() + if err != nil { + return + } + *(*int32)(&((*T)[temp126].FieldDataType)), err = decoder.Int32() + if err != nil { + return + } + *(*int16)(&((*T)[temp126].DataTypeSize)), err = decoder.Int16() + if err != nil { + return + } + *(*int32)(&((*T)[temp126].TypeModifier)), err = decoder.Int32() + if err != nil { + return + } + *(*int16)(&((*T)[temp126].FormatCode)), err = decoder.Int16() + if err != nil { + return + } + + } + + return +} + +func (T *RowDescription) WriteTo(encoder *fed.Encoder) (err error) { + temp127 := uint16(len((*T))) + + err = encoder.Uint16(uint16(temp127)) + if err != nil { + return + } + + for _, temp128 := range *T { + err = encoder.String(string(temp128.Name)) + if err != nil { + return + } + + err = encoder.Int32(int32(temp128.TableID)) + if err != nil { + return + } + + err = encoder.Int16(int16(temp128.ColumnAttributeNumber)) + if err != nil { + return + } + + err = encoder.Int32(int32(temp128.FieldDataType)) + if err != nil { + return + } + + err = encoder.Int16(int16(temp128.DataTypeSize)) + if err != nil { + return + } + + err = encoder.Int32(int32(temp128.TypeModifier)) + if err != nil { + return + } + + err = encoder.Int16(int16(temp128.FormatCode)) + if err != nil { + return + } + + } + + return +} + +var _ fed.Packet = (*RowDescription)(nil) + +type SASLInitialResponsePayload struct { + Mechanism string + InitialClientResponse []uint8 +} + +type SASLInitialResponse SASLInitialResponsePayload + +func (T *SASLInitialResponse) Type() fed.Type { + return TypeSASLInitialResponse +} + +func (T *SASLInitialResponse) Length() (length int) { + length += len((*T).Mechanism) + 1 + + temp129 := int32(len((*T).InitialClientResponse)) + _ = temp129 + + length += 4 + + for _, temp130 := range (*T).InitialClientResponse { + _ = temp130 + + length += 1 + + } + + return +} + +func (T *SASLInitialResponse) ReadFrom(decoder *fed.Decoder) (err error) { + if decoder.Type() != T.Type() { + return ErrUnexpectedPacket + } + + *(*string)(&((*T).Mechanism)), err = decoder.String() + if err != nil { + return + } + var temp131 int32 + *(*int32)(&(temp131)), err = decoder.Int32() + if err != nil { + return + } + + if temp131 == -1 { + (*T).InitialClientResponse = nil + } else { + if (*T).InitialClientResponse == nil { + (*T).InitialClientResponse = make([]uint8, int(temp131)) + } else { + (*T).InitialClientResponse = slices.Resize((*T).InitialClientResponse, int(temp131)) + } + + for temp132 := 0; temp132 < int(temp131); temp132++ { + *(*uint8)(&((*T).InitialClientResponse[temp132])), err = decoder.Uint8() + if err != nil { + return + } + + } + } + + return +} + +func (T *SASLInitialResponse) WriteTo(encoder *fed.Encoder) (err error) { + err = encoder.String(string((*T).Mechanism)) + if err != nil { + return + } + + temp133 := int32(len((*T).InitialClientResponse)) + + if (*T).InitialClientResponse == nil { + temp133 = -1 + } + + err = encoder.Int32(int32(temp133)) + if err != nil { + return + } + + for _, temp134 := range (*T).InitialClientResponse { + err = encoder.Uint8(uint8(temp134)) + if err != nil { + return + } + + } + + return +} + +var _ fed.Packet = (*SASLInitialResponse)(nil) + +type SASLResponse []uint8 + +func (T *SASLResponse) Type() fed.Type { + return TypeSASLResponse +} + +func (T *SASLResponse) Length() (length int) { + for _, temp135 := range *T { + _ = temp135 + + length += 1 + + } + + return +} + +func (T *SASLResponse) ReadFrom(decoder *fed.Decoder) (err error) { + if decoder.Type() != T.Type() { + return ErrUnexpectedPacket + } + + (*T) = (*T)[:0] + + for { + if decoder.Position() >= decoder.Length() { + break + } + + (*T) = slices.Resize((*T), len((*T))+1) + + *(*uint8)(&((*T)[len((*T))-1])), err = decoder.Uint8() + if err != nil { + return + } + + } + + return +} + +func (T *SASLResponse) WriteTo(encoder *fed.Encoder) (err error) { + for _, temp136 := range *T { + err = encoder.Uint8(uint8(temp136)) + if err != nil { + return + } + + } + + return +} + +var _ fed.Packet = (*SASLResponse)(nil) + +type StartupPayloadControlPayloadCancelKey struct { + ProcessID int32 + SecretKey int32 +} + +type StartupPayloadControlPayloadCancel StartupPayloadControlPayloadCancelKey + +func (*StartupPayloadControlPayloadCancel) StartupPayloadControlPayloadMode() int16 { + return 5678 +} + +func (T *StartupPayloadControlPayloadCancel) Length() (length int) { + length += 4 + + length += 4 + + return +} + +func (T *StartupPayloadControlPayloadCancel) ReadFrom(decoder *fed.Decoder) (err error) { + *(*int32)(&((*T).ProcessID)), err = decoder.Int32() + if err != nil { + return + } + *(*int32)(&((*T).SecretKey)), err = decoder.Int32() + if err != nil { + return + } + + return +} + +func (T *StartupPayloadControlPayloadCancel) WriteTo(encoder *fed.Encoder) (err error) { + err = encoder.Int32(int32((*T).ProcessID)) + if err != nil { + return + } + + err = encoder.Int32(int32((*T).SecretKey)) + if err != nil { + return + } + + return +} + +type StartupPayloadControlPayloadGSSAPI struct{} + +func (*StartupPayloadControlPayloadGSSAPI) StartupPayloadControlPayloadMode() int16 { + return 5680 +} + +func (T *StartupPayloadControlPayloadGSSAPI) Length() (length int) { + + return +} + +func (T *StartupPayloadControlPayloadGSSAPI) ReadFrom(decoder *fed.Decoder) (err error) { + + return +} + +func (T *StartupPayloadControlPayloadGSSAPI) WriteTo(encoder *fed.Encoder) (err error) { + + return +} + +type StartupPayloadControlPayloadSSL struct{} + +func (*StartupPayloadControlPayloadSSL) StartupPayloadControlPayloadMode() int16 { + return 5679 +} + +func (T *StartupPayloadControlPayloadSSL) Length() (length int) { + + return +} + +func (T *StartupPayloadControlPayloadSSL) ReadFrom(decoder *fed.Decoder) (err error) { + + return +} + +func (T *StartupPayloadControlPayloadSSL) WriteTo(encoder *fed.Encoder) (err error) { + + return +} + +type StartupPayloadControlPayloadMode interface { + StartupPayloadControlPayloadMode() int16 + + Length() int + ReadFrom(decoder *fed.Decoder) error + WriteTo(encoder *fed.Encoder) error +} +type StartupPayloadControlPayload struct { + Mode StartupPayloadControlPayloadMode +} + +type StartupPayloadControl StartupPayloadControlPayload + +func (*StartupPayloadControl) StartupPayloadMode() int16 { + return 1234 +} + +func (T *StartupPayloadControl) Length() (length int) { + length += 2 + + length += (*T).Mode.Length() + + return +} + +func (T *StartupPayloadControl) ReadFrom(decoder *fed.Decoder) (err error) { + var temp137 int16 + + *(*int16)(&(temp137)), err = decoder.Int16() + if err != nil { + return + } + + switch temp137 { + case 5678: + (*T).Mode = new(StartupPayloadControlPayloadCancel) + case 5680: + (*T).Mode = new(StartupPayloadControlPayloadGSSAPI) + case 5679: + (*T).Mode = new(StartupPayloadControlPayloadSSL) + default: + err = ErrInvalidFormat + return + } + + err = (*T).Mode.ReadFrom(decoder) + if err != nil { + return + } + + return +} + +func (T *StartupPayloadControl) WriteTo(encoder *fed.Encoder) (err error) { + err = encoder.Int16(int16((*T).Mode.StartupPayloadControlPayloadMode())) + if err != nil { + return + } + + err = (*T).Mode.WriteTo(encoder) + if err != nil { + return + } + + return +} + +type StartupPayloadVersion3PayloadParameter struct { + Key string + Value string +} + +type StartupPayloadVersion3Payload struct { + MinorVersion int16 + Parameters []StartupPayloadVersion3PayloadParameter +} + +type StartupPayloadVersion3 StartupPayloadVersion3Payload + +func (*StartupPayloadVersion3) StartupPayloadMode() int16 { + return 3 +} + +func (T *StartupPayloadVersion3) Length() (length int) { + length += 2 + + for _, temp138 := range (*T).Parameters { + _ = temp138 + + length += len(temp138.Key) + 1 + + length += len(temp138.Value) + 1 + + } + + var temp139 string + _ = temp139 + + length += len(temp139) + 1 + + return +} + +func (T *StartupPayloadVersion3) ReadFrom(decoder *fed.Decoder) (err error) { + *(*int16)(&((*T).MinorVersion)), err = decoder.Int16() + if err != nil { + return + } + (*T).Parameters = (*T).Parameters[:0] + + for { + (*T).Parameters = slices.Resize((*T).Parameters, len((*T).Parameters)+1) + + *(*string)(&((*T).Parameters[len((*T).Parameters)-1].Key)), err = decoder.String() + if err != nil { + return + } + if (*T).Parameters[len((*T).Parameters)-1].Key == *new(string) { + (*T).Parameters = (*T).Parameters[:len((*T).Parameters)-1] + break + } + *(*string)(&((*T).Parameters[len((*T).Parameters)-1].Value)), err = decoder.String() + if err != nil { + return + } + } + + return +} + +func (T *StartupPayloadVersion3) WriteTo(encoder *fed.Encoder) (err error) { + err = encoder.Int16(int16((*T).MinorVersion)) + if err != nil { + return + } + + for _, temp140 := range (*T).Parameters { + err = encoder.String(string(temp140.Key)) + if err != nil { + return + } + + err = encoder.String(string(temp140.Value)) + if err != nil { + return + } + + } + + var temp141 string + + err = encoder.String(string(temp141)) + if err != nil { + return + } + + return +} + +type StartupPayloadMode interface { + StartupPayloadMode() int16 + + Length() int + ReadFrom(decoder *fed.Decoder) error + WriteTo(encoder *fed.Encoder) error +} +type StartupPayload struct { + Mode StartupPayloadMode +} + +type Startup StartupPayload + +func (T *Startup) Type() fed.Type { + return 0 +} + +func (T *Startup) Length() (length int) { + length += 2 + + length += (*T).Mode.Length() + + return +} + +func (T *Startup) ReadFrom(decoder *fed.Decoder) (err error) { + if decoder.Type() != T.Type() { + return ErrUnexpectedPacket + } + + var temp142 int16 + + *(*int16)(&(temp142)), err = decoder.Int16() + if err != nil { + return + } + + switch temp142 { + case 1234: + (*T).Mode = new(StartupPayloadControl) + case 3: + (*T).Mode = new(StartupPayloadVersion3) + default: + err = ErrInvalidFormat + return + } + + err = (*T).Mode.ReadFrom(decoder) + if err != nil { + return + } + + return +} + +func (T *Startup) WriteTo(encoder *fed.Encoder) (err error) { + err = encoder.Int16(int16((*T).Mode.StartupPayloadMode())) + if err != nil { + return + } + + err = (*T).Mode.WriteTo(encoder) + if err != nil { + return + } + + return +} + +var _ fed.Packet = (*Startup)(nil) + +type Sync struct{} + +func (T *Sync) Type() fed.Type { + return TypeSync +} + +func (T *Sync) Length() (length int) { + + return +} + +func (T *Sync) ReadFrom(decoder *fed.Decoder) (err error) { + if decoder.Type() != T.Type() { + return ErrUnexpectedPacket + } + + return +} + +func (T *Sync) WriteTo(encoder *fed.Encoder) (err error) { + + return +} + +var _ fed.Packet = (*Sync)(nil) + +type Terminate struct{} + +func (T *Terminate) Type() fed.Type { + return TypeTerminate +} + +func (T *Terminate) Length() (length int) { + + return +} + +func (T *Terminate) ReadFrom(decoder *fed.Decoder) (err error) { + if decoder.Type() != T.Type() { + return ErrUnexpectedPacket + } + + return +} + +func (T *Terminate) WriteTo(encoder *fed.Encoder) (err error) { + + return +} + +var _ fed.Packet = (*Terminate)(nil) diff --git a/lib/fed/packets/v3.0/parameterstatus.go b/lib/fed/packets/v3.0/parameterstatus.go deleted file mode 100644 index 2280971fac953618dc054a0c9c196df76dc117df..0000000000000000000000000000000000000000 --- a/lib/fed/packets/v3.0/parameterstatus.go +++ /dev/null @@ -1,24 +0,0 @@ -package packets - -import "gfx.cafe/gfx/pggat/lib/fed" - -type ParameterStatus struct { - Key string - Value string -} - -func (T *ParameterStatus) ReadFromPacket(packet fed.Packet) bool { - if packet.Type() != TypeParameterStatus { - return false - } - p := packet.ReadString(&T.Key) - p = p.ReadString(&T.Value) - return true -} - -func (T *ParameterStatus) IntoPacket(packet fed.Packet) fed.Packet { - packet = packet.Reset(TypeParameterStatus, len(T.Key)+len(T.Value)+2) - packet = packet.AppendString(T.Key) - packet = packet.AppendString(T.Value) - return packet -} diff --git a/lib/fed/packets/v3.0/parse.go b/lib/fed/packets/v3.0/parse.go deleted file mode 100644 index 1ae827a42c91c05cd4d5528bc569eeb4bfa8e51c..0000000000000000000000000000000000000000 --- a/lib/fed/packets/v3.0/parse.go +++ /dev/null @@ -1,38 +0,0 @@ -package packets - -import ( - "gfx.cafe/gfx/pggat/lib/fed" - "gfx.cafe/gfx/pggat/lib/util/slices" -) - -type Parse struct { - Destination string - Query string - ParameterDataTypes []int32 -} - -func (T *Parse) ReadFromPacket(packet fed.Packet) bool { - if packet.Type() != TypeParse { - return false - } - p := packet.ReadString(&T.Destination) - p = p.ReadString(&T.Query) - var parameterDataTypesCount int16 - p = p.ReadInt16(¶meterDataTypesCount) - T.ParameterDataTypes = slices.Resize(T.ParameterDataTypes, int(parameterDataTypesCount)) - for i := 0; i < int(parameterDataTypesCount); i++ { - p = p.ReadInt32(&T.ParameterDataTypes[i]) - } - return true -} - -func (T *Parse) IntoPacket(packet fed.Packet) fed.Packet { - packet = packet.Reset(TypeParse, len(T.Destination)+len(T.Query)+4+len(T.ParameterDataTypes)*4) - packet = packet.AppendString(T.Destination) - packet = packet.AppendString(T.Query) - packet = packet.AppendInt16(int16(len(T.ParameterDataTypes))) - for _, v := range T.ParameterDataTypes { - packet = packet.AppendInt32(v) - } - return packet -} diff --git a/lib/fed/packets/v3.0/passwordmessage.go b/lib/fed/packets/v3.0/passwordmessage.go deleted file mode 100644 index 7994328304204bceb80eac06877ee526bbfbd457..0000000000000000000000000000000000000000 --- a/lib/fed/packets/v3.0/passwordmessage.go +++ /dev/null @@ -1,23 +0,0 @@ -package packets - -import ( - "gfx.cafe/gfx/pggat/lib/fed" -) - -type PasswordMessage struct { - Password string -} - -func (T *PasswordMessage) ReadFromPacket(packet fed.Packet) bool { - if packet.Type() != TypeAuthenticationResponse { - return false - } - packet.ReadString(&T.Password) - return true -} - -func (T *PasswordMessage) IntoPacket(packet fed.Packet) fed.Packet { - packet = packet.Reset(TypeAuthenticationResponse, len(T.Password)+1) - packet = packet.AppendString(T.Password) - return packet -} diff --git a/lib/fed/packets/v3.0/query.go b/lib/fed/packets/v3.0/query.go deleted file mode 100644 index 5a0e43afdd9b09518ecea02420c4e28c65f1ddda..0000000000000000000000000000000000000000 --- a/lib/fed/packets/v3.0/query.go +++ /dev/null @@ -1,19 +0,0 @@ -package packets - -import "gfx.cafe/gfx/pggat/lib/fed" - -type Query string - -func (T *Query) ReadFromPacket(packet fed.Packet) bool { - if packet.Type() != TypeQuery { - return false - } - packet.ReadString((*string)(T)) - return true -} - -func (T *Query) IntoPacket(packet fed.Packet) fed.Packet { - packet = packet.Reset(TypeQuery, len(*T)+1) - packet = packet.AppendString(string(*T)) - return packet -} diff --git a/lib/fed/packets/v3.0/readyforquery.go b/lib/fed/packets/v3.0/readyforquery.go deleted file mode 100644 index aaf111dd3c4f74413934ebd337056bf8fc9ed5eb..0000000000000000000000000000000000000000 --- a/lib/fed/packets/v3.0/readyforquery.go +++ /dev/null @@ -1,21 +0,0 @@ -package packets - -import ( - "gfx.cafe/gfx/pggat/lib/fed" -) - -type ReadyForQuery byte - -func (T *ReadyForQuery) ReadFromPacket(packet fed.Packet) bool { - if packet.Type() != TypeReadyForQuery { - return false - } - packet.ReadUint8((*byte)(T)) - return true -} - -func (T *ReadyForQuery) IntoPacket(packet fed.Packet) fed.Packet { - packet = fed.NewPacket(TypeReadyForQuery, 1) - packet = packet.AppendUint8(byte(*T)) - return packet -} diff --git a/lib/fed/packets/v3.0/rowdescription.go b/lib/fed/packets/v3.0/rowdescription.go deleted file mode 100644 index fa4001c520d36fae689a42a7e50d9a304eb4dd3c..0000000000000000000000000000000000000000 --- a/lib/fed/packets/v3.0/rowdescription.go +++ /dev/null @@ -1,63 +0,0 @@ -package packets - -import ( - "gfx.cafe/gfx/pggat/lib/fed" - "gfx.cafe/gfx/pggat/lib/util/slices" -) - -type RowDescriptionField struct { - Name string - TableID int32 - ColumnID int16 - Type int32 - TypeLength int16 - TypeModifier int32 - FormatCode int16 -} - -type RowDescription struct { - Fields []RowDescriptionField -} - -func (T *RowDescription) ReadFromPacket(packet fed.Packet) bool { - if packet.Type() != TypeRowDescription { - return false - } - - var fieldsPerRow uint16 - p := packet.ReadUint16(&fieldsPerRow) - T.Fields = slices.Resize(T.Fields, int(fieldsPerRow)) - for i := 0; i < int(fieldsPerRow); i++ { - p = p.ReadString(&T.Fields[i].Name) - p = p.ReadInt32(&T.Fields[i].TableID) - p = p.ReadInt16(&T.Fields[i].ColumnID) - p = p.ReadInt32(&T.Fields[i].Type) - p = p.ReadInt16(&T.Fields[i].TypeLength) - p = p.ReadInt32(&T.Fields[i].TypeModifier) - p = p.ReadInt16(&T.Fields[i].FormatCode) - } - - return true -} - -func (T *RowDescription) IntoPacket(packet fed.Packet) fed.Packet { - size := 2 - for _, v := range T.Fields { - size += len(v.Name) + 1 - size += 4 + 2 + 4 + 2 + 4 + 2 - } - - packet = packet.Reset(TypeRowDescription, size) - packet = packet.AppendUint16(uint16(len(T.Fields))) - for _, v := range T.Fields { - packet = packet.AppendString(v.Name) - packet = packet.AppendInt32(v.TableID) - packet = packet.AppendInt16(v.ColumnID) - packet = packet.AppendInt32(v.Type) - packet = packet.AppendInt16(v.TypeLength) - packet = packet.AppendInt32(v.TypeModifier) - packet = packet.AppendInt16(v.FormatCode) - } - - return packet -} diff --git a/lib/fed/packets/v3.0/saslinitialresponse.go b/lib/fed/packets/v3.0/saslinitialresponse.go deleted file mode 100644 index b9046788c0f16a71d1bfca4669e51ee8c54d45ab..0000000000000000000000000000000000000000 --- a/lib/fed/packets/v3.0/saslinitialresponse.go +++ /dev/null @@ -1,35 +0,0 @@ -package packets - -import ( - "gfx.cafe/gfx/pggat/lib/fed" - "gfx.cafe/gfx/pggat/lib/util/slices" -) - -type SASLInitialResponse struct { - Mechanism string - InitialResponse []byte -} - -func (T *SASLInitialResponse) ReadFromPacket(packet fed.Packet) bool { - if packet.Type() != TypeAuthenticationResponse { - return false - } - - p := packet.ReadString(&T.Mechanism) - - var initialResponseSize int32 - p = p.ReadInt32(&initialResponseSize) - - T.InitialResponse = slices.Resize(T.InitialResponse, int(initialResponseSize)) - p = p.ReadBytes(T.InitialResponse) - - return true -} - -func (T *SASLInitialResponse) IntoPacket(packet fed.Packet) fed.Packet { - packet = packet.Reset(TypeAuthenticationResponse, len(T.Mechanism)+5+len(T.InitialResponse)) - packet = packet.AppendString(T.Mechanism) - packet = packet.AppendInt32(int32(len(T.InitialResponse))) - packet = packet.AppendBytes(T.InitialResponse) - return packet -} diff --git a/lib/fed/packets/v3.0/types.go b/lib/fed/packets/v3.0/types.go deleted file mode 100644 index f1d5335e7923940a588442a40b88e299d074a09a..0000000000000000000000000000000000000000 --- a/lib/fed/packets/v3.0/types.go +++ /dev/null @@ -1,42 +0,0 @@ -package packets - -import "gfx.cafe/gfx/pggat/lib/fed" - -const ( - TypeAuthentication fed.Type = 'R' - TypeBackendKeyData fed.Type = 'K' - TypeBind fed.Type = 'B' - TypeBindComplete fed.Type = '2' - TypeClose fed.Type = 'C' - TypeCloseComplete fed.Type = '3' - TypeCommandComplete fed.Type = 'C' - TypeCopyData fed.Type = 'd' - TypeCopyDone fed.Type = 'c' - TypeCopyFail fed.Type = 'f' - TypeCopyInResponse fed.Type = 'G' - TypeCopyOutResponse fed.Type = 'H' - TypeCopyBothResponse fed.Type = 'W' - TypeDataRow fed.Type = 'D' - TypeDescribe fed.Type = 'D' - TypeEmptyQueryResponse fed.Type = 'I' - TypeErrorResponse fed.Type = 'E' - TypeExecute fed.Type = 'E' - TypeFlush fed.Type = 'H' - TypeFunctionCall fed.Type = 'F' - TypeFunctionCallResponse fed.Type = 'V' - TypeAuthenticationResponse fed.Type = 'p' - TypeNegotiateProtocolVersion fed.Type = 'v' - TypeNoData fed.Type = 'n' - TypeNoticeResponse fed.Type = 'N' - TypeNotificationResponse fed.Type = 'A' - TypeParameterDescription fed.Type = 't' - TypeParameterStatus fed.Type = 'S' - TypeParse fed.Type = 'P' - TypeParseComplete fed.Type = '1' - TypePortalSuspended fed.Type = 's' - TypeQuery fed.Type = 'Q' - TypeReadyForQuery fed.Type = 'Z' - TypeRowDescription fed.Type = 'T' - TypeSync fed.Type = 'S' - TypeTerminate fed.Type = 'X' -) diff --git a/lib/fed/readwriter.go b/lib/fed/readwriter.go deleted file mode 100644 index bde9a0d17f45d0b48b682e4c87d2108b419ff9dd..0000000000000000000000000000000000000000 --- a/lib/fed/readwriter.go +++ /dev/null @@ -1,20 +0,0 @@ -package fed - -type Reader interface { - ReadPacket(typed bool, buffer Packet) (Packet, error) -} - -type Writer interface { - WritePacket(Packet) error -} - -type ReadWriter interface { - Reader - Writer -} - -type ReadWriteCloser interface { - ReadWriter - - Close() error -} diff --git a/lib/fed/ssl.go b/lib/fed/ssl.go deleted file mode 100644 index 9b830d23ded6eef3b32461fb91053ec67a3d61ae..0000000000000000000000000000000000000000 --- a/lib/fed/ssl.go +++ /dev/null @@ -1,19 +0,0 @@ -package fed - -import "crypto/tls" - -type SSL interface { - SSL() bool -} - -type SSLClient interface { - SSL - - EnableSSLClient(config *tls.Config) error -} - -type SSLServer interface { - SSL - - EnableSSLServer(config *tls.Config) error -} diff --git a/lib/gat/handler.go b/lib/gat/handler.go index 6026c1e6778260a9f25d5a2ce66e5b14677c051f..b0d2d339c14e119b9e56ddd5bacf46bce0319f8b 100644 --- a/lib/gat/handler.go +++ b/lib/gat/handler.go @@ -15,7 +15,7 @@ type Handler interface { type CancellableHandler interface { Handler - Cancel(key [8]byte) + Cancel(key fed.BackendKey) } type MetricsHandler interface { diff --git a/lib/gat/handlers/discovery/discoverers/google_cloud_sql/discoverer.go b/lib/gat/handlers/discovery/discoverers/google_cloud_sql/discoverer.go index 6bb9351b023cd1c14533778c68fe9c1a575b239d..8bd3fa07d6e98783e6f557a109bc655f09f8ddb6 100644 --- a/lib/gat/handlers/discovery/discoverers/google_cloud_sql/discoverer.go +++ b/lib/gat/handlers/discovery/discoverers/google_cloud_sql/discoverer.go @@ -6,6 +6,7 @@ import ( "strings" "gfx.cafe/gfx/pggat/lib/gat/pool/recipe" + "gfx.cafe/gfx/pggat/lib/util/flip" "github.com/caddyserver/caddy/v2" sqladmin "google.golang.org/api/sqladmin/v1beta4" @@ -134,27 +135,32 @@ func (T *Discoverer) instanceToCluster(primary *sqladmin.DatabaseInstance, repli } var result authQueryResult - client := new(gsql.Client) - err := gsql.ExtendedQuery(client, &result, "SELECT usename, passwd FROM pg_shadow WHERE usename=$1", user.Name) - if err != nil { - return discovery.Cluster{}, err - } - err = client.Close() - if err != nil { - return discovery.Cluster{}, err - } - initialPacket, err := client.ReadPacket(true, nil) - if err != nil { - return discovery.Cluster{}, err - } - _, err, err2 := bouncers.Bounce(fed.NewConn(client), admin, initialPacket) - if err != nil { + inward, outward := gsql.NewPair() + + var b flip.Bank + b.Queue(func() error { + return gsql.ExtendedQuery(inward, &result, "SELECT usename, passwd FROM pg_shadow WHERE usename=$1", user.Name) + }) + + b.Queue(func() error { + initialPacket, err := outward.ReadPacket(true) + if err != nil { + return err + } + err, err2 := bouncers.Bounce(outward, admin, initialPacket) + if err != nil { + return err + } + if err2 != nil { + return err2 + } + return outward.Close() + }) + + if err = b.Wait(); err != nil { return discovery.Cluster{}, err } - if err2 != nil { - return discovery.Cluster{}, err2 - } password = result.Password } diff --git a/lib/gat/handlers/discovery/module.go b/lib/gat/handlers/discovery/module.go index bd6614d2e3f9350789e84dd0cb2637f060d85bbd..3652a482255fbb723c260cf9b57de265e4123248 100644 --- a/lib/gat/handlers/discovery/module.go +++ b/lib/gat/handlers/discovery/module.go @@ -556,7 +556,7 @@ func (T *Module) Handle(conn *fed.Conn) error { return p.Serve(conn) } -func (T *Module) Cancel(key [8]byte) { +func (T *Module) Cancel(key fed.BackendKey) { T.mu.RLock() defer T.mu.RUnlock() T.pools.Range(func(_ string, _ string, p pool.WithCredentials) bool { diff --git a/lib/gat/handlers/pgbouncer/module.go b/lib/gat/handlers/pgbouncer/module.go index a5a8f025fcdc70e1c491edd94bd21d854f08dc38..0dd0baafc43eef66cd60f726a7d85a8e60fcc24d 100644 --- a/lib/gat/handlers/pgbouncer/module.go +++ b/lib/gat/handlers/pgbouncer/module.go @@ -20,6 +20,7 @@ import ( "gfx.cafe/gfx/pggat/lib/gat/poolers/transaction" "gfx.cafe/gfx/pggat/lib/perror" "gfx.cafe/gfx/pggat/lib/util/dur" + "gfx.cafe/gfx/pggat/lib/util/flip" "gfx.cafe/gfx/pggat/lib/util/slices" "gfx.cafe/gfx/pggat/lib/auth/credentials" @@ -107,19 +108,26 @@ func (T *Module) getPassword(user, database string) (string, bool) { } var result authQueryResult - client := new(gsql.Client) - err := gsql.ExtendedQuery(client, &result, T.Config.PgBouncer.AuthQuery, user) - if err != nil { - T.log.Warn("auth query failed", zap.Error(err)) - return "", false - } - err = client.Close() - if err != nil { - T.log.Warn("auth query failed", zap.Error(err)) - return "", false - } - err = authPool.ServeBot(client) - if err != nil && !errors.Is(err, io.EOF) { + + var b flip.Bank + + inward, outward := gsql.NewPair() + b.Queue(func() error { + if err := gsql.ExtendedQuery(inward, &result, T.Config.PgBouncer.AuthQuery, user); err != nil { + return err + } + return inward.Close() + }) + + b.Queue(func() error { + err := authPool.ServeBot(outward) + if err != nil && !errors.Is(err, io.EOF) { + return err + } + return nil + }) + + if err := b.Wait(); err != nil { T.log.Warn("auth query failed", zap.Error(err)) return "", false } @@ -285,13 +293,7 @@ func (T *Module) lookup(user, database string) (pool.WithCredentials, bool) { func (T *Module) Handle(conn *fed.Conn) error { // check ssl if T.Config.PgBouncer.ClientTLSSSLMode.IsRequired() { - var ssl bool - netConn, ok := conn.ReadWriteCloser.(*fed.NetConn) - if ok { - ssl = netConn.SSL() - } - - if !ssl { + if !conn.SSL { return perror.New( perror.FATAL, perror.InvalidPassword, @@ -346,7 +348,7 @@ func (T *Module) ReadMetrics(metrics *metrics.Handler) { }) } -func (T *Module) Cancel(key [8]byte) { +func (T *Module) Cancel(key fed.BackendKey) { T.mu.RLock() defer T.mu.RUnlock() T.pools.Range(func(_ string, _ string, p pool.WithCredentials) bool { diff --git a/lib/gat/handlers/pool/module.go b/lib/gat/handlers/pool/module.go index 61b0085a7abd477aac62cd69d0d83d37df226374..ef57d02e42edbf73219a9b66155faaffd6fa7249 100644 --- a/lib/gat/handlers/pool/module.go +++ b/lib/gat/handlers/pool/module.go @@ -97,7 +97,7 @@ func (T *Module) Handle(conn *fed.Conn) error { return T.pool.Serve(conn) } -func (T *Module) Cancel(key [8]byte) { +func (T *Module) Cancel(key fed.BackendKey) { T.pool.Cancel(key) } diff --git a/lib/gat/handlers/require_ssl/module.go b/lib/gat/handlers/require_ssl/module.go index 47f7cb8e63bb3f6ce31fd810505154aa1817a941..476a8285e12db50108b43d5fb435aa1aa8f97bca 100644 --- a/lib/gat/handlers/require_ssl/module.go +++ b/lib/gat/handlers/require_ssl/module.go @@ -26,15 +26,8 @@ func (T *Module) CaddyModule() caddy.ModuleInfo { } func (T *Module) Handle(conn *fed.Conn) error { - var ssl bool - - sslConn, ok := conn.ReadWriteCloser.(fed.SSL) - if ok { - ssl = sslConn.SSL() - } - if T.SSL { - if !ssl { + if !conn.SSL { return perror.New( perror.FATAL, perror.InvalidPassword, @@ -44,7 +37,7 @@ func (T *Module) Handle(conn *fed.Conn) error { return nil } - if ssl { + if conn.SSL { return perror.New( perror.FATAL, perror.InvalidPassword, diff --git a/lib/gat/listen.go b/lib/gat/listen.go index baa1090cef04d4ea7c474b0e98d3807af28d2c0f..7204a61222fa347492060a8c196ee5d1b02be5f8 100644 --- a/lib/gat/listen.go +++ b/lib/gat/listen.go @@ -35,9 +35,7 @@ func (T *Listener) accept() (*fed.Conn, error) { if err != nil { return nil, err } - return fed.NewConn( - fed.NewNetConn(raw), - ), nil + return fed.NewConn(raw), nil } func (T *Listener) Provision(ctx caddy.Context) error { diff --git a/lib/gat/matchers/localaddress.go b/lib/gat/matchers/localaddress.go index c9ac3093f475bf7f3b6ddd3a9c6f128ff68f3933..920d2852733269c18e18f044df48528c5276e5b3 100644 --- a/lib/gat/matchers/localaddress.go +++ b/lib/gat/matchers/localaddress.go @@ -48,11 +48,7 @@ func (T *LocalAddress) Provision(ctx caddy.Context) error { } func (T *LocalAddress) Matches(conn *fed.Conn) bool { - netConn, ok := conn.ReadWriteCloser.(*fed.NetConn) - if !ok { - return false - } - switch addr := netConn.LocalAddr().(type) { + switch addr := conn.NetConn.LocalAddr().(type) { case *net.TCPAddr: expected, ok := T.addr.(*net.TCPAddr) if !ok { diff --git a/lib/gat/matchers/ssl.go b/lib/gat/matchers/ssl.go index 57ae1a0acb907587d5c30070051af0a5a30d4017..255bde81dd008ff70c925f00fa9d3f76f9c722cb 100644 --- a/lib/gat/matchers/ssl.go +++ b/lib/gat/matchers/ssl.go @@ -25,11 +25,7 @@ func (T *SSL) CaddyModule() caddy.ModuleInfo { } func (T *SSL) Matches(conn *fed.Conn) bool { - sslConn, ok := conn.ReadWriteCloser.(fed.SSL) - if !ok { - return T.SSL == false - } - return sslConn.SSL() == T.SSL + return conn.SSL == T.SSL } var _ gat.Matcher = (*SSL)(nil) diff --git a/lib/gat/pool/conn.go b/lib/gat/pool/conn.go index 065a645895951e6693e756a2054e03f45f89b031..c1ea8981e07e6487e41bc72d0c49f126a1cb26d8 100644 --- a/lib/gat/pool/conn.go +++ b/lib/gat/pool/conn.go @@ -55,7 +55,7 @@ func (T *pooledConn) GetInitialParameters() map[strutil.CIString]string { return T.conn.InitialParameters } -func (T *pooledConn) GetBackendKey() [8]byte { +func (T *pooledConn) GetBackendKey() fed.BackendKey { return T.conn.BackendKey } diff --git a/lib/gat/pool/flow.go b/lib/gat/pool/flow.go index e12636210e444859639229cf308bb4e48c2b6cec..712255fcf206e81e5cfe29ee250290a0faa6d922 100644 --- a/lib/gat/pool/flow.go +++ b/lib/gat/pool/flow.go @@ -2,7 +2,6 @@ package pool import ( "gfx.cafe/gfx/pggat/lib/bouncer/backends/v0" - "gfx.cafe/gfx/pggat/lib/fed" "gfx.cafe/gfx/pggat/lib/fed/middlewares/eqp" "gfx.cafe/gfx/pggat/lib/fed/middlewares/ps" packets "gfx.cafe/gfx/pggat/lib/fed/packets/v3.0" @@ -43,8 +42,6 @@ func syncInitialParameters(options Config, client *pooledClient, server *pooledS clientParams := client.GetInitialParameters() serverParams := server.GetInitialParameters() - var packet fed.Packet - for key, value := range clientParams { // skip already set params if serverParams[key] == value { @@ -52,8 +49,7 @@ func syncInitialParameters(options Config, client *pooledClient, server *pooledS Key: key.String(), Value: serverParams[key], } - packet = p.IntoPacket(packet) - clientErr = client.GetConn().WritePacket(packet) + clientErr = client.GetConn().WritePacket(&p) if clientErr != nil { return } @@ -70,8 +66,7 @@ func syncInitialParameters(options Config, client *pooledClient, server *pooledS Key: key.String(), Value: value, } - packet = p.IntoPacket(packet) - clientErr = client.GetConn().WritePacket(packet) + clientErr = client.GetConn().WritePacket(&p) if clientErr != nil { return } @@ -80,7 +75,7 @@ func syncInitialParameters(options Config, client *pooledClient, server *pooledS continue } - serverErr, _, packet = backends.SetParameter(server.GetConn(), nil, packet, key, value) + serverErr, _ = backends.SetParameter(server.GetConn(), nil, key, value) if serverErr != nil { return } @@ -98,8 +93,7 @@ func syncInitialParameters(options Config, client *pooledClient, server *pooledS Key: key.String(), Value: value, } - packet = p.IntoPacket(packet) - clientErr = client.GetConn().WritePacket(packet) + clientErr = client.GetConn().WritePacket(&p) if clientErr != nil { return } diff --git a/lib/gat/pool/pool.go b/lib/gat/pool/pool.go index 8399e39b80bb5ba6e913de1415d8a4dbafc9b7c1..258ced2197dc5d878d51b13bbd5770168ed4c767 100644 --- a/lib/gat/pool/pool.go +++ b/lib/gat/pool/pool.go @@ -29,7 +29,7 @@ type Pool struct { recipes map[string]*Recipe recipeScaleOrder slices.Sorted[string] clients map[uuid.UUID]*pooledClient - clientsByKey map[[8]byte]*pooledClient + clientsByKey map[fed.BackendKey]*pooledClient servers map[uuid.UUID]*pooledServer serversByRecipe map[string][]*pooledServer mu sync.RWMutex @@ -265,7 +265,7 @@ func (T *Pool) releaseServer(server *pooledServer) { if T.config.ServerResetQuery != "" { server.SetState(metrics.ConnStateRunningResetQuery, uuid.Nil) - err, _, _ := backends.QueryString(server.GetConn(), nil, nil, T.config.ServerResetQuery) + err, _ := backends.QueryString(server.GetConn(), nil, T.config.ServerResetQuery) if err != nil { T.removeServer(server) return @@ -295,7 +295,7 @@ func (T *Pool) Serve( // ServeBot is for clients that don't need initial parameters, cancelling queries, and are ready now. Use Serve for // real clients func (T *Pool) ServeBot( - conn fed.ReadWriteCloser, + conn *fed.Conn, ) error { defer func() { _ = conn.Close() @@ -303,9 +303,7 @@ func (T *Pool) ServeBot( client := newClient( T.config, - &fed.Conn{ - ReadWriteCloser: conn, - }, + conn, ) return T.serve(client, true) @@ -330,8 +328,6 @@ func (T *Pool) serve(client *pooledClient, initialized bool) error { } }() - var packet fed.Packet - if !initialized { server = T.acquireServer(client) if server == nil { @@ -347,8 +343,7 @@ func (T *Pool) serve(client *pooledClient, initialized bool) error { } p := packets.ReadyForQuery('I') - packet = p.IntoPacket(packet) - err = client.GetConn().WritePacket(packet) + err = client.GetConn().WritePacket(&p) if err != nil { return err } @@ -361,7 +356,8 @@ func (T *Pool) serve(client *pooledClient, initialized bool) error { server = nil } - packet, err = client.GetConn().ReadPacket(true, packet) + var packet fed.Packet + packet, err = client.GetConn().ReadPacket(true) if err != nil { return err } @@ -375,8 +371,9 @@ func (T *Pool) serve(client *pooledClient, initialized bool) error { err, serverErr = pair(T.config, client, server) } if err == nil && serverErr == nil { - packet, err, serverErr = bouncers.Bounce(client.GetConn(), server.GetConn(), packet) + err, serverErr = bouncers.Bounce(client.GetConn(), server.GetConn(), packet) } + if serverErr != nil { return serverErr } else { @@ -398,7 +395,7 @@ func (T *Pool) addClient(client *pooledClient) { } T.clients[client.GetID()] = client if T.clientsByKey == nil { - T.clientsByKey = make(map[[8]byte]*pooledClient) + T.clientsByKey = make(map[fed.BackendKey]*pooledClient) } T.clientsByKey[client.GetBackendKey()] = client T.pooler.AddClient(client.GetID()) @@ -418,7 +415,7 @@ func (T *Pool) removeClientL1(client *pooledClient) { delete(T.clientsByKey, client.GetBackendKey()) } -func (T *Pool) Cancel(key [8]byte) { +func (T *Pool) Cancel(key fed.BackendKey) { T.mu.RLock() defer T.mu.RUnlock() diff --git a/lib/gat/pool/recipe/dialer.go b/lib/gat/pool/recipe/dialer.go index 8202c2b9a6b1633fb835e7c092d9e8a84757ee69..b11ac3a98efea8fea1c4ea03079f4104705ad94d 100644 --- a/lib/gat/pool/recipe/dialer.go +++ b/lib/gat/pool/recipe/dialer.go @@ -28,9 +28,7 @@ func (T Dialer) Dial() (*fed.Conn, error) { if err != nil { return nil, err } - conn := fed.NewConn( - fed.NewNetConn(c), - ) + conn := fed.NewConn(c) conn.User = T.Username conn.Database = T.Database err = backends.Accept( @@ -48,14 +46,12 @@ func (T Dialer) Dial() (*fed.Conn, error) { return conn, nil } -func (T Dialer) Cancel(key [8]byte) { +func (T Dialer) Cancel(key fed.BackendKey) { c, err := net.Dial(T.Network, T.Address) if err != nil { return } - conn := fed.NewConn( - fed.NewNetConn(c), - ) + conn := fed.NewConn(c) defer func() { _ = conn.Close() }() @@ -64,5 +60,5 @@ func (T Dialer) Cancel(key [8]byte) { } // wait for server to close the connection, this means that the server received it ok - _, _ = conn.ReadPacket(true, nil) + _, _ = conn.ReadPacket(true) } diff --git a/lib/gat/pool/recipe/recipe.go b/lib/gat/pool/recipe/recipe.go index aeb25e76eb3a4a81b6c4061df7a615274ffe8b7e..78a79391ad159a1e286ac6b0cd69b7aa7f86ea45 100644 --- a/lib/gat/pool/recipe/recipe.go +++ b/lib/gat/pool/recipe/recipe.go @@ -70,6 +70,6 @@ func (T *Recipe) Dial() (*fed.Conn, error) { return T.config.Dialer.Dial() } -func (T *Recipe) Cancel(key [8]byte) { +func (T *Recipe) Cancel(key fed.BackendKey) { T.config.Dialer.Cancel(key) } diff --git a/lib/gat/poolers/session/pooler.go b/lib/gat/poolers/session/pooler.go index 8f0dd004ce3ab9caf066e670325726eaf8508f23..18385ba9fbf9ef4c6d5c724abc4e3f7e883c3716 100644 --- a/lib/gat/poolers/session/pooler.go +++ b/lib/gat/poolers/session/pooler.go @@ -12,7 +12,7 @@ import ( type Pooler struct { queue []uuid.UUID servers map[uuid.UUID]struct{} - ready *sync.Cond + ready sync.Cond closed bool mu sync.Mutex } @@ -38,9 +38,10 @@ func (T *Pooler) AddServer(server uuid.UUID) { } T.servers[server] = struct{}{} - if T.ready != nil { - T.ready.Signal() + if T.ready.L == nil { + T.ready.L = &T.mu } + T.ready.Signal() } func (T *Pooler) DeleteServer(server uuid.UUID) { @@ -79,8 +80,8 @@ func (T *Pooler) AcquireBlocking() uuid.UUID { } for len(T.queue) == 0 { - if T.ready == nil { - T.ready = sync.NewCond(&T.mu) + if T.ready.L == nil { + T.ready.L = &T.mu } T.ready.Wait() } @@ -122,9 +123,10 @@ func (T *Pooler) Close() { defer T.mu.Unlock() T.closed = true - if T.ready != nil { - T.ready.Broadcast() + if T.ready.L == nil { + T.ready.L = &T.mu } + T.ready.Broadcast() } var _ pool.Pooler = (*Pooler)(nil) diff --git a/lib/gat/server.go b/lib/gat/server.go index d31a0f6d593725e6214bbc6a9c98772a21d16a9d..81a1cd58e605f87d638697f36e5e08aedf3d2f2c 100644 --- a/lib/gat/server.go +++ b/lib/gat/server.go @@ -12,7 +12,6 @@ import ( "gfx.cafe/gfx/pggat/lib/bouncer/frontends/v0" "gfx.cafe/gfx/pggat/lib/fed" - packets "gfx.cafe/gfx/pggat/lib/fed/packets/v3.0" "gfx.cafe/gfx/pggat/lib/gat/metrics" "gfx.cafe/gfx/pggat/lib/perror" ) @@ -95,7 +94,7 @@ func (T *Server) Stop() error { return nil } -func (T *Server) Cancel(key [8]byte) { +func (T *Server) Cancel(key fed.BackendKey) { for _, cancellableHandler := range T.cancellableHandlers { cancellableHandler.Cancel(key) } @@ -123,23 +122,21 @@ func (T *Server) Serve(conn *fed.Conn) { return } - errResp := packets.ErrorResponse{ - Error: perror.Wrap(err), - } - _ = conn.WritePacket(errResp.IntoPacket(nil)) + errResp := perror.ToPacket(perror.Wrap(err)) + _ = conn.WritePacket(errResp) return } } // database not found - errResp := packets.ErrorResponse{ - Error: perror.New( + errResp := perror.ToPacket( + perror.New( perror.FATAL, perror.InvalidPassword, fmt.Sprintf(`Database "%s" not found`, conn.Database), ), - } - _ = conn.WritePacket(errResp.IntoPacket(nil)) + ) + _ = conn.WritePacket(errResp) T.log.Warn("database not found", zap.String("user", conn.User), zap.String("database", conn.Database)) } @@ -153,7 +150,7 @@ func (T *Server) accept(listener *Listener, conn *fed.Conn) { tlsConfig = listener.ssl.ServerTLSConfig() } - var cancelKey [8]byte + var cancelKey fed.BackendKey var isCanceling bool var err error cancelKey, isCanceling, err = frontends.Accept(conn, tlsConfig) diff --git a/lib/gsql/addr.go b/lib/gsql/addr.go deleted file mode 100644 index 61bcf5d2439817290ec46ef99a1ed926d9003004..0000000000000000000000000000000000000000 --- a/lib/gsql/addr.go +++ /dev/null @@ -1,15 +0,0 @@ -package gsql - -import "net" - -type Addr struct{} - -func (Addr) Network() string { - return "gsql" -} - -func (Addr) String() string { - return "local gsql client" -} - -var _ net.Addr = Addr{} diff --git a/lib/gsql/client.go b/lib/gsql/client.go deleted file mode 100644 index de0a0630725fab6bf7b678fe490196a813a992f3..0000000000000000000000000000000000000000 --- a/lib/gsql/client.go +++ /dev/null @@ -1,146 +0,0 @@ -package gsql - -import ( - "io" - "net" - "sync" - - "gfx.cafe/gfx/pggat/lib/fed" - "gfx.cafe/gfx/pggat/lib/util/ring" - "gfx.cafe/gfx/pggat/lib/util/slices" -) - -type batch struct { - result ResultWriter - packets []fed.Packet -} - -type Client struct { - write ResultWriter - read ring.Ring[fed.Packet] - - queue ring.Ring[batch] - - closed bool - mu sync.Mutex - - readC *sync.Cond - writeC *sync.Cond -} - -func (T *Client) Do(result ResultWriter, packets ...fed.Packet) { - T.mu.Lock() - defer T.mu.Unlock() - - T.queue.PushBack(batch{ - result: result, - packets: packets, - }) - - if T.readC != nil { - T.readC.Broadcast() - } -} - -func (T *Client) queueNext() bool { - b, ok := T.queue.PopFront() - if ok { - for _, packet := range b.packets { - T.read.PushBack(packet) - } - T.write = b.result - if T.writeC != nil { - T.writeC.Broadcast() - } - return true - } - - return false -} - -func (T *Client) ReadPacket(typed bool, buffer fed.Packet) (packet fed.Packet, err error) { - packet = buffer - - T.mu.Lock() - defer T.mu.Unlock() - - var p fed.Packet - for { - var ok bool - p, ok = T.read.PopFront() - if ok { - break - } - - // try to add next in queue - if T.queueNext() { - continue - } - - if T.closed { - err = io.EOF - return - } - - if T.readC == nil { - T.readC = sync.NewCond(&T.mu) - } - T.readC.Wait() - } - - if (p.Type() == 0 && typed) || (p.Type() != 0 && !typed) { - err = ErrTypedMismatch - return - } - - packet = slices.Resize(packet, len(p)) - copy(packet, p) - return -} - -func (T *Client) WritePacket(packet fed.Packet) error { - T.mu.Lock() - defer T.mu.Unlock() - - for T.write == nil { - if T.read.Length() == 0 && T.queueNext() { - continue - } - - if T.closed { - return io.EOF - } - - if T.writeC == nil { - T.writeC = sync.NewCond(&T.mu) - } - T.writeC.Wait() - } - - if err := T.write.WritePacket(packet); err != nil { - return err - } - - return nil -} - -func (T *Client) Close() error { - T.mu.Lock() - defer T.mu.Unlock() - - if T.closed { - return net.ErrClosed - } - - T.closed = true - - if T.writeC != nil { - T.writeC.Broadcast() - } - if T.readC != nil { - T.readC.Broadcast() - } - return nil -} - -var _ fed.ReadWriteCloser = (*Client)(nil) diff --git a/lib/gsql/eq.go b/lib/gsql/eq.go index 7908d0a819d20fe147ff594113385a2d5a1acd22..3cfc8d49ecec61e2a664687bdb6124f475610a69 100644 --- a/lib/gsql/eq.go +++ b/lib/gsql/eq.go @@ -8,19 +8,18 @@ import ( packets "gfx.cafe/gfx/pggat/lib/fed/packets/v3.0" ) -func ExtendedQuery(client *Client, result any, query string, args ...any) error { +func ExtendedQuery(client *fed.Conn, result any, query string, args ...any) error { if len(args) == 0 { - Query(client, []any{result}, query) - return nil + return Query(client, []any{result}, query) } - var pkts []fed.Packet - // parse parse := packets.Parse{ Query: query, } - pkts = append(pkts, parse.IntoPacket(nil)) + if err := client.WritePacket(&parse); err != nil { + return err + } // bind params := make([][]byte, 0, len(args)) @@ -58,25 +57,46 @@ outer: params = append(params, value) } bind := packets.Bind{ - ParameterValues: params, + Parameters: params, + } + if err := client.WritePacket(&bind); err != nil { + return err } - pkts = append(pkts, bind.IntoPacket(nil)) // describe describe := packets.Describe{ Which: 'P', } - pkts = append(pkts, describe.IntoPacket(nil)) + if err := client.WritePacket(&describe); err != nil { + return err + } // execute execute := packets.Execute{} - pkts = append(pkts, execute.IntoPacket(nil)) + if err := client.WritePacket(&execute); err != nil { + return err + } // sync - sync := fed.NewPacket(packets.TypeSync) - pkts = append(pkts, sync) + sync := packets.Sync{} + if err := client.WritePacket(&sync); err != nil { + return err + } // result - client.Do(NewQueryWriter(result), pkts...) + if err := readQueryResults(client, result); err != nil { + return err + } + + // make sure we receive ready for query + packet, err := client.ReadPacket(true) + if err != nil { + return err + } + + if packet.Type() != packets.TypeReadyForQuery { + return ErrExpectedReadyForQuery + } + return nil } diff --git a/lib/gsql/errors.go b/lib/gsql/errors.go index a550f7496561030d181eedbcbc8ba281007e2d61..86c95c7766102bd9c30a5b3d629e45f449ed31a9 100644 --- a/lib/gsql/errors.go +++ b/lib/gsql/errors.go @@ -3,9 +3,9 @@ package gsql import "errors" var ( - ErrResultTooBig = errors.New("got too many rows for result") - ErrExtraFields = errors.New("received unexpected fields") - ErrResultMustBeNonNil = errors.New("result must be non nil") - ErrUnexpectedType = errors.New("unexpected result type") - ErrTypedMismatch = errors.New("tried to read typed packet as untyped or untyped packet as typed") + ErrResultTooBig = errors.New("got too many rows for result") + ErrExtraFields = errors.New("received unexpected fields") + ErrResultMustBeNonNil = errors.New("result must be non nil") + ErrUnexpectedType = errors.New("unexpected result type") + ErrExpectedReadyForQuery = errors.New("expected query to end with ReadyForQuery") ) diff --git a/lib/gsql/pair.go b/lib/gsql/pair.go new file mode 100644 index 0000000000000000000000000000000000000000..8355d5d13bb0e2726b516efe399dab2ff47e528b --- /dev/null +++ b/lib/gsql/pair.go @@ -0,0 +1,14 @@ +package gsql + +import ( + "gfx.cafe/gfx/pggat/lib/fed" + "gfx.cafe/gfx/pggat/lib/util/mio" +) + +func NewPair() (*fed.Conn, *fed.Conn) { + conn := new(mio.Conn) + inward := fed.NewConn(mio.InwardConn{Conn: conn}) + outward := fed.NewConn(mio.OutwardConn{Conn: conn}) + + return inward, outward +} diff --git a/lib/gsql/query.go b/lib/gsql/query.go index c4c8f7f4bade875322000a62aadea58dbe3d0b60..73e236a386bbd023e719cb68197bcc2e0703b699 100644 --- a/lib/gsql/query.go +++ b/lib/gsql/query.go @@ -5,44 +5,34 @@ import ( packets "gfx.cafe/gfx/pggat/lib/fed/packets/v3.0" ) -func Query(client *Client, results []any, query string) { +func Query(client *fed.Conn, results []any, query string) error { var q = packets.Query(query) - - client.Do(NewQueryWriter(results...), q.IntoPacket(nil)) -} - -type QueryWriter struct { - writers []RowWriter - writerNum int -} - -func NewQueryWriter(results ...any) *QueryWriter { - var writers = make([]RowWriter, 0, len(results)) - for _, result := range results { - writers = append(writers, MakeRowWriter(result)) - } - - return &QueryWriter{ - writers: writers, + if err := client.WritePacket(&q); err != nil { + return err } -} -func (T *QueryWriter) WritePacket(packet fed.Packet) error { - if T.writerNum >= len(T.writers) { - // ignore - return nil + if err := readQueryResults(client, results...); err != nil { + return err } - result := &T.writers[T.writerNum] - if err := result.WritePacket(packet); err != nil { + // make sure we receive ready for query + packet, err := client.ReadPacket(true) + if err != nil { return err } - if result.Done() { - T.writerNum++ + if packet.Type() != packets.TypeReadyForQuery { + return ErrExpectedReadyForQuery } return nil } -var _ ResultWriter = (*QueryWriter)(nil) +func readQueryResults(client *fed.Conn, results ...any) error { + for _, result := range results { + if err := readRows(client, result); err != nil { + return err + } + } + return nil +} diff --git a/lib/gsql/query_test.go b/lib/gsql/query_test.go index 320bf4d5d048e267b97b92692472d56f84e83985..ed9606eb297b20425f26456047c37869c6974115 100644 --- a/lib/gsql/query_test.go +++ b/lib/gsql/query_test.go @@ -3,12 +3,15 @@ package gsql import ( "log" "net" + "net/http" + _ "net/http/pprof" "testing" "gfx.cafe/gfx/pggat/lib/auth/credentials" "gfx.cafe/gfx/pggat/lib/bouncer/backends/v0" "gfx.cafe/gfx/pggat/lib/bouncer/bouncers/v2" "gfx.cafe/gfx/pggat/lib/fed" + "gfx.cafe/gfx/pggat/lib/util/flip" ) type Result struct { @@ -17,13 +20,17 @@ type Result struct { } func TestQuery(t *testing.T) { + go func() { + panic(http.ListenAndServe(":8080", nil)) + }() + // open server s, err := net.Dial("tcp", "localhost:5432") if err != nil { t.Error(err) return } - server := fed.NewConn(fed.NewNetConn(s)) + server := fed.NewConn(s) err = backends.Accept( server, "", @@ -41,30 +48,33 @@ func TestQuery(t *testing.T) { return } + inward, outward := NewPair() + var res Result - client := new(Client) - err = ExtendedQuery(client, &res, "SELECT usename, passwd FROM pg_shadow WHERE usename=$1", "postgres") - if err != nil { - t.Error(err) - return - } - err = client.Close() - if err != nil { - t.Error(err) - } - var initial fed.Packet - initial, err = client.ReadPacket(true, initial) - if err != nil { + var b flip.Bank + b.Queue(func() error { + return ExtendedQuery(inward, &res, "SELECT usename, passwd FROM pg_shadow WHERE usename=$1", "postgres") + }) + + b.Queue(func() error { + initial, err := outward.ReadPacket(true) + if err != nil { + return err + } + clientErr, serverErr := bouncers.Bounce(outward, server, initial) + if clientErr != nil { + return clientErr + } + if serverErr != nil { + return serverErr + } + return outward.Close() + }) + + if err = b.Wait(); err != nil { t.Error(err) } - _, clientErr, serverErr := bouncers.Bounce(fed.NewConn(client), server, initial) - if clientErr != nil { - t.Error(clientErr) - } - if serverErr != nil { - t.Error(serverErr) - } log.Printf("%#v", res) } diff --git a/lib/gsql/result.go b/lib/gsql/result.go deleted file mode 100644 index 11c084500333e529c726cf7bdd05a63b97eef2e7..0000000000000000000000000000000000000000 --- a/lib/gsql/result.go +++ /dev/null @@ -1,7 +0,0 @@ -package gsql - -import "gfx.cafe/gfx/pggat/lib/fed" - -type ResultWriter interface { - fed.Writer -} diff --git a/lib/gsql/row.go b/lib/gsql/row.go index 574e8e7738cc52e972109effc9411636fd60ddf6..c6da94d94aeab937a61e55a36de4e0e1dae634cc 100644 --- a/lib/gsql/row.go +++ b/lib/gsql/row.go @@ -1,39 +1,61 @@ package gsql import ( - "errors" "reflect" "strconv" "gfx.cafe/gfx/pggat/lib/fed" packets "gfx.cafe/gfx/pggat/lib/fed/packets/v3.0" + "gfx.cafe/gfx/pggat/lib/perror" ) -type RowWriter struct { - result reflect.Value - rd packets.RowDescription - row int - done bool -} +func readRows(client *fed.Conn, result any) error { + res := reflect.ValueOf(result) + row := 0 + var rd packets.RowDescription -func MakeRowWriter(result any) RowWriter { - return RowWriter{ - result: reflect.ValueOf(result), - } -} + for { + packet, err := client.ReadPacket(true) + if err != nil { + return err + } -func NewRowWriter(result any) *RowWriter { - w := MakeRowWriter(result) - return &w + switch packet.Type() { + case packets.TypeRowDescription: + err = fed.ToConcrete(&rd, packet) + if err != nil { + return err + } + case packets.TypeDataRow: + var dr packets.DataRow + err = fed.ToConcrete(&dr, packet) + if err != nil { + return err + } + for i, col := range dr { + if err = setColumn(res, rd, row, i, col); err != nil { + return err + } + } + row += 1 + case packets.TypeErrorResponse: + var p packets.ErrorResponse + err = fed.ToConcrete(&p, packet) + if err != nil { + return err + } + return perror.FromPacket(&p) + case packets.TypeCommandComplete: + return nil + } + } } -func (T *RowWriter) set(i int, col []byte) error { - if i >= len(T.rd.Fields) { +func setColumn(result reflect.Value, rd packets.RowDescription, row, i int, col []byte) error { + if i >= len(rd) { return ErrExtraFields } - desc := T.rd.Fields[i] - - result := T.result + desc := rd[i] // unptr for result.Kind() == reflect.Pointer { @@ -52,22 +74,22 @@ outer: kind := result.Kind() switch kind { case reflect.Array: - if T.row >= result.Len() { + if row >= result.Len() { return ErrResultTooBig } - result = result.Index(T.row) + result = result.Index(row) break outer case reflect.Slice: - for T.row >= result.Len() { + for row >= result.Len() { if !result.CanSet() { return ErrResultTooBig } result.Set(reflect.Append(result, reflect.Zero(result.Type().Elem()))) } - result = result.Index(T.row) + result = result.Index(row) break outer case reflect.Struct, reflect.Map: - if T.row != 0 { + if row != 0 { return ErrResultTooBig } break outer @@ -224,39 +246,3 @@ outer2: return ErrUnexpectedType } } - -func (T *RowWriter) WritePacket(packet fed.Packet) error { - switch packet.Type() { - case packets.TypeRowDescription: - if !T.rd.ReadFromPacket(packet) { - return errors.New("invalid format") - } - case packets.TypeDataRow: - var dr packets.DataRow - if !dr.ReadFromPacket(packet) { - return errors.New("invalid format") - } - for i, col := range dr.Columns { - if err := T.set(i, col); err != nil { - return err - } - } - T.row += 1 - case packets.TypeErrorResponse: - var err packets.ErrorResponse - if !err.ReadFromPacket(packet) { - return errors.New("invalid format") - } - return err.Error - case packets.TypeCommandComplete: - T.done = true - return nil - } - return nil -} - -func (T *RowWriter) Done() bool { - return T.done -} - -var _ ResultWriter = (*RowWriter)(nil) diff --git a/lib/perror/packet.go b/lib/perror/packet.go new file mode 100644 index 0000000000000000000000000000000000000000..606c1071ee62e6fd38263b74ec8e96e9dcc1cd6e --- /dev/null +++ b/lib/perror/packet.go @@ -0,0 +1,60 @@ +package perror + +import packets "gfx.cafe/gfx/pggat/lib/fed/packets/v3.0" + +func FromPacket(packet *packets.ErrorResponse) Error { + var severity Severity + var code Code + var message string + var extra []ExtraField + + for _, field := range *packet { + switch field.Code { + case 'S': + severity = Severity(field.Value) + case 'C': + code = Code(field.Value) + case 'M': + message = field.Value + default: + extra = append(extra, ExtraField{ + Type: Extra(field.Code), + Value: field.Value, + }) + } + } + + return New( + severity, + code, + message, + extra..., + ) +} + +func ToPacket(err Error) *packets.ErrorResponse { + var resp packets.ErrorResponse + resp = append( + resp, + packets.ErrorResponseField{ + Code: 'S', + Value: string(err.Severity()), + }, + packets.ErrorResponseField{ + Code: 'C', + Value: string(err.Code()), + }, + packets.ErrorResponseField{ + Code: 'M', + Value: err.Message(), + }, + ) + extra := err.Extra() + for _, field := range extra { + resp = append(resp, packets.ErrorResponseField{ + Code: uint8(field.Type), + Value: field.Value, + }) + } + return &resp +} diff --git a/lib/util/flip/bank.go b/lib/util/flip/bank.go index 12273bb9a6885049c0640cd136bbf2fab94cb09e..3880be76c7e2d41299f354cda47ef1cb5ea85d39 100644 --- a/lib/util/flip/bank.go +++ b/lib/util/flip/bank.go @@ -1,57 +1,29 @@ package flip -import ( - "sync" -) - -type Bank struct { - pending []func() error - mu sync.Mutex -} +type Bank []func() error func (T *Bank) Queue(fn func() error) { - T.mu.Lock() - defer T.mu.Unlock() - T.pending = append(T.pending, fn) -} - -func (T *Bank) take() []func() error { - T.mu.Lock() - defer T.mu.Unlock() - v := T.pending - T.pending = nil - return v -} - -func (T *Bank) give(sz []func() error) { - T.mu.Lock() - defer T.mu.Unlock() - if T.pending == nil { - T.pending = sz[:0] - } + *T = append(*T, fn) } func (T *Bank) Wait() error { - batch := T.take() - defer T.give(batch) - - if len(batch) == 0 { + if len(*T) == 0 { return nil } - if len(batch) == 1 { - return batch[0]() + if len(*T) == 1 { + return (*T)[0]() } - ch := make(chan error, len(batch)) + ch := make(chan error, len(*T)) - for _, pending := range batch { + for _, pending := range *T { go func(pending func() error) { ch <- pending() }(pending) } - for i := 0; i < len(batch); i++ { + for i := 0; i < len(*T); i++ { err := <-ch if err != nil { return err diff --git a/lib/util/mio/conn.go b/lib/util/mio/conn.go new file mode 100644 index 0000000000000000000000000000000000000000..6117bc7cd8a5137e00b0808c6926a5634f6c0028 --- /dev/null +++ b/lib/util/mio/conn.go @@ -0,0 +1,121 @@ +package mio + +import ( + "fmt" + "net" + "time" +) + +type Conn struct { + out ReadWriteCloser + in ReadWriteCloser +} + +func (T *Conn) Close() error { + if err := T.out.Close(); err != nil { + return err + } + return T.in.Close() +} + +type OutwardConn struct { + *Conn +} + +func (T OutwardConn) Read(b []byte) (n int, err error) { + return T.out.Read(b) +} + +func (T OutwardConn) Write(b []byte) (n int, err error) { + return T.in.Write(b) +} + +func (T OutwardConn) LocalAddr() net.Addr { + return ConnAddr{ + Outward: true, + Conn: T.Conn, + } +} + +func (T OutwardConn) RemoteAddr() net.Addr { + return ConnAddr{ + Outward: false, + Conn: T.Conn, + } +} + +func (T OutwardConn) SetDeadline(t time.Time) error { + if err := T.SetReadDeadline(t); err != nil { + return err + } + + return T.SetWriteDeadline(t) +} + +func (T OutwardConn) SetReadDeadline(t time.Time) error { + return T.out.SetReadDeadline(t) +} + +func (T OutwardConn) SetWriteDeadline(t time.Time) error { + return T.in.SetWriteDeadline(t) +} + +type InwardConn struct { + *Conn +} + +func (T InwardConn) Read(b []byte) (n int, err error) { + return T.in.Read(b) +} + +func (T InwardConn) Write(b []byte) (n int, err error) { + return T.out.Write(b) +} + +func (T InwardConn) LocalAddr() net.Addr { + return ConnAddr{ + Outward: false, + Conn: T.Conn, + } +} + +func (T InwardConn) RemoteAddr() net.Addr { + return ConnAddr{ + Outward: true, + Conn: T.Conn, + } +} + +func (T InwardConn) SetDeadline(t time.Time) error { + if err := T.SetReadDeadline(t); err != nil { + return err + } + + return T.SetWriteDeadline(t) +} + +func (T InwardConn) SetReadDeadline(t time.Time) error { + return T.in.SetReadDeadline(t) +} + +func (T InwardConn) SetWriteDeadline(t time.Time) error { + return T.out.SetWriteDeadline(t) +} + +var _ net.Conn = OutwardConn{} +var _ net.Conn = InwardConn{} + +type ConnAddr struct { + Outward bool + Conn *Conn +} + +func (T ConnAddr) Network() string { + return "mio" +} + +func (T ConnAddr) String() string { + return fmt.Sprintf("memory conn(%p)", T.Conn) +} + +var _ net.Addr = ConnAddr{} diff --git a/lib/util/mio/listener.go b/lib/util/mio/listener.go new file mode 100644 index 0000000000000000000000000000000000000000..6c2d373530e8f5556b493caf5ea6239c8a7d22c7 --- /dev/null +++ b/lib/util/mio/listener.go @@ -0,0 +1,144 @@ +package mio + +import ( + "errors" + "fmt" + "net" + "sync" + + "gfx.cafe/gfx/pggat/lib/util/ring" +) + +var ( + listeners map[string]*Listener + listenersMu sync.RWMutex +) + +type Listener struct { + address string + incoming ring.Ring[*Conn] + all []*Conn + a sync.Cond + closed bool + mu sync.Mutex +} + +func Listen(address string) (*Listener, error) { + listenersMu.Lock() + defer listenersMu.Unlock() + + if _, ok := listeners[address]; ok { + return nil, errors.New("address already in use") + } + + l := &Listener{ + address: address, + } + if listeners == nil { + listeners = make(map[string]*Listener) + } + listeners[address] = l + + return l, nil +} + +func (T *Listener) Accept() (net.Conn, error) { + T.mu.Lock() + defer T.mu.Unlock() + + for T.incoming.Length() == 0 { + if T.closed { + return nil, net.ErrClosed + } + + if T.a.L == nil { + T.a.L = &T.mu + } + T.a.Wait() + } + + c, _ := T.incoming.PopFront() + return OutwardConn{Conn: c}, nil +} + +func (T *Listener) close() error { + T.mu.Lock() + defer T.mu.Unlock() + + if T.closed { + return net.ErrClosed + } + T.closed = true + for _, c := range T.all { + _ = c.Close() + } + + return nil +} + +func (T *Listener) Close() error { + if err := T.close(); err != nil { + return err + } + + listenersMu.Lock() + defer listenersMu.Unlock() + + delete(listeners, T.address) + + return nil +} + +func (T *Listener) Addr() net.Addr { + return ListenerAddr{ + Listener: T, + } +} + +var _ net.Listener = (*Listener)(nil) + +func lookup(address string) *Listener { + listenersMu.RLock() + defer listenersMu.RUnlock() + + l, _ := listeners[address] + return l +} + +func Dial(address string) (net.Conn, error) { + l := lookup(address) + + if l == nil { + return nil, errors.New("address not found") + } + + l.mu.Lock() + defer l.mu.Unlock() + + c := new(Conn) + + l.all = append(l.all, c) + l.incoming.PushBack(c) + if l.a.L == nil { + l.a.L = &l.mu + } + l.a.Signal() + + return OutwardConn{ + Conn: c, + }, nil +} + +type ListenerAddr struct { + Listener *Listener +} + +func (T ListenerAddr) Network() string { + return "mio" +} + +func (T ListenerAddr) String() string { + return fmt.Sprintf("memory listener(%p)", T.Listener) +} + +var _ net.Addr = ListenerAddr{} diff --git a/lib/util/mio/readwritecloser.go b/lib/util/mio/readwritecloser.go new file mode 100644 index 0000000000000000000000000000000000000000..9acb2a4abfb58223a1465ccb007d22c173146d6c --- /dev/null +++ b/lib/util/mio/readwritecloser.go @@ -0,0 +1,132 @@ +package mio + +import ( + "context" + "io" + "net" + "sync" + "time" +) + +type ReadWriteCloser struct { + buf []byte + r sync.Cond + closed bool + readDeadline time.Time + readDeadlineTimer *time.Timer + mu sync.Mutex +} + +func NewReadWriteCloserSize(size int) *ReadWriteCloser { + return &ReadWriteCloser{ + buf: make([]byte, 0, size), + } +} + +func (T *ReadWriteCloser) Read(b []byte) (n int, err error) { + T.mu.Lock() + defer T.mu.Unlock() + + for len(T.buf) == 0 { + if T.closed { + return 0, io.EOF + } + + if T.readDeadline != (time.Time{}) && time.Now().After(T.readDeadline) { + return 0, context.DeadlineExceeded + } + + if T.r.L == nil { + T.r.L = &T.mu + } + T.r.Wait() + } + + n = copy(b, T.buf) + copy(T.buf, T.buf[n:]) + T.buf = T.buf[:len(T.buf)-n] + + return +} + +func (T *ReadWriteCloser) Write(b []byte) (n int, err error) { + T.mu.Lock() + defer T.mu.Unlock() + + if T.closed { + return 0, net.ErrClosed + } + + T.buf = append(T.buf, b...) + n = len(b) + + if T.r.L == nil { + T.r.L = &T.mu + } + T.r.Broadcast() + + return +} + +func (T *ReadWriteCloser) Close() error { + T.mu.Lock() + defer T.mu.Unlock() + + if T.closed { + return net.ErrClosed + } + T.closed = true + + if T.readDeadlineTimer != nil { + T.readDeadlineTimer.Stop() + } + + if T.r.L == nil { + T.r.L = &T.mu + } + T.r.Broadcast() + + return nil +} + +func (T *ReadWriteCloser) readDeadlineExceeded() { + T.mu.Lock() + defer T.mu.Unlock() + + if T.r.L == nil { + T.r.L = &T.mu + } + T.r.Broadcast() +} + +func (T *ReadWriteCloser) SetReadDeadline(t time.Time) error { + T.mu.Lock() + defer T.mu.Unlock() + + if T.closed { + return net.ErrClosed + } + + if t == (time.Time{}) { + if T.readDeadlineTimer != nil { + T.readDeadlineTimer.Stop() + } + } else { + if T.readDeadlineTimer == nil { + T.readDeadlineTimer = time.AfterFunc(t.Sub(time.Now()), T.readDeadlineExceeded) + } else { + T.readDeadlineTimer.Reset(t.Sub(time.Now())) + } + } + + return nil +} + +func (T *ReadWriteCloser) SetWriteDeadline(_ time.Time) error { + // all writes happen without blocking + return nil +} + +func (T *ReadWriteCloser) SetDeadline(t time.Time) error { + return T.SetReadDeadline(t) +} diff --git a/pgbouncer.ini b/pgbouncer.ini index 428dbd8b0a5b045ffedfa82d061e6dfccc05ecf3..73dbd84942fafe96e5d09957cb032810930329e1 100644 --- a/pgbouncer.ini +++ b/pgbouncer.ini @@ -7,4 +7,4 @@ auth_user = postgres server_idle_timeout = 10 [databases] -* = host=/tmp/ datestyle=Postgres,MDY timezone=PST8PDT +* = host=localhost datestyle=Postgres,MDY timezone=PST8PDT diff --git a/test/capturer.go b/test/capturer.go deleted file mode 100644 index 3bdc1e3a7fb37763f31566ca47f87552417d7dc1..0000000000000000000000000000000000000000 --- a/test/capturer.go +++ /dev/null @@ -1,37 +0,0 @@ -package test - -import ( - "bytes" - "fmt" - - "gfx.cafe/gfx/pggat/lib/fed" - "gfx.cafe/gfx/pggat/lib/gsql" -) - -type Capturer struct { - Packets []fed.Packet -} - -func (T *Capturer) WritePacket(packet fed.Packet) error { - T.Packets = append(T.Packets, bytes.Clone(packet)) - return nil -} - -func (T *Capturer) Check(other *Capturer) error { - if len(T.Packets) != len(other.Packets) { - return fmt.Errorf("wrong number of packets! got %d but expected %d", len(other.Packets), len(T.Packets)) - } - - for i := range T.Packets { - expected := T.Packets[i] - actual := other.Packets[i] - - if !bytes.Equal(expected.Bytes(), actual.Bytes()) { - return fmt.Errorf("mismatched packet! expected %v but got %v", expected.Bytes(), actual.Bytes()) - } - } - - return nil -} - -var _ gsql.ResultWriter = (*Capturer)(nil) diff --git a/test/runner.go b/test/runner.go index d23e94c631e58064f1d933793dcb7a782834a316..c1f24ccc563ed15570d3eb9d676e0a22651716c1 100644 --- a/test/runner.go +++ b/test/runner.go @@ -1,12 +1,14 @@ package test import ( + "bytes" "errors" "fmt" "io" "gfx.cafe/gfx/pggat/lib/bouncer/bouncers/v2" "gfx.cafe/gfx/pggat/lib/fed" + "gfx.cafe/gfx/pggat/lib/fed/middlewares/unterminate" packets "gfx.cafe/gfx/pggat/lib/fed/packets/v3.0" "gfx.cafe/gfx/pggat/lib/gat/pool/recipe" "gfx.cafe/gfx/pggat/lib/gsql" @@ -26,67 +28,91 @@ func MakeRunner(config Config, test Test) Runner { } } -func (T *Runner) prepare(client *gsql.Client, until int) []Capturer { - results := make([]Capturer, until) - +func (T *Runner) prepare(client *fed.Conn, until int) error { for i := 0; i < until; i++ { x := T.test.Instructions[i] switch v := x.(type) { case inst.SimpleQuery: q := packets.Query(v) - client.Do(&results[i], q.IntoPacket(nil)) + if err := client.WritePacket(&q); err != nil { + return err + } case inst.Sync: - client.Do(&results[i], fed.NewPacket(packets.TypeSync)) + if err := client.WritePacket(&packets.Sync{}); err != nil { + return err + } case inst.Parse: p := packets.Parse{ Destination: v.Destination, Query: v.Query, } - client.Do(&results[i], p.IntoPacket(nil)) + if err := client.WritePacket(&p); err != nil { + return err + } case inst.Bind: p := packets.Bind{ Destination: v.Destination, Source: v.Source, } - client.Do(&results[i], p.IntoPacket(nil)) + if err := client.WritePacket(&p); err != nil { + return err + } case inst.DescribePortal: p := packets.Describe{ - Which: 'P', - Target: string(v), + Which: 'P', + Name: string(v), + } + if err := client.WritePacket(&p); err != nil { + return err } - client.Do(&results[i], p.IntoPacket(nil)) case inst.DescribePreparedStatement: p := packets.Describe{ - Which: 'S', - Target: string(v), + Which: 'S', + Name: string(v), + } + if err := client.WritePacket(&p); err != nil { + return err } - client.Do(&results[i], p.IntoPacket(nil)) case inst.Execute: p := packets.Execute{ Target: string(v), } - client.Do(&results[i], p.IntoPacket(nil)) + if err := client.WritePacket(&p); err != nil { + return err + } case inst.ClosePortal: p := packets.Close{ - Which: 'P', - Target: string(v), + Which: 'P', + Name: string(v), + } + if err := client.WritePacket(&p); err != nil { + return err } - client.Do(&results[i], p.IntoPacket(nil)) case inst.ClosePreparedStatement: p := packets.Close{ - Which: 'S', - Target: string(v), + Which: 'S', + Name: string(v), + } + if err := client.WritePacket(&p); err != nil { + return err } - client.Do(&results[i], p.IntoPacket(nil)) case inst.CopyData: p := packets.CopyData(v) - client.Do(&results[i], p.IntoPacket(nil)) + if err := client.WritePacket(&p); err != nil { + return err + } case inst.CopyDone: - client.Do(&results[i], fed.NewPacket(packets.TypeCopyDone)) + if err := client.WritePacket(&packets.CopyDone{}); err != nil { + return err + } } } - return results + if err := client.WritePacket(&packets.Terminate{}); err != nil { + return err + } + + return client.Flush() } func (T *Runner) runModeL1(dialer recipe.Dialer, client *fed.Conn) error { @@ -98,9 +124,11 @@ func (T *Runner) runModeL1(dialer recipe.Dialer, client *fed.Conn) error { _ = server.Close() }() + client.Middleware = append(client.Middleware, unterminate.Unterminate) + for { var p fed.Packet - p, err = client.ReadPacket(true, p) + p, err = client.ReadPacket(true) if err != nil { if errors.Is(err, io.EOF) { break @@ -108,7 +136,7 @@ func (T *Runner) runModeL1(dialer recipe.Dialer, client *fed.Conn) error { return err } - _, clientErr, serverErr := bouncers.Bounce(client, server, p) + clientErr, serverErr := bouncers.Bounce(client, server, p) if clientErr != nil { return clientErr } @@ -120,29 +148,31 @@ func (T *Runner) runModeL1(dialer recipe.Dialer, client *fed.Conn) error { return nil } -func (T *Runner) runModeOnce(dialer recipe.Dialer) ([]Capturer, error) { - var client gsql.Client - results := T.prepare(&client, len(T.test.Instructions)) - if err := client.Close(); err != nil { +func (T *Runner) runModeOnce(dialer recipe.Dialer) ([]byte, error) { + inward, outward := gsql.NewPair() + if err := T.prepare(inward, len(T.test.Instructions)); err != nil { + return nil, err + } + + if err := T.runModeL1(dialer, outward); err != nil { return nil, err } - if err := T.runModeL1(dialer, fed.NewConn(&client)); err != nil { + if err := inward.Close(); err != nil { return nil, err } - return results, nil + return io.ReadAll(inward.NetConn) } func (T *Runner) runModeFail(dialer recipe.Dialer) error { for i := 1; i < len(T.test.Instructions)+1; i++ { - var client gsql.Client - T.prepare(&client, i) - if err := client.Close(); err != nil { + inward, outward := gsql.NewPair() + if err := T.prepare(inward, i); err != nil { return err } - if err := T.runModeL1(dialer, fed.NewConn(&client)); err != nil && !errors.Is(err, io.EOF) { + if err := T.runModeL1(dialer, outward); err != nil && !errors.Is(err, io.EOF) { return err } } @@ -150,7 +180,7 @@ func (T *Runner) runModeFail(dialer recipe.Dialer) error { return nil } -func (T *Runner) runMode(dialer recipe.Dialer) ([]Capturer, error) { +func (T *Runner) runMode(dialer recipe.Dialer) ([]byte, error) { instances := T.config.Stress if instances < 1 || T.test.SideEffects { return T.runModeOnce(dialer) @@ -175,14 +205,8 @@ func (T *Runner) runMode(dialer recipe.Dialer) ([]Capturer, error) { if err != nil { return err } - if len(expected) != len(actual) { - return fmt.Errorf("wrong number of results! expected %d but got %d", len(expected), len(actual)) - } - for i, exp := range expected { - act := actual[i] - if err = exp.Check(&act); err != nil { - return err - } + if !bytes.Equal(expected, actual) { + return fmt.Errorf("mismatched results: expected %v but got %v", expected, actual) } return nil }) @@ -198,7 +222,7 @@ func (T *Runner) runMode(dialer recipe.Dialer) ([]Capturer, error) { func (T *Runner) Run() error { var errs []error - var expected []Capturer + var expected []byte // modes for name, mode := range T.config.Modes { @@ -216,30 +240,13 @@ func (T *Runner) Run() error { continue } - if len(expected) != len(actual) { + if !bytes.Equal(expected, actual) { errs = append(errs, ErrorIn{ Name: name, - Err: fmt.Errorf("wrong number of results! expected %d but got %d", len(expected), len(actual)), + Err: fmt.Errorf("mismatched results: expected %v but got %v", expected, actual), }) continue } - - var modeErrs []error - - for i, exp := range expected { - act := actual[i] - - if err = exp.Check(&act); err != nil { - modeErrs = append(modeErrs, fmt.Errorf("instruction %d: %s", i+1, err.Error())) - } - } - - if len(modeErrs) > 0 { - errs = append(errs, ErrorIn{ - Name: name, - Err: Errors(modeErrs), - }) - } } if len(errs) > 0 {