gost_software/vendor/github.com/isofew/go-stun/stun/gen.go
2018-05-17 13:14:45 +01:00

204 lines
5.2 KiB
Go

//+build ignore
//go:generate go run gen.go
// This program generates STUN parameters: methods, attributes and error codes by reading IANA registry.
package main
import (
"bytes"
"encoding/xml"
"fmt"
"go/format"
"io/ioutil"
"net/http"
"os"
"regexp"
"strings"
"unicode"
"unicode/utf8"
)
func main() {
err := generate("http://www.iana.org/assignments/stun-parameters/stun-parameters.xml", "registry.go")
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}
func loadRegistry(url string) (*Registry, error) {
resp, err := http.Get(url)
if err != nil {
return nil, err
}
defer resp.Body.Close()
b, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
r := &Registry{}
err = xml.Unmarshal(b, r)
if err != nil {
return nil, err
}
name := regexp.MustCompile("^([\\w-]+)(.*was\\s+([\\w-]+))?")
for _, reg := range r.Registry {
for _, r := range reg.Records {
m := name.FindStringSubmatch(r.Description)
if m != nil {
r.Value = strings.ToLower(r.Value)
r.Name = m[1]
if r.Name == "Reserved" && m[3] != "" {
r.Name = m[3]
r.Deprecated = true
}
r.Ref.Data = strings.TrimPrefix(r.Ref.Data, "rfc")
r.Ref.Data = strings.TrimPrefix(r.Ref.Data, "RFC-")
}
}
}
return r, nil
}
type Record struct {
Value string `xml:"value"`
Description string `xml:"description"`
Name string
Deprecated bool
Ref struct {
Type string `xml:"type,attr"`
Data string `xml:"data,attr"`
} `xml:"xref"`
}
func (r *Record) IsValid() bool {
return r.Name != "Reserved" && r.Name != "Unassigned" && (r.Ref.Type == "rfc" || r.Ref.Type == "draft")
}
type Registry struct {
Title string `xml:"title"`
Updated string `xml:"updated"`
Registry []struct {
Id string `xml:"id,attr"`
Records []*Record `xml:"record"`
} `xml:"registry"`
}
func (reg *Registry) GetRecords(id string) []*Record {
for _, it := range reg.Registry {
if it.Id == id {
return it.Records
}
}
return nil
}
func generate(url, file string) error {
reg, err := loadRegistry(url)
if err != nil {
return err
}
b := &bytes.Buffer{}
fmt.Fprintf(b, "package stun\n\n")
fmt.Fprintf(b, "// Do not edit. This file is generated by 'go generate gen.go'\n")
fmt.Fprintf(b, "// This file provides STUN parameters managed by the Internet Assigned Numbers Authority (IANA).\n")
fmt.Fprintf(b, "// %s, Updated: %s.\n\n", reg.Title, reg.Updated)
genMethods(reg.GetRecords("stun-parameters-2"), b)
genAttributes(reg.GetRecords("stun-parameters-4"), b)
genErrors(reg.GetRecords("stun-parameters-6"), b)
src, err := format.Source(b.Bytes())
if err != nil {
return err
}
if err = ioutil.WriteFile(file, src, 0644); err != nil {
return err
}
return nil
}
func genMethods(records []*Record, b *bytes.Buffer) error {
c, m := &bytes.Buffer{}, &bytes.Buffer{}
ref := ""
for _, it := range records {
if it.IsValid() {
if ref == it.Ref.Data {
fmt.Fprintf(c, "Method%v uint16 = %s\n", it.Name, it.Value)
} else {
ref = it.Ref.Data
fmt.Fprintf(c, "Method%v uint16 = %s // RFC %s\n", it.Name, it.Value, ref)
}
fmt.Fprintf(m, "Method%v: \"%s\",\n", it.Name, it.Name)
}
}
fmt.Fprintf(b, "// STUN methods.\n")
fmt.Fprintf(b, "const (\n%s)\n", c.Bytes())
fmt.Fprintf(b, "// STUN method names.\n")
fmt.Fprintf(b, "var methodNames = map[uint16]string{\n%s}\n", m.Bytes())
return nil
}
func genAttributes(records []*Record, b *bytes.Buffer) error {
c, d, m := &bytes.Buffer{}, &bytes.Buffer{}, &bytes.Buffer{}
ref := ""
for _, it := range records {
if it.IsValid() {
a := c
if it.Deprecated {
a = d
}
v := strings.Replace(it.Name, "_", "-", -1)
n := strings.Replace(v, "-", " ", -1)
parts := strings.Fields(n)
for i, s := range parts {
switch s {
case "", "ID":
default:
r, n := utf8.DecodeRuneInString(s)
s = string(unicode.ToUpper(r)) + strings.ToLower(s[n:])
}
parts[i] = s
}
n = strings.Join(parts, "")
if ref == it.Ref.Data || it.Deprecated {
fmt.Fprintf(a, "Attr%v uint16 = %s\n", n, it.Value)
} else {
ref = it.Ref.Data
fmt.Fprintf(a, "Attr%v uint16 = %s // RFC %s\n", n, it.Value, ref)
}
fmt.Fprintf(m, "Attr%v: \"%s\",\n", n, v)
}
}
fmt.Fprintf(b, "// STUN attributes.\n")
fmt.Fprintf(b, "const (\n%s)\n", c.Bytes())
fmt.Fprintf(b, "// Deprecated: For backwards compatibility only.\n")
fmt.Fprintf(b, "const (\n%s)\n", d.Bytes())
fmt.Fprintf(b, "// STUN attribute names.\n")
fmt.Fprintf(b, "var attrNames = map[uint16]string{\n%s}\n", m.Bytes())
return nil
}
func genErrors(records []*Record, b *bytes.Buffer) error {
c, m := &bytes.Buffer{}, &bytes.Buffer{}
ref := ""
for _, it := range records {
if it.IsValid() {
n := strings.Replace(strings.Title(it.Description), " ", "", -1)
if ref == it.Ref.Data {
fmt.Fprintf(c, "Code%v int = %s\n", n, it.Value)
} else {
ref = it.Ref.Data
fmt.Fprintf(c, "Code%v int = %s // RFC %s\n", n, it.Value, ref)
}
fmt.Fprintf(m, "Code%v: \"%s\",\n", n, it.Description)
}
}
fmt.Fprintf(b, "// STUN error codes.\n")
fmt.Fprintf(b, "const (\n%s)\n", c.Bytes())
fmt.Fprintf(b, "// STUN error texts.\n")
fmt.Fprintf(b, "var errorText = map[int]string{\n%s}\n", m.Bytes())
return nil
}