commit c2edff6142980892930d56b4d97f7aa4a0650f4f
parent 0da91c7d665bcbadeb67e22762a4bcb818e1ca4f
Author: Oliver Lowe <o@olowe.co>
Date: Fri, 5 Jul 2024 14:12:36 +1000
sdp: handle parsing connection info
This is not stored in the Session struct yet. The parsing code feels
untidy, but we can come back to that later. We have tests so it should
be easy enough to refactor.
Diffstat:
2 files changed, 77 insertions(+), 0 deletions(-)
diff --git a/sdp/sdp.go b/sdp/sdp.go
@@ -272,3 +272,54 @@ func parseMedia(s string) (Media, error) {
m.Format = fields[3:]
return m, nil
}
+
+type ConnInfo struct {
+ Type string // TODO(otl): only "IP4", "IP6" valid... new int type?
+ Address string // IPv4, IPv6 literal or a hostname
+ TTL int // time to live
+ Count int // number of addresses after Address
+}
+
+func parseConnInfo(s string) (ConnInfo, error) {
+ fields := strings.Fields(s)
+ if len(fields) != 3 {
+ return ConnInfo{}, fmt.Errorf("expected %d fields, got %d", 3, len(fields))
+ }
+ if fields[0] != "IN" {
+ return ConnInfo{}, fmt.Errorf("unsupported class %q, expected IN", fields[0])
+ }
+
+ conn := ConnInfo{Type: fields[1]}
+ if fields[1] != "IP4" && fields[1] != "IP6" {
+ return conn, fmt.Errorf("unsupported network type %s", fields[2])
+ }
+ conn.Type = fields[1]
+ addr := strings.Split(fields[2], "/")
+ conn.Address = addr[0]
+ if len(addr) == 1 {
+ return conn, nil
+ }
+
+ subfields := make([]int, len(addr[1:]))
+ for i := range subfields {
+ var err error
+ subfields[i], err = strconv.Atoi(addr[i+1])
+ if err != nil {
+ return conn, fmt.Errorf("parse address subfield %d: %w", i, err)
+ }
+ }
+
+ if conn.Type == "IP4" && len(subfields) == 2 {
+ conn.TTL = subfields[0]
+ conn.Count = subfields[1]
+ } else if conn.Type == "IP4" && len(subfields) == 1 {
+ conn.TTL = subfields[0]
+ }
+
+ if conn.Type == "IP6" && len(subfields) > 1 {
+ return conn, fmt.Errorf("parse address: only 1 subfield allowed, read %d", len(subfields))
+ } else if conn.Type == "IP6" && len(subfields) == 1 {
+ conn.Count = subfields[0]
+ }
+ return conn, nil
+}
diff --git a/sdp/sdp_test.go b/sdp/sdp_test.go
@@ -101,3 +101,29 @@ func TestBandwidth(t *testing.T) {
})
}
}
+
+func TestConnInfo(t *testing.T) {
+ var cases = []struct {
+ name string
+ line string
+ want ConnInfo
+ }{
+ {"ipv4", "IN IP4 192.0.2.1", ConnInfo{"IP4", "192.0.2.1", 0, 0}},
+ {"ipv4 ttl", "IN IP4 233.252.0.1/127", ConnInfo{"IP4", "233.252.0.1", 127, 0}},
+ {"ipv4 ttl count", "IN IP4 233.252.0.1/127/3", ConnInfo{"IP4", "233.252.0.1", 127, 3}},
+ {"ipv6", "IN IP6 2001:db8::1", ConnInfo{"IP6", "2001:db8::1", 0, 0}},
+ {"ipv6 count", "IN IP6 ff00::db8:0:101/3", ConnInfo{"IP6", "ff00::db8:0:101", 0, 3}},
+ }
+
+ for _, tt := range cases {
+ t.Run(tt.name, func(t *testing.T) {
+ got, err := parseConnInfo(tt.line)
+ if err != nil {
+ t.Fatalf("parse %s: %v", tt.line, err)
+ }
+ if !reflect.DeepEqual(tt.want, got) {
+ t.Errorf("parseConnInfo(%q) = %+v, want %+v", tt.line, got, tt.want)
+ }
+ })
+ }
+}