blob: 673065f6569d20f99b5b645ef5f52f39dc16f638 [file] [log] [blame]
Mikio Hara8108b4b2013-06-07 14:52:58 +09001// 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// +build ignore
6
7// This program generates internet protocol constatns and tables by
8// reading IANA protocol registries.
9//
10// Usage of this program:
11// go run gen.go > iana.go
12package main
13
14import (
15 "bytes"
16 "encoding/xml"
17 "fmt"
18 "go/format"
19 "io"
20 "net/http"
21 "os"
22 "strconv"
23 "strings"
24)
25
26var registries = []struct {
27 url string
28 parse func(io.Writer, io.Reader) error
29}{
30 {
31 "http://www.iana.org/assignments/icmp-parameters",
32 parseICMPv4Parameters,
33 },
34 {
35 "http://www.iana.org/assignments/protocol-numbers/protocol-numbers.xml",
36 parseProtocolNumbers,
37 },
38}
39
40func main() {
41 var bb bytes.Buffer
42 fmt.Fprintf(&bb, "// go run gen.go\n")
43 fmt.Fprintf(&bb, "// GENERATED BY THE COMMAND ABOVE; DO NOT EDIT\n\n")
44 fmt.Fprintf(&bb, "package ipv4\n\n")
45 for _, r := range registries {
46 resp, err := http.Get(r.url)
47 if err != nil {
48 fmt.Fprintln(os.Stderr, err)
49 os.Exit(1)
50 }
51 defer resp.Body.Close()
52 if resp.StatusCode != http.StatusOK {
53 fmt.Fprintf(os.Stderr, "got HTTP status code %v for %v\n", resp.StatusCode, r.url)
54 os.Exit(1)
55 }
56 if err := r.parse(&bb, resp.Body); err != nil {
57 fmt.Fprintln(os.Stderr, err)
58 os.Exit(1)
59 }
60 fmt.Fprintf(&bb, "\n")
61 }
62 b, err := format.Source(bb.Bytes())
63 if err != nil {
64 fmt.Fprintln(os.Stderr, err)
65 os.Exit(1)
66 }
67 os.Stdout.Write(b)
68}
69
70func parseICMPv4Parameters(w io.Writer, r io.Reader) error {
71 dec := xml.NewDecoder(r)
72 var icp icmpv4Parameters
73 if err := dec.Decode(&icp); err != nil {
74 return err
75 }
76 prs := icp.escape(0)
77 fmt.Fprintf(w, "// %s, Updated: %s\n", icp.Title, icp.Updated)
78 fmt.Fprintf(w, "const (\n")
79 for _, pr := range prs {
80 if pr.Descr == "" {
81 continue
82 }
83 fmt.Fprintf(w, "ICMPType%s ICMPType = %d", pr.Descr, pr.Value)
84 fmt.Fprintf(w, "// %s\n", pr.OrigDescr)
85 }
86 fmt.Fprintf(w, ")\n\n")
87 fmt.Fprintf(w, "// %s, Updated: %s\n", icp.Title, icp.Updated)
88 fmt.Fprintf(w, "var icmpTypes = map[ICMPType]string{\n")
89 for _, pr := range prs {
90 if pr.Descr == "" {
91 continue
92 }
93 fmt.Fprintf(w, "%d: %q,\n", pr.Value, strings.ToLower(pr.OrigDescr))
94 }
95 fmt.Fprintf(w, "}\n")
96 return nil
97}
98
99type icmpv4Parameters struct {
100 XMLName xml.Name `xml:"registry"`
101 Title string `xml:"title"`
102 Updated string `xml:"updated"`
103 Registries []icmpv4ParamRegistry `xml:"registry"`
104}
105
106type icmpv4ParamRegistry struct {
107 Title string `xml:"title"`
108 Records []icmpv4ParamRecord `xml:"record"`
109}
110
111type icmpv4ParamRecord struct {
112 Value string `xml:"value"`
113 Descr string `xml:"description"`
114}
115
116type canonICMPv4ParamRecord struct {
117 OrigDescr string
118 Descr string
119 Value int
120}
121
122func (icp *icmpv4Parameters) escape(id int) []canonICMPv4ParamRecord {
123 prs := make([]canonICMPv4ParamRecord, len(icp.Registries[id].Records))
124 sr := strings.NewReplacer(
125 "Messages", "",
126 "Message", "",
127 "ICMP", "",
128 "+", "P",
129 "-", "",
130 "/", "",
131 ".", "",
132 " ", "",
133 )
134 for i, pr := range icp.Registries[id].Records {
135 if strings.Contains(pr.Descr, "Reserved") ||
136 strings.Contains(pr.Descr, "Unassigned") ||
137 strings.Contains(pr.Descr, "Deprecated") ||
138 strings.Contains(pr.Descr, "Experiment") ||
139 strings.Contains(pr.Descr, "experiment") {
140 continue
141 }
142 ss := strings.Split(pr.Descr, "\n")
143 if len(ss) > 1 {
144 prs[i].Descr = strings.Join(ss, " ")
145 } else {
146 prs[i].Descr = ss[0]
147 }
148 s := strings.TrimSpace(prs[i].Descr)
149 prs[i].OrigDescr = s
150 prs[i].Descr = sr.Replace(s)
151 prs[i].Value, _ = strconv.Atoi(pr.Value)
152 }
153 return prs
154}
155
156func parseProtocolNumbers(w io.Writer, r io.Reader) error {
157 dec := xml.NewDecoder(r)
158 var pn protocolNumbers
159 if err := dec.Decode(&pn); err != nil {
160 return err
161 }
162 prs := pn.escape()
163 prs = append([]canonProtocolRecord{{
164 Name: "IP",
165 Descr: "IPv4 encapsulation, pseudo protocol number",
166 Value: 0,
167 }}, prs...)
168 fmt.Fprintf(w, "// %s, Updated: %s\n", pn.Title, pn.Updated)
169 fmt.Fprintf(w, "const (\n")
170 for _, pr := range prs {
171 if pr.Name == "" {
172 continue
173 }
174 fmt.Fprintf(w, "ianaProtocol%s = %d", pr.Name, pr.Value)
175 s := pr.Descr
176 if s == "" {
177 s = pr.OrigName
178 }
179 fmt.Fprintf(w, "// %s\n", s)
180 }
181 fmt.Fprintf(w, ")\n")
182 return nil
183}
184
185type protocolNumbers struct {
186 XMLName xml.Name `xml:"registry"`
187 Title string `xml:"title"`
188 Updated string `xml:"updated"`
189 RegTitle string `xml:"registry>title"`
190 Note string `xml:"registry>note"`
191 Records []protocolRecord `xml:"registry>record"`
192}
193
194type protocolRecord struct {
195 Value string `xml:"value"`
196 Name string `xml:"name"`
197 Descr string `xml:"description"`
198}
199
200type canonProtocolRecord struct {
201 OrigName string
202 Name string
203 Descr string
204 Value int
205}
206
207func (pn *protocolNumbers) escape() []canonProtocolRecord {
208 prs := make([]canonProtocolRecord, len(pn.Records))
209 sr := strings.NewReplacer(
210 "-in-", "in",
211 "-within-", "within",
212 "-over-", "over",
213 "+", "P",
214 "-", "",
215 "/", "",
216 ".", "",
217 " ", "",
218 )
219 for i, pr := range pn.Records {
220 prs[i].OrigName = pr.Name
221 s := strings.TrimSpace(pr.Name)
222 switch pr.Name {
223 case "ISIS over IPv4":
224 prs[i].Name = "ISIS"
225 case "manet":
226 prs[i].Name = "MANET"
227 default:
228 prs[i].Name = sr.Replace(s)
229 }
230 ss := strings.Split(pr.Descr, "\n")
231 for i := range ss {
232 ss[i] = strings.TrimSpace(ss[i])
233 }
234 if len(ss) > 1 {
235 prs[i].Descr = strings.Join(ss, " ")
236 } else {
237 prs[i].Descr = ss[0]
238 }
239 prs[i].Value, _ = strconv.Atoi(pr.Value)
240 }
241 return prs
242}