github.com/Andyfoo/golang/x/net@v0.0.0-20190901054642-57c1bf301704/internal/iana/gen.go (about)

     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  // +build ignore
     6  
     7  //go:generate go run gen.go
     8  
     9  // This program generates internet protocol constants and tables by
    10  // reading IANA protocol registries.
    11  package main
    12  
    13  import (
    14  	"bytes"
    15  	"encoding/xml"
    16  	"fmt"
    17  	"go/format"
    18  	"io"
    19  	"io/ioutil"
    20  	"net/http"
    21  	"os"
    22  	"strconv"
    23  	"strings"
    24  )
    25  
    26  var registries = []struct {
    27  	url   string
    28  	parse func(io.Writer, io.Reader) error
    29  }{
    30  	{
    31  		"https://www.iana.org/assignments/dscp-registry/dscp-registry.xml",
    32  		parseDSCPRegistry,
    33  	},
    34  	{
    35  		"https://www.iana.org/assignments/protocol-numbers/protocol-numbers.xml",
    36  		parseProtocolNumbers,
    37  	},
    38  	{
    39  		"https://www.iana.org/assignments/address-family-numbers/address-family-numbers.xml",
    40  		parseAddrFamilyNumbers,
    41  	},
    42  }
    43  
    44  func main() {
    45  	var bb bytes.Buffer
    46  	fmt.Fprintf(&bb, "// go generate gen.go\n")
    47  	fmt.Fprintf(&bb, "// Code generated by the command above; DO NOT EDIT.\n\n")
    48  	fmt.Fprintf(&bb, "// Package iana provides protocol number resources managed by the Internet Assigned Numbers Authority (IANA).\n")
    49  	fmt.Fprintf(&bb, `package iana // import "github.com/Andyfoo/golang/x/net/internal/iana"`+"\n\n")
    50  	for _, r := range registries {
    51  		resp, err := http.Get(r.url)
    52  		if err != nil {
    53  			fmt.Fprintln(os.Stderr, err)
    54  			os.Exit(1)
    55  		}
    56  		defer resp.Body.Close()
    57  		if resp.StatusCode != http.StatusOK {
    58  			fmt.Fprintf(os.Stderr, "got HTTP status code %v for %v\n", resp.StatusCode, r.url)
    59  			os.Exit(1)
    60  		}
    61  		if err := r.parse(&bb, resp.Body); err != nil {
    62  			fmt.Fprintln(os.Stderr, err)
    63  			os.Exit(1)
    64  		}
    65  		fmt.Fprintf(&bb, "\n")
    66  	}
    67  	b, err := format.Source(bb.Bytes())
    68  	if err != nil {
    69  		fmt.Fprintln(os.Stderr, err)
    70  		os.Exit(1)
    71  	}
    72  	if err := ioutil.WriteFile("const.go", b, 0644); err != nil {
    73  		fmt.Fprintln(os.Stderr, err)
    74  		os.Exit(1)
    75  	}
    76  }
    77  
    78  func parseDSCPRegistry(w io.Writer, r io.Reader) error {
    79  	dec := xml.NewDecoder(r)
    80  	var dr dscpRegistry
    81  	if err := dec.Decode(&dr); err != nil {
    82  		return err
    83  	}
    84  	fmt.Fprintf(w, "// %s, Updated: %s\n", dr.Title, dr.Updated)
    85  	fmt.Fprintf(w, "const (\n")
    86  	for _, dr := range dr.escapeDSCP() {
    87  		fmt.Fprintf(w, "DiffServ%s = %#02x", dr.Name, dr.Value)
    88  		fmt.Fprintf(w, "// %s\n", dr.OrigName)
    89  	}
    90  	for _, er := range dr.escapeECN() {
    91  		fmt.Fprintf(w, "%s = %#02x", er.Descr, er.Value)
    92  		fmt.Fprintf(w, "// %s\n", er.OrigDescr)
    93  	}
    94  	fmt.Fprintf(w, ")\n")
    95  	return nil
    96  }
    97  
    98  type dscpRegistry struct {
    99  	XMLName    xml.Name `xml:"registry"`
   100  	Title      string   `xml:"title"`
   101  	Updated    string   `xml:"updated"`
   102  	Note       string   `xml:"note"`
   103  	Registries []struct {
   104  		Title      string `xml:"title"`
   105  		Registries []struct {
   106  			Title   string `xml:"title"`
   107  			Records []struct {
   108  				Name  string `xml:"name"`
   109  				Space string `xml:"space"`
   110  			} `xml:"record"`
   111  		} `xml:"registry"`
   112  		Records []struct {
   113  			Value string `xml:"value"`
   114  			Descr string `xml:"description"`
   115  		} `xml:"record"`
   116  	} `xml:"registry"`
   117  }
   118  
   119  type canonDSCPRecord struct {
   120  	OrigName string
   121  	Name     string
   122  	Value    int
   123  }
   124  
   125  func (drr *dscpRegistry) escapeDSCP() []canonDSCPRecord {
   126  	var drs []canonDSCPRecord
   127  	for _, preg := range drr.Registries {
   128  		if !strings.Contains(preg.Title, "Differentiated Services Field Codepoints") {
   129  			continue
   130  		}
   131  		for _, reg := range preg.Registries {
   132  			if !strings.Contains(reg.Title, "Pool 1 Codepoints") {
   133  				continue
   134  			}
   135  			drs = make([]canonDSCPRecord, len(reg.Records))
   136  			sr := strings.NewReplacer(
   137  				"+", "",
   138  				"-", "",
   139  				"/", "",
   140  				".", "",
   141  				" ", "",
   142  			)
   143  			for i, dr := range reg.Records {
   144  				s := strings.TrimSpace(dr.Name)
   145  				drs[i].OrigName = s
   146  				drs[i].Name = sr.Replace(s)
   147  				n, err := strconv.ParseUint(dr.Space, 2, 8)
   148  				if err != nil {
   149  					continue
   150  				}
   151  				drs[i].Value = int(n) << 2
   152  			}
   153  		}
   154  	}
   155  	return drs
   156  }
   157  
   158  type canonECNRecord struct {
   159  	OrigDescr string
   160  	Descr     string
   161  	Value     int
   162  }
   163  
   164  func (drr *dscpRegistry) escapeECN() []canonECNRecord {
   165  	var ers []canonECNRecord
   166  	for _, reg := range drr.Registries {
   167  		if !strings.Contains(reg.Title, "ECN Field") {
   168  			continue
   169  		}
   170  		ers = make([]canonECNRecord, len(reg.Records))
   171  		sr := strings.NewReplacer(
   172  			"Capable", "",
   173  			"Not-ECT", "",
   174  			"ECT(1)", "",
   175  			"ECT(0)", "",
   176  			"CE", "",
   177  			"(", "",
   178  			")", "",
   179  			"+", "",
   180  			"-", "",
   181  			"/", "",
   182  			".", "",
   183  			" ", "",
   184  		)
   185  		for i, er := range reg.Records {
   186  			s := strings.TrimSpace(er.Descr)
   187  			ers[i].OrigDescr = s
   188  			ss := strings.Split(s, " ")
   189  			if len(ss) > 1 {
   190  				ers[i].Descr = strings.Join(ss[1:], " ")
   191  			} else {
   192  				ers[i].Descr = ss[0]
   193  			}
   194  			ers[i].Descr = sr.Replace(er.Descr)
   195  			n, err := strconv.ParseUint(er.Value, 2, 8)
   196  			if err != nil {
   197  				continue
   198  			}
   199  			ers[i].Value = int(n)
   200  		}
   201  	}
   202  	return ers
   203  }
   204  
   205  func parseProtocolNumbers(w io.Writer, r io.Reader) error {
   206  	dec := xml.NewDecoder(r)
   207  	var pn protocolNumbers
   208  	if err := dec.Decode(&pn); err != nil {
   209  		return err
   210  	}
   211  	prs := pn.escape()
   212  	prs = append([]canonProtocolRecord{{
   213  		Name:  "IP",
   214  		Descr: "IPv4 encapsulation, pseudo protocol number",
   215  		Value: 0,
   216  	}}, prs...)
   217  	fmt.Fprintf(w, "// %s, Updated: %s\n", pn.Title, pn.Updated)
   218  	fmt.Fprintf(w, "const (\n")
   219  	for _, pr := range prs {
   220  		if pr.Name == "" {
   221  			continue
   222  		}
   223  		fmt.Fprintf(w, "Protocol%s = %d", pr.Name, pr.Value)
   224  		s := pr.Descr
   225  		if s == "" {
   226  			s = pr.OrigName
   227  		}
   228  		fmt.Fprintf(w, "// %s\n", s)
   229  	}
   230  	fmt.Fprintf(w, ")\n")
   231  	return nil
   232  }
   233  
   234  type protocolNumbers struct {
   235  	XMLName  xml.Name `xml:"registry"`
   236  	Title    string   `xml:"title"`
   237  	Updated  string   `xml:"updated"`
   238  	RegTitle string   `xml:"registry>title"`
   239  	Note     string   `xml:"registry>note"`
   240  	Records  []struct {
   241  		Value string `xml:"value"`
   242  		Name  string `xml:"name"`
   243  		Descr string `xml:"description"`
   244  	} `xml:"registry>record"`
   245  }
   246  
   247  type canonProtocolRecord struct {
   248  	OrigName string
   249  	Name     string
   250  	Descr    string
   251  	Value    int
   252  }
   253  
   254  func (pn *protocolNumbers) escape() []canonProtocolRecord {
   255  	prs := make([]canonProtocolRecord, len(pn.Records))
   256  	sr := strings.NewReplacer(
   257  		"-in-", "in",
   258  		"-within-", "within",
   259  		"-over-", "over",
   260  		"+", "P",
   261  		"-", "",
   262  		"/", "",
   263  		".", "",
   264  		" ", "",
   265  	)
   266  	for i, pr := range pn.Records {
   267  		if strings.Contains(pr.Name, "Deprecated") ||
   268  			strings.Contains(pr.Name, "deprecated") {
   269  			continue
   270  		}
   271  		prs[i].OrigName = pr.Name
   272  		s := strings.TrimSpace(pr.Name)
   273  		switch pr.Name {
   274  		case "ISIS over IPv4":
   275  			prs[i].Name = "ISIS"
   276  		case "manet":
   277  			prs[i].Name = "MANET"
   278  		default:
   279  			prs[i].Name = sr.Replace(s)
   280  		}
   281  		ss := strings.Split(pr.Descr, "\n")
   282  		for i := range ss {
   283  			ss[i] = strings.TrimSpace(ss[i])
   284  		}
   285  		if len(ss) > 1 {
   286  			prs[i].Descr = strings.Join(ss, " ")
   287  		} else {
   288  			prs[i].Descr = ss[0]
   289  		}
   290  		prs[i].Value, _ = strconv.Atoi(pr.Value)
   291  	}
   292  	return prs
   293  }
   294  
   295  func parseAddrFamilyNumbers(w io.Writer, r io.Reader) error {
   296  	dec := xml.NewDecoder(r)
   297  	var afn addrFamilylNumbers
   298  	if err := dec.Decode(&afn); err != nil {
   299  		return err
   300  	}
   301  	afrs := afn.escape()
   302  	fmt.Fprintf(w, "// %s, Updated: %s\n", afn.Title, afn.Updated)
   303  	fmt.Fprintf(w, "const (\n")
   304  	for _, afr := range afrs {
   305  		if afr.Name == "" {
   306  			continue
   307  		}
   308  		fmt.Fprintf(w, "AddrFamily%s = %d", afr.Name, afr.Value)
   309  		fmt.Fprintf(w, "// %s\n", afr.Descr)
   310  	}
   311  	fmt.Fprintf(w, ")\n")
   312  	return nil
   313  }
   314  
   315  type addrFamilylNumbers struct {
   316  	XMLName  xml.Name `xml:"registry"`
   317  	Title    string   `xml:"title"`
   318  	Updated  string   `xml:"updated"`
   319  	RegTitle string   `xml:"registry>title"`
   320  	Note     string   `xml:"registry>note"`
   321  	Records  []struct {
   322  		Value string `xml:"value"`
   323  		Descr string `xml:"description"`
   324  	} `xml:"registry>record"`
   325  }
   326  
   327  type canonAddrFamilyRecord struct {
   328  	Name  string
   329  	Descr string
   330  	Value int
   331  }
   332  
   333  func (afn *addrFamilylNumbers) escape() []canonAddrFamilyRecord {
   334  	afrs := make([]canonAddrFamilyRecord, len(afn.Records))
   335  	sr := strings.NewReplacer(
   336  		"IP version 4", "IPv4",
   337  		"IP version 6", "IPv6",
   338  		"Identifier", "ID",
   339  		"-", "",
   340  		"-", "",
   341  		"/", "",
   342  		".", "",
   343  		" ", "",
   344  	)
   345  	for i, afr := range afn.Records {
   346  		if strings.Contains(afr.Descr, "Unassigned") ||
   347  			strings.Contains(afr.Descr, "Reserved") {
   348  			continue
   349  		}
   350  		afrs[i].Descr = afr.Descr
   351  		s := strings.TrimSpace(afr.Descr)
   352  		switch s {
   353  		case "IP (IP version 4)":
   354  			afrs[i].Name = "IPv4"
   355  		case "IP6 (IP version 6)":
   356  			afrs[i].Name = "IPv6"
   357  		case "AFI for L2VPN information":
   358  			afrs[i].Name = "L2VPN"
   359  		case "E.164 with NSAP format subaddress":
   360  			afrs[i].Name = "E164withSubaddress"
   361  		case "MT IP: Multi-Topology IP version 4":
   362  			afrs[i].Name = "MTIPv4"
   363  		case "MAC/24":
   364  			afrs[i].Name = "MACFinal24bits"
   365  		case "MAC/40":
   366  			afrs[i].Name = "MACFinal40bits"
   367  		case "IPv6/64":
   368  			afrs[i].Name = "IPv6Initial64bits"
   369  		default:
   370  			n := strings.Index(s, "(")
   371  			if n > 0 {
   372  				s = s[:n]
   373  			}
   374  			n = strings.Index(s, ":")
   375  			if n > 0 {
   376  				s = s[:n]
   377  			}
   378  			afrs[i].Name = sr.Replace(s)
   379  		}
   380  		afrs[i].Value, _ = strconv.Atoi(afr.Value)
   381  	}
   382  	return afrs
   383  }