From 80e84b29001632380340c0e05d3c9ad3b607dc88 Mon Sep 17 00:00:00 2001 From: negbie Date: Mon, 29 Jun 2020 18:20:01 +0200 Subject: [PATCH] Move dialog handling into own package Fix some linter warnings --- {sip => dialog}/dialog.go | 137 +++++++++++++++++--------------- {sip => dialog}/messages.go | 54 +++++++------ {sip => dialog}/receiver.go | 34 +++++--- {sip => dialog}/route.go | 29 ++++--- {sip => dialog}/trace.go | 10 +-- {sip => dialog}/transport.go | 35 ++++---- dialog/util.go | 30 +++++++ dsp/awgn.go | 6 +- dsp/awgn_test.go | 9 ++- dsp/dsp.go | 6 +- dsp/dsp_test.go | 9 ++- example/echo/echo_test.go | 15 ++-- example/echo2/echo2_test.go | 28 ++++--- example/echo3/echo3_test.go | 20 ++--- example/options/options_test.go | 11 +-- example/rawsip/rawsip_test.go | 9 ++- fone/main.go | 24 +++--- rtp/dtmf.go | 6 +- rtp/rtp.go | 6 +- rtp/session.go | 11 +-- rtp/session_test.go | 6 +- sdp/codec.go | 6 +- sdp/codecs.go | 54 ++++++------- sdp/media.go | 6 +- sdp/origin.go | 7 +- sdp/sdp_test.go | 75 ++++++++--------- sip/addr.go | 7 +- sip/addr_test.go | 31 ++++---- sip/charsets.go | 6 +- sip/charsets_test.go | 6 +- sip/errors.go | 6 +- sip/escape.go | 6 +- sip/escape_test.go | 18 ++--- sip/method.go | 6 +- sip/msg.go | 6 +- sip/msg_test.go | 79 +++++++++--------- sip/msgerror.go | 6 +- sip/param.go | 6 +- sip/payload.go | 6 +- sip/prefs.go | 6 +- sip/quote.go | 6 +- sip/quote_test.go | 27 +++---- sip/status.go | 6 +- sip/uri.go | 9 ++- sip/uri_test.go | 49 ++++++------ sip/uriheader.go | 6 +- sip/uriparam.go | 6 +- sip/util.go | 26 +----- sip/via.go | 9 ++- sip/xheader.go | 6 +- util/util.go | 10 ++- 51 files changed, 531 insertions(+), 467 deletions(-) rename {sip => dialog}/dialog.go (78%) rename {sip => dialog}/messages.go (77%) rename {sip => dialog}/receiver.go (79%) rename {sip => dialog}/route.go (80%) rename {sip => dialog}/trace.go (93%) rename {sip => dialog}/transport.go (79%) create mode 100644 dialog/util.go diff --git a/sip/dialog.go b/dialog/dialog.go similarity index 78% rename from sip/dialog.go rename to dialog/dialog.go index cf38178..7e397d6 100755 --- a/sip/dialog.go +++ b/dialog/dialog.go @@ -14,7 +14,7 @@ // SIP Dialog Transport. -package sip +package dialog import ( "bytes" @@ -26,14 +26,15 @@ import ( "github.com/jart/gosip/rtp" "github.com/jart/gosip/sdp" + "github.com/jart/gosip/sip" "github.com/jart/gosip/util" ) const ( - DialogProceeding = iota - DialogRinging - DialogAnswered - DialogHangup + Proceeding = iota + Ringing + Answered + Hangup ) var ( @@ -51,9 +52,9 @@ type Dialog struct { } type dialogState struct { - sockMsgs <-chan *Msg + sockMsgs <-chan *sip.Msg sockErrs <-chan error - csockMsgs <-chan *Msg + csockMsgs <-chan *sip.Msg csockErrs <-chan error errChan chan<- error stateChan chan<- int @@ -65,12 +66,12 @@ type dialogState struct { sock *net.UDPConn // Outbound message socket (connected for ICMP) csock *net.UDPConn // Inbound socket for Contact field. 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. - request *Msg // Current outbound request message. + invite *sip.Msg // Our INVITE that established the dialog. + remote *sip.Msg // Message from remote UA that established dialog. + request *sip.Msg // Current outbound request message. requestResends int // Number of REsends of message so far. requestTimer <-chan time.Time // Resend timer for message. - response *Msg // Current outbound request message. + response *sip.Msg // Current outbound request message. responseResends int // Number of REsends of message so far. responseTimer <-chan time.Time // Resend timer for message. lseq int // Local CSeq value. @@ -79,7 +80,7 @@ type dialogState struct { } // NewDialog creates a phone call. -func NewDialog(invite *Msg) (dl *Dialog, err error) { +func NewDialog(invite *sip.Msg) (dl *Dialog, err error) { errChan := make(chan error) stateChan := make(chan int) peerChan := make(chan *net.UDPAddr) @@ -148,13 +149,13 @@ func (dls *dialogState) run() { } } -func (dls *dialogState) sendRequest(request *Msg) bool { +func (dls *dialogState) sendRequest(request *sip.Msg) bool { host, port, err := RouteMessage(nil, nil, request) if err != nil { dls.errChan <- err return false } - wantSRV := dls.state < DialogAnswered + wantSRV := dls.state < Answered routes, err := RouteAddress(host, port, wantSRV) if err != nil { dls.errChan <- err @@ -177,7 +178,7 @@ func (dls *dialogState) popRoute() bool { return dls.popRoute() } dls.populate(dls.request) - if dls.state < DialogAnswered { + if dls.state < Answered { dls.rseq = 0 dls.remote = nil dls.lseq = dls.request.CSeq @@ -199,7 +200,7 @@ func (dls *dialogState) connect() bool { return false } dls.sock = conn.(*net.UDPConn) - sockMsgs := make(chan *Msg) + sockMsgs := make(chan *sip.Msg) sockErrs := make(chan error) dls.sockMsgs = sockMsgs dls.sockErrs = sockErrs @@ -215,7 +216,7 @@ func (dls *dialogState) connect() bool { return false } dls.csock = cconn.(*net.UDPConn) - csockMsgs := make(chan *Msg) + csockMsgs := make(chan *sip.Msg) csockErrs := make(chan error) dls.csockMsgs = csockMsgs dls.csockErrs = csockErrs @@ -225,24 +226,28 @@ func (dls *dialogState) connect() bool { return true } -func (dls *dialogState) populate(msg *Msg) { +func (dls *dialogState) populate(msg *sip.Msg) { laddr := dls.sock.LocalAddr().(*net.UDPAddr) lhost := laddr.IP.String() lport := uint16(laddr.Port) if msg.Via == nil { - msg.Via = &Via{Host: lhost} + msg.Via = &sip.Via{Host: lhost} } msg.Via.Port = lport branch := msg.Via.Param.Get("branch") if branch != nil { branch.Value = util.GenerateBranch() } else { - msg.Via.Param = &Param{"branch", util.GenerateBranch(), msg.Via.Param} + msg.Via.Param = &sip.Param{ + Name: "branch", + Value: util.GenerateBranch(), + Next: msg.Via.Param, + } } if msg.Contact == nil { - msg.Contact = &Addr{Uri: &URI{Scheme: "sip", Host: lhost}} + msg.Contact = &sip.Addr{Uri: &sip.URI{Scheme: "sip", Host: lhost}} } if dls.csock != nil { msg.Contact.Uri.Port = uint16(dls.csock.LocalAddr().(*net.UDPAddr).Port) @@ -250,10 +255,14 @@ func (dls *dialogState) populate(msg *Msg) { msg.Contact.Uri.Port = lport } if msg.Contact.Uri.Param.Get("transport") == nil { - msg.Contact.Uri.Param = &URIParam{"transport", "udp", msg.Contact.Uri.Param} + msg.Contact.Uri.Param = &sip.URIParam{ + Name: "transport", + Value: "udp", + Next: msg.Contact.Uri.Param, + } } - if msg.Method == MethodInvite { + if msg.Method == sip.MethodInvite { if ms, ok := msg.Payload.(*sdp.SDP); ok { if ms.Addr == "" { ms.Addr = lhost @@ -269,9 +278,9 @@ func (dls *dialogState) populate(msg *Msg) { PopulateMessage(nil, nil, msg) } -func (dls *dialogState) handleMessage(msg *Msg) bool { +func (dls *dialogState) handleMessage(msg *sip.Msg) bool { if msg.VersionMajor != 2 || msg.VersionMinor != 0 { - if !dls.send(NewResponse(msg, StatusVersionNotSupported)) { + if !dls.send(NewResponse(msg, sip.StatusVersionNotSupported)) { return false } dls.errChan <- errors.New("Remote UA is using a strange SIP version") @@ -279,7 +288,7 @@ func (dls *dialogState) handleMessage(msg *Msg) bool { } if msg.CallID != dls.request.CallID { log.Printf("Received message doesn't match dialog\r\n") - return dls.send(NewResponse(msg, StatusCallTransactionDoesNotExist)) + return dls.send(NewResponse(msg, sip.StatusCallTransactionDoesNotExist)) } if msg.IsResponse() { return dls.handleResponse(msg) @@ -288,12 +297,12 @@ func (dls *dialogState) handleMessage(msg *Msg) bool { } } -func (dls *dialogState) handleResponse(msg *Msg) bool { +func (dls *dialogState) handleResponse(msg *sip.Msg) bool { if !ResponseMatch(dls.request, msg) { log.Printf("Received response doesn't match transaction\r\n") return true } - if msg.Status >= StatusOK && dls.request.Method == MethodInvite { + if msg.Status >= sip.StatusOK && dls.request.Method == sip.MethodInvite { if msg.Contact == nil { dls.errChan <- errors.New("Remote UA sent >=200 response w/o Contact") return false @@ -304,49 +313,49 @@ func (dls *dialogState) handleResponse(msg *Msg) bool { } dls.routes = nil dls.requestTimer = nil - if msg.Status <= StatusOK { + if msg.Status <= sip.StatusOK { dls.checkSDP(msg) } switch msg.Status { - case StatusTrying: - dls.transition(DialogProceeding) - case StatusRinging, StatusSessionProgress: - dls.transition(DialogRinging) - case StatusOK: + case sip.StatusTrying: + dls.transition(Proceeding) + case sip.StatusRinging, sip.StatusSessionProgress: + dls.transition(Ringing) + case sip.StatusOK: switch msg.CSeqMethod { - case MethodInvite: + case sip.MethodInvite: if dls.remote == nil { - dls.transition(DialogAnswered) + dls.transition(Answered) } dls.remote = msg - case MethodBye, MethodCancel: - dls.transition(DialogHangup) + case sip.MethodBye, sip.MethodCancel: + dls.transition(Hangup) return false } - case StatusServiceUnavailable: + case sip.StatusServiceUnavailable: if dls.request == dls.invite { log.Printf("Service unavailable: %s (%s)\r\n", dls.sock.RemoteAddr(), dls.dest) return dls.popRoute() } else { - dls.errChan <- &ResponseError{Msg: msg} + dls.errChan <- &sip.ResponseError{Msg: msg} return false } - case StatusMovedPermanently, StatusMovedTemporarily: + case sip.StatusMovedPermanently, sip.StatusMovedTemporarily: dls.invite.Request = msg.Contact.Uri dls.invite.Route = nil return dls.sendRequest(dls.invite) default: - if msg.Status > StatusOK { - dls.errChan <- &ResponseError{Msg: msg} + if msg.Status > sip.StatusOK { + dls.errChan <- &sip.ResponseError{Msg: msg} return false } } return true } -func (dls *dialogState) handleRequest(msg *Msg) bool { +func (dls *dialogState) handleRequest(msg *sip.Msg) bool { if msg.MaxForwards <= 0 { - if !dls.send(NewResponse(msg, StatusTooManyHops)) { + if !dls.send(NewResponse(msg, sip.StatusTooManyHops)) { return false } dls.errChan <- errors.New("Remote froot loop detected") @@ -357,39 +366,39 @@ func (dls *dialogState) handleRequest(msg *Msg) bool { } else { if msg.CSeq < dls.rseq { // RFC 3261 mandates a 500 response for out of order requests. - return dls.send(NewResponse(msg, StatusInternalServerError)) + return dls.send(NewResponse(msg, sip.StatusInternalServerError)) } dls.rseq = msg.CSeq } switch msg.Method { - case MethodBye: - if !dls.send(NewResponse(msg, StatusOK)) { + case sip.MethodBye: + if !dls.send(NewResponse(msg, sip.StatusOK)) { return false } - dls.transition(DialogHangup) + dls.transition(Hangup) return false - case MethodOptions: // Probably a keep-alive ping. - return dls.send(NewResponse(msg, StatusOK)) - case MethodInvite: // Re-INVITEs are used to change the RTP or signalling path. + case sip.MethodOptions: // Probably a keep-alive ping. + return dls.send(NewResponse(msg, sip.StatusOK)) + case sip.MethodInvite: // Re-INVITEs are used to change the RTP or signalling path. dls.remote = msg dls.checkSDP(msg) - return dls.sendResponse(NewResponse(msg, StatusOK)) - case MethodAck: // Re-INVITE response has been ACK'd. + return dls.sendResponse(NewResponse(msg, sip.StatusOK)) + case sip.MethodAck: // Re-INVITE response has been ACK'd. dls.response = nil dls.responseTimer = nil return true default: - return dls.send(NewResponse(msg, StatusMethodNotAllowed)) + return dls.send(NewResponse(msg, sip.StatusMethodNotAllowed)) } } -func (dls *dialogState) checkSDP(msg *Msg) { +func (dls *dialogState) checkSDP(msg *sip.Msg) { if ms, ok := msg.Payload.(*sdp.SDP); ok { dls.peerChan <- &net.UDPAddr{IP: net.ParseIP(ms.Addr), Port: int(ms.Audio.Port)} } } -func (dls *dialogState) send(msg *Msg) bool { +func (dls *dialogState) send(msg *sip.Msg) bool { if msg.MaxForwards > 0 { msg.MaxForwards-- if msg.MaxForwards == 0 { @@ -432,7 +441,7 @@ func (dls *dialogState) resendRequest() bool { } // sendResponse is used to reliably send a response to an INVITE only. -func (dls *dialogState) sendResponse(msg *Msg) bool { +func (dls *dialogState) sendResponse(msg *sip.Msg) bool { dls.response = msg dls.responseResends = 0 dls.responseTimer = time.After(duration(resendInterval)) @@ -461,17 +470,17 @@ func (dls *dialogState) resendResponse() bool { func (dls *dialogState) sendHangup() bool { switch dls.state { - case DialogProceeding, DialogRinging: + case Proceeding, Ringing: return dls.send(NewCancel(dls.invite)) - case DialogAnswered: + case Answered: return dls.sendRequest(NewBye(dls.invite, dls.remote, &dls.lseq)) - case DialogHangup: + case Hangup: panic("Why didn't the event loop break?") default: // o A UA or proxy cannot send CANCEL for a transaction until it gets a // provisional response for the request. This was allowed in RFC 2543 // but leads to potential race conditions. - dls.transition(DialogHangup) + dls.transition(Hangup) return false } } @@ -493,7 +502,7 @@ func (dls *dialogState) cleanupSock() { if dls.sock != nil { dls.sock.Close() dls.sock = nil - _, _ = <-dls.sockMsgs + <-dls.sockMsgs <-dls.sockErrs } } @@ -502,7 +511,7 @@ func (dls *dialogState) cleanupCSock() { if dls.csock != nil { dls.csock.Close() dls.csock = nil - _, _ = <-dls.csockMsgs + <-dls.csockMsgs <-dls.csockErrs } } diff --git a/sip/messages.go b/dialog/messages.go similarity index 77% rename from sip/messages.go rename to dialog/messages.go index a83ea3d..e625277 100644 --- a/sip/messages.go +++ b/dialog/messages.go @@ -1,22 +1,24 @@ // Copyright 2020 Justine Alexandra Roberts Tunney -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -package sip +package dialog import ( - "github.com/jart/gosip/util" "log" + + "github.com/jart/gosip/sip" + "github.com/jart/gosip/util" ) const ( @@ -24,8 +26,8 @@ const ( GosipAllow = "INVITE, ACK, CANCEL, BYE, OPTIONS" ) -func NewRequest(tp *Transport, method string, to, from *Addr) *Msg { - return &Msg{ +func NewRequest(tp *Transport, method string, to, from *sip.Addr) *sip.Msg { + return &sip.Msg{ Method: method, Request: to.Uri.Copy(), Via: tp.Via.Copy().Branch(), @@ -38,10 +40,10 @@ func NewRequest(tp *Transport, method string, to, from *Addr) *Msg { } } -func NewResponse(msg *Msg, status int) *Msg { - return &Msg{ +func NewResponse(msg *sip.Msg, status int) *sip.Msg { + return &sip.Msg{ Status: status, - Phrase: Phrase(status), + Phrase: sip.Phrase(status), Via: msg.Via, From: msg.From, To: msg.To, @@ -55,9 +57,9 @@ func NewResponse(msg *Msg, status int) *Msg { } // http://tools.ietf.org/html/rfc3261#section-17.1.1.3 -func NewAck(msg, invite *Msg) *Msg { - return &Msg{ - Method: MethodAck, +func NewAck(msg, invite *sip.Msg) *sip.Msg { + return &sip.Msg{ + Method: sip.MethodAck, Request: msg.Contact.Uri, From: msg.From, To: msg.To, @@ -72,44 +74,44 @@ func NewAck(msg, invite *Msg) *Msg { } } -func NewCancel(invite *Msg) *Msg { - if invite.IsResponse() || invite.Method != MethodInvite { +func NewCancel(invite *sip.Msg) *sip.Msg { + if invite.IsResponse() || invite.Method != sip.MethodInvite { log.Printf("Can't CANCEL anything non-INVITE:\r\n%s", invite) } - return &Msg{ - Method: MethodCancel, + return &sip.Msg{ + Method: sip.MethodCancel, Request: invite.Request, Via: invite.Via, From: invite.From, To: invite.To, CallID: invite.CallID, CSeq: invite.CSeq, - CSeqMethod: MethodCancel, + CSeqMethod: sip.MethodCancel, Route: invite.Route, } } -func NewBye(invite, remote *Msg, lseq *int) *Msg { +func NewBye(invite, remote *sip.Msg, lseq *int) *sip.Msg { if lseq == nil { lseq = new(int) *lseq = invite.CSeq } *lseq++ - return &Msg{ - Method: MethodBye, + return &sip.Msg{ + Method: sip.MethodBye, Request: remote.Contact.Uri, From: invite.From, To: remote.To, CallID: invite.CallID, CSeq: *lseq, - CSeqMethod: MethodBye, + CSeqMethod: sip.MethodBye, Route: remote.RecordRoute.Reversed(), } } // Returns true if `resp` can be considered an appropriate response to `msg`. // Do not use for ACKs. -func ResponseMatch(req, rsp *Msg) bool { +func ResponseMatch(req, rsp *sip.Msg) bool { return (rsp.IsResponse() && rsp.CSeq == req.CSeq && rsp.CSeqMethod == req.Method && @@ -120,10 +122,10 @@ func ResponseMatch(req, rsp *Msg) bool { // Returns true if `ack` can be considered an appropriate response to `msg`. // We don't enforce a matching Via because some VoIP software will generate a // new branch for ACKs. -func AckMatch(msg, ack *Msg) bool { +func AckMatch(msg, ack *sip.Msg) bool { return (!ack.IsResponse() && - ack.Method == MethodAck && + ack.Method == sip.MethodAck && ack.CSeq == msg.CSeq && - ack.CSeqMethod == MethodAck && + ack.CSeqMethod == sip.MethodAck && ack.Via.Last().CompareHostPort(msg.Via)) } diff --git a/sip/receiver.go b/dialog/receiver.go similarity index 79% rename from sip/receiver.go rename to dialog/receiver.go index f0d8080..19f575c 100644 --- a/sip/receiver.go +++ b/dialog/receiver.go @@ -12,16 +12,18 @@ // See the License for the specific language governing permissions and // limitations under the License. -package sip +package dialog import ( "log" "net" "strconv" "time" + + "github.com/jart/gosip/sip" ) -func ReceiveMessages(sock *net.UDPConn, c chan<- *Msg, e chan<- error) { +func ReceiveMessages(sock *net.UDPConn, c chan<- *sip.Msg, e chan<- error) { buf := make([]byte, 2048) laddr := sock.LocalAddr().(*net.UDPAddr) lhost := laddr.IP.String() @@ -37,7 +39,7 @@ func ReceiveMessages(sock *net.UDPConn, c chan<- *Msg, e chan<- error) { if *tracing { trace("recv", packet, addr) } - msg, err := ParseMsg(packet) + msg, err := sip.ParseMsg(packet) if err != nil { log.Printf("Dropping SIP message: %s\r\n", err) continue @@ -54,7 +56,7 @@ func ReceiveMessages(sock *net.UDPConn, c chan<- *Msg, e chan<- error) { close(e) // Must be unbuffered! } -func addReceived(msg *Msg, addr *net.UDPAddr) { +func addReceived(msg *sip.Msg, addr *net.UDPAddr) { if msg.IsResponse() { return } @@ -64,7 +66,11 @@ func addReceived(msg *Msg, addr *net.UDPAddr) { port := strconv.Itoa(addr.Port) if rport == nil { - msg.Via.Param = &Param{"rport", port, msg.Via.Param} + msg.Via.Param = &sip.Param{ + Name: "rport", + Value: port, + Next: msg.Via.Param, + } } else { // implied rport is 5060, but some NAT will use another port,we use real port instead @@ -75,26 +81,34 @@ func addReceived(msg *Msg, addr *net.UDPAddr) { } if msg.Via.Host != addr.IP.String() { if msg.Via.Param.Get("received") == nil { - msg.Via.Param = &Param{"received", addr.IP.String(), msg.Via.Param} + msg.Via.Param = &sip.Param{ + Name: "received", + Value: addr.IP.String(), + Next: msg.Via.Param, + } } } } -func addTimestamp(msg *Msg, ts time.Time) { +func addTimestamp(msg *sip.Msg, ts time.Time) { if *timestampTagging { - msg.Via.Param = &Param{"usi", strconv.FormatInt(ts.UnixNano()/int64(time.Microsecond), 10), msg.Via.Param} + msg.Via.Param = &sip.Param{ + Name: "usi", + Value: strconv.FormatInt(ts.UnixNano()/int64(time.Microsecond), 10), + Next: msg.Via.Param, + } } } // RFC3261 16.4 Route Information Preprocessing // RFC3261 16.12.1.2: Traversing a Strict-Routing Proxy -func fixMessagesFromStrictRouters(lhost string, lport uint16, msg *Msg) { +func fixMessagesFromStrictRouters(lhost string, lport uint16, msg *sip.Msg) { if msg.Request != nil && msg.Request.Param.Get("lr") != nil && msg.Route != nil && msg.Request.Host == lhost && or5060(msg.Request.Port) == lport { - var oldReq, newReq *URI + var oldReq, newReq *sip.URI if msg.Route.Next == nil { oldReq, newReq = msg.Request, msg.Route.Uri msg.Request = msg.Route.Uri diff --git a/sip/route.go b/dialog/route.go similarity index 80% rename from sip/route.go rename to dialog/route.go index 613c191..3cdd88d 100644 --- a/sip/route.go +++ b/dialog/route.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package sip +package dialog import ( "errors" @@ -20,6 +20,7 @@ import ( "net" "strconv" + "github.com/jart/gosip/sip" "github.com/jart/gosip/util" ) @@ -28,7 +29,7 @@ type AddressRoute struct { Next *AddressRoute } -func PopulateMessage(via *Via, contact *Addr, msg *Msg) { +func PopulateMessage(via *sip.Via, contact *sip.Addr, msg *sip.Msg) { if !msg.IsResponse() { if msg.Via == nil { msg.Via = via @@ -37,7 +38,7 @@ func PopulateMessage(via *Via, contact *Addr, msg *Msg) { msg.Contact = contact } if msg.To == nil { - msg.To = &Addr{Uri: msg.Request} + msg.To = &sip.Addr{Uri: msg.Request} } if msg.From == nil { msg.From = msg.Contact.Copy() @@ -59,15 +60,23 @@ func PopulateMessage(via *Via, contact *Addr, msg *Msg) { msg.UserAgent = GosipUA } if msg.Via.Param.Get("branch") == nil { - msg.Via.Param = &Param{"branch", util.GenerateBranch(), msg.Via.Param} + msg.Via.Param = &sip.Param{ + Name: "branch", + Value: util.GenerateBranch(), + Next: msg.Via.Param, + } } if msg.From.Param.Get("tag") == nil { - msg.From.Param = &Param{"tag", util.GenerateTag(), msg.From.Param} + msg.From.Param = &sip.Param{ + Name: "tag", + Value: util.GenerateTag(), + Next: msg.From.Param, + } } } } -func RouteMessage(via *Via, contact *Addr, msg *Msg) (host string, port uint16, err error) { +func RouteMessage(via *sip.Via, contact *sip.Addr, msg *sip.Msg) (host string, port uint16, err error) { if msg.IsResponse() { if via.CompareHostPort(msg.Via) { msg.Via = msg.Via.Next @@ -103,7 +112,7 @@ func RouteMessage(via *Via, contact *Addr, msg *Msg) (host string, port uint16, } else { // RFC3261 16.12.1.2: Traversing a Strict-Routing Proxy msg.Route = msg.Route.Copy() - msg.Route.Last().Next = &Addr{Uri: msg.Request} + msg.Route.Last().Next = &sip.Addr{Uri: msg.Request} msg.Request = msg.Route.Uri msg.Route = msg.Route.Next host, port = msg.Request.Host, msg.Request.Port @@ -120,7 +129,7 @@ func RouteAddress(host string, port uint16, wantSRV bool) (routes *AddressRoute, if port == 0 { port = 5060 } - return &AddressRoute{Address: net.JoinHostPort(host, portstr(port))}, nil + return &AddressRoute{Address: net.JoinHostPort(host, util.Portstr(port))}, nil } if port == 0 { if wantSRV { @@ -129,7 +138,7 @@ func RouteAddress(host string, port uint16, wantSRV bool) (routes *AddressRoute, s := "" for i := len(srvs) - 1; i >= 0; i-- { routes = &AddressRoute{ - Address: net.JoinHostPort(srvs[i].Target, portstr(srvs[i].Port)), + Address: net.JoinHostPort(srvs[i].Target, util.Portstr(srvs[i].Port)), Next: routes, } s = " " + routes.Address + s @@ -141,7 +150,7 @@ func RouteAddress(host string, port uint16, wantSRV bool) (routes *AddressRoute, } port = 5060 } - addr, err := net.ResolveUDPAddr("udp", net.JoinHostPort(host, portstr(port))) + addr, err := net.ResolveUDPAddr("udp", net.JoinHostPort(host, util.Portstr(port))) if err != nil { return nil, err } diff --git a/sip/trace.go b/dialog/trace.go similarity index 93% rename from sip/trace.go rename to dialog/trace.go index 785c538..03e4475 100644 --- a/sip/trace.go +++ b/dialog/trace.go @@ -1,18 +1,18 @@ // Copyright 2020 Justine Alexandra Roberts Tunney -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -package sip +package dialog import ( "flag" @@ -30,7 +30,7 @@ func trace(dir string, pkt []byte, addr net.Addr) { size := len(pkt) bar := strings.Repeat("-", 72) suffix := "\r\n" - if pkt != nil && len(pkt) > 0 && pkt[len(pkt)-1] == '\n' { + if len(pkt) > 0 && pkt[len(pkt)-1] == '\n' { suffix = "" } log.Printf( diff --git a/sip/transport.go b/dialog/transport.go similarity index 79% rename from sip/transport.go rename to dialog/transport.go index 0fab075..5cf7e99 100755 --- a/sip/transport.go +++ b/dialog/transport.go @@ -1,11 +1,11 @@ // Copyright 2020 Justine Alexandra Roberts Tunney -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -15,21 +15,24 @@ // SIP Transport Layer. Responsible for serializing messages to/from // your network. -package sip +package dialog import ( "bytes" "net" "time" + + "github.com/jart/gosip/sip" + "github.com/jart/gosip/util" ) // Transport sends and receives SIP messages over UDP with stateless routing. type Transport struct { - C <-chan *Msg + C <-chan *sip.Msg E <-chan error Sock *net.UDPConn - Via *Via - Contact *Addr + Via *sip.Via + Contact *sip.Addr } // Creates a new stateless network mechanism for transmitting and receiving SIP @@ -40,8 +43,8 @@ type Transport struct { // port. This value is also used for contact headers which tell other // user-agents where to send responses and hence should only contain an IP or // canonical address. -func NewTransport(contact *Addr) (tp *Transport, err error) { - saddr := net.JoinHostPort(contact.Uri.Host, portstr(contact.Uri.Port)) +func NewTransport(contact *sip.Addr) (tp *Transport, err error) { + saddr := net.JoinHostPort(contact.Uri.Host, util.Portstr(contact.Uri.Port)) conn, err := net.ListenPacket("udp", saddr) if err != nil { return nil, err @@ -51,15 +54,19 @@ func NewTransport(contact *Addr) (tp *Transport, err error) { contact = contact.Copy() contact.Next = nil contact.Uri.Port = uint16(addr.Port) - contact.Uri.Param = &URIParam{"transport", "udp", contact.Uri.Param} - c := make(chan *Msg) + contact.Uri.Param = &sip.URIParam{ + Name: "transport", + Value: "udp", + Next: contact.Uri.Param, + } + c := make(chan *sip.Msg) e := make(chan error) tp = &Transport{ C: c, E: e, Sock: sock, Contact: contact, - Via: &Via{ + Via: &sip.Via{ Host: addr.IP.String(), Port: uint16(addr.Port), }, @@ -69,13 +76,13 @@ func NewTransport(contact *Addr) (tp *Transport, err error) { } // Sends a SIP message. -func (tp *Transport) Send(msg *Msg) error { +func (tp *Transport) Send(msg *sip.Msg) error { PopulateMessage(tp.Via, tp.Contact, msg) host, port, err := RouteMessage(tp.Via, tp.Contact, msg) if err != nil { return err } - addr, err := net.ResolveUDPAddr("udp", net.JoinHostPort(host, portstr(port))) + addr, err := net.ResolveUDPAddr("udp", net.JoinHostPort(host, util.Portstr(port))) if err != nil { return err } diff --git a/dialog/util.go b/dialog/util.go new file mode 100644 index 0000000..9f40b3b --- /dev/null +++ b/dialog/util.go @@ -0,0 +1,30 @@ +// Copyright 2020 Justine Alexandra Roberts Tunney +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package dialog + +import ( + "time" +) + +func duration(ms *int) time.Duration { + return time.Duration(*ms) * time.Millisecond +} + +func or5060(port uint16) uint16 { + if port == 0 { + return 5060 + } + return port +} diff --git a/dsp/awgn.go b/dsp/awgn.go index d348164..e710204 100644 --- a/dsp/awgn.go +++ b/dsp/awgn.go @@ -1,11 +1,11 @@ // Copyright 2020 Justine Alexandra Roberts Tunney -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. diff --git a/dsp/awgn_test.go b/dsp/awgn_test.go index adab1ba..fc96982 100644 --- a/dsp/awgn_test.go +++ b/dsp/awgn_test.go @@ -1,11 +1,11 @@ // Copyright 2020 Justine Alexandra Roberts Tunney -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -15,8 +15,9 @@ package dsp_test import ( - "github.com/jart/gosip/dsp" "testing" + + "github.com/jart/gosip/dsp" ) func TestAWGN(t *testing.T) { diff --git a/dsp/dsp.go b/dsp/dsp.go index 05ce37e..3bbc680 100755 --- a/dsp/dsp.go +++ b/dsp/dsp.go @@ -1,11 +1,11 @@ // Copyright 2020 Justine Alexandra Roberts Tunney -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. diff --git a/dsp/dsp_test.go b/dsp/dsp_test.go index eda1a13..b0f5ae2 100755 --- a/dsp/dsp_test.go +++ b/dsp/dsp_test.go @@ -1,11 +1,11 @@ // Copyright 2020 Justine Alexandra Roberts Tunney -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -15,8 +15,9 @@ package dsp_test import ( - "github.com/jart/gosip/dsp" "testing" + + "github.com/jart/gosip/dsp" ) func TestL16MixSat160(t *testing.T) { diff --git a/example/echo/echo_test.go b/example/echo/echo_test.go index 561dbf8..a4cbd49 100755 --- a/example/echo/echo_test.go +++ b/example/echo/echo_test.go @@ -1,11 +1,11 @@ // Copyright 2020 Justine Alexandra Roberts Tunney -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -147,15 +147,16 @@ package echo_test import ( "bytes" - "github.com/jart/gosip/rtp" - "github.com/jart/gosip/sdp" - "github.com/jart/gosip/sip" - "github.com/jart/gosip/util" "log" "math/rand" "net" "testing" "time" + + "github.com/jart/gosip/rtp" + "github.com/jart/gosip/sdp" + "github.com/jart/gosip/sip" + "github.com/jart/gosip/util" ) func TestCallToEchoApp(t *testing.T) { diff --git a/example/echo2/echo2_test.go b/example/echo2/echo2_test.go index 5517dd0..3d1579a 100755 --- a/example/echo2/echo2_test.go +++ b/example/echo2/echo2_test.go @@ -1,11 +1,11 @@ // Copyright 2020 Justine Alexandra Roberts Tunney -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -17,14 +17,16 @@ package echo2_test import ( - "github.com/jart/gosip/dsp" - "github.com/jart/gosip/rtp" - "github.com/jart/gosip/sdp" - "github.com/jart/gosip/sip" "log" "net" "testing" "time" + + "github.com/jart/gosip/dialog" + "github.com/jart/gosip/dsp" + "github.com/jart/gosip/rtp" + "github.com/jart/gosip/sdp" + "github.com/jart/gosip/sip" ) func TestCallToEchoApp(t *testing.T) { @@ -40,14 +42,14 @@ func TestCallToEchoApp(t *testing.T) { rtpaddr := rs.Sock.LocalAddr().(*net.UDPAddr) // Create the SIP UDP transport layer. - tp, err := sip.NewTransport(from) + tp, err := dialog.NewTransport(from) if err != nil { t.Fatal(err) } defer tp.Sock.Close() // Send an INVITE message with an SDP media session description. - invite := sip.NewRequest(tp, sip.MethodInvite, to, from) + invite := dialog.NewRequest(tp, sip.MethodInvite, to, from) invite.Payload = sdp.New(rtpaddr, sdp.ULAWCodec, sdp.DTMFCodec) err = tp.Send(invite) if err != nil { @@ -91,7 +93,7 @@ loop: case msg = <-tp.C: if msg.IsResponse() { if msg.Status >= sip.StatusOK && msg.CSeq == invite.CSeq { - err = tp.Send(sip.NewAck(msg, invite)) + err = tp.Send(dialog.NewAck(msg, invite)) if err != nil { t.Fatal("SIP send failed:", err) } @@ -129,7 +131,7 @@ loop: } else { if msg.Method == "BYE" { log.Printf("Remote Hangup!") - err = tp.Send(sip.NewResponse(invite, sip.StatusOK)) + err = tp.Send(dialog.NewResponse(invite, sip.StatusOK)) if err != nil { t.Fatal("SIP send failed:", err) } @@ -148,9 +150,9 @@ loop: resendTimer = time.After(resendInterval) case <-deathTimer: if answered { - resend = sip.NewBye(invite, msg, nil) + resend = dialog.NewBye(invite, msg, nil) } else { - resend = sip.NewCancel(invite) + resend = dialog.NewCancel(invite) } err = tp.Send(resend) if err != nil { diff --git a/example/echo3/echo3_test.go b/example/echo3/echo3_test.go index 6e3d6f7..0fb5bb2 100755 --- a/example/echo3/echo3_test.go +++ b/example/echo3/echo3_test.go @@ -1,11 +1,11 @@ // Copyright 2020 Justine Alexandra Roberts Tunney -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -17,14 +17,16 @@ package echo3_test import ( + "net" + "testing" + "time" + + "github.com/jart/gosip/dialog" "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) { @@ -49,7 +51,7 @@ func TestCallToEchoApp(t *testing.T) { } // Create a SIP phone call. - dl, err := sip.NewDialog(invite) + dl, err := dialog.NewDialog(invite) if err != nil { t.Fatal(err) } @@ -79,9 +81,9 @@ func TestCallToEchoApp(t *testing.T) { return case state := <-dl.OnState: switch state { - case sip.DialogAnswered: + case dialog.Answered: answered = true - case sip.DialogHangup: + case dialog.Hangup: if !answered { t.Error("Call didn't get answered!") } diff --git a/example/options/options_test.go b/example/options/options_test.go index ef1af6c..8dccd31 100755 --- a/example/options/options_test.go +++ b/example/options/options_test.go @@ -1,11 +1,11 @@ // Copyright 2020 Justine Alexandra Roberts Tunney -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -18,11 +18,12 @@ package options_test import ( "bytes" - "github.com/jart/gosip/sip" - "github.com/jart/gosip/util" "net" "testing" "time" + + "github.com/jart/gosip/sip" + "github.com/jart/gosip/util" ) func TestOptions(t *testing.T) { diff --git a/example/rawsip/rawsip_test.go b/example/rawsip/rawsip_test.go index 06747a4..806db9b 100755 --- a/example/rawsip/rawsip_test.go +++ b/example/rawsip/rawsip_test.go @@ -1,11 +1,11 @@ // Copyright 2020 Justine Alexandra Roberts Tunney -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -18,12 +18,13 @@ package rawsip_test import ( - "github.com/jart/gosip/util" "net" "strconv" "strings" "testing" "time" + + "github.com/jart/gosip/util" ) // An 'OPTIONS' message is used to: diff --git a/fone/main.go b/fone/main.go index a4b17f3..4def14e 100644 --- a/fone/main.go +++ b/fone/main.go @@ -1,11 +1,11 @@ // Copyright 2020 Justine Alexandra Roberts Tunney -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -25,11 +25,6 @@ import ( "errors" "flag" "fmt" - "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" "io/ioutil" "log" "net" @@ -38,6 +33,13 @@ import ( "os/signal" "time" "unsafe" + + "github.com/jart/gosip/dialog" + "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" ) const ( @@ -132,7 +134,7 @@ func main() { } // Create SIP Dialog State Machine - dl, err := sip.NewDialog(invite) + dl, err := dialog.NewDialog(invite) if err != nil { panic(err) } @@ -213,10 +215,10 @@ func main() { case rs.Peer = <-dl.OnPeer: case state := <-dl.OnState: switch state { - case sip.DialogAnswered: + case dialog.Answered: answered = true keyboardStart() - case sip.DialogHangup: + case dialog.Hangup: if answered { return } else { diff --git a/rtp/dtmf.go b/rtp/dtmf.go index fd6473a..c6bdd8b 100755 --- a/rtp/dtmf.go +++ b/rtp/dtmf.go @@ -1,11 +1,11 @@ // Copyright 2020 Justine Alexandra Roberts Tunney -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. diff --git a/rtp/rtp.go b/rtp/rtp.go index c18cd32..f66eee4 100755 --- a/rtp/rtp.go +++ b/rtp/rtp.go @@ -1,11 +1,11 @@ // Copyright 2020 Justine Alexandra Roberts Tunney -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. diff --git a/rtp/session.go b/rtp/session.go index ac8e2ef..bd4cb1a 100644 --- a/rtp/session.go +++ b/rtp/session.go @@ -1,11 +1,11 @@ // Copyright 2020 Justine Alexandra Roberts Tunney -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -18,13 +18,14 @@ package rtp import ( "errors" - "github.com/jart/gosip/dsp" - "github.com/jart/gosip/sdp" "log" "math/rand" "net" "strconv" "strings" + + "github.com/jart/gosip/dsp" + "github.com/jart/gosip/sdp" ) const ( diff --git a/rtp/session_test.go b/rtp/session_test.go index 11ef791..b7eac0d 100644 --- a/rtp/session_test.go +++ b/rtp/session_test.go @@ -1,11 +1,11 @@ // Copyright 2020 Justine Alexandra Roberts Tunney -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. diff --git a/sdp/codec.go b/sdp/codec.go index 8567756..e29b8ba 100644 --- a/sdp/codec.go +++ b/sdp/codec.go @@ -1,11 +1,11 @@ // Copyright 2020 Justine Alexandra Roberts Tunney -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. diff --git a/sdp/codecs.go b/sdp/codecs.go index 658f781..8129f77 100755 --- a/sdp/codecs.go +++ b/sdp/codecs.go @@ -1,11 +1,11 @@ // Copyright 2020 Justine Alexandra Roberts Tunney -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -38,29 +38,29 @@ var ( Opus = Codec{PT: 111, Name: "opus", Rate: 48000, Param: "2"} StandardCodecs = map[uint8]Codec{ - 0: ULAWCodec, // G.711 μ-Law is the de-facto codec (SpanDSP g711.h) - 3: Codec{PT: 3, Name: "GSM", Rate: 8000}, // Uncool codec asterisk ppl like (SpanDSP gsm0610.h) - 4: Codec{PT: 4, Name: "G723", Rate: 8000}, // Worthless. - 5: Codec{PT: 5, Name: "DVI4", Rate: 8000}, // Adaptive pulse code modulation (SpanDSP ima_adpcm.h) - 6: Codec{PT: 6, Name: "DVI4", Rate: 16000}, // Adaptive pulse code modulation 16khz (SpanDSP ima_adpcm.h) - 7: Codec{PT: 7, Name: "LPC", Rate: 8000}, // Chat with your friends ww2 field marshall style (SpanDSP lpc10.h) - 8: Codec{PT: 8, Name: "PCMA", Rate: 8000}, // G.711 variant of μ-Law used in yurop (SpanDSP g711.h) - 9: Codec{PT: 9, Name: "G722", Rate: 8000}, // Used for Polycom HD Voice; Rate actually 16khz LOL (SpanDSP g722.h) - 10: Codec{PT: 10, Name: "L16", Rate: 44100, Param: "2"}, // 16-bit signed PCM stereo/mono (mind your MTU; adjust ptime) - 11: Codec{PT: 11, Name: "L16", Rate: 44100}, - 12: Codec{PT: 12, Name: "QCELP", Rate: 8000}, - 13: Codec{PT: 13, Name: "CN", Rate: 8000}, // RFC3389 comfort noise - 14: Codec{PT: 14, Name: "MPA", Rate: 90000}, - 15: Codec{PT: 15, Name: "G728", Rate: 8000}, - 16: Codec{PT: 16, Name: "DVI4", Rate: 11025}, - 17: Codec{PT: 17, Name: "DVI4", Rate: 22050}, - 18: Codec{PT: 18, Name: "G729", Rate: 8000}, // Best telephone voice codec (if you got $10 bucks) - 25: Codec{PT: 25, Name: "CelB", Rate: 90000}, - 26: Codec{PT: 26, Name: "JPEG", Rate: 90000}, - 28: Codec{PT: 28, Name: "nv", Rate: 90000}, - 31: Codec{PT: 31, Name: "H261", Rate: 90000}, // RFC4587 Video - 32: Codec{PT: 32, Name: "MPV", Rate: 90000}, - 33: Codec{PT: 33, Name: "MP2T", Rate: 90000}, - 34: Codec{PT: 34, Name: "H263", Rate: 90000}, // $$$ video + 0: ULAWCodec, // G.711 μ-Law is the de-facto codec (SpanDSP g711.h) + 3: {PT: 3, Name: "GSM", Rate: 8000}, // Uncool codec asterisk ppl like (SpanDSP gsm0610.h) + 4: {PT: 4, Name: "G723", Rate: 8000}, // Worthless. + 5: {PT: 5, Name: "DVI4", Rate: 8000}, // Adaptive pulse code modulation (SpanDSP ima_adpcm.h) + 6: {PT: 6, Name: "DVI4", Rate: 16000}, // Adaptive pulse code modulation 16khz (SpanDSP ima_adpcm.h) + 7: {PT: 7, Name: "LPC", Rate: 8000}, // Chat with your friends ww2 field marshall style (SpanDSP lpc10.h) + 8: {PT: 8, Name: "PCMA", Rate: 8000}, // G.711 variant of μ-Law used in yurop (SpanDSP g711.h) + 9: {PT: 9, Name: "G722", Rate: 8000}, // Used for Polycom HD Voice; Rate actually 16khz LOL (SpanDSP g722.h) + 10: {PT: 10, Name: "L16", Rate: 44100, Param: "2"}, // 16-bit signed PCM stereo/mono (mind your MTU; adjust ptime) + 11: {PT: 11, Name: "L16", Rate: 44100}, + 12: {PT: 12, Name: "QCELP", Rate: 8000}, + 13: {PT: 13, Name: "CN", Rate: 8000}, // RFC3389 comfort noise + 14: {PT: 14, Name: "MPA", Rate: 90000}, + 15: {PT: 15, Name: "G728", Rate: 8000}, + 16: {PT: 16, Name: "DVI4", Rate: 11025}, + 17: {PT: 17, Name: "DVI4", Rate: 22050}, + 18: {PT: 18, Name: "G729", Rate: 8000}, // Best telephone voice codec (if you got $10 bucks) + 25: {PT: 25, Name: "CelB", Rate: 90000}, + 26: {PT: 26, Name: "JPEG", Rate: 90000}, + 28: {PT: 28, Name: "nv", Rate: 90000}, + 31: {PT: 31, Name: "H261", Rate: 90000}, // RFC4587 Video + 32: {PT: 32, Name: "MPV", Rate: 90000}, + 33: {PT: 33, Name: "MP2T", Rate: 90000}, + 34: {PT: 34, Name: "H263", Rate: 90000}, // $$$ video } ) diff --git a/sdp/media.go b/sdp/media.go index 85e629b..4130ac3 100644 --- a/sdp/media.go +++ b/sdp/media.go @@ -1,11 +1,11 @@ // Copyright 2020 Justine Alexandra Roberts Tunney -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. diff --git a/sdp/origin.go b/sdp/origin.go index b171023..c0a0b6c 100644 --- a/sdp/origin.go +++ b/sdp/origin.go @@ -1,11 +1,11 @@ // Copyright 2020 Justine Alexandra Roberts Tunney -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -16,6 +16,7 @@ package sdp import ( "bytes" + "github.com/jart/gosip/util" ) diff --git a/sdp/sdp_test.go b/sdp/sdp_test.go index 3adc3be..119a625 100755 --- a/sdp/sdp_test.go +++ b/sdp/sdp_test.go @@ -1,11 +1,11 @@ // Copyright 2020 Justine Alexandra Roberts Tunney -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -16,8 +16,9 @@ package sdp_test import ( "fmt" - "github.com/jart/gosip/sdp" "testing" + + "github.com/jart/gosip/sdp" ) type sdpTest struct { @@ -30,7 +31,7 @@ type sdpTest struct { var sdpTests = []sdpTest{ - sdpTest{ + { name: "Asterisk PCMU+DTMF", s: ("v=0\r\n" + "o=root 31589 31589 IN IP4 10.0.0.38\r\n" + @@ -58,18 +59,18 @@ var sdpTests = []sdpTest{ Proto: "RTP/AVP", Port: 30126, Codecs: []sdp.Codec{ - sdp.Codec{PT: 0, Name: "PCMU", Rate: 8000}, - sdp.Codec{PT: 101, Name: "telephone-event", Rate: 8000, Fmtp: "0-16"}, + {PT: 0, Name: "PCMU", Rate: 8000}, + {PT: 101, Name: "telephone-event", Rate: 8000, Fmtp: "0-16"}, }, }, Attrs: [][2]string{ - [2]string{"silenceSupp", "off - - - -"}, + {"silenceSupp", "off - - - -"}, }, Ptime: 20, }, }, - sdpTest{ + { name: "Audio+Video+Implicit+Fmtp", s: "v=0\r\n" + "o=- 3366701332 3366701332 IN IP4 1.2.3.4\r\n" + @@ -102,21 +103,21 @@ var sdpTests = []sdpTest{ Proto: "RTP/AVP", Port: 32898, Codecs: []sdp.Codec{ - sdp.Codec{PT: 18, Name: "G729", Rate: 8000, Fmtp: "annexb=yes"}, + {PT: 18, Name: "G729", Rate: 8000, Fmtp: "annexb=yes"}, }, }, Video: &sdp.Media{ Proto: "RTP/AVP", Port: 32900, Codecs: []sdp.Codec{ - sdp.Codec{PT: 34, Name: "H263", Rate: 90000}, + {PT: 34, Name: "H263", Rate: 90000}, }, }, Attrs: [][2]string{}, }, }, - sdpTest{ + { name: "Implicit Codecs", s: "v=0\r\n" + "o=- 3366701332 3366701332 IN IP4 1.2.3.4\r\n" + @@ -152,10 +153,10 @@ var sdpTests = []sdpTest{ Proto: "RTP/AVP", Port: 32898, Codecs: []sdp.Codec{ - sdp.Codec{PT: 9, Name: "G722", Rate: 8000}, - sdp.Codec{PT: 18, Name: "G729", Rate: 8000}, - sdp.Codec{PT: 0, Name: "PCMU", Rate: 8000}, - sdp.Codec{PT: 101, Name: "telephone-event", Rate: 8000}, + {PT: 9, Name: "G722", Rate: 8000}, + {PT: 18, Name: "G729", Rate: 8000}, + {PT: 0, Name: "PCMU", Rate: 8000}, + {PT: 101, Name: "telephone-event", Rate: 8000}, }, }, Ptime: 20, @@ -163,7 +164,7 @@ var sdpTests = []sdpTest{ }, }, - sdpTest{ + { name: "IPv6", s: "v=0\r\n" + "o=- 3366701332 3366701332 IN IP6 dead:beef::666\r\n" + @@ -199,10 +200,10 @@ var sdpTests = []sdpTest{ Proto: "RTP/AVP", Port: 32898, Codecs: []sdp.Codec{ - sdp.Codec{PT: 9, Name: "G722", Rate: 8000}, - sdp.Codec{PT: 18, Name: "G729", Rate: 8000}, - sdp.Codec{PT: 0, Name: "PCMU", Rate: 8000}, - sdp.Codec{PT: 101, Name: "telephone-event", Rate: 8000}, + {PT: 9, Name: "G722", Rate: 8000}, + {PT: 18, Name: "G729", Rate: 8000}, + {PT: 0, Name: "PCMU", Rate: 8000}, + {PT: 101, Name: "telephone-event", Rate: 8000}, }, }, Ptime: 20, @@ -210,7 +211,7 @@ var sdpTests = []sdpTest{ }, }, - sdpTest{ + { name: "pjmedia long sdp is long", s: ("v=0\r\n" + "o=- 3457169218 3457169218 IN IP4 10.11.34.37\r\n" + @@ -247,26 +248,26 @@ var sdpTests = []sdpTest{ Proto: "RTP/AVP", Port: 4000, Codecs: []sdp.Codec{ - sdp.Codec{PT: 103, Name: "speex", Rate: 16000}, - sdp.Codec{PT: 102, Name: "speex", Rate: 8000}, - sdp.Codec{PT: 104, Name: "speex", Rate: 32000}, - sdp.Codec{PT: 113, Name: "iLBC", Rate: 8000, Fmtp: "mode=30"}, - sdp.Codec{PT: 3, Name: "GSM", Rate: 8000}, - sdp.Codec{PT: 0, Name: "PCMU", Rate: 8000}, - sdp.Codec{PT: 8, Name: "PCMA", Rate: 8000}, - sdp.Codec{PT: 9, Name: "G722", Rate: 8000}, - sdp.Codec{PT: 101, Name: "telephone-event", Rate: 8000, Fmtp: "0-15"}, + {PT: 103, Name: "speex", Rate: 16000}, + {PT: 102, Name: "speex", Rate: 8000}, + {PT: 104, Name: "speex", Rate: 32000}, + {PT: 113, Name: "iLBC", Rate: 8000, Fmtp: "mode=30"}, + {PT: 3, Name: "GSM", Rate: 8000}, + {PT: 0, Name: "PCMU", Rate: 8000}, + {PT: 8, Name: "PCMA", Rate: 8000}, + {PT: 9, Name: "G722", Rate: 8000}, + {PT: 101, Name: "telephone-event", Rate: 8000, Fmtp: "0-15"}, }, }, Ptime: 20, Attrs: [][2]string{ - [2]string{"rtcp", "4001 IN IP4 10.11.34.37"}, - [2]string{"X-nat", "0"}, + {"rtcp", "4001 IN IP4 10.11.34.37"}, + {"X-nat", "0"}, }, }, }, - sdpTest{ + { name: "mp3 tcp", s: ("v=0\r\n" + "o=- 3366701332 3366701334 IN IP4 10.11.34.37\r\n" + @@ -291,7 +292,7 @@ var sdpTests = []sdpTest{ Proto: "TCP/IP", Port: 80, Codecs: []sdp.Codec{ - sdp.Codec{PT: 111, Name: "MP3", Rate: 44100, Param: "2"}, + {PT: 111, Name: "MP3", Rate: 44100, Param: "2"}, }, }, Attrs: [][2]string{}, @@ -341,7 +342,7 @@ func sdpCompareCodecs(t *testing.T, name string, corrects, codecs []sdp.Codec) { if len(corrects) != len(codecs) { t.Error(name, "len(Codecs)", len(corrects), "!=", len(codecs)) } else { - for i, _ := range corrects { + for i := range corrects { c1, c2 := &corrects[i], &codecs[i] if c1 == nil || c2 == nil { t.Error(name, "where my codecs at?") @@ -426,7 +427,7 @@ func TestParse(t *testing.T) { } else if len(sdp.Attrs) != len(test.sdp.Attrs) { t.Error(test.name, "Attrs length not same") } else { - for i, _ := range sdp.Attrs { + for i := range sdp.Attrs { p1, p2 := test.sdp.Attrs[i], sdp.Attrs[i] if p1[0] != p2[0] || p1[1] != p2[1] { t.Error(test.name, "attr", p1, "!=", p2) diff --git a/sip/addr.go b/sip/addr.go index 20c21f5..acb56c7 100755 --- a/sip/addr.go +++ b/sip/addr.go @@ -1,11 +1,11 @@ // Copyright 2020 Justine Alexandra Roberts Tunney -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -34,6 +34,7 @@ package sip import ( "bytes" + "github.com/jart/gosip/util" ) diff --git a/sip/addr_test.go b/sip/addr_test.go index e96ac68..26dd269 100755 --- a/sip/addr_test.go +++ b/sip/addr_test.go @@ -1,11 +1,11 @@ // Copyright 2020 Justine Alexandra Roberts Tunney -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -16,9 +16,10 @@ package sip_test import ( "bytes" - "github.com/jart/gosip/sip" "reflect" "testing" + + "github.com/jart/gosip/sip" ) type addrTest struct { @@ -31,7 +32,7 @@ type addrTest struct { var addrTests = []addrTest{ - addrTest{ + { name: "Basic address", s: "", addr: sip.Addr{ @@ -42,7 +43,7 @@ var addrTests = []addrTest{ }, }, - addrTest{ + { name: "Address parameter", s: ";tag=deadbeef", addr: sip.Addr{ @@ -54,7 +55,7 @@ var addrTests = []addrTest{ }, }, - addrTest{ + { name: "Address parameter spacing", s: "\t ;\t tag\t = \tdeadbeef", s_canonical: ";tag=deadbeef", @@ -67,7 +68,7 @@ var addrTests = []addrTest{ }, }, - addrTest{ + { name: "Address parameter quoted", s: ";tag=\"deadbeef\"", s_canonical: ";tag=deadbeef", @@ -80,7 +81,7 @@ var addrTests = []addrTest{ }, }, - addrTest{ + { name: "Address parameter quoted spacing", s: "\t ;\t tag\t = \t\"deadbeef\"", s_canonical: ";tag=deadbeef", @@ -93,7 +94,7 @@ var addrTests = []addrTest{ }, }, - addrTest{ + { name: "Address parameter quoted escaped", s: ";tag=\"\\\"deadbeef\\\"\"", addr: sip.Addr{ @@ -105,7 +106,7 @@ var addrTests = []addrTest{ }, }, - addrTest{ + { name: "URI parameter", s: "", addr: sip.Addr{ @@ -118,7 +119,7 @@ var addrTests = []addrTest{ }, }, - addrTest{ + { name: "Address + URI parameter", s: ";tag=deadbeef", addr: sip.Addr{ @@ -132,7 +133,7 @@ var addrTests = []addrTest{ }, }, - addrTest{ + { s: `, Ditto `, addr: sip.Addr{ Uri: &sip.URI{ @@ -150,7 +151,7 @@ var addrTests = []addrTest{ }, }, - addrTest{ + { s: `, , `, addr: sip.Addr{ Uri: &sip.URI{ @@ -172,7 +173,7 @@ var addrTests = []addrTest{ }, }, - addrTest{ + { s: "\"\\\"\\\"Justine \\\\Tunney \" " + ";tag=deadbeef", addr: sip.Addr{ diff --git a/sip/charsets.go b/sip/charsets.go index 26843f6..f8a6706 100644 --- a/sip/charsets.go +++ b/sip/charsets.go @@ -1,11 +1,11 @@ // Copyright 2020 Justine Alexandra Roberts Tunney -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. diff --git a/sip/charsets_test.go b/sip/charsets_test.go index d1afee3..5b56200 100644 --- a/sip/charsets_test.go +++ b/sip/charsets_test.go @@ -1,11 +1,11 @@ // Copyright 2020 Justine Alexandra Roberts Tunney -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. diff --git a/sip/errors.go b/sip/errors.go index 435543d..e426892 100644 --- a/sip/errors.go +++ b/sip/errors.go @@ -1,11 +1,11 @@ // Copyright 2020 Justine Alexandra Roberts Tunney -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. diff --git a/sip/escape.go b/sip/escape.go index 7cde76e..8d285d8 100644 --- a/sip/escape.go +++ b/sip/escape.go @@ -1,11 +1,11 @@ // Copyright 2020 Justine Alexandra Roberts Tunney -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. diff --git a/sip/escape_test.go b/sip/escape_test.go index fc916bb..b99451e 100644 --- a/sip/escape_test.go +++ b/sip/escape_test.go @@ -1,11 +1,11 @@ // Copyright 2020 Justine Alexandra Roberts Tunney -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -27,29 +27,25 @@ type escapeTest struct { } var escapeTests = []escapeTest{ - - escapeTest{ + { name: "Param Normal", in: "hello", out: "hello", p: paramc, }, - - escapeTest{ + { name: "User Normal", in: "hello", out: "hello", p: userc, }, - - escapeTest{ + { name: "Param Spacing", in: "hello there", out: "hello%20there", p: paramc, }, - - escapeTest{ + { name: "User Spacing", in: "hello there", out: "hello%20there", diff --git a/sip/method.go b/sip/method.go index f2fd8d1..94b4998 100644 --- a/sip/method.go +++ b/sip/method.go @@ -1,11 +1,11 @@ // Copyright 2020 Justine Alexandra Roberts Tunney -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. diff --git a/sip/msg.go b/sip/msg.go index 25d8812..9ddac8f 100755 --- a/sip/msg.go +++ b/sip/msg.go @@ -1,11 +1,11 @@ // Copyright 2020 Justine Alexandra Roberts Tunney -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. diff --git a/sip/msg_test.go b/sip/msg_test.go index 5cd2892..0885316 100755 --- a/sip/msg_test.go +++ b/sip/msg_test.go @@ -1,11 +1,11 @@ // Copyright 2020 Justine Alexandra Roberts Tunney -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -15,9 +15,10 @@ package sip_test import ( - "github.com/jart/gosip/sip" "reflect" "testing" + + "github.com/jart/gosip/sip" ) const ( @@ -63,12 +64,12 @@ type msgTest struct { var msgTests = []msgTest{ - msgTest{ + { s: "", e: sip.MsgIncompleteError{Msg: []uint8{}}, }, - msgTest{ + { name: "UTF8 Phrase", s: "SIP/2.0 200 ◕◡◕\r\n" + "\r\n", @@ -79,7 +80,7 @@ var msgTests = []msgTest{ }, }, - msgTest{ + { name: "Left Padding", s: "SIP/2.0 200 OK\r\n" + "Expires: 666\r\n" + @@ -92,7 +93,7 @@ var msgTests = []msgTest{ }, }, - msgTest{ + { name: "Extension Headers", s: "SIP/2.0 200 OK\r\n" + "X-LOL: omfg\r\n" + @@ -105,7 +106,7 @@ var msgTests = []msgTest{ }, }, - msgTest{ + { name: "Multiple Addresses", s: "SIP/2.0 200 OK\r\n" + "From: , \r\n" + @@ -129,7 +130,7 @@ var msgTests = []msgTest{ }, }, - msgTest{ + { name: "Line Continuation Warning", s: "SIP/2.0 200 OK\r\n" + "Warning: Morning and evening\r\n" + @@ -152,7 +153,7 @@ var msgTests = []msgTest{ }, }, - msgTest{ + { name: "Line Continuation Warning Followed By Extended Header", s: "SIP/2.0 200 OK\r\n" + "Warning: Morning and evening\r\n" + @@ -177,7 +178,7 @@ var msgTests = []msgTest{ }, }, - msgTest{ + { name: "Line Continuation Extended Followed By Extended", s: "SIP/2.0 200 OK\r\n" + "X-Warning: Come buy our orchard fruits,\r\n" + @@ -200,7 +201,7 @@ var msgTests = []msgTest{ }, }, - msgTest{ + { name: "Line Continuation Extended Followed By Extended 2", s: "SIP/2.0 200 OK\r\n" + "NewFangledHeader: newfangled value\r\n" + @@ -223,7 +224,7 @@ var msgTests = []msgTest{ }, }, - msgTest{ + { name: "Line Continuations Addr", s: "SIP/2.0 200 OK\r\n" + "From:\r\n" + @@ -249,7 +250,7 @@ var msgTests = []msgTest{ }, }, - msgTest{ + { name: "Extended header looks like standard headers", s: "SIP/2.0 200 OK\r\n" + "viaz: floor\r\n" + @@ -285,7 +286,7 @@ var msgTests = []msgTest{ }, }, - msgTest{ + { name: "Address Unquoted Display", s: "SIP/2.0 200 OK\r\n" + "From: Kitty \r\n" + @@ -304,7 +305,7 @@ var msgTests = []msgTest{ }, }, - msgTest{ + { name: "Address Quoted Display", s: "SIP/2.0 200 OK\r\n" + "From: \"Hello \\\"Kitty\\\" ◕◡◕\" \r\n" + @@ -323,7 +324,7 @@ var msgTests = []msgTest{ }, }, - msgTest{ + { name: "Address Quoted Display Multiline", s: "SIP/2.0 200 OK\r\n" + "From: \"oh\r\n" + @@ -346,7 +347,7 @@ var msgTests = []msgTest{ }, }, - msgTest{ + { name: "Address Unquoted Display Multiline", s: "SIP/2.0 200 OK\r\n" + "From: oh\r\n" + @@ -369,7 +370,7 @@ var msgTests = []msgTest{ }, }, - msgTest{ + { name: "Addr Tag", s: "SIP/2.0 200 OK\r\n" + "From: ;tag=omfg\r\n" + @@ -388,7 +389,7 @@ var msgTests = []msgTest{ }, }, - msgTest{ + { name: "Addr Tag Quoted", // TODO(jart): Crash when extra spacing in here. s: "SIP/2.0 200 OK\r\n" + @@ -408,7 +409,7 @@ var msgTests = []msgTest{ }, }, - msgTest{ + { name: "Addr Tag Bare", s: "SIP/2.0 200 OK\r\n" + "From: ;tag\r\n" + @@ -427,7 +428,7 @@ var msgTests = []msgTest{ }, }, - msgTest{ + { name: "Missing Angle Brackets With Tag Belongs to Addr Not URI", s: "SIP/2.0 200 OK\r\n" + "From: sip:lol.com;tag=omfg\r\n" + @@ -447,7 +448,7 @@ var msgTests = []msgTest{ }, // // TODO(jart): Implement me. - // msgTest{ + // { // name: "Content Type Params", // s: "SIP/2.0 200 OK\r\n" + // "Content-Type: multipart/signed;\r\n" + @@ -462,7 +463,7 @@ var msgTests = []msgTest{ // }, // }, - msgTest{ + { name: "Via Host Only", s: "SIP/2.0 200 OK\r\n" + "Via: SIP/2.0/UDP 8.8.4.4\r\n" + @@ -480,7 +481,7 @@ var msgTests = []msgTest{ }, }, - msgTest{ + { name: "Via Port", s: "SIP/2.0 200 OK\r\n" + "Via: SIP/2.0/UDP 8.8.4.4:666\r\n" + @@ -499,7 +500,7 @@ var msgTests = []msgTest{ }, }, - msgTest{ + { name: "Via Port Spacing", s: "SIP/2.0 200 OK\r\n" + "Via: SIP/2.0/UDP 8.8.4.4 \t : \t 666\r\n" + @@ -518,7 +519,7 @@ var msgTests = []msgTest{ }, }, - msgTest{ + { name: "Via Line Continuation", s: "SIP/2.0 200 OK\r\n" + "Via: SIP/2.0/UDP 10.11.34.37 ,\r\n" + @@ -545,7 +546,7 @@ var msgTests = []msgTest{ }, }, - msgTest{ + { name: "Via Multiple Lines", s: "SIP/2.0 200 OK\r\n" + "Via: SIP/2.0/UDP 10.11.34.37\r\n" + @@ -570,7 +571,7 @@ var msgTests = []msgTest{ }, }, - msgTest{ + { name: "Via Multiple Lines Continuation", s: "SIP/2.0 200 OK\r\n" + "Via: SIP/2.0/UDP 10.11.34.37\r\n" + @@ -608,7 +609,7 @@ var msgTests = []msgTest{ }, }, - msgTest{ + { name: "Via Param", s: "SIP/2.0 200 OK\r\n" + "Via: SIP/ 2.0/TCP spindle.example.com ;branch=z9hG4bK9ikj8\r\n" + @@ -627,7 +628,7 @@ var msgTests = []msgTest{ }, }, - msgTest{ + { name: "Via Param Torture", s: "SIP/2.0 200 OK\r\n" + "v: SIP / 2.0 / TCP spindle.example.com ;\r\n" + @@ -647,7 +648,7 @@ var msgTests = []msgTest{ }, }, - msgTest{ + { name: "Via Torture", s: "SIP/2.0 200 OK\r\n" + "Via : SIP / 2.0\r\n" + @@ -686,7 +687,7 @@ var msgTests = []msgTest{ }, }, - msgTest{ + { name: "OPTIONS", s: "OPTIONS sip:10.11.34.37:42367 SIP/2.0\r\n" + "Via: SIP/2.0/UDP 10.11.34.37:42367;rport;branch=9dc39c3c3e84\r\n" + @@ -752,7 +753,7 @@ var msgTests = []msgTest{ }, }, - msgTest{ + { s: "SIP/2.0 200 OK\r\n" + "Via: SIP/2.0/UDP 127.0.0.1:52711;branch=z9hG4bK-03d1d81e94a0;received=127.0.0.1;rport=52711\r\n" + "From: ;tag=4568e274dbd8\r\n" + @@ -851,7 +852,7 @@ var msgTests = []msgTest{ }, }, - msgTest{ + { name: "Flowroute Fun", s: flowroute, msg: sip.Msg{ @@ -924,7 +925,7 @@ var msgTests = []msgTest{ }, }, - msgTest{ + { name: "INVITE", s: "INVITE sip:10.11.34.37 SIP/2.0\r\n" + "via: SIP/2.0/UDP 10.11.34.37:59516;rport;branch=z9hG4bKS308QB9UUpNyD\r\n" + @@ -1026,7 +1027,7 @@ var msgTests = []msgTest{ }, }, - msgTest{ + { name: "RFC4475 Torture Message #1", s: "INVITE sip:vivekg@chair-dnrc.example.com;unknownparam SIP/2.0\r\n" + "TO :\r\n" + @@ -1172,7 +1173,7 @@ var msgTests = []msgTest{ }, }, - msgTest{ + { name: "RFC4475 Torture Message #2", s: torture2, msg: sip.Msg{ diff --git a/sip/msgerror.go b/sip/msgerror.go index 4ea2b68..380f6c8 100644 --- a/sip/msgerror.go +++ b/sip/msgerror.go @@ -1,11 +1,11 @@ // Copyright 2020 Justine Alexandra Roberts Tunney -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. diff --git a/sip/param.go b/sip/param.go index 3d331ca..7353003 100644 --- a/sip/param.go +++ b/sip/param.go @@ -1,11 +1,11 @@ // Copyright 2020 Justine Alexandra Roberts Tunney -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. diff --git a/sip/payload.go b/sip/payload.go index e196466..ced4310 100644 --- a/sip/payload.go +++ b/sip/payload.go @@ -1,11 +1,11 @@ // Copyright 2020 Justine Alexandra Roberts Tunney -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. diff --git a/sip/prefs.go b/sip/prefs.go index e5dfc3f..e32a69d 100755 --- a/sip/prefs.go +++ b/sip/prefs.go @@ -1,11 +1,11 @@ // Copyright 2020 Justine Alexandra Roberts Tunney -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. diff --git a/sip/quote.go b/sip/quote.go index ff2bb2f..e8f6dab 100644 --- a/sip/quote.go +++ b/sip/quote.go @@ -1,11 +1,11 @@ // Copyright 2020 Justine Alexandra Roberts Tunney -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. diff --git a/sip/quote_test.go b/sip/quote_test.go index 043d308..e7fcfb8 100644 --- a/sip/quote_test.go +++ b/sip/quote_test.go @@ -1,11 +1,11 @@ // Copyright 2020 Justine Alexandra Roberts Tunney -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -26,44 +26,37 @@ type quoteTest struct { } var quoteTests = []quoteTest{ - - quoteTest{ + { name: "Normal value", in: "hello", out: "hello", }, - - quoteTest{ + { name: "Space doesn't quotes", in: "hello there", out: "hello there", }, - - quoteTest{ + { name: "Less than adds quotes", in: "hello there<", out: "\"hello there<\"", }, - - quoteTest{ + { name: "CRLF with space after works", in: "hello\r\n there!", out: "\"hello\r\n there!\"", }, - - quoteTest{ + { name: "CRLF without space truncates", in: "hello\r\nthere!", out: "\"hello\"", }, - - quoteTest{ + { name: "Escapable character escapes", in: "hello\"there", out: "\"hello\\\"there\"", }, - - quoteTest{ + { name: "Unescapable character truncates", in: "hello\xFFthere", out: "\"hello\"", diff --git a/sip/status.go b/sip/status.go index 4bfa061..d4ee56a 100755 --- a/sip/status.go +++ b/sip/status.go @@ -1,11 +1,11 @@ // Copyright 2020 Justine Alexandra Roberts Tunney -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. diff --git a/sip/uri.go b/sip/uri.go index 5c08aa7..126a869 100755 --- a/sip/uri.go +++ b/sip/uri.go @@ -1,11 +1,11 @@ // Copyright 2020 Justine Alexandra Roberts Tunney -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -36,6 +36,7 @@ package sip import ( "bytes" + "github.com/jart/gosip/util" ) @@ -104,7 +105,7 @@ func (uri *URI) Append(b *bytes.Buffer) { } if uri.Port > 0 { b.WriteByte(':') - b.WriteString(portstr(uri.Port)) + b.WriteString(util.Portstr(uri.Port)) } uri.Param.Append(b) uri.Header.Append(b) diff --git a/sip/uri_test.go b/sip/uri_test.go index 0601c2d..d62372f 100755 --- a/sip/uri_test.go +++ b/sip/uri_test.go @@ -1,11 +1,11 @@ // Copyright 2020 Justine Alexandra Roberts Tunney -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -16,9 +16,10 @@ package sip_test import ( "errors" - "github.com/jart/gosip/sip" "reflect" "testing" + + "github.com/jart/gosip/sip" ) type uriTest struct { @@ -30,22 +31,22 @@ type uriTest struct { var uriTests = []uriTest{ - uriTest{ + { s: "", e: errors.New("Incomplete URI: "), }, - uriTest{ + { s: "sip:", e: errors.New("Incomplete URI: sip:"), }, - uriTest{ + { s: "sip:example.com:LOL", e: errors.New("Error in URI at pos 16: sip:example.com:LOL"), }, - uriTest{ + { s: "sip:example.com", uri: &sip.URI{ Scheme: "sip", @@ -53,7 +54,7 @@ var uriTests = []uriTest{ }, }, - uriTest{ + { s: "sip:example.com:5060", uri: &sip.URI{ Scheme: "sip", @@ -62,7 +63,7 @@ var uriTests = []uriTest{ }, }, - uriTest{ + { s: "sips:jart@google.com", uri: &sip.URI{ Scheme: "sips", @@ -71,7 +72,7 @@ var uriTests = []uriTest{ }, }, - uriTest{ + { s: "sips:jart@google.com:5060", uri: &sip.URI{ Scheme: "sips", @@ -81,7 +82,7 @@ var uriTests = []uriTest{ }, }, - uriTest{ + { s: "sips:jart:letmein@google.com", uri: &sip.URI{ Scheme: "sips", @@ -91,7 +92,7 @@ var uriTests = []uriTest{ }, }, - uriTest{ + { s: "sips:jart:LetMeIn@google.com:5060", uri: &sip.URI{ Scheme: "sips", @@ -102,7 +103,7 @@ var uriTests = []uriTest{ }, }, - uriTest{ + { s: "sips:GOOGLE.com", uri: &sip.URI{ Scheme: "sips", @@ -111,7 +112,7 @@ var uriTests = []uriTest{ skipFormat: true, }, - uriTest{ + { s: "sip:[dead:beef::666]:5060", uri: &sip.URI{ Scheme: "sip", @@ -120,12 +121,12 @@ var uriTests = []uriTest{ }, }, - uriTest{ + { s: "sip:dead:beef::666:5060", e: errors.New("Error in URI at pos 9: sip:dead:beef::666:5060"), }, - uriTest{ + { s: "tel:+12126660420", uri: &sip.URI{ Scheme: "tel", @@ -133,7 +134,7 @@ var uriTests = []uriTest{ }, }, - uriTest{ + { s: "sip:bob%20barker:priceisright@[dead:beef::666]:5060;isup-oli=00", uri: &sip.URI{ Scheme: "sip", @@ -145,12 +146,12 @@ var uriTests = []uriTest{ }, }, - uriTest{ + { s: "sips:google.com ;lol ;h=omg", e: errors.New("Error in URI at pos 15: sips:google.com ;lol ;h=omg"), }, - uriTest{ + { s: "SIP:example.com", uri: &sip.URI{ Scheme: "sip", @@ -159,7 +160,7 @@ var uriTests = []uriTest{ skipFormat: true, }, - uriTest{ + { s: "sips:alice@atlanta.com?priority=urgent&subject=project%20x", uri: &sip.URI{ Scheme: "sips", @@ -176,7 +177,7 @@ var uriTests = []uriTest{ }, }, - uriTest{ + { s: "sip:+1-212-555-1212:1234@gateway.com;user=phone", uri: &sip.URI{ Scheme: "sip", @@ -187,7 +188,7 @@ var uriTests = []uriTest{ }, }, - uriTest{ + { s: "sip:atlanta.com;method=register?to=alice%40atlanta.com", uri: &sip.URI{ Scheme: "sip", @@ -197,7 +198,7 @@ var uriTests = []uriTest{ }, }, - uriTest{ + { s: "sip:alice;day=tuesday@atlanta.com", uri: &sip.URI{ Scheme: "sip", diff --git a/sip/uriheader.go b/sip/uriheader.go index d09facf..7c26389 100644 --- a/sip/uriheader.go +++ b/sip/uriheader.go @@ -1,11 +1,11 @@ // Copyright 2020 Justine Alexandra Roberts Tunney -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. diff --git a/sip/uriparam.go b/sip/uriparam.go index d77c560..7b1c705 100644 --- a/sip/uriparam.go +++ b/sip/uriparam.go @@ -1,11 +1,11 @@ // Copyright 2020 Justine Alexandra Roberts Tunney -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. diff --git a/sip/util.go b/sip/util.go index 4c5bee7..ffc91c9 100644 --- a/sip/util.go +++ b/sip/util.go @@ -1,11 +1,11 @@ // Copyright 2020 Justine Alexandra Roberts Tunney -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -14,26 +14,6 @@ package sip -import ( - "strconv" - "time" -) - -func duration(ms *int) time.Duration { - return time.Duration(*ms) * time.Millisecond -} - -func or5060(port uint16) uint16 { - if port == 0 { - return 5060 - } - return port -} - -func portstr(port uint16) string { - return strconv.FormatInt(int64(port), 10) -} - func unhex(b byte) byte { switch { case '0' <= b && b <= '9': diff --git a/sip/via.go b/sip/via.go index 982ddb9..231ef9b 100755 --- a/sip/via.go +++ b/sip/via.go @@ -1,11 +1,11 @@ // Copyright 2020 Justine Alexandra Roberts Tunney -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -18,8 +18,9 @@ package sip import ( "bytes" - "github.com/jart/gosip/util" "strconv" + + "github.com/jart/gosip/util" ) // Example: SIP/2.0/UDP 1.2.3.4:5060;branch=z9hG4bK556f77e6. diff --git a/sip/xheader.go b/sip/xheader.go index 84a335e..23ea54d 100644 --- a/sip/xheader.go +++ b/sip/xheader.go @@ -1,11 +1,11 @@ // Copyright 2020 Justine Alexandra Roberts Tunney -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. diff --git a/util/util.go b/util/util.go index 9e8342f..d461bf1 100755 --- a/util/util.go +++ b/util/util.go @@ -1,11 +1,11 @@ // Copyright 2020 Justine Alexandra Roberts Tunney -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -92,3 +92,7 @@ func append(buf []byte, s string) []byte { } return buf } + +func Portstr(port uint16) string { + return strconv.FormatInt(int64(port), 10) +}