Browse Source

Use linked lists for parameters.

pull/2/head
Justine Alexandra Roberts Tunney 11 years ago
parent
commit
556208ab65
21 changed files with 700 additions and 807 deletions
  1. +4
    -4
      example/echo/echo_test.go
  2. +15
    -18
      example/options/options_test.go
  3. +5
    -5
      sip/addr.go
  4. +10
    -30
      sip/addr_test.go
  5. +4
    -4
      sip/dialog.go
  6. +1
    -1
      sip/msg.go
  7. +345
    -363
      sip/msg_parse.go
  8. +69
    -52
      sip/msg_test.go
  9. +39
    -0
      sip/param.go
  10. +0
    -63
      sip/params.go
  11. +3
    -3
      sip/receiver.go
  12. +8
    -10
      sip/route.go
  13. +2
    -8
      sip/sip.rl
  14. +1
    -1
      sip/transport.go
  15. +11
    -49
      sip/uri.go
  16. +83
    -163
      sip/uri_parse.go
  17. +2
    -8
      sip/uri_parse.rl
  18. +6
    -17
      sip/uri_test.go
  19. +44
    -0
      sip/uriheader.go
  20. +40
    -0
      sip/uriparam.go
  21. +8
    -8
      sip/via.go

+ 4
- 4
example/echo/echo_test.go View File

@ -177,9 +177,9 @@ func TestCallToEchoApp(t *testing.T) {
Port: uint16(raddr.Port),
},
Via: &sip.Via{
Host: laddr.IP.String(),
Port: uint16(laddr.Port),
Params: sip.Params{"branch": util.GenerateBranch()},
Host: laddr.IP.String(),
Port: uint16(laddr.Port),
Param: &sip.Param{"branch", util.GenerateBranch(), nil},
},
From: &sip.Addr{
Display: "Echo Test",
@ -188,7 +188,7 @@ func TestCallToEchoApp(t *testing.T) {
Host: laddr.IP.String(),
Port: uint16(laddr.Port),
},
Params: sip.Params{"tag": util.GenerateTag()},
Param: &sip.Param{"tag", util.GenerateTag(), nil},
},
To: &sip.Addr{
Uri: &sip.URI{


+ 15
- 18
example/options/options_test.go View File

@ -7,7 +7,6 @@ import (
"github.com/jart/gosip/sip"
"github.com/jart/gosip/util"
"net"
"reflect"
"testing"
"time"
)
@ -27,6 +26,8 @@ func TestOptions(t *testing.T) {
CallID: util.GenerateCallID(),
Method: "OPTIONS",
CSeqMethod: "OPTIONS",
Accept: "application/sdp",
UserAgent: "pokémon/1.o",
Request: &sip.URI{
Scheme: "sip",
User: "echo",
@ -34,11 +35,11 @@ func TestOptions(t *testing.T) {
Port: uint16(raddr.Port),
},
Via: &sip.Via{
Version: "2.0",
Proto: "UDP",
Host: laddr.IP.String(),
Port: uint16(laddr.Port),
Params: sip.Params{"branch": util.GenerateBranch()},
Version: "2.0",
Protocol: "UDP",
Host: laddr.IP.String(),
Port: uint16(laddr.Port),
Param: &sip.Param{"branch", util.GenerateBranch(), nil},
},
Contact: &sip.Addr{
Uri: &sip.URI{
@ -52,7 +53,7 @@ func TestOptions(t *testing.T) {
Host: "justinetunney.com",
Port: 5060,
},
Params: sip.Params{"tag": util.GenerateTag()},
Param: &sip.Param{"tag", util.GenerateTag(), nil},
},
To: &sip.Addr{
Uri: &sip.URI{
@ -60,10 +61,6 @@ func TestOptions(t *testing.T) {
Port: uint16(raddr.Port),
},
},
Headers: map[string]string{
"Accept": "application/sdp",
"User-Agent": "pokémon/1.o",
},
}
var b bytes.Buffer
@ -95,14 +92,14 @@ func TestOptions(t *testing.T) {
if options.CSeq != msg.CSeq || options.CSeqMethod != msg.CSeqMethod {
t.Error("CSeq didnt match")
}
if !reflect.DeepEqual(options.From, msg.From) {
t.Error("From headers didn't match:\n%#v\n%#v", options.From, msg.From)
if options.From.String() != msg.From.String() {
t.Errorf("From headers didn't match:\n%s\n%s\n\n%s", options.From, msg.From, memory[0:amt])
}
if _, ok := msg.To.Params["tag"]; !ok {
t.Error("Remote UA didnt tag To header")
if msg.To.Param.Get("tag") == nil {
t.Errorf("Remote UA didnt tag To header:\n%s\n\n%s", msg.To, memory[0:amt])
}
msg.To.Params = nil
if !reflect.DeepEqual(options.To, msg.To) {
t.Error("To mismatch:\n%#v\n%#v", options.To, msg.To)
msg.To.Param = nil
if options.To.String() != msg.To.String() {
t.Errorf("To headers didn't match:\n%s\n%s\n\n%s", options.To, msg.To, memory[0:amt])
}
}

+ 5
- 5
sip/addr.go View File

@ -27,7 +27,7 @@ import (
type Addr struct {
Uri *URI // never nil
Display string // blank if not specified
Params Params // these look like ;key=lol;rport;key=wut
Param *Param // these look like ;key=lol;rport;key=wut
Next *Addr // for comma separated lists of addresses
}
@ -49,7 +49,7 @@ func ParseAddrBytes(s []byte) (addr *Addr, err error) {
func (addr *Addr) String() string {
if addr == nil {
return "<nil>"
return ""
}
var b bytes.Buffer
addr.Append(&b)
@ -66,7 +66,7 @@ func (addr *Addr) Or(other *Addr) *Addr {
// Sets newly generated tag ID and returns self.
func (addr *Addr) Tag() *Addr {
addr.Params["tag"] = util.GenerateTag()
addr.Param = &Param{"tag", util.GenerateTag(), addr.Param}
return addr
}
@ -79,7 +79,7 @@ func (addr *Addr) Append(b *bytes.Buffer) error {
b.WriteByte('<')
addr.Uri.Append(b)
b.WriteByte('>')
addr.Params.AppendQuoted(b)
addr.Param.Append(b)
if addr.Next != nil {
b.WriteByte(',')
b.WriteByte(' ')
@ -95,7 +95,7 @@ func (addr *Addr) Copy() *Addr {
}
res := new(Addr)
res.Uri = addr.Uri.Copy()
res.Params = addr.Params.Copy()
res.Param = addr.Param
res.Next = addr.Next.Copy()
return res
}


+ 10
- 30
sip/addr_test.go View File

@ -35,9 +35,7 @@ var addrTests = []addrTest{
Scheme: "sip",
Host: "pokemon.net",
},
Params: sip.Params{
"tag": "deadbeef",
},
Param: &sip.Param{"tag", "deadbeef", nil},
},
},
@ -50,9 +48,7 @@ var addrTests = []addrTest{
Scheme: "sip",
Host: "pokemon.net",
},
Params: sip.Params{
"tag": "deadbeef",
},
Param: &sip.Param{"tag", "deadbeef", nil},
},
},
@ -65,9 +61,7 @@ var addrTests = []addrTest{
Scheme: "sip",
Host: "pokemon.net",
},
Params: sip.Params{
"tag": "deadbeef",
},
Param: &sip.Param{"tag", "deadbeef", nil},
},
},
@ -80,9 +74,7 @@ var addrTests = []addrTest{
Scheme: "sip",
Host: "pokemon.net",
},
Params: sip.Params{
"tag": "deadbeef",
},
Param: &sip.Param{"tag", "deadbeef", nil},
},
},
@ -94,9 +86,7 @@ var addrTests = []addrTest{
Scheme: "sip",
Host: "pokemon.net",
},
Params: sip.Params{
"tag": "\"deadbeef\"",
},
Param: &sip.Param{"tag", "\"deadbeef\"", nil},
},
},
@ -108,9 +98,7 @@ var addrTests = []addrTest{
Scheme: "sip",
User: "brave",
Host: "toaster.net",
Params: sip.Params{
"isup-oli": "29",
},
Param: &sip.URIParam{"isup-oli", "29", nil},
},
},
},
@ -123,13 +111,9 @@ var addrTests = []addrTest{
Scheme: "sip",
User: "brave",
Host: "toaster.net",
Params: sip.Params{
"isup-oli": "29",
},
},
Params: sip.Params{
"tag": "deadbeef",
Param: &sip.URIParam{"isup-oli", "29", nil},
},
Param: &sip.Param{"tag", "deadbeef", nil},
},
},
@ -182,13 +166,9 @@ var addrTests = []addrTest{
Scheme: "sip",
User: "jart",
Host: "google.com",
Params: sip.Params{
"isup-oli": "29",
},
},
Params: sip.Params{
"tag": "deadbeef",
Param: &sip.URIParam{"isup-oli", "29", nil},
},
Param: &sip.Param{"tag", "deadbeef", nil},
},
},
}


+ 4
- 4
sip/dialog.go View File

@ -214,9 +214,9 @@ func (dls *dialogState) populate(msg *Msg) {
lhost := laddr.IP.String()
lport := uint16(laddr.Port)
msg.Via = &Via{
Host: lhost,
Port: lport,
Params: Params{"branch": util.GenerateBranch()},
Host: lhost,
Port: lport,
Param: &Param{"branch", util.GenerateBranch(), nil},
}
if msg.Contact == nil {
if dls.csock != nil {
@ -227,7 +227,7 @@ func (dls *dialogState) populate(msg *Msg) {
Scheme: "sip",
Host: lhost,
Port: lport,
Params: Params{"transport": "udp"},
Param: &URIParam{"transport", "udp", nil},
},
}
}


+ 1
- 1
sip/msg.go View File

@ -461,7 +461,7 @@ func (msg *Msg) Append(b *bytes.Buffer) error {
payload := msg.Payload.Data()
b.WriteString("Content-Length: ")
b.WriteString(strconv.Itoa(len(payload)))
b.WriteString("\r\n\n\n")
b.WriteString("\r\n\r\n")
b.Write(payload)
} else {
b.WriteString("Content-Length: 0\r\n\r\n")


+ 345
- 363
sip/msg_parse.go
File diff suppressed because it is too large
View File


+ 69
- 52
sip/msg_test.go View File

@ -313,9 +313,7 @@ var msgTests = []msgTest{
Scheme: "sip",
Host: "lol.com",
},
Params: sip.Params{
"tag": "omfg",
},
Param: &sip.Param{"tag", "omfg", nil},
},
},
},
@ -335,9 +333,7 @@ var msgTests = []msgTest{
Scheme: "sip",
Host: "lol.com",
},
Params: sip.Params{
"tag": "◕◡◕",
},
Param: &sip.Param{"tag", "◕◡◕", nil},
},
},
},
@ -356,9 +352,7 @@ var msgTests = []msgTest{
Scheme: "sip",
Host: "lol.com",
},
Params: sip.Params{
"tag": "",
},
Param: &sip.Param{"tag", "", nil},
},
},
},
@ -377,9 +371,7 @@ var msgTests = []msgTest{
Scheme: "sip",
Host: "lol.com",
},
Params: sip.Params{
"tag": "omfg",
},
Param: &sip.Param{"tag", "omfg", nil},
},
},
},
@ -560,7 +552,7 @@ var msgTests = []msgTest{
Version: "2.0",
Transport: "TCP",
Host: "spindle.example.com",
Params: sip.Params{"branch": "z9hG4bK9ikj8"},
Param: &sip.Param{"branch", "z9hG4bK9ikj8", nil},
},
},
},
@ -580,7 +572,7 @@ var msgTests = []msgTest{
Version: "2.0",
Transport: "TCP",
Host: "spindle.example.com",
Params: sip.Params{"branch": "z9hG4bK9ikj8"},
Param: &sip.Param{"branch", "z9hG4bK9ikj8", nil},
},
},
},
@ -605,19 +597,19 @@ var msgTests = []msgTest{
Version: "2.0",
Transport: "UDP",
Host: "192.0.2.2",
Params: sip.Params{"branch": "390skdjuw"},
Param: &sip.Param{"branch", "390skdjuw", nil},
Next: &sip.Via{
Protocol: "SIP",
Version: "2.0",
Transport: "TCP",
Host: "spindle.example.com",
Params: sip.Params{"branch": "z9hG4bK9ikj8"},
Param: &sip.Param{"branch", "z9hG4bK9ikj8", nil},
Next: &sip.Via{
Protocol: "SIP",
Version: "2.0",
Transport: "UDP",
Host: "192.168.255.111",
Params: sip.Params{"branch": "z9hG4bK30239"},
Param: &sip.Param{"branch", "z9hG4bK30239", nil},
},
},
},
@ -656,7 +648,7 @@ var msgTests = []msgTest{
Transport: "UDP",
Host: "10.11.34.37",
Port: 42367,
Params: sip.Params{"rport": "", "branch": "9dc39c3c3e84"},
Param: &sip.Param{"branch", "9dc39c3c3e84", &sip.Param{"rport", "", nil}},
},
To: &sip.Addr{
Uri: &sip.URI{
@ -670,9 +662,9 @@ var msgTests = []msgTest{
Scheme: "sip",
Host: "10.11.34.37",
Port: 42367,
Params: sip.Params{"laffo": ""},
Param: &sip.URIParam{"laffo", "", nil},
},
Params: sip.Params{"tag": "11917cbc0513"},
Param: &sip.Param{"tag", "11917cbc0513", nil},
},
Contact: &sip.Addr{
Uri: &sip.URI{
@ -728,10 +720,17 @@ var msgTests = []msgTest{
Transport: "UDP",
Host: "127.0.0.1",
Port: 52711,
Params: sip.Params{
"branch": "z9hG4bK-03d1d81e94a0",
"received": "127.0.0.1",
"rport": "52711",
Param: &sip.Param{
Name: "rport",
Value: "52711",
Next: &sip.Param{
Name: "received",
Value: "127.0.0.1",
Next: &sip.Param{
Name: "branch",
Value: "z9hG4bK-03d1d81e94a0",
},
},
},
},
From: &sip.Addr{
@ -739,9 +738,9 @@ var msgTests = []msgTest{
Scheme: "sip",
Host: "127.0.0.1",
Port: 52711,
Params: sip.Params{"transport": "udp"},
Param: &sip.URIParam{"transport", "udp", nil},
},
Params: sip.Params{"tag": "4568e274dbd8"},
Param: &sip.Param{"tag", "4568e274dbd8", nil},
},
To: &sip.Addr{
Uri: &sip.URI{
@ -750,7 +749,7 @@ var msgTests = []msgTest{
Host: "127.0.0.1",
Port: 5060,
},
Params: sip.Params{"tag": "as71a0fa72"},
Param: &sip.Param{"tag", "as71a0fa72", nil},
},
Contact: &sip.Addr{
Uri: &sip.URI{
@ -814,7 +813,7 @@ var msgTests = []msgTest{
Transport: "UDP",
Host: "1.2.3.4",
Port: 55345,
Params: sip.Params{"branch": "z9hG4bK-d1d81e94a099"},
Param: &sip.Param{"branch", "z9hG4bK-d1d81e94a099", nil},
},
From: &sip.Addr{
Uri: &sip.URI{
@ -822,7 +821,7 @@ var msgTests = []msgTest{
User: "+12126660420",
Host: "fl.gg",
},
Params: sip.Params{"tag": "68e274dbd83b"},
Param: &sip.Param{"tag", "68e274dbd83b", nil},
},
To: &sip.Addr{
Uri: &sip.URI{
@ -830,7 +829,7 @@ var msgTests = []msgTest{
User: "+12125650666",
Host: "fl.gg",
},
Params: sip.Params{"tag": "gK0cacc73a"},
Param: &sip.Param{"tag", "gK0cacc73a", nil},
},
Contact: &sip.Addr{
Uri: &sip.URI{
@ -845,14 +844,14 @@ var msgTests = []msgTest{
Scheme: "sip",
Host: "216.115.69.133",
Port: 5060,
Params: sip.Params{"lr": ""},
Param: &sip.URIParam{"lr", "", nil},
},
Next: &sip.Addr{
Uri: &sip.URI{
Scheme: "sip",
Host: "216.115.69.144",
Port: 5060,
Params: sip.Params{"lr": ""},
Param: &sip.URIParam{"lr", "", nil},
},
},
},
@ -918,7 +917,7 @@ var msgTests = []msgTest{
Transport: "UDP",
Host: "10.11.34.37",
Port: 59516,
Params: sip.Params{"rport": "", "branch": "z9hG4bKS308QB9UUpNyD"},
Param: &sip.Param{"branch", "z9hG4bKS308QB9UUpNyD", &sip.Param{"rport", "", nil}},
},
To: &sip.Addr{
Uri: &sip.URI{
@ -932,7 +931,7 @@ var msgTests = []msgTest{
Host: "10.11.34.37",
Port: 59516,
},
Params: sip.Params{"tag": "S1jX7UtK5Zerg"},
Param: &sip.Param{"tag", "S1jX7UtK5Zerg", nil},
},
Contact: &sip.Addr{
Uri: &sip.URI{
@ -1015,7 +1014,7 @@ var msgTests = []msgTest{
Scheme: "sip",
User: "vivekg",
Host: "chair-dnrc.example.com",
Params: sip.Params{"unknownparam": ""},
Param: &sip.URIParam{"unknownparam", "", nil},
},
To: &sip.Addr{
Uri: &sip.URI{
@ -1023,7 +1022,7 @@ var msgTests = []msgTest{
User: "vivekg",
Host: "chair-dnrc.example.com",
},
Params: sip.Params{"tag": "1918181833n"},
Param: &sip.Param{"tag", "1918181833n", nil},
},
From: &sip.Addr{
Display: "J Rosenberg \\\"",
@ -1032,7 +1031,7 @@ var msgTests = []msgTest{
User: "jdrosen",
Host: "example.com",
},
Params: sip.Params{"tag": "98asjd8"},
Param: &sip.Param{"tag", "98asjd8", nil},
},
MaxForwards: 68,
CallID: "wsinv.ndaksdj@192.0.2.1",
@ -1043,19 +1042,19 @@ var msgTests = []msgTest{
Version: "2.0",
Transport: "UDP",
Host: "192.0.2.2",
Params: sip.Params{"branch": "390skdjuw"},
Param: &sip.Param{"branch", "390skdjuw", nil},
Next: &sip.Via{
Protocol: "SIP",
Version: "2.0",
Transport: "TCP",
Host: "spindle.example.com",
Params: sip.Params{"branch": "z9hG4bK9ikj8"},
Param: &sip.Param{"branch", "z9hG4bK9ikj8", nil},
Next: &sip.Via{
Protocol: "SIP",
Version: "2.0",
Transport: "UDP",
Host: "192.168.255.111",
Params: sip.Params{"branch": "z9hG4bK30239"},
Param: &sip.Param{"branch", "z9hG4bK30239", nil},
},
},
},
@ -1069,10 +1068,17 @@ var msgTests = []msgTest{
Uri: &sip.URI{
Scheme: "sip",
Host: "services.example.com",
Params: sip.Params{
"lr": "",
"unknownwith": "value",
"unknown-no-value": "",
Param: &sip.URIParam{
Name: "unknown-no-value",
Value: "",
Next: &sip.URIParam{
Name: "unknownwith",
Value: "value",
Next: &sip.URIParam{
Name: "lr",
Value: "",
},
},
},
},
},
@ -1083,10 +1089,17 @@ var msgTests = []msgTest{
User: "jdrosen",
Host: "example.com",
},
Params: sip.Params{
"newparam": "newvalue",
"secondparam": "",
"q": "0.33",
Param: &sip.Param{
Name: "q",
Value: "0.33",
Next: &sip.Param{
Name: "secondparam",
Value: "",
Next: &sip.Param{
Name: "newparam",
Value: "newvalue",
},
},
},
},
Payload: &sip.MiscPayload{
@ -1133,7 +1146,7 @@ var msgTests = []msgTest{
Version: "2.0",
Transport: "TCP",
Host: "host1.example.com",
Params: sip.Params{"branch": "z9hG4bK-.!%66*_+`'~"},
Param: &sip.Param{"branch", "z9hG4bK-.!%66*_+`'~", nil},
},
To: &sip.Addr{
Display: "BEL:\x07 NUL:\x00 DEL:\x7F",
@ -1150,9 +1163,13 @@ var msgTests = []msgTest{
User: "mundane",
Host: "example.com",
},
Params: sip.Params{
"fromParam''~+*_!.-%": "\xD1\x80\xD0\xB0\xD0\xB1\xD0\xBE\xD1\x82\xD0\xB0\xD1\x8E\xD1\x89\xD0\xB8\xD0\xB9",
"tag": "_token~1'+`*%!-.",
Param: &sip.Param{
Name: "tag",
Value: "_token~1'+`*%!-.",
Next: &sip.Param{
Name: "fromParam''~+*_!.-%",
Value: "\xD1\x80\xD0\xB0\xD0\xB1\xD0\xBE\xD1\x82\xD0\xB0\xD1\x8E\xD1\x89\xD0\xB8\xD0\xB9",
},
},
},
Headers: sip.Headers{


+ 39
- 0
sip/param.go View File

@ -0,0 +1,39 @@
// Addr / Via Parameter Library
package sip
import (
"bytes"
)
// Param is a linked list of ;key="values" for Addr/Via parameters.
type Param struct {
Name string
Value string
Next *Param
}
// Get returns an entry in O(n) time.
func (p *Param) Get(name string) *Param {
if p == nil {
return nil
}
if p.Name == name {
return p
}
return p.Next.Get(name)
}
// Append serializes parameters in insertion order.
func (p *Param) Append(b *bytes.Buffer) {
if p == nil {
return
}
p.Next.Append(b)
b.WriteByte(';')
appendSanitized(b, []byte(p.Name), tokenc)
if p.Value != "" {
b.WriteByte('=')
appendQuoted(b, []byte(p.Value))
}
}

+ 0
- 63
sip/params.go View File

@ -1,63 +0,0 @@
package sip
import (
"bytes"
"sort"
)
type Params map[string]string
func (params Params) Copy() Params {
res := make(Params, len(params))
for k, v := range params {
res[k] = v
}
return res
}
func (params Params) Append(b *bytes.Buffer) {
if params != nil && len(params) > 0 {
keys := make([]string, len(params))
i := 0
for k, _ := range params {
keys[i] = k
i++
}
sort.Strings(keys)
for _, k := range keys {
b.WriteByte(';')
appendEscaped(b, []byte(k), paramc)
v := params[k]
if v != "" {
b.WriteByte('=')
appendEscaped(b, []byte(v), paramc)
}
}
}
}
func (params Params) AppendQuoted(b *bytes.Buffer) {
if params != nil && len(params) > 0 {
keys := make([]string, len(params))
i := 0
for k, _ := range params {
keys[i] = k
i++
}
sort.Strings(keys)
for _, k := range keys {
b.WriteByte(';')
appendSanitized(b, []byte(k), tokenc)
v := params[k]
if v != "" {
b.WriteByte('=')
appendQuoted(b, []byte(v))
}
}
}
}
func (params Params) Has(k string) bool {
_, ok := params["lr"]
return ok
}

+ 3
- 3
sip/receiver.go View File

@ -42,13 +42,13 @@ func ReceiveMessages(sock *net.UDPConn, c chan<- *Msg, e chan<- error) {
func addReceived(msg *Msg, addr *net.UDPAddr) {
if msg.Via.Host != addr.IP.String() || int(msg.Via.Port) != addr.Port {
msg.Via.Params["received"] = addr.String()
msg.Via.Param = &Param{"received", addr.String(), msg.Via.Param}
}
}
func addTimestamp(msg *Msg, ts time.Time) {
if *timestampTagging {
msg.Via.Params["µsi"] = strconv.FormatInt(ts.UnixNano()/int64(time.Microsecond), 10)
msg.Via.Param = &Param{"usi", strconv.FormatInt(ts.UnixNano()/int64(time.Microsecond), 10), msg.Via.Param}
}
}
@ -56,7 +56,7 @@ func addTimestamp(msg *Msg, ts time.Time) {
// RFC3261 16.12.1.2: Traversing a Strict-Routing Proxy
func fixMessagesFromStrictRouters(lhost string, lport uint16, msg *Msg) {
if msg.Request != nil &&
msg.Request.Params.Has("lr") &&
msg.Request.Param.Get("lr") != nil &&
msg.Route != nil &&
msg.Request.Host == lhost &&
or5060(msg.Request.Port) == lport {


+ 8
- 10
sip/route.go View File

@ -25,7 +25,7 @@ func PopulateMessage(via *Via, contact *Addr, msg *Msg) {
}
if msg.From == nil {
msg.From = msg.Contact.Copy()
msg.From.Uri.Params = nil
msg.From.Uri.Param = nil
}
if msg.CallID == "" {
msg.CallID = util.GenerateCallID()
@ -42,13 +42,11 @@ func PopulateMessage(via *Via, contact *Addr, msg *Msg) {
if msg.UserAgent == "" {
msg.UserAgent = GosipUA
}
if _, ok := msg.Via.Params["branch"]; !ok {
msg.Via = msg.Via.Copy()
msg.Via.Params["branch"] = util.GenerateBranch()
if msg.Via.Param.Get("branch") == nil {
msg.Via.Param = &Param{"branch", util.GenerateBranch(), msg.Via.Param}
}
if _, ok := msg.From.Params["tag"]; !ok {
msg.From = msg.From.Copy()
msg.From.Params["tag"] = util.GenerateTag()
if msg.From.Param.Get("tag") == nil {
msg.From.Param = &Param{"tag", util.GenerateTag(), msg.From.Param}
}
}
}
@ -59,8 +57,8 @@ func RouteMessage(via *Via, contact *Addr, msg *Msg) (host string, port uint16,
msg.Via = msg.Via.Next
}
host, port = msg.Via.Host, msg.Via.Port
if received, ok := msg.Via.Params["received"]; ok {
host = received
if received := msg.Via.Param.Get("received"); received != nil {
host = received.Value
}
} else {
if contact.CompareHostPort(msg.Route) {
@ -70,7 +68,7 @@ func RouteMessage(via *Via, contact *Addr, msg *Msg) (host string, port uint16,
if msg.Method == "REGISTER" {
return "", 0, errors.New("Don't route REGISTER requests")
}
if msg.Route.Uri.Params.Has("lr") {
if msg.Route.Uri.Param.Get("lr") != nil {
// RFC3261 16.12.1.1 Basic SIP Trapezoid
host, port = msg.Route.Uri.Host, msg.Route.Uri.Port
} else {


+ 2
- 8
sip/sip.rl View File

@ -147,10 +147,7 @@ action ViaPort {
}
action ViaParam {
if via.Params == nil {
via.Params = Params{}
}
via.Params[name] = string(buf[0:amt])
via.Param = &Param{name, string(buf[0:amt]), via.Param}
}
action gxh {
@ -196,10 +193,7 @@ action AddrUri {
}
action AddrParam {
if addr.Params == nil {
addr.Params = Params{}
}
addr.Params[name] = string(buf[0:amt])
addr.Param = &Param{name, string(buf[0:amt]), addr.Param}
}
action Addr {


+ 1
- 1
sip/transport.go View File

@ -37,7 +37,7 @@ func NewTransport(contact *Addr) (tp *Transport, err error) {
contact = contact.Copy()
contact.Next = nil
contact.Uri.Port = uint16(addr.Port)
contact.Uri.Params["transport"] = "udp"
contact.Uri.Param = &URIParam{"transport", "udp", contact.Uri.Param}
c := make(chan *Msg)
e := make(chan error)
tp = &Transport{


+ 11
- 49
sip/uri.go View File

@ -24,7 +24,6 @@ import (
"bytes"
"errors"
"github.com/jart/gosip/util"
"sort"
)
const (
@ -37,16 +36,14 @@ var (
URIBadPort = errors.New("invalid port number")
)
type URIHeaders map[string]string
type URI struct {
Scheme string // e.g. sip, sips, tel, etc.
User string // e.g. sip:USER@host
Pass string // e.g. sip:user:PASS@host
Host string // e.g. example.com, 1.2.3.4, etc.
Port uint16 // e.g. 5060, 80, etc.
Params Params // e.g. ;isup-oli=00;day=tuesday
Headers URIHeaders // e.g. ?subject=project%20x&lol=cat
Scheme string // e.g. sip, sips, tel, etc.
User string // e.g. sip:USER@host
Pass string // e.g. sip:user:PASS@host
Host string // e.g. example.com, 1.2.3.4, etc.
Port uint16 // e.g. 5060, 80, etc.
Param *URIParam // e.g. ;isup-oli=00;day=tuesday
Header *URIHeader // e.g. ?subject=project%20x&lol=cat
}
//go:generate ragel -Z -G2 -o uri_parse.go uri_parse.rl
@ -58,8 +55,8 @@ func (uri *URI) Copy() *URI {
}
res := new(URI)
*res = *uri
res.Params = uri.Params.Copy()
res.Headers = uri.Headers.Copy()
res.Param = uri.Param
res.Header = uri.Header
return res
}
@ -102,8 +99,8 @@ func (uri *URI) Append(b *bytes.Buffer) {
b.WriteByte(':')
b.WriteString(portstr(uri.Port))
}
uri.Params.Append(b)
uri.Headers.Append(b)
uri.Param.Append(b)
uri.Header.Append(b)
}
func (uri *URI) CompareHostPort(other *URI) bool {
@ -126,38 +123,3 @@ func (uri *URI) GetPort() uint16 {
return uri.Port
}
}
func (headers URIHeaders) Copy() URIHeaders {
res := make(URIHeaders, len(headers))
for k, v := range headers {
res[k] = v
}
return res
}
func (headers URIHeaders) Append(b *bytes.Buffer) {
if headers != nil && len(headers) > 0 {
keys := make([]string, len(headers))
i := 0
for k, _ := range headers {
keys[i] = k
i++
}
sort.Strings(keys)
first := true
for _, k := range keys {
if first {
b.WriteByte('?')
first = false
} else {
b.WriteByte('&')
}
appendEscaped(b, []byte(k), headerc)
v := headers[k]
if v != "" {
b.WriteByte('=')
appendEscaped(b, []byte(v), headerc)
}
}
}
}

+ 83
- 163
sip/uri_parse.go View File

@ -49,7 +49,7 @@ func ParseURIBytes(data []byte) (uri *URI, err error) {
var hex byte
//line uri_parse.rl:171
//line uri_parse.rl:165
@ -58,7 +58,7 @@ func ParseURIBytes(data []byte) (uri *URI, err error) {
cs = uri_start
}
//line uri_parse.rl:174
//line uri_parse.rl:168
if bytes.IndexByte(data, '@') == -1 {
cs = uri_en_uriSansUser;
} else {
@ -723,10 +723,7 @@ tr74:
//line uri_parse.rl:113
if uri.Params == nil {
uri.Params = Params{}
}
uri.Params[b1] = b2
uri.Param = &URIParam{b1, b2, uri.Param}
goto st13
tr79:
@ -737,10 +734,7 @@ tr79:
//line uri_parse.rl:113
if uri.Params == nil {
uri.Params = Params{}
}
uri.Params[b1] = b2
uri.Param = &URIParam{b1, b2, uri.Param}
goto st13
st13:
@ -748,7 +742,7 @@ tr79:
goto _test_eof13
}
st_case_13:
//line uri_parse.go:752
//line uri_parse.go:746
switch data[p] {
case 33:
goto tr22
@ -780,13 +774,9 @@ tr79:
}
goto st0
tr72:
//line uri_parse.rl:104
//line uri_parse.rl:51
if 'A' <= data[p] && data[p] <= 'Z' {
buf[amt] = data[p] + 0x20
} else {
buf[amt] = data[p]
}
buf[amt] = data[p]
amt++
goto st47
@ -808,13 +798,9 @@ tr22:
b2 = string(buf[0:amt])
amt = 0
//line uri_parse.rl:104
//line uri_parse.rl:51
if 'A' <= data[p] && data[p] <= 'Z' {
buf[amt] = data[p] + 0x20
} else {
buf[amt] = data[p]
}
buf[amt] = data[p]
amt++
goto st47
@ -823,7 +809,7 @@ tr22:
goto _test_eof47
}
st_case_47:
//line uri_parse.go:827
//line uri_parse.go:813
switch data[p] {
case 33:
goto tr72
@ -876,7 +862,7 @@ tr23:
goto _test_eof14
}
st_case_14:
//line uri_parse.go:880
//line uri_parse.go:866
switch {
case data[p] < 65:
if 48 <= data[p] && data[p] <= 57 {
@ -901,7 +887,7 @@ tr24:
goto _test_eof15
}
st_case_15:
//line uri_parse.go:905
//line uri_parse.go:891
switch {
case data[p] < 65:
if 48 <= data[p] && data[p] <= 57 {
@ -927,7 +913,7 @@ tr75:
goto _test_eof16
}
st_case_16:
//line uri_parse.go:931
//line uri_parse.go:917
switch data[p] {
case 33:
goto tr26
@ -963,24 +949,16 @@ tr26:
amt = 0
//line uri_parse.rl:104
//line uri_parse.rl:51
if 'A' <= data[p] && data[p] <= 'Z' {
buf[amt] = data[p] + 0x20
} else {
buf[amt] = data[p]
}
buf[amt] = data[p]
amt++
goto st48
tr77:
//line uri_parse.rl:104
//line uri_parse.rl:51
if 'A' <= data[p] && data[p] <= 'Z' {
buf[amt] = data[p] + 0x20
} else {
buf[amt] = data[p]
}
buf[amt] = data[p]
amt++
goto st48
@ -997,7 +975,7 @@ tr29:
goto _test_eof48
}
st_case_48:
//line uri_parse.go:1001
//line uri_parse.go:979
switch data[p] {
case 33:
goto tr77
@ -1043,7 +1021,7 @@ tr27:
goto _test_eof17
}
st_case_17:
//line uri_parse.go:1047
//line uri_parse.go:1025
switch {
case data[p] < 65:
if 48 <= data[p] && data[p] <= 57 {
@ -1068,7 +1046,7 @@ tr28:
goto _test_eof18
}
st_case_18:
//line uri_parse.go:1072
//line uri_parse.go:1050
switch {
case data[p] < 65:
if 48 <= data[p] && data[p] <= 57 {
@ -1096,10 +1074,7 @@ tr76:
//line uri_parse.rl:113
if uri.Params == nil {
uri.Params = Params{}
}
uri.Params[b1] = b2
uri.Param = &URIParam{b1, b2, uri.Param}
goto st19
tr80:
@ -1110,10 +1085,7 @@ tr80:
//line uri_parse.rl:113
if uri.Params == nil {
uri.Params = Params{}
}
uri.Params[b1] = b2
uri.Param = &URIParam{b1, b2, uri.Param}
goto st19
tr83:
@ -1122,12 +1094,9 @@ tr83:
b1 = string(buf[0:amt])
amt = 0
//line uri_parse.rl:120
//line uri_parse.rl:117
if uri.Headers == nil {
uri.Headers = URIHeaders{}
}
uri.Headers[b1] = b2
uri.Header = &URIHeader{b1, b2, uri.Header}
goto st19
tr87:
@ -1136,12 +1105,9 @@ tr87:
b2 = string(buf[0:amt])
amt = 0
//line uri_parse.rl:120
//line uri_parse.rl:117
if uri.Headers == nil {
uri.Headers = URIHeaders{}
}
uri.Headers[b1] = b2
uri.Header = &URIHeader{b1, b2, uri.Header}
goto st19
st19:
@ -1149,7 +1115,7 @@ tr87:
goto _test_eof19
}
st_case_19:
//line uri_parse.go:1153
//line uri_parse.go:1119
switch data[p] {
case 33:
goto tr30
@ -1220,7 +1186,7 @@ tr30:
goto _test_eof49
}
st_case_49:
//line uri_parse.go:1224
//line uri_parse.go:1190
switch data[p] {
case 33:
goto tr81
@ -1273,7 +1239,7 @@ tr31:
goto _test_eof20
}
st_case_20:
//line uri_parse.go:1277
//line uri_parse.go:1243
switch {
case data[p] < 65:
if 48 <= data[p] && data[p] <= 57 {
@ -1298,7 +1264,7 @@ tr32:
goto _test_eof21
}
st_case_21:
//line uri_parse.go:1302
//line uri_parse.go:1268
switch {
case data[p] < 65:
if 48 <= data[p] && data[p] <= 57 {
@ -1324,7 +1290,7 @@ tr84:
goto _test_eof22
}
st_case_22:
//line uri_parse.go:1328
//line uri_parse.go:1294
switch data[p] {
case 33:
goto tr34
@ -1390,7 +1356,7 @@ tr37:
goto _test_eof50
}
st_case_50:
//line uri_parse.go:1394
//line uri_parse.go:1360
switch data[p] {
case 33:
goto tr85
@ -1436,7 +1402,7 @@ tr35:
goto _test_eof23
}
st_case_23:
//line uri_parse.go:1440
//line uri_parse.go:1406
switch {
case data[p] < 65:
if 48 <= data[p] && data[p] <= 57 {
@ -1461,7 +1427,7 @@ tr36:
goto _test_eof24
}
st_case_24:
//line uri_parse.go:1465
//line uri_parse.go:1431
switch {
case data[p] < 65:
if 48 <= data[p] && data[p] <= 57 {
@ -1527,7 +1493,7 @@ tr39:
goto _test_eof26
}
st_case_26:
//line uri_parse.go:1531
//line uri_parse.go:1497
switch data[p] {
case 46:
goto tr39
@ -1558,7 +1524,7 @@ tr40:
goto _test_eof51
}
st_case_51:
//line uri_parse.go:1562
//line uri_parse.go:1528
switch data[p] {
case 58:
goto st12
@ -1609,7 +1575,7 @@ tr42:
goto _test_eof28
}
st_case_28:
//line uri_parse.go:1613
//line uri_parse.go:1579
switch data[p] {
case 43:
goto tr42
@ -1645,7 +1611,7 @@ tr43:
goto _test_eof29
}
st_case_29:
//line uri_parse.go:1649
//line uri_parse.go:1615
switch data[p] {
case 43:
goto tr44
@ -1701,7 +1667,7 @@ tr89:
goto _test_eof52
}
st_case_52:
//line uri_parse.go:1705
//line uri_parse.go:1671
switch data[p] {
case 43:
goto tr89
@ -1741,7 +1707,7 @@ tr90:
goto _test_eof30
}
st_case_30:
//line uri_parse.go:1745
//line uri_parse.go:1711
if 48 <= data[p] && data[p] <= 57 {
goto tr46
}
@ -1757,7 +1723,7 @@ tr46:
goto _test_eof53
}
st_case_53:
//line uri_parse.go:1761
//line uri_parse.go:1727
switch data[p] {
case 59:
goto st31
@ -1782,10 +1748,7 @@ tr97:
//line uri_parse.rl:113
if uri.Params == nil {
uri.Params = Params{}
}
uri.Params[b1] = b2
uri.Param = &URIParam{b1, b2, uri.Param}
goto st31
tr102:
@ -1796,10 +1759,7 @@ tr102:
//line uri_parse.rl:113
if uri.Params == nil {
uri.Params = Params{}
}
uri.Params[b1] = b2
uri.Param = &URIParam{b1, b2, uri.Param}
goto st31
st31:
@ -1807,7 +1767,7 @@ tr102:
goto _test_eof31
}
st_case_31:
//line uri_parse.go:1811
//line uri_parse.go:1771
switch data[p] {
case 33:
goto tr47
@ -1839,13 +1799,9 @@ tr102:
}
goto st0
tr95:
//line uri_parse.rl:104
//line uri_parse.rl:51
if 'A' <= data[p] && data[p] <= 'Z' {
buf[amt] = data[p] + 0x20
} else {
buf[amt] = data[p]
}
buf[amt] = data[p]
amt++
goto st54
@ -1867,13 +1823,9 @@ tr47:
b2 = string(buf[0:amt])
amt = 0
//line uri_parse.rl:104
//line uri_parse.rl:51
if 'A' <= data[p] && data[p] <= 'Z' {
buf[amt] = data[p] + 0x20
} else {
buf[amt] = data[p]
}
buf[amt] = data[p]
amt++
goto st54
@ -1882,7 +1834,7 @@ tr47:
goto _test_eof54
}
st_case_54:
//line uri_parse.go:1886
//line uri_parse.go:1838
switch data[p] {
case 33:
goto tr95
@ -1935,7 +1887,7 @@ tr48:
goto _test_eof32
}
st_case_32:
//line uri_parse.go:1939
//line uri_parse.go:1891
switch {
case data[p] < 65:
if 48 <= data[p] && data[p] <= 57 {
@ -1960,7 +1912,7 @@ tr49:
goto _test_eof33
}
st_case_33:
//line uri_parse.go:1964
//line uri_parse.go:1916
switch {
case data[p] < 65:
if 48 <= data[p] && data[p] <= 57 {
@ -1986,7 +1938,7 @@ tr98:
goto _test_eof34
}
st_case_34:
//line uri_parse.go:1990
//line uri_parse.go:1942
switch data[p] {
case 33:
goto tr51
@ -2022,24 +1974,16 @@ tr51:
amt = 0
//line uri_parse.rl:104
//line uri_parse.rl:51
if 'A' <= data[p] && data[p] <= 'Z' {
buf[amt] = data[p] + 0x20
} else {
buf[amt] = data[p]
}
buf[amt] = data[p]
amt++
goto st55
tr100:
//line uri_parse.rl:104
//line uri_parse.rl:51
if 'A' <= data[p] && data[p] <= 'Z' {
buf[amt] = data[p] + 0x20
} else {
buf[amt] = data[p]
}
buf[amt] = data[p]
amt++
goto st55
@ -2056,7 +2000,7 @@ tr54:
goto _test_eof55
}
st_case_55:
//line uri_parse.go:2060
//line uri_parse.go:2004
switch data[p] {
case 33:
goto tr100
@ -2102,7 +2046,7 @@ tr52:
goto _test_eof35
}
st_case_35:
//line uri_parse.go:2106
//line uri_parse.go:2050
switch {
case data[p] < 65:
if 48 <= data[p] && data[p] <= 57 {
@ -2127,7 +2071,7 @@ tr53:
goto _test_eof36
}
st_case_36:
//line uri_parse.go:2131
//line uri_parse.go:2075
switch {
case data[p] < 65:
if 48 <= data[p] && data[p] <= 57 {
@ -2155,10 +2099,7 @@ tr99:
//line uri_parse.rl:113
if uri.Params == nil {
uri.Params = Params{}
}
uri.Params[b1] = b2
uri.Param = &URIParam{b1, b2, uri.Param}
goto st37
tr103:
@ -2169,10 +2110,7 @@ tr103:
//line uri_parse.rl:113
if uri.Params == nil {
uri.Params = Params{}
}
uri.Params[b1] = b2
uri.Param = &URIParam{b1, b2, uri.Param}
goto st37
tr106:
@ -2181,12 +2119,9 @@ tr106:
b1 = string(buf[0:amt])
amt = 0
//line uri_parse.rl:120
//line uri_parse.rl:117
if uri.Headers == nil {
uri.Headers = URIHeaders{}
}
uri.Headers[b1] = b2
uri.Header = &URIHeader{b1, b2, uri.Header}
goto st37
tr110:
@ -2195,12 +2130,9 @@ tr110:
b2 = string(buf[0:amt])
amt = 0
//line uri_parse.rl:120
//line uri_parse.rl:117
if uri.Headers == nil {
uri.Headers = URIHeaders{}
}
uri.Headers[b1] = b2
uri.Header = &URIHeader{b1, b2, uri.Header}
goto st37
st37:
@ -2208,7 +2140,7 @@ tr110:
goto _test_eof37
}
st_case_37:
//line uri_parse.go:2212
//line uri_parse.go:2144
switch data[p] {
case 33:
goto tr55
@ -2279,7 +2211,7 @@ tr55:
goto _test_eof56
}
st_case_56:
//line uri_parse.go:2283
//line uri_parse.go:2215
switch data[p] {
case 33:
goto tr104
@ -2332,7 +2264,7 @@ tr56:
goto _test_eof38
}
st_case_38:
//line uri_parse.go:2336
//line uri_parse.go:2268
switch {
case data[p] < 65:
if 48 <= data[p] && data[p] <= 57 {
@ -2357,7 +2289,7 @@ tr57:
goto _test_eof39
}
st_case_39:
//line uri_parse.go:2361
//line uri_parse.go:2293
switch {
case data[p] < 65:
if 48 <= data[p] && data[p] <= 57 {
@ -2383,7 +2315,7 @@ tr107:
goto _test_eof40
}
st_case_40:
//line uri_parse.go:2387
//line uri_parse.go:2319
switch data[p] {
case 33:
goto tr59
@ -2449,7 +2381,7 @@ tr62:
goto _test_eof57
}
st_case_57:
//line uri_parse.go:2453
//line uri_parse.go:2385
switch data[p] {
case 33:
goto tr108
@ -2495,7 +2427,7 @@ tr60:
goto _test_eof41
}
st_case_41:
//line uri_parse.go:2499
//line uri_parse.go:2431
switch {
case data[p] < 65:
if 48 <= data[p] && data[p] <= 57 {
@ -2520,7 +2452,7 @@ tr61:
goto _test_eof42
}
st_case_42:
//line uri_parse.go:2524
//line uri_parse.go:2456
switch {
case data[p] < 65:
if 48 <= data[p] && data[p] <= 57 {
@ -2586,7 +2518,7 @@ tr64:
goto _test_eof44
}
st_case_44:
//line uri_parse.go:2590
//line uri_parse.go:2522
switch data[p] {
case 46:
goto tr64
@ -2617,7 +2549,7 @@ tr65:
goto _test_eof58
}
st_case_58:
//line uri_parse.go:2621
//line uri_parse.go:2553
switch data[p] {
case 58:
goto st30
@ -2701,10 +2633,7 @@ tr65:
//line uri_parse.rl:113
if uri.Params == nil {
uri.Params = Params{}
}
uri.Params[b1] = b2
uri.Param = &URIParam{b1, b2, uri.Param}
case 49, 56:
//line uri_parse.rl:94
@ -2712,12 +2641,9 @@ tr65:
b1 = string(buf[0:amt])
amt = 0
//line uri_parse.rl:120
//line uri_parse.rl:117
if uri.Headers == nil {
uri.Headers = URIHeaders{}
}
uri.Headers[b1] = b2
uri.Header = &URIHeader{b1, b2, uri.Header}
case 48, 55:
//line uri_parse.rl:99
@ -2727,10 +2653,7 @@ tr65:
//line uri_parse.rl:113
if uri.Params == nil {
uri.Params = Params{}
}
uri.Params[b1] = b2
uri.Param = &URIParam{b1, b2, uri.Param}
case 50, 57:
//line uri_parse.rl:99
@ -2738,21 +2661,18 @@ tr65:
b2 = string(buf[0:amt])
amt = 0
//line uri_parse.rl:120
//line uri_parse.rl:117
if uri.Headers == nil {
uri.Headers = URIHeaders{}
}
uri.Headers[b1] = b2
uri.Header = &URIHeader{b1, b2, uri.Header}
//line uri_parse.go:2749
//line uri_parse.go:2669
}
}
_out: {}
}
//line uri_parse.rl:180
//line uri_parse.rl:174
if cs < uri_first_final {
if p == pe {


+ 2
- 8
sip/uri_parse.rl View File

@ -111,17 +111,11 @@ func ParseURIBytes(data []byte) (uri *URI, err error) {
}
action param {
if uri.Params == nil {
uri.Params = Params{}
}
uri.Params[b1] = b2
uri.Param = &URIParam{b1, b2, uri.Param}
}
action header {
if uri.Headers == nil {
uri.Headers = URIHeaders{}
}
uri.Headers[b1] = b2
uri.Header = &URIHeader{b1, b2, uri.Header}
}
# Byte character definitions.


+ 6
- 17
sip/uri_test.go View File

@ -127,9 +127,7 @@ var uriTests = []uriTest{
Pass: "priceisright",
Host: "dead:beef::666",
Port: 5060,
Params: sip.Params{
"isup-oli": "00",
},
Param: &sip.URIParam{"isup-oli", "00", nil},
},
},
@ -153,10 +151,7 @@ var uriTests = []uriTest{
Scheme: "sips",
User: "alice",
Host: "atlanta.com",
Headers: sip.URIHeaders{
"subject": "project x",
"priority": "urgent",
},
Header: &sip.URIHeader{"subject", "project x", &sip.URIHeader{"priority", "urgent", nil}},
},
},
@ -167,9 +162,7 @@ var uriTests = []uriTest{
User: "+1-212-555-1212",
Pass: "1234",
Host: "gateway.com",
Params: sip.Params{
"user": "phone",
},
Param: &sip.URIParam{"user", "phone", nil},
},
},
@ -178,12 +171,8 @@ var uriTests = []uriTest{
uri: &sip.URI{
Scheme: "sip",
Host: "atlanta.com",
Params: sip.Params{
"method": "register",
},
Headers: sip.URIHeaders{
"to": "alice@atlanta.com",
},
Param: &sip.URIParam{"method", "register", nil},
Header: &sip.URIHeader{"to", "alice@atlanta.com", nil},
},
},
@ -220,7 +209,7 @@ func TestFormatURI(t *testing.T) {
}
uri := test.uri.String()
if test.s != uri {
t.Error(test.s, "!=", uri)
t.Errorf("\n%s !=\n%s", test.s, uri)
}
}
}

+ 44
- 0
sip/uriheader.go View File

@ -0,0 +1,44 @@
// URI Header Library
package sip
import (
"bytes"
"strings"
)
// URIHeader is a linked list of ?key=values for URI headers.
type URIHeader struct {
Name string
Value string
Next *URIHeader
}
// Get returns an entry in O(n) time.
func (p *URIHeader) Get(name string) *URIHeader {
if p == nil {
return nil
}
if strings.EqualFold(p.Name, name) {
return p
}
return p.Next.Get(name)
}
// Append serializes URI headers in insertion order.
func (p *URIHeader) Append(b *bytes.Buffer) {
if p == nil {
return
}
if p.Next != nil {
p.Next.Append(b)
b.WriteByte('&')
} else {
b.WriteByte('?')
}
appendEscaped(b, []byte(p.Name), paramc)
if p.Value != "" {
b.WriteByte('=')
appendEscaped(b, []byte(p.Value), paramc)
}
}

+ 40
- 0
sip/uriparam.go View File

@ -0,0 +1,40 @@
// URI Parameter Library
package sip
import (
"bytes"
"strings"
)
// URIParam is a linked list of ;key=values for URI parameters.
type URIParam struct {
Name string
Value string
Next *URIParam
}
// Get returns an entry in O(n) time.
func (p *URIParam) Get(name string) *URIParam {
if p == nil {
return nil
}
if strings.EqualFold(p.Name, name) {
return p
}
return p.Next.Get(name)
}
// Append serializes URI parameters in insertion order.
func (p *URIParam) Append(b *bytes.Buffer) {
if p == nil {
return
}
p.Next.Append(b)
b.WriteByte(';')
appendEscaped(b, []byte(p.Name), paramc)
if p.Value != "" {
b.WriteByte('=')
appendEscaped(b, []byte(p.Value), paramc)
}
}

+ 8
- 8
sip/via.go View File

@ -21,7 +21,7 @@ type Via struct {
Transport string // transport type "UDP"
Host string // name or ip of egress interface
Port uint16 // network port number
Params Params // params like branch, received, rport, etc.
Param *Param // param like branch, received, rport, etc.
Next *Via // pointer to next via header if any
}
@ -52,7 +52,7 @@ func (via *Via) Append(b *bytes.Buffer) error {
b.WriteString(":")
b.WriteString(strconv.Itoa(int(via.Port)))
}
via.Params.Append(b)
via.Param.Append(b)
return nil
}
@ -67,14 +67,14 @@ func (via *Via) Copy() *Via {
res.Transport = via.Transport
res.Host = via.Host
res.Port = via.Port
res.Params = via.Params.Copy()
res.Param = via.Param
res.Next = via.Next.Copy()
return res
}
// Branch mutates via with a newly generated branch ID.
// Branch adds a randomly generated branch ID.
func (via *Via) Branch() *Via {
via.Params["branch"] = util.GenerateBranch()
via.Param = &Param{"branch", util.GenerateBranch(), via.Param}
return via
}
@ -107,9 +107,9 @@ func (via *Via) CompareHostPort(other *Via) bool {
func (via *Via) CompareBranch(other *Via) bool {
if via != nil && other != nil {
if b1, ok := via.Params["branch"]; ok {
if b2, ok := other.Params["branch"]; ok {
if b1 == b2 {
if b1 := via.Param.Get("branch"); b1 != nil {
if b2 := other.Param.Get("branch"); b2 != nil {
if b1.Value == b2.Value {
return true
}
}


Loading…
Cancel
Save