Generate pack/unpack for all RRs (#360)

Add dns:txt parsing helper to prevent compile errors. This allows
us to generate all unpack/pack function.

Add pack to the RR interface definition and add this method to
PrivateRR.

We still use typeToUnpack to select which types don't use reflection.
This commit is contained in:
Miek Gieben 2016-06-05 07:53:12 +01:00
parent 3f53d75269
commit 907a4aef57
6 changed files with 2313 additions and 105 deletions

2
dns.go
View File

@ -34,6 +34,8 @@ type RR interface {
copy() RR
// len returns the length (in octets) of the uncompressed RR in wire format.
len() int
// pack packs an RR into wire format.
pack([]byte, int, map[string]int, bool) (int, error)
}
// RR_Header is the header all DNS resource records share.

52
msg.go
View File

@ -1354,56 +1354,8 @@ func PackRR(rr RR, msg []byte, off int, compression map[string]int, compress boo
_, ok := typeToUnpack[rr.Header().Rrtype]
switch ok {
case true:
// Shortcut reflection, `pack' needs to be added to the RR interface so we can just do this:
// off1, err = t.pack(msg, off, compression, compress)
// TODO(miek): revert the logic and make a blacklist for types that still use reflection. Kill
// typeToUnpack and just generate all the pack and unpack functions even though we don't use
// them for all types (yet).
switch t := rr.(type) {
case *RR_Header:
// we can be called with an empty RR, consisting only out of the header, see update_test.go's
// TestDynamicUpdateZeroRdataUnpack for an example. This is OK as RR_Header also implements the RR interface.
off1, err = t.pack(msg, off, compression, compress)
case *ANY:
// Also "weird" setup, see (again) update_test.go's TestRemoveRRset, where the Rrtype is 1 but the type is *ANY.
off1, err = t.pack(msg, off, compression, compress)
case *A:
off1, err = t.pack(msg, off, compression, compress)
case *AAAA:
off1, err = t.pack(msg, off, compression, compress)
case *CNAME:
off1, err = t.pack(msg, off, compression, compress)
case *DNAME:
off1, err = t.pack(msg, off, compression, compress)
case *HINFO:
off1, err = t.pack(msg, off, compression, compress)
case *L32:
off1, err = t.pack(msg, off, compression, compress)
case *LOC:
off1, err = t.pack(msg, off, compression, compress)
case *MB:
off1, err = t.pack(msg, off, compression, compress)
case *MD:
off1, err = t.pack(msg, off, compression, compress)
case *MF:
off1, err = t.pack(msg, off, compression, compress)
case *MG:
off1, err = t.pack(msg, off, compression, compress)
case *MX:
off1, err = t.pack(msg, off, compression, compress)
case *NID:
off1, err = t.pack(msg, off, compression, compress)
case *NS:
off1, err = t.pack(msg, off, compression, compress)
case *PTR:
off1, err = t.pack(msg, off, compression, compress)
case *RP:
off1, err = t.pack(msg, off, compression, compress)
case *SRV:
off1, err = t.pack(msg, off, compression, compress)
case *DNSKEY:
off1, err = t.pack(msg, off, compression, compress)
}
off1, err = rr.pack(msg, off, compression, compress)
// TODO(miek): revert the logic and make a blacklist for types that still use reflection. Kill typeToUnpack.
default:
off1, err = packStructCompress(rr, msg, off, compression, compress)
}

View File

@ -29,37 +29,6 @@ import (
// * NINFO
// * PrivateRR
// What types are we generating, should be kept in sync with typeToUnpack in msg.go
var generate = map[string]bool{
"AAAA": true,
"ANY": true,
"A": true,
"CNAME": true,
"DNAME": true,
"DNSKEY": true,
"HINFO": true,
"L32": true,
"LOC": true,
"MB": true,
"MD": true,
"MF": true,
"MG": true,
"MR": true,
"MX": true,
"NID": true,
"NS": true,
"PTR": true,
"RP": true,
"SRV": true,
}
func shouldGenerate(name string) bool {
_, ok := generate[name]
return ok
}
// For later: IPSECKEY is weird.
var packageHdr = `
// *** DO NOT MODIFY ***
// AUTOGENERATED BY go generate from msg_generate.go
@ -123,7 +92,7 @@ func main() {
for _, name := range namedTypes {
o := scope.Lookup(name)
st, isEmbedded := getTypeStruct(o.Type(), scope)
if isEmbedded || !shouldGenerate(name) {
if isEmbedded {
continue
}
@ -143,17 +112,17 @@ return off, err
`)
}
//if _, ok := st.Field(i).Type().(*types.Slice); ok {
//switch st.Tag(i) {
//case `dns:"-"`:
//// ignored
//case `dns:"cdomain-name"`, `dns:"domain-name"`, `dns:"txt"`:
//o("for _, x := range rr.%s { l += len(x) + 1 }\n")
//default:
//log.Fatalln(name, st.Field(i).Name(), st.Tag(i))
//}
//continue
//}
if _, ok := st.Field(i).Type().(*types.Slice); ok {
switch st.Tag(i) {
case `dns:"-"`:
// ignored
case `dns:"txt"`:
o("off, err = packStringTxt(rr.%s, msg, off)\n")
default:
//log.Fatalln(name, st.Field(i).Name(), st.Tag(i))
}
continue
}
switch st.Tag(i) {
case `dns:"-"`:
@ -202,7 +171,7 @@ return off, err
for _, name := range namedTypes {
o := scope.Lookup(name)
st, isEmbedded := getTypeStruct(o.Type(), scope)
if isEmbedded || !shouldGenerate(name) {
if isEmbedded {
continue
}
@ -226,17 +195,17 @@ return rr, off, err
`)
}
//if _, ok := st.Field(i).Type().(*types.Slice); ok {
//switch st.Tag(i) {
//case `dns:"-"`:
//// ignored
//case `dns:"cdomain-name"`, `dns:"domain-name"`, `dns:"txt"`:
//o("for _, x := range rr.%s { l += len(x) + 1 }\n")
//default:
//log.Fatalln(name, st.Field(i).Name(), st.Tag(i))
//}
//continue
//}
if _, ok := st.Field(i).Type().(*types.Slice); ok {
switch st.Tag(i) {
case `dns:"-"`:
// ignored
case `dns:"txt"`:
o("rr.%s, off, err = unpackStringTxt(msg, off)\n")
default:
//log.Fatalln(name, st.Field(i).Name(), st.Tag(i))
}
continue
}
switch st.Tag(i) {
case `dns:"-"`:

View File

@ -397,3 +397,20 @@ func packStringHex(s string, msg []byte, off int) (int, error) {
off += len(h)
return off, nil
}
func unpackStringTxt(msg []byte, off int) ([]string, int, error) {
txt, off, err := unpackTxt(msg, off)
if err != nil {
return nil, len(msg), err
}
return txt, off, nil
}
func packStringTxt(s []string, msg []byte, off int) (int, error) {
txtTmp := make([]byte, 256*4+1) // If the whole string consists out of \DDD we need this many.
off, err := packTxt(s, msg, off, txtTmp)
if err != nil {
return len(msg), err
}
return off, nil
}

View File

@ -65,6 +65,14 @@ func (r *PrivateRR) copy() RR {
}
return rr
}
func (r *PrivateRR) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
n, err := r.Data.Pack(msg[off:])
if err != nil {
return len(msg), err
}
off += n
return off, nil
}
// PrivateHandle registers a private resource record type. It requires
// string and numeric representation of private RR type and generator function as argument.

2260
zmsg.go

File diff suppressed because it is too large Load Diff