|  | // Copyright 2013 The Go Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style | 
|  | // license that can be found in the LICENSE file. | 
|  |  | 
|  | // +build ignore | 
|  |  | 
|  | //go:generate go run gen.go | 
|  |  | 
|  | // This program generates system adaptation constants and types, | 
|  | // internet protocol constants and tables by reading template files | 
|  | // and IANA protocol registries. | 
|  | package main | 
|  |  | 
|  | import ( | 
|  | "bytes" | 
|  | "encoding/xml" | 
|  | "fmt" | 
|  | "go/format" | 
|  | "io" | 
|  | "io/ioutil" | 
|  | "net/http" | 
|  | "os" | 
|  | "os/exec" | 
|  | "runtime" | 
|  | "strconv" | 
|  | "strings" | 
|  | ) | 
|  |  | 
|  | func main() { | 
|  | if err := genzsys(); err != nil { | 
|  | fmt.Fprintln(os.Stderr, err) | 
|  | os.Exit(1) | 
|  | } | 
|  | if err := geniana(); err != nil { | 
|  | fmt.Fprintln(os.Stderr, err) | 
|  | os.Exit(1) | 
|  | } | 
|  | } | 
|  |  | 
|  | func genzsys() error { | 
|  | defs := "defs_" + runtime.GOOS + ".go" | 
|  | f, err := os.Open(defs) | 
|  | if err != nil { | 
|  | if os.IsNotExist(err) { | 
|  | return nil | 
|  | } | 
|  | return err | 
|  | } | 
|  | f.Close() | 
|  | cmd := exec.Command("go", "tool", "cgo", "-godefs", defs) | 
|  | b, err := cmd.Output() | 
|  | if err != nil { | 
|  | return err | 
|  | } | 
|  | b, err = format.Source(b) | 
|  | if err != nil { | 
|  | return err | 
|  | } | 
|  | zsys := "zsys_" + runtime.GOOS + ".go" | 
|  | switch runtime.GOOS { | 
|  | case "freebsd", "linux": | 
|  | zsys = "zsys_" + runtime.GOOS + "_" + runtime.GOARCH + ".go" | 
|  | } | 
|  | if err := ioutil.WriteFile(zsys, b, 0644); err != nil { | 
|  | return err | 
|  | } | 
|  | return nil | 
|  | } | 
|  |  | 
|  | var registries = []struct { | 
|  | url   string | 
|  | parse func(io.Writer, io.Reader) error | 
|  | }{ | 
|  | { | 
|  | "http://www.iana.org/assignments/icmp-parameters/icmp-parameters.xml", | 
|  | parseICMPv4Parameters, | 
|  | }, | 
|  | } | 
|  |  | 
|  | func geniana() error { | 
|  | var bb bytes.Buffer | 
|  | fmt.Fprintf(&bb, "// go generate gen.go\n") | 
|  | fmt.Fprintf(&bb, "// GENERATED BY THE COMMAND ABOVE; DO NOT EDIT\n\n") | 
|  | fmt.Fprintf(&bb, "package ipv4\n\n") | 
|  | for _, r := range registries { | 
|  | resp, err := http.Get(r.url) | 
|  | if err != nil { | 
|  | return err | 
|  | } | 
|  | defer resp.Body.Close() | 
|  | if resp.StatusCode != http.StatusOK { | 
|  | return fmt.Errorf("got HTTP status code %v for %v\n", resp.StatusCode, r.url) | 
|  | } | 
|  | if err := r.parse(&bb, resp.Body); err != nil { | 
|  | return err | 
|  | } | 
|  | fmt.Fprintf(&bb, "\n") | 
|  | } | 
|  | b, err := format.Source(bb.Bytes()) | 
|  | if err != nil { | 
|  | return err | 
|  | } | 
|  | if err := ioutil.WriteFile("iana.go", b, 0644); err != nil { | 
|  | return err | 
|  | } | 
|  | return nil | 
|  | } | 
|  |  | 
|  | func parseICMPv4Parameters(w io.Writer, r io.Reader) error { | 
|  | dec := xml.NewDecoder(r) | 
|  | var icp icmpv4Parameters | 
|  | if err := dec.Decode(&icp); err != nil { | 
|  | return err | 
|  | } | 
|  | prs := icp.escape() | 
|  | fmt.Fprintf(w, "// %s, Updated: %s\n", icp.Title, icp.Updated) | 
|  | fmt.Fprintf(w, "const (\n") | 
|  | for _, pr := range prs { | 
|  | if pr.Descr == "" { | 
|  | continue | 
|  | } | 
|  | fmt.Fprintf(w, "ICMPType%s ICMPType = %d", pr.Descr, pr.Value) | 
|  | fmt.Fprintf(w, "// %s\n", pr.OrigDescr) | 
|  | } | 
|  | fmt.Fprintf(w, ")\n\n") | 
|  | fmt.Fprintf(w, "// %s, Updated: %s\n", icp.Title, icp.Updated) | 
|  | fmt.Fprintf(w, "var icmpTypes = map[ICMPType]string{\n") | 
|  | for _, pr := range prs { | 
|  | if pr.Descr == "" { | 
|  | continue | 
|  | } | 
|  | fmt.Fprintf(w, "%d: %q,\n", pr.Value, strings.ToLower(pr.OrigDescr)) | 
|  | } | 
|  | fmt.Fprintf(w, "}\n") | 
|  | return nil | 
|  | } | 
|  |  | 
|  | type icmpv4Parameters struct { | 
|  | XMLName    xml.Name `xml:"registry"` | 
|  | Title      string   `xml:"title"` | 
|  | Updated    string   `xml:"updated"` | 
|  | Registries []struct { | 
|  | Title   string `xml:"title"` | 
|  | Records []struct { | 
|  | Value string `xml:"value"` | 
|  | Descr string `xml:"description"` | 
|  | } `xml:"record"` | 
|  | } `xml:"registry"` | 
|  | } | 
|  |  | 
|  | type canonICMPv4ParamRecord struct { | 
|  | OrigDescr string | 
|  | Descr     string | 
|  | Value     int | 
|  | } | 
|  |  | 
|  | func (icp *icmpv4Parameters) escape() []canonICMPv4ParamRecord { | 
|  | id := -1 | 
|  | for i, r := range icp.Registries { | 
|  | if strings.Contains(r.Title, "Type") || strings.Contains(r.Title, "type") { | 
|  | id = i | 
|  | break | 
|  | } | 
|  | } | 
|  | if id < 0 { | 
|  | return nil | 
|  | } | 
|  | prs := make([]canonICMPv4ParamRecord, len(icp.Registries[id].Records)) | 
|  | sr := strings.NewReplacer( | 
|  | "Messages", "", | 
|  | "Message", "", | 
|  | "ICMP", "", | 
|  | "+", "P", | 
|  | "-", "", | 
|  | "/", "", | 
|  | ".", "", | 
|  | " ", "", | 
|  | ) | 
|  | for i, pr := range icp.Registries[id].Records { | 
|  | if strings.Contains(pr.Descr, "Reserved") || | 
|  | strings.Contains(pr.Descr, "Unassigned") || | 
|  | strings.Contains(pr.Descr, "Deprecated") || | 
|  | strings.Contains(pr.Descr, "Experiment") || | 
|  | strings.Contains(pr.Descr, "experiment") { | 
|  | continue | 
|  | } | 
|  | ss := strings.Split(pr.Descr, "\n") | 
|  | if len(ss) > 1 { | 
|  | prs[i].Descr = strings.Join(ss, " ") | 
|  | } else { | 
|  | prs[i].Descr = ss[0] | 
|  | } | 
|  | s := strings.TrimSpace(prs[i].Descr) | 
|  | prs[i].OrigDescr = s | 
|  | prs[i].Descr = sr.Replace(s) | 
|  | prs[i].Value, _ = strconv.Atoi(pr.Value) | 
|  | } | 
|  | return prs | 
|  | } |