Browse Source

Use interface for Msg.Payload.

pull/2/head
Justine Alexandra Roberts Tunney 11 years ago
parent
commit
34a4025591
11 changed files with 1163 additions and 1131 deletions
  1. +7
    -10
      example/echo/echo_test.go
  2. +2
    -6
      example/echo2/echo2_test.go
  3. +15
    -6
      example/echo3/echo3_test.go
  4. +13
    -0
      sdp/sdp.go
  5. +7
    -22
      sip/dialog.go
  6. +0
    -9
      sip/messages.go
  7. +18
    -18
      sip/msg.go
  8. +1029
    -1021
      sip/msg_parse.go
  9. +10
    -2
      sip/msg_parse.rl
  10. +43
    -37
      sip/msg_test.go
  11. +19
    -0
      sip/payload.go

+ 7
- 10
example/echo/echo_test.go View File

@ -204,9 +204,8 @@ func TestCallToEchoApp(t *testing.T) {
Port: uint16(laddr.Port),
},
},
ContentType: "application/sdp",
UserAgent: "gosip/1.o",
Payload: sdp.New(rtpaddr, sdp.ULAWCodec, sdp.DTMFCodec).String(),
UserAgent: "gosip/1.o",
Payload: sdp.New(rtpaddr, sdp.ULAWCodec, sdp.DTMFCodec),
}
// Turn invite message into a packet and send via UDP socket.
@ -247,16 +246,14 @@ func TestCallToEchoApp(t *testing.T) {
if !msg.IsResponse() || msg.Status != 200 || msg.Phrase != "OK" {
t.Fatal("wanted 200 ok but got:", msg.Status, msg.Phrase)
}
if msg.Payload == "" || msg.ContentType != "application/sdp" {
t.Fatal("200 ok didn't have sdp payload")
}
// Figure out where they want us to send RTP.
rsdp, err := sdp.Parse(msg.Payload)
if err != nil {
t.Fatal("failed to parse sdp", err)
var rrtpaddr *net.UDPAddr
if ms, ok := msg.Payload.(*sdp.SDP); ok {
rrtpaddr = &net.UDPAddr{IP: net.ParseIP(ms.Addr), Port: int(ms.Audio.Port)}
} else {
t.Fatal("200 ok didn't have sdp payload")
}
rrtpaddr := &net.UDPAddr{IP: net.ParseIP(rsdp.Addr), Port: int(rsdp.Audio.Port)}
// Acknowledge the 200 OK to answer the call.
var ack sip.Msg


+ 2
- 6
example/echo2/echo2_test.go View File

@ -34,7 +34,7 @@ func TestCallToEchoApp(t *testing.T) {
// Send an INVITE message with an SDP media session description.
invite := sip.NewRequest(tp, sip.MethodInvite, to, from)
sip.AttachSDP(invite, sdp.New(rtpaddr, sdp.ULAWCodec, sdp.DTMFCodec))
invite.Payload = sdp.New(rtpaddr, sdp.ULAWCodec, sdp.DTMFCodec)
err = tp.Send(invite)
if err != nil {
t.Fatal(err)
@ -108,12 +108,8 @@ loop:
t.Errorf("Got %d %s", msg.Status, msg.Phrase)
return
}
if msg.ContentType == sdp.ContentType {
if ms, ok := msg.Payload.(*sdp.SDP); ok {
log.Printf("Establishing media session")
ms, err := sdp.Parse(msg.Payload)
if err != nil {
t.Fatal("Failed to parse SDP", err)
}
rs.Peer = &net.UDPAddr{IP: net.ParseIP(ms.Addr), Port: int(ms.Audio.Port)}
}
} else {


+ 15
- 6
example/echo3/echo3_test.go View File

@ -5,18 +5,15 @@ package echo2_test
import (
"github.com/jart/gosip/dsp"
"github.com/jart/gosip/rtp"
"github.com/jart/gosip/sdp"
"github.com/jart/gosip/sip"
"github.com/jart/gosip/util"
"net"
"testing"
"time"
)
func TestCallToEchoApp(t *testing.T) {
invite := &sip.Msg{
Method: sip.MethodInvite,
Request: &sip.URI{User: "echo", Host: "127.0.0.1", Port: 5060},
}
// Create RTP audio session.
rs, err := rtp.NewSession("")
if err != nil {
@ -25,8 +22,20 @@ func TestCallToEchoApp(t *testing.T) {
defer rs.Close()
rtpPort := uint16(rs.Sock.LocalAddr().(*net.UDPAddr).Port)
invite := &sip.Msg{
Method: sip.MethodInvite,
Request: &sip.URI{User: "echo", Host: "127.0.0.1", Port: 5060},
Payload: &sdp.SDP{
Origin: sdp.Origin{ID: util.GenerateOriginID()},
Audio: &sdp.Media{
Port: rtpPort,
Codecs: []sdp.Codec{sdp.ULAWCodec, sdp.DTMFCodec},
},
},
}
// Create a SIP phone call.
dl, err := sip.NewDialog(invite, rtpPort)
dl, err := sip.NewDialog(invite)
if err != nil {
t.Fatal(err)
}


+ 13
- 0
sdp/sdp.go View File

@ -247,6 +247,19 @@ func Parse(s string) (sdp *SDP, err error) {
return sdp, nil
}
func (sdp *SDP) ContentType() string {
return ContentType
}
func (sdp *SDP) Data() []byte {
if sdp == nil {
return nil
}
var b bytes.Buffer
sdp.Append(&b)
return b.Bytes()
}
func (sdp *SDP) String() string {
if sdp == nil {
return ""


+ 7
- 22
sip/dialog.go View File

@ -48,7 +48,6 @@ type dialogState struct {
addr string // Destination ip:port.
sock *net.UDPConn // Outbound message socket (connected for ICMP)
csock *net.UDPConn // Inbound socket for Contact field.
sdp *sdp.SDP // Media session description.
routes *AddressRoute // List of SRV addresses to attempt contacting.
invite *Msg // Our INVITE that established the dialog.
remote *Msg // Message from remote UA that established dialog.
@ -64,27 +63,17 @@ type dialogState struct {
}
// NewDialog creates a phone call.
func NewDialog(invite *Msg, rtpPort uint16) (dl *Dialog, err error) {
func NewDialog(invite *Msg) (dl *Dialog, err error) {
errChan := make(chan error)
stateChan := make(chan int)
peerChan := make(chan *net.UDPAddr)
sendHangupChan := make(chan bool, 4)
ms := &sdp.SDP{
Origin: sdp.Origin{
ID: util.GenerateOriginID(),
},
Audio: &sdp.Media{
Port: rtpPort,
Codecs: []sdp.Codec{sdp.ULAWCodec, sdp.DTMFCodec},
},
}
dls := &dialogState{
errChan: errChan,
stateChan: stateChan,
peerChan: peerChan,
sendHangupChan: sendHangupChan,
invite: invite,
sdp: ms,
}
go dls.run()
return &Dialog{
@ -243,9 +232,10 @@ func (dls *dialogState) populate(msg *Msg) {
}
}
if msg.Method == MethodInvite {
dls.sdp.Addr = lhost
dls.sdp.Origin.Addr = lhost
AttachSDP(msg, dls.sdp)
if ms, ok := msg.Payload.(*sdp.SDP); ok {
ms.Addr = lhost
ms.Origin.Addr = lhost
}
}
PopulateMessage(nil, nil, msg)
}
@ -365,13 +355,8 @@ func (dls *dialogState) handleRequest(msg *Msg) bool {
}
func (dls *dialogState) checkSDP(msg *Msg) {
if msg.ContentType == sdp.ContentType {
ms, err := sdp.Parse(msg.Payload)
if err != nil {
log.Println("Bad SDP payload:", err)
} else {
dls.peerChan <- &net.UDPAddr{IP: net.ParseIP(ms.Addr), Port: int(ms.Audio.Port)}
}
if ms, ok := msg.Payload.(*sdp.SDP); ok {
dls.peerChan <- &net.UDPAddr{IP: net.ParseIP(ms.Addr), Port: int(ms.Audio.Port)}
}
}


+ 0
- 9
sip/messages.go View File

@ -1,7 +1,6 @@
package sip
import (
"github.com/jart/gosip/sdp"
"github.com/jart/gosip/util"
"log"
)
@ -114,11 +113,3 @@ func AckMatch(msg, ack *Msg) bool {
ack.CSeqMethod == MethodAck &&
ack.Via.Last().CompareHostPort(msg.Via))
}
func AttachSDP(msg *Msg, ms *sdp.SDP) {
if msg.Headers == nil {
msg.Headers = Headers{}
}
msg.ContentType = sdp.ContentType
msg.Payload = ms.String()
}

+ 18
- 18
sip/msg.go View File

@ -18,11 +18,11 @@ type Msg struct {
// Fields that aren't headers.
VersionMajor uint8
VersionMinor uint8
Method string // Indicates type of request (if request)
Request *URI // dest URI (nil if response)
Status int // Indicates happiness of response (if response)
Phrase string // Explains happiness of response (if response)
Payload string // Stuff that comes after two line breaks
Method string // Indicates type of request (if request)
Request *URI // dest URI (nil if response)
Status int // Indicates happiness of response (if response)
Phrase string // Explains happiness of response (if response)
Payload Payload // Stuff that comes after two line breaks
// Special non-SIP fields.
SourceAddr *net.UDPAddr // Set by transport layer as received address.
@ -39,7 +39,6 @@ type Msg struct {
CSeqMethod string // Helps with matching to orig message
MaxForwards int // 0 has context specific meaning
UserAgent string
ContentType string
// All the other RFC 3261 headers in plus some extras.
Accept string
@ -217,16 +216,6 @@ func (msg *Msg) Append(b *bytes.Buffer) error {
}
}
if msg.ContentType != "" {
b.WriteString("Content-Type: ")
b.WriteString(msg.ContentType)
b.WriteString("\r\n")
}
b.WriteString("Content-Length: ")
b.WriteString(strconv.Itoa(len(msg.Payload)))
b.WriteString("\r\n")
if msg.Accept != "" {
b.WriteString("Accept: ")
b.WriteString(msg.Accept)
@ -465,8 +454,19 @@ func (msg *Msg) Append(b *bytes.Buffer) error {
}
}
b.WriteString("\r\n")
b.WriteString(msg.Payload)
if msg.Payload != nil {
b.WriteString("Content-Type: ")
b.WriteString(msg.Payload.ContentType())
b.WriteString("\r\n")
payload := msg.Payload.Data()
b.WriteString("Content-Length: ")
b.WriteString(strconv.Itoa(len(payload)))
b.WriteString("\r\n\n\n")
b.Write(payload)
} else {
b.WriteString("Content-Length: 0\r\n\r\n")
}
return nil
}


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


+ 10
- 2
sip/msg_parse.rl View File

@ -4,6 +4,7 @@ import (
// "bytes"
"errors"
"fmt"
"github.com/jart/gosip/sdp"
)
%% machine msg;
@ -36,6 +37,7 @@ func ParseMsgBytes(data []byte) (msg *Msg, err error) {
amt := 0
mark := 0
clen := 0
ctype := ""
// var b1 string
var hex byte
@ -174,7 +176,7 @@ func ParseMsgBytes(data []byte) (msg *Msg, err error) {
}
action ContentType {
msg.ContentType = string(data[mark:p])
ctype = string(data[mark:p])
}
action CSeq {
@ -477,7 +479,13 @@ func ParseMsgBytes(data []byte) (msg *Msg, err error) {
if clen != len(data) - p {
return nil, errors.New(fmt.Sprintf("Content-Length incorrect: %d != %d", clen, len(data) - p))
}
msg.Payload = string(data[p:len(data)])
if ctype == sdp.ContentType {
ms, err := sdp.Parse(string(data[p:len(data)]))
if err != nil { return nil, err }
msg.Payload = ms
} else {
msg.Payload = &MiscPayload{T: ctype, D: data[p:len(data)]}
}
}
return msg, nil


+ 43
- 37
sip/msg_test.go View File

@ -87,7 +87,7 @@ var msgTests = []msgTest{
"Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, SUBSCRIBE, NOTIFY, INFO, PUBLISH\r\n" +
"Supported: replaces, timer\r\n" +
"Contact: <sip:echo@127.0.0.1:5060>\r\n" +
"Content-Type: application/sdp\r\n" +
"Content-Type: application/sdp-lol\r\n" +
"Content-Length: 255\r\n" +
"\r\n" +
"v=0\r\n" +
@ -149,19 +149,21 @@ var msgTests = []msgTest{
Port: 5060,
},
},
ContentType: "application/sdp",
Payload: "v=0\r\n" +
"o=root 736606944 736606944 IN IP4 127.0.0.1\r\n" +
"s=Asterisk PBX 10.11.1\r\n" +
"c=IN IP4 127.0.0.1\r\n" +
"t=0 0\r\n" +
"m=audio 23452 RTP/AVP 0 101\r\n" +
"a=rtpmap:0 PCMU/8000\r\n" +
"a=rtpmap:101 telephone-event/8000\r\n" +
"a=fmtp:101 0-16\r\n" +
"a=silenceSupp:off - - - -\r\n" +
"a=ptime:20\r\n" +
"a=sendrecv\r\n",
Payload: &sip.MiscPayload{
T: "application/sdp-lol",
D: []byte("v=0\r\n" +
"o=root 736606944 736606944 IN IP4 127.0.0.1\r\n" +
"s=Asterisk PBX 10.11.1\r\n" +
"c=IN IP4 127.0.0.1\r\n" +
"t=0 0\r\n" +
"m=audio 23452 RTP/AVP 0 101\r\n" +
"a=rtpmap:0 PCMU/8000\r\n" +
"a=rtpmap:101 telephone-event/8000\r\n" +
"a=fmtp:101 0-16\r\n" +
"a=silenceSupp:off - - - -\r\n" +
"a=ptime:20\r\n" +
"a=sendrecv\r\n"),
},
},
},
@ -175,7 +177,7 @@ var msgTests = []msgTest{
"Record-Route: <sip:216.115.69.133:5060;lr>\r\n" +
"Record-Route: <sip:216.115.69.144:5060;lr>\r\n" +
"Contact: <sip:+12125650666@4.55.22.99:5060>\r\n" +
"Content-Type: application/sdp\r\n" +
"Content-Type: application/sdp-lol\r\n" +
"Content-Length: 168\r\n" +
"\r\n" +
"v=0\r\n" +
@ -194,7 +196,6 @@ var msgTests = []msgTest{
CallID: "042736d4-0bd9-4681-ab86-7321443ff58a",
CSeq: 31109,
CSeqMethod: "INVITE",
ContentType: "application/sdp",
Via: &sip.Via{
Version: "2.0",
Proto: "UDP",
@ -242,15 +243,18 @@ var msgTests = []msgTest{
},
},
},
Payload: "v=0\r\n" +
"o=- 24294 7759 IN IP4 4.55.22.66\r\n" +
"s=-\r\n" +
"c=IN IP4 4.55.22.66\r\n" +
"t=0 0\r\n" +
"m=audio 19580 RTP/AVP 0 101\r\n" +
"a=rtpmap:101 telephone-event/8000\r\n" +
"a=fmtp:101 0-15\r\n" +
"a=maxptime:20\r\n",
Payload: &sip.MiscPayload{
T: "application/sdp-lol",
D: []byte("v=0\r\n" +
"o=- 24294 7759 IN IP4 4.55.22.66\r\n" +
"s=-\r\n" +
"c=IN IP4 4.55.22.66\r\n" +
"t=0 0\r\n" +
"m=audio 19580 RTP/AVP 0 101\r\n" +
"a=rtpmap:101 telephone-event/8000\r\n" +
"a=fmtp:101 0-15\r\n" +
"a=maxptime:20\r\n"),
},
},
},
@ -270,7 +274,7 @@ var msgTests = []msgTest{
"Allow: INVITE, ACK, BYE, CANCEL, OPTIONS, PRACK, MESSAGE, SUBSCRIBE, NOTIFY, REFER, UPDATE, INFO\r\n" +
"Supported: timer, 100rel\r\n" +
"Allow-Events: talk\r\n" +
"Content-Type: application/sdp\r\n" +
"Content-Type: application/sdp-lol\r\n" +
"Content-Disposition: session\r\n" +
"Content-Length: 218\r\n" +
"\r\n" +
@ -335,17 +339,19 @@ var msgTests = []msgTest{
AllowEvents: "talk",
ContentDisposition: "session",
Supported: "timer, 100rel",
ContentType: "application/sdp",
Payload: "v=0\r\n" +
"o=- 2862054018559638081 6057228511765453924 IN IP4 10.11.34.37\r\n" +
"s=-\r\n" +
"c=IN IP4 10.11.34.37\r\n" +
"t=0 0\r\n" +
"m=audio 23448 RTP/AVP 0 101\r\n" +
"a=rtpmap:0 PCMU/8000\r\n" +
"a=rtpmap:101 telephone-event/8000\r\n" +
"a=fmtp:101 0-16\r\n" +
"a=ptime:20\r\n",
Payload: &sip.MiscPayload{
T: "application/sdp-lol",
D: []byte("v=0\r\n" +
"o=- 2862054018559638081 6057228511765453924 IN IP4 10.11.34.37\r\n" +
"s=-\r\n" +
"c=IN IP4 10.11.34.37\r\n" +
"t=0 0\r\n" +
"m=audio 23448 RTP/AVP 0 101\r\n" +
"a=rtpmap:0 PCMU/8000\r\n" +
"a=rtpmap:101 telephone-event/8000\r\n" +
"a=fmtp:101 0-16\r\n" +
"a=ptime:20\r\n"),
},
},
},
}


+ 19
- 0
sip/payload.go View File

@ -0,0 +1,19 @@
package sip
type Payload interface {
ContentType() string
Data() []byte
}
type MiscPayload struct {
T string
D []byte
}
func (p *MiscPayload) ContentType() string {
return p.T
}
func (p *MiscPayload) Data() []byte {
return p.D
}

Loading…
Cancel
Save