diff --git a/sip/dialog.go b/sip/dialog.go index 19aabab..4beac58 100755 --- a/sip/dialog.go +++ b/sip/dialog.go @@ -14,7 +14,6 @@ import ( ) const ( - DialogInit = 0 DialogProceeding = 1 DialogRinging = 2 DialogAnswered = 3 @@ -24,7 +23,7 @@ const ( ) var ( - looseSignalling = flag.Bool("looseSignalling", false, "Permit SIP messages from servers other than the next hop.") + looseSignalling = flag.Bool("looseSignalling", true, "Permit SIP messages from servers other than the next hop.") ) // Dialog represents an outbound SIP phone call. @@ -87,7 +86,7 @@ func NewDialog(invite *Msg) (dl *Dialog, err error) { func (dls *dialogState) run() { defer dls.sabotage() defer dls.cleanup() - if !dls.sendRequest(dls.invite, true) { + if !dls.sendRequest(dls.invite) { return } for { @@ -129,12 +128,13 @@ func (dls *dialogState) run() { } } -func (dls *dialogState) sendRequest(request *Msg, wantSRV bool) bool { +func (dls *dialogState) sendRequest(request *Msg) bool { host, port, err := RouteMessage(nil, nil, request) if err != nil { dls.errChan <- err return false } + wantSRV := dls.state < DialogAnswered routes, err := RouteAddress(host, port, wantSRV) if err != nil { dls.errChan <- err @@ -156,73 +156,69 @@ func (dls *dialogState) popRoute() bool { if !dls.connect() { return dls.popRoute() } - PopulateMessage(nil, nil, dls.request) - dls.lseq = dls.request.CSeq + dls.populate(dls.request) + if dls.state < DialogAnswered { + dls.rseq = 0 + dls.remote = nil + dls.lseq = dls.request.CSeq + } dls.requestResends = 0 dls.requestTimer = time.After(resendInterval) return dls.send(dls.request) } func (dls *dialogState) connect() bool { - if dls.sock != nil && dls.sock.RemoteAddr().String() == dls.addr { - return true - } + if dls.sock == nil || dls.sock.RemoteAddr().String() != dls.addr { + // Create socket through which we send messages. This socket is connected to + // the remote address so we can receive ICMP unavailable errors. It also + // allows us to discover the appropriate IP address for this machine. + dls.cleanupSock() + conn, err := net.Dial("udp", dls.addr) + if err != nil { + log.Printf("net.Dial(udp, %s) failed: %s", dls.addr, err) + return false + } + dls.sock = conn.(*net.UDPConn) + sockMsgs := make(chan *Msg) + sockErrs := make(chan error) + dls.sockMsgs = sockMsgs + dls.sockErrs = sockErrs + go ReceiveMessages(dls.sock, sockMsgs, sockErrs) - // Create socket through which we send messages. This socket is connected to - // the remote address so we can receive ICMP unavailable errors. It also - // allows us to discover the appropriate IP address for this machine. - dls.cleanupSock() - conn, err := net.Dial("udp", dls.addr) - if err != nil { - log.Printf("net.Dial(udp, %s) failed: %s", dls.addr, err) - return false + // But a connected UDP socket can only receive packets from a single host. + // SIP signalling paths can change depending on the environment, so we need + // to be able to accept packets from anyone. + if dls.csock == nil && *looseSignalling { + cconn, err := net.ListenPacket("udp", ":0") + if err != nil { + log.Printf("net.ListenPacket(udp, :0) failed: %s", err) + return false + } + dls.csock = cconn.(*net.UDPConn) + csockMsgs := make(chan *Msg) + csockErrs := make(chan error) + dls.csockMsgs = csockMsgs + dls.csockErrs = csockErrs + go ReceiveMessages(dls.csock, csockMsgs, csockErrs) + } } - dls.sock = conn.(*net.UDPConn) - dls.rseq = 0 - dls.remote = nil - laddr := conn.LocalAddr().(*net.UDPAddr) + return true +} + +func (dls *dialogState) populate(msg *Msg) { + laddr := dls.sock.LocalAddr().(*net.UDPAddr) lhost := laddr.IP.String() lport := uint16(laddr.Port) - dls.request.Via = &Via{ + msg.Via = &Via{ Host: lhost, Port: lport, Params: Params{"branch": util.GenerateBranch()}, } - sockMsgs := make(chan *Msg) - sockErrs := make(chan error) - dls.sockMsgs = sockMsgs - dls.sockErrs = sockErrs - go ReceiveMessages(dls.request.Contact, dls.sock, sockMsgs, sockErrs) - - // But a connected UDP socket can only receive packets from a single host. - // SIP signalling paths can change depending on the environment, so we need - // to be able to accept packets from anyone. - if *looseSignalling { - if dls.csock == nil { - cconn, err := net.ListenPacket("udp", ":0") - if err != nil { - log.Printf("net.ListenPacket(udp, :0) failed: %s", err) - return false - } - dls.csock = cconn.(*net.UDPConn) - dls.request.Contact = &Addr{ - Uri: &URI{ - Scheme: "sip", - Host: lhost, - Port: uint16(dls.csock.LocalAddr().(*net.UDPAddr).Port), - Params: Params{"transport": "udp"}, - }, - } - } else { - dls.request.Contact.Uri.Host = lhost + if msg.Contact == nil { + if dls.csock != nil { + lport = uint16(dls.csock.LocalAddr().(*net.UDPAddr).Port) } - csockMsgs := make(chan *Msg) - csockErrs := make(chan error) - dls.csockMsgs = csockMsgs - dls.csockErrs = csockErrs - go ReceiveMessages(dls.request.Contact, dls.csock, csockMsgs, csockErrs) - } else { - dls.request.Contact = &Addr{ + msg.Contact = &Addr{ Uri: &URI{ Scheme: "sip", Host: lhost, @@ -231,8 +227,7 @@ func (dls *dialogState) connect() bool { }, } } - - return true + PopulateMessage(nil, nil, msg) } func (dls *dialogState) handleMessage(msg *Msg) bool { @@ -300,7 +295,7 @@ func (dls *dialogState) handleResponse(msg *Msg) bool { case StatusMovedPermanently, StatusMovedTemporarily: dls.invite.Request = msg.Contact.Uri dls.invite.Route = nil - return dls.sendRequest(dls.invite, true) + return dls.sendRequest(dls.invite) default: if msg.Status > StatusOK { dls.errChan <- &ResponseError{Msg: msg} @@ -435,7 +430,7 @@ func (dls *dialogState) sendHangup() bool { case DialogProceeding, DialogRinging: return dls.send(NewCancel(dls.invite)) case DialogAnswered: - return dls.sendRequest(NewBye(dls.invite, dls.remote, &dls.lseq), false) + return dls.sendRequest(NewBye(dls.invite, dls.remote, &dls.lseq)) case DialogHangup: panic("Why didn't the event loop break?") default: diff --git a/sip/messages.go b/sip/messages.go index 81943a6..c047d78 100644 --- a/sip/messages.go +++ b/sip/messages.go @@ -85,7 +85,6 @@ func NewBye(invite, remote *Msg, lseq *int) *Msg { return &Msg{ Method: MethodBye, Request: remote.Contact.Uri, - Via: invite.Via.Copy().Branch(), From: invite.From, To: remote.To, CallID: invite.CallID, diff --git a/sip/receiver.go b/sip/receiver.go index a6a17d1..0c7ad21 100644 --- a/sip/receiver.go +++ b/sip/receiver.go @@ -7,8 +7,11 @@ import ( "time" ) -func ReceiveMessages(contact *Addr, sock *net.UDPConn, c chan<- *Msg, e chan<- error) { +func ReceiveMessages(sock *net.UDPConn, c chan<- *Msg, e chan<- error) { buf := make([]byte, 2048) + laddr := sock.LocalAddr().(*net.UDPAddr) + lhost := laddr.IP.String() + lport := uint16(laddr.Port) for { amt, addr, err := sock.ReadFromUDP(buf) if err != nil { @@ -27,10 +30,10 @@ func ReceiveMessages(contact *Addr, sock *net.UDPConn, c chan<- *Msg, e chan<- e } addReceived(msg, addr) addTimestamp(msg, ts) - if contact.CompareHostPort(msg.Route) { + if msg.Route != nil && msg.Route.Uri.Host == lhost && or5060(msg.Route.Uri.Port) == lport { msg.Route = msg.Route.Next } - fixMessagesFromStrictRouters(contact, msg) + fixMessagesFromStrictRouters(lhost, lport, msg) c <- msg } close(c) @@ -51,8 +54,12 @@ func addTimestamp(msg *Msg, ts time.Time) { // RFC3261 16.4 Route Information Preprocessing // RFC3261 16.12.1.2: Traversing a Strict-Routing Proxy -func fixMessagesFromStrictRouters(contacts *Addr, msg *Msg) { - if msg.Request != nil && msg.Request.Params.Has("lr") && msg.Route != nil && contacts.Uri.CompareHostPort(msg.Request) { +func fixMessagesFromStrictRouters(lhost string, lport uint16, msg *Msg) { + if msg.Request != nil && + msg.Request.Params.Has("lr") && + msg.Route != nil && + msg.Request.Host == lhost && + or5060(msg.Request.Port) == lport { var oldReq, newReq *URI if msg.Route.Next == nil { oldReq, newReq = msg.Request, msg.Route.Uri diff --git a/sip/transport.go b/sip/transport.go index fcb31ed..0ed09c1 100755 --- a/sip/transport.go +++ b/sip/transport.go @@ -50,7 +50,7 @@ func NewTransport(contact *Addr) (tp *Transport, err error) { Port: uint16(addr.Port), }, } - go ReceiveMessages(contact, sock, c, e) + go ReceiveMessages(sock, c, e) return } diff --git a/sip/util.go b/sip/util.go index f140eaf..8e9cc07 100644 --- a/sip/util.go +++ b/sip/util.go @@ -6,6 +6,13 @@ import ( "strings" ) +func or5060(port uint16) uint16 { + if port == 0 { + return 5060 + } + return port +} + func portstr(port uint16) string { return strconv.FormatInt(int64(port), 10) }