From 06ae052c32ad33e69884cc0d656018c153a45039 Mon Sep 17 00:00:00 2001 From: Miek Gieben Date: Fri, 16 Dec 2011 10:06:28 +0100 Subject: [PATCH] Implement returning errors from the scanner --- dns.go | 2 +- parse_test.go | 2 +- zscan.go | 82 ++++++++++++++++++++++++++++++++------------------- zscan_rr.go | 46 ++++++++++++++--------------- 4 files changed, 75 insertions(+), 57 deletions(-) diff --git a/dns.go b/dns.go index ee6c1260..e632b4ae 100644 --- a/dns.go +++ b/dns.go @@ -154,7 +154,7 @@ func (s RRset) Ok() bool { type Exchange struct { Request *Msg // The question sent. Reply *Msg // The answer to the question that was sent. - Error error // If something when wrong, this contains the error. + ErrorMsg error // If something when wrong, this contains the error. } // DNS resource records. diff --git a/parse_test.go b/parse_test.go index 5725665a..da0bb196 100644 --- a/parse_test.go +++ b/parse_test.go @@ -122,7 +122,7 @@ func TestParse(t *testing.T) { t.Logf("`%s' should be equal to\n`%s', but is `%s'\n", i, o, rr.String()) t.Fail() } else { - t.Logf("RR is %s", rr.String()) + t.Logf("RR is OK: `%s'", rr.String()) } } } diff --git a/zscan.go b/zscan.go index 9b6d4a29..802ebcb2 100644 --- a/zscan.go +++ b/zscan.go @@ -61,26 +61,34 @@ type Lex struct { column int // column in the fil } +type Token struct { + Rr RR // the scanned resource record + Err *ParseError // when an error occured, this is the specifics +} + // NewRR parses the string s and returns the RR contained in there. If the string // contains more than one RR, only the first is returned. If an error is detected -// an error is returned. +// that error error is returned. // If the class is not specified, the IN class is assumed. If the TTL is not // specified DefaultTtl is assumed. func NewRR(s string) (RR, error) { - cr := make(chan RR) + t := make(chan Token) if s[len(s)-1] != '\n' { // We need a closing newline - go ParseZone(strings.NewReader(s+"\n"), cr) + go ParseZone(strings.NewReader(s+"\n"), t) } else { - go ParseZone(strings.NewReader(s), cr) + go ParseZone(strings.NewReader(s), t) } - r := <-cr // There are no error send as of yet - return r, nil // Todo: errors + r := <-t + if r.Err != nil { + return nil, r.Err + } + return r.Rr, nil } -// ParseZone reads a RFC 1035 zone from r. It returns each parsed RR on the -// channel cr. The channel cr is closed by ParseZone when the end of r is reached. -func ParseZone(r io.Reader, cr chan RR) { - defer close(cr) +// ParseZone reads a RFC 1035 zone from r. It returns each parsed RR or on error +// on the channel t. The channel t is closed by ParseZone when the end of r is reached. +func ParseZone(r io.Reader, t chan Token) { + defer close(t) var s scanner.Scanner c := make(chan Lex) s.Init(r) @@ -105,9 +113,9 @@ func ParseZone(r io.Reader, cr chan RR) { } switch st { case _EXPECT_OWNER: - // Set the defaults here - h.Ttl = DefaultTtl - h.Class = ClassINET + // Set the defaults here + h.Ttl = DefaultTtl + h.Class = ClassINET switch l.value { case _NEWLINE: // Empty line st = _EXPECT_OWNER @@ -115,12 +123,14 @@ func ParseZone(r io.Reader, cr chan RR) { h.Name = l.token st = _EXPECT_OWNER_BL default: - fmt.Printf("%s\n", &ParseError{"Error at the start", l}) - st = _EXPECT_OWNER + t <- Token{Err: &ParseError{"Error at the start", l}} + return + //st = _EXPECT_OWNER } case _EXPECT_OWNER_BL: if l.value != _BLANK { - fmt.Printf("%s\n", &ParseError{"No blank after owner", l}) + t <- Token{Err: &ParseError{"No blank after owner", l}} + return } st = _EXPECT_ANY case _EXPECT_ANY: @@ -131,28 +141,33 @@ func ParseZone(r io.Reader, cr chan RR) { case _CLASS: h.Class, ok = Str_class[strings.ToUpper(l.token)] if !ok { - fmt.Printf("%s\n", &ParseError{"Unknown class", l}) + t <- Token{Err: &ParseError{"Unknown class", l}} + return } st = _EXPECT_ANY_NOCLASS_BL case _STRING: // TTL is this case ttl, ok := strconv.Atoi(l.token) if ok != nil { - fmt.Printf("%s\n", &ParseError{"Not a TTL", l}) + t <- Token{Err: &ParseError{"Not a TTL", l}} + return } else { h.Ttl = uint32(ttl) } st = _EXPECT_ANY_NOTTL_BL default: - fmt.Printf("%s\n", &ParseError{"Expecting RR type, TTL or class, not this...", l}) + t <- Token{Err: &ParseError{"Expecting RR type, TTL or class, not this...", l}} + return } case _EXPECT_ANY_NOCLASS_BL: if l.value != _BLANK { - fmt.Printf("%s\n", &ParseError{"No blank before NOCLASS", l}) + t <- Token{Err: &ParseError{"No blank before NOCLASS", l}} + return } st = _EXPECT_ANY_NOCLASS case _EXPECT_ANY_NOTTL_BL: if l.value != _BLANK { - fmt.Printf("%s\n", &ParseError{"No blank before NOTTL", l}) + t <- Token{Err: &ParseError{"No blank before NOTTL", l}} + return } st = _EXPECT_ANY_NOTTL case _EXPECT_ANY_NOTTL: @@ -160,7 +175,8 @@ func ParseZone(r io.Reader, cr chan RR) { case _CLASS: h.Class, ok = Str_class[strings.ToUpper(l.token)] if !ok { - fmt.Printf("%s\n", &ParseError{"Unknown class", l}) + t <- Token{Err: &ParseError{"Unknown class", l}} + return } st = _EXPECT_RRTYPE_BL case _RRTYPE: @@ -172,7 +188,8 @@ func ParseZone(r io.Reader, cr chan RR) { case _STRING: // TTL ttl, ok := strconv.Atoi(l.token) if ok != nil { - fmt.Printf("%s\n", &ParseError{"Not a TTL", l}) + t <- Token{Err: &ParseError{"Not a TTL", l}} + return } else { h.Ttl = uint32(ttl) } @@ -181,25 +198,30 @@ func ParseZone(r io.Reader, cr chan RR) { h.Rrtype, _ = Str_rr[strings.ToUpper(l.token)] st = _EXPECT_RDATA default: - fmt.Printf("%s\n", &ParseError{"Expecting RR type or TTL, not this...", l}) + t <- Token{Err: &ParseError{"Expecting RR type or TTL, not this...", l}} + return } case _EXPECT_RRTYPE_BL: if l.value != _BLANK { - fmt.Printf("%s\n", &ParseError{"No blank after", l}) + t <- Token{Err: &ParseError{"No blank after", l}} + return } st = _EXPECT_RRTYPE case _EXPECT_RRTYPE: if l.value != _RRTYPE { - fmt.Printf("%s\n", &ParseError{"Unknown RR type", l}) + t <- Token{Err: &ParseError{"Unknown RR type", l}} + return } h.Rrtype, _ = Str_rr[strings.ToUpper(l.token)] st = _EXPECT_RDATA case _EXPECT_RDATA: + // I could save my token here...? l r, e := setRR(h, c) if e != nil { - fmt.Printf("%v\n", e) + t <- Token{Err: e} + return } - cr <- r + t <- Token{Rr: r} st = _EXPECT_OWNER } } @@ -330,7 +352,7 @@ func zlexer(s scanner.Scanner, c chan Lex) { } brace-- if brace < 0 { - fmt.Printf("Error\n") + fmt.Printf("%s\n", &ParseError{"Extra closing brace", l}) } default: if commt { @@ -341,6 +363,4 @@ func zlexer(s scanner.Scanner, c chan Lex) { } tok = s.Scan() } - // Hmm - // fmt.Printf("XX %s XXX", str) } diff --git a/zscan_rr.go b/zscan_rr.go index 55ea7397..b0934b62 100644 --- a/zscan_rr.go +++ b/zscan_rr.go @@ -11,13 +11,11 @@ import ( // All data from the channel c is either _STRING or _BLANK. // After the rdata there may come 1 _BLANK and then a _NEWLINE // or immediately a _NEWLINE. If this is not the case we flag -// an error: garbage after rdata. +// an *ParseError: garbage after rdata. -func setRR(h RR_Header, c chan Lex) (RR, error) { - var ( - r RR - e error - ) +func setRR(h RR_Header, c chan Lex) (RR, *ParseError) { + var r RR + e := new(ParseError) switch h.Rrtype { case TypeA: r, e = setA(h, c) @@ -87,7 +85,7 @@ func setRR(h RR_Header, c chan Lex) (RR, error) { return r, e } -func slurpRemainder(c chan Lex) error { +func slurpRemainder(c chan Lex) *ParseError { l := <-c if DEBUG { fmt.Printf("%\v", l) @@ -112,7 +110,7 @@ func slurpRemainder(c chan Lex) error { return nil } -func setA(h RR_Header, c chan Lex) (RR, error) { +func setA(h RR_Header, c chan Lex) (RR, *ParseError) { rr := new(RR_A) rr.Hdr = h @@ -124,7 +122,7 @@ func setA(h RR_Header, c chan Lex) (RR, error) { return rr, nil } -func setAAAA(h RR_Header, c chan Lex) (RR, error) { +func setAAAA(h RR_Header, c chan Lex) (RR, *ParseError) { rr := new(RR_AAAA) rr.Hdr = h @@ -136,7 +134,7 @@ func setAAAA(h RR_Header, c chan Lex) (RR, error) { return rr, nil } -func setNS(h RR_Header, c chan Lex) (RR, error) { +func setNS(h RR_Header, c chan Lex) (RR, *ParseError) { rr := new(RR_NS) rr.Hdr = h @@ -148,7 +146,7 @@ func setNS(h RR_Header, c chan Lex) (RR, error) { return rr, nil } -func setMX(h RR_Header, c chan Lex) (RR, error) { +func setMX(h RR_Header, c chan Lex) (RR, *ParseError) { rr := new(RR_MX) rr.Hdr = h @@ -167,7 +165,7 @@ func setMX(h RR_Header, c chan Lex) (RR, error) { return rr, nil } -func setCNAME(h RR_Header, c chan Lex) (RR, error) { +func setCNAME(h RR_Header, c chan Lex) (RR, *ParseError) { rr := new(RR_CNAME) rr.Hdr = h @@ -179,7 +177,7 @@ func setCNAME(h RR_Header, c chan Lex) (RR, error) { return rr, nil } -func setSOA(h RR_Header, c chan Lex) (RR, error) { +func setSOA(h RR_Header, c chan Lex) (RR, *ParseError) { rr := new(RR_SOA) rr.Hdr = h @@ -198,7 +196,7 @@ func setSOA(h RR_Header, c chan Lex) (RR, error) { <-c // _BLANK var j int - var e error + var e error for i := 0; i < 5; i++ { l = <-c if j, e = strconv.Atoi(l.token); e != nil { @@ -221,7 +219,7 @@ func setSOA(h RR_Header, c chan Lex) (RR, error) { return rr, nil } -func setRRSIG(h RR_Header, c chan Lex) (RR, error) { +func setRRSIG(h RR_Header, c chan Lex) (RR, *ParseError) { rr := new(RR_RRSIG) rr.Hdr = h l := <-c @@ -297,7 +295,7 @@ func setRRSIG(h RR_Header, c chan Lex) (RR, error) { return rr, nil } -func setNSEC(h RR_Header, c chan Lex) (RR, error) { +func setNSEC(h RR_Header, c chan Lex) (RR, *ParseError) { rr := new(RR_NSEC) rr.Hdr = h @@ -328,7 +326,7 @@ func setNSEC(h RR_Header, c chan Lex) (RR, error) { return rr, nil } -func setNSEC3(h RR_Header, c chan Lex) (RR, error) { +func setNSEC3(h RR_Header, c chan Lex) (RR, *ParseError) { rr := new(RR_NSEC3) rr.Hdr = h @@ -382,7 +380,7 @@ func setNSEC3(h RR_Header, c chan Lex) (RR, error) { return rr, nil } -func setDNSKEY(h RR_Header, c chan Lex) (RR, error) { +func setDNSKEY(h RR_Header, c chan Lex) (RR, *ParseError) { rr := new(RR_DNSKEY) rr.Hdr = h @@ -424,7 +422,7 @@ func setDNSKEY(h RR_Header, c chan Lex) (RR, error) { } /* -func setNSEC3PARAM(h RR_Header, c chan Lex) (RR, error) { +func setNSEC3PARAM(h RR_Header, c chan Lex) (RR, *ParseError) { rr := new(RR_NSEC3PARAM) rr.Hdr = h rdf := fields(data[mark:p], 4) @@ -449,7 +447,7 @@ func setNSEC3PARAM(h RR_Header, c chan Lex) (RR, error) { } */ -func setTXT(h RR_Header, c chan Lex) (RR, error) { +func setTXT(h RR_Header, c chan Lex) (RR, *ParseError) { rr := new(RR_TXT) rr.Hdr = h @@ -472,7 +470,7 @@ func setTXT(h RR_Header, c chan Lex) (RR, error) { } /* -func setDS(h RR_Header, c chan Lex) (RR, error) { +func setDS(h RR_Header, c chan Lex) (RR, *ParseError) { rr := new(RR_DS) rr.Hdr = h action setDS { @@ -503,7 +501,7 @@ func setDS(h RR_Header, c chan Lex) (RR, error) { zp.RR <- rr } -func setCNAME(h RR_Header, c chan Lex) (RR, error) { +func setCNAME(h RR_Header, c chan Lex) (RR, *ParseError) { rr := new(RR_CNAME) rr.Hdr = h action setDLV { @@ -534,7 +532,7 @@ func setCNAME(h RR_Header, c chan Lex) (RR, error) { zp.RR <- rr } -func setCNAME(h RR_Header, c chan Lex) (RR, error) { +func setCNAME(h RR_Header, c chan Lex) (RR, *ParseError) { rr := new(RR_CNAME) rr.Hdr = h action setTA { @@ -566,7 +564,7 @@ func setCNAME(h RR_Header, c chan Lex) (RR, error) { } -func setSSHFP(h RR_Header, c chan Lex) (RR, error) { +func setSSHFP(h RR_Header, c chan Lex) (RR, *ParseError) { rr := new(RR_CNAME) rr.Hdr = h var (