1// Copyright 2013 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5//go:build ignore
6// +build ignore
7
8//go:generate go run gen.go
9
10// This program generates system adaptation constants and types,
11// internet protocol constants and tables by reading template files
12// and IANA protocol registries.
13package main
14
15import (
16	"bytes"
17	"encoding/xml"
18	"fmt"
19	"go/format"
20	"io"
21	"io/ioutil"
22	"net/http"
23	"os"
24	"os/exec"
25	"runtime"
26	"strconv"
27	"strings"
28)
29
30func main() {
31	if err := genzsys(); err != nil {
32		fmt.Fprintln(os.Stderr, err)
33		os.Exit(1)
34	}
35	if err := geniana(); err != nil {
36		fmt.Fprintln(os.Stderr, err)
37		os.Exit(1)
38	}
39}
40
41func genzsys() error {
42	defs := "defs_" + runtime.GOOS + ".go"
43	f, err := os.Open(defs)
44	if err != nil {
45		if os.IsNotExist(err) {
46			return nil
47		}
48		return err
49	}
50	f.Close()
51	cmd := exec.Command("go", "tool", "cgo", "-godefs", defs)
52	b, err := cmd.Output()
53	if err != nil {
54		return err
55	}
56	b, err = format.Source(b)
57	if err != nil {
58		return err
59	}
60	zsys := "zsys_" + runtime.GOOS + ".go"
61	switch runtime.GOOS {
62	case "freebsd", "linux":
63		zsys = "zsys_" + runtime.GOOS + "_" + runtime.GOARCH + ".go"
64	}
65	if err := ioutil.WriteFile(zsys, b, 0644); err != nil {
66		return err
67	}
68	return nil
69}
70
71var registries = []struct {
72	url   string
73	parse func(io.Writer, io.Reader) error
74}{
75	{
76		"https://www.iana.org/assignments/icmp-parameters/icmp-parameters.xml",
77		parseICMPv4Parameters,
78	},
79}
80
81func geniana() error {
82	var bb bytes.Buffer
83	fmt.Fprintf(&bb, "// go generate gen.go\n")
84	fmt.Fprintf(&bb, "// Code generated by the command above; DO NOT EDIT.\n\n")
85	fmt.Fprintf(&bb, "package ipv4\n\n")
86	for _, r := range registries {
87		resp, err := http.Get(r.url)
88		if err != nil {
89			return err
90		}
91		defer resp.Body.Close()
92		if resp.StatusCode != http.StatusOK {
93			return fmt.Errorf("got HTTP status code %v for %v\n", resp.StatusCode, r.url)
94		}
95		if err := r.parse(&bb, resp.Body); err != nil {
96			return err
97		}
98		fmt.Fprintf(&bb, "\n")
99	}
100	b, err := format.Source(bb.Bytes())
101	if err != nil {
102		return err
103	}
104	if err := ioutil.WriteFile("iana.go", b, 0644); err != nil {
105		return err
106	}
107	return nil
108}
109
110func parseICMPv4Parameters(w io.Writer, r io.Reader) error {
111	dec := xml.NewDecoder(r)
112	var icp icmpv4Parameters
113	if err := dec.Decode(&icp); err != nil {
114		return err
115	}
116	prs := icp.escape()
117	fmt.Fprintf(w, "// %s, Updated: %s\n", icp.Title, icp.Updated)
118	fmt.Fprintf(w, "const (\n")
119	for _, pr := range prs {
120		if pr.Descr == "" {
121			continue
122		}
123		fmt.Fprintf(w, "ICMPType%s ICMPType = %d", pr.Descr, pr.Value)
124		fmt.Fprintf(w, "// %s\n", pr.OrigDescr)
125	}
126	fmt.Fprintf(w, ")\n\n")
127	fmt.Fprintf(w, "// %s, Updated: %s\n", icp.Title, icp.Updated)
128	fmt.Fprintf(w, "var icmpTypes = map[ICMPType]string{\n")
129	for _, pr := range prs {
130		if pr.Descr == "" {
131			continue
132		}
133		fmt.Fprintf(w, "%d: %q,\n", pr.Value, strings.ToLower(pr.OrigDescr))
134	}
135	fmt.Fprintf(w, "}\n")
136	return nil
137}
138
139type icmpv4Parameters struct {
140	XMLName    xml.Name `xml:"registry"`
141	Title      string   `xml:"title"`
142	Updated    string   `xml:"updated"`
143	Registries []struct {
144		Title   string `xml:"title"`
145		Records []struct {
146			Value string `xml:"value"`
147			Descr string `xml:"description"`
148		} `xml:"record"`
149	} `xml:"registry"`
150}
151
152type canonICMPv4ParamRecord struct {
153	OrigDescr string
154	Descr     string
155	Value     int
156}
157
158func (icp *icmpv4Parameters) escape() []canonICMPv4ParamRecord {
159	id := -1
160	for i, r := range icp.Registries {
161		if strings.Contains(r.Title, "Type") || strings.Contains(r.Title, "type") {
162			id = i
163			break
164		}
165	}
166	if id < 0 {
167		return nil
168	}
169	prs := make([]canonICMPv4ParamRecord, len(icp.Registries[id].Records))
170	sr := strings.NewReplacer(
171		"Messages", "",
172		"Message", "",
173		"ICMP", "",
174		"+", "P",
175		"-", "",
176		"/", "",
177		".", "",
178		" ", "",
179	)
180	for i, pr := range icp.Registries[id].Records {
181		if strings.Contains(pr.Descr, "Reserved") ||
182			strings.Contains(pr.Descr, "Unassigned") ||
183			strings.Contains(pr.Descr, "Deprecated") ||
184			strings.Contains(pr.Descr, "Experiment") ||
185			strings.Contains(pr.Descr, "experiment") {
186			continue
187		}
188		ss := strings.Split(pr.Descr, "\n")
189		if len(ss) > 1 {
190			prs[i].Descr = strings.Join(ss, " ")
191		} else {
192			prs[i].Descr = ss[0]
193		}
194		s := strings.TrimSpace(prs[i].Descr)
195		prs[i].OrigDescr = s
196		prs[i].Descr = sr.Replace(s)
197		prs[i].Value, _ = strconv.Atoi(pr.Value)
198	}
199	return prs
200}
201