ab9dd18bec
See https://github.com/hashicorp/consul/issues/3977 While trying to improve furthermore #3948 (This pull request is still valid since we are not using Compression to compute the result anyway). I saw a strange behaviour of dns library. Basically, msg.Len() and len(msg.Pack()) disagree on Message len. Thus, calculation of DNS response is false consul relies on msg.Len() instead of the result of Pack() This is linked to miekg/dns#453 and a fix has been provided with miekg/dns#454 Would it be possible to upgrade miekg/dns to a more recent function ? Consul might for instance upgrade to a post 1.0 release such as https://github.com/miekg/dns/releases/tag/v1.0.4
189 lines
4.9 KiB
Go
189 lines
4.9 KiB
Go
//+build ignore
|
|
|
|
// compression_generate.go is meant to run with go generate. It will use
|
|
// go/{importer,types} to track down all the RR struct types. Then for each type
|
|
// it will look to see if there are (compressible) names, if so it will add that
|
|
// type to compressionLenHelperType and comressionLenSearchType which "fake" the
|
|
// compression so that Len() is fast.
|
|
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"go/format"
|
|
"go/importer"
|
|
"go/types"
|
|
"log"
|
|
"os"
|
|
)
|
|
|
|
var packageHdr = `
|
|
// Code generated by "go run compress_generate.go"; DO NOT EDIT.
|
|
|
|
package dns
|
|
|
|
`
|
|
|
|
// getTypeStruct will take a type and the package scope, and return the
|
|
// (innermost) struct if the type is considered a RR type (currently defined as
|
|
// those structs beginning with a RR_Header, could be redefined as implementing
|
|
// the RR interface). The bool return value indicates if embedded structs were
|
|
// resolved.
|
|
func getTypeStruct(t types.Type, scope *types.Scope) (*types.Struct, bool) {
|
|
st, ok := t.Underlying().(*types.Struct)
|
|
if !ok {
|
|
return nil, false
|
|
}
|
|
if st.Field(0).Type() == scope.Lookup("RR_Header").Type() {
|
|
return st, false
|
|
}
|
|
if st.Field(0).Anonymous() {
|
|
st, _ := getTypeStruct(st.Field(0).Type(), scope)
|
|
return st, true
|
|
}
|
|
return nil, false
|
|
}
|
|
|
|
func main() {
|
|
// Import and type-check the package
|
|
pkg, err := importer.Default().Import("github.com/miekg/dns")
|
|
fatalIfErr(err)
|
|
scope := pkg.Scope()
|
|
|
|
var domainTypes []string // Types that have a domain name in them (either compressible or not).
|
|
var cdomainTypes []string // Types that have a compressible domain name in them (subset of domainType)
|
|
Names:
|
|
for _, name := range scope.Names() {
|
|
o := scope.Lookup(name)
|
|
if o == nil || !o.Exported() {
|
|
continue
|
|
}
|
|
st, _ := getTypeStruct(o.Type(), scope)
|
|
if st == nil {
|
|
continue
|
|
}
|
|
if name == "PrivateRR" {
|
|
continue
|
|
}
|
|
|
|
if scope.Lookup("Type"+o.Name()) == nil && o.Name() != "RFC3597" {
|
|
log.Fatalf("Constant Type%s does not exist.", o.Name())
|
|
}
|
|
|
|
for i := 1; i < st.NumFields(); i++ {
|
|
if _, ok := st.Field(i).Type().(*types.Slice); ok {
|
|
if st.Tag(i) == `dns:"domain-name"` {
|
|
domainTypes = append(domainTypes, o.Name())
|
|
continue Names
|
|
}
|
|
if st.Tag(i) == `dns:"cdomain-name"` {
|
|
cdomainTypes = append(cdomainTypes, o.Name())
|
|
domainTypes = append(domainTypes, o.Name())
|
|
continue Names
|
|
}
|
|
continue
|
|
}
|
|
|
|
switch {
|
|
case st.Tag(i) == `dns:"domain-name"`:
|
|
domainTypes = append(domainTypes, o.Name())
|
|
continue Names
|
|
case st.Tag(i) == `dns:"cdomain-name"`:
|
|
cdomainTypes = append(cdomainTypes, o.Name())
|
|
domainTypes = append(domainTypes, o.Name())
|
|
continue Names
|
|
}
|
|
}
|
|
}
|
|
|
|
b := &bytes.Buffer{}
|
|
b.WriteString(packageHdr)
|
|
|
|
// compressionLenHelperType - all types that have domain-name/cdomain-name can be used for compressing names
|
|
|
|
fmt.Fprint(b, "func compressionLenHelperType(c map[string]int, r RR) {\n")
|
|
fmt.Fprint(b, "switch x := r.(type) {\n")
|
|
for _, name := range domainTypes {
|
|
o := scope.Lookup(name)
|
|
st, _ := getTypeStruct(o.Type(), scope)
|
|
|
|
fmt.Fprintf(b, "case *%s:\n", name)
|
|
for i := 1; i < st.NumFields(); i++ {
|
|
out := func(s string) { fmt.Fprintf(b, "compressionLenHelper(c, x.%s)\n", st.Field(i).Name()) }
|
|
|
|
if _, ok := st.Field(i).Type().(*types.Slice); ok {
|
|
switch st.Tag(i) {
|
|
case `dns:"domain-name"`:
|
|
fallthrough
|
|
case `dns:"cdomain-name"`:
|
|
// For HIP we need to slice over the elements in this slice.
|
|
fmt.Fprintf(b, `for i := range x.%s {
|
|
compressionLenHelper(c, x.%s[i])
|
|
}
|
|
`, st.Field(i).Name(), st.Field(i).Name())
|
|
}
|
|
continue
|
|
}
|
|
|
|
switch {
|
|
case st.Tag(i) == `dns:"cdomain-name"`:
|
|
fallthrough
|
|
case st.Tag(i) == `dns:"domain-name"`:
|
|
out(st.Field(i).Name())
|
|
}
|
|
}
|
|
}
|
|
fmt.Fprintln(b, "}\n}\n\n")
|
|
|
|
// compressionLenSearchType - search cdomain-tags types for compressible names.
|
|
|
|
fmt.Fprint(b, "func compressionLenSearchType(c map[string]int, r RR) (int, bool) {\n")
|
|
fmt.Fprint(b, "switch x := r.(type) {\n")
|
|
for _, name := range cdomainTypes {
|
|
o := scope.Lookup(name)
|
|
st, _ := getTypeStruct(o.Type(), scope)
|
|
|
|
fmt.Fprintf(b, "case *%s:\n", name)
|
|
j := 1
|
|
for i := 1; i < st.NumFields(); i++ {
|
|
out := func(s string, j int) {
|
|
fmt.Fprintf(b, "k%d, ok%d := compressionLenSearch(c, x.%s)\n", j, j, st.Field(i).Name())
|
|
}
|
|
|
|
// There are no slice types with names that can be compressed.
|
|
|
|
switch {
|
|
case st.Tag(i) == `dns:"cdomain-name"`:
|
|
out(st.Field(i).Name(), j)
|
|
j++
|
|
}
|
|
}
|
|
k := "k1"
|
|
ok := "ok1"
|
|
for i := 2; i < j; i++ {
|
|
k += fmt.Sprintf(" + k%d", i)
|
|
ok += fmt.Sprintf(" && ok%d", i)
|
|
}
|
|
fmt.Fprintf(b, "return %s, %s\n", k, ok)
|
|
}
|
|
fmt.Fprintln(b, "}\nreturn 0, false\n}\n\n")
|
|
|
|
// gofmt
|
|
res, err := format.Source(b.Bytes())
|
|
if err != nil {
|
|
b.WriteTo(os.Stderr)
|
|
log.Fatal(err)
|
|
}
|
|
|
|
f, err := os.Create("zcompress.go")
|
|
fatalIfErr(err)
|
|
defer f.Close()
|
|
f.Write(res)
|
|
}
|
|
|
|
func fatalIfErr(err error) {
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
}
|