// 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 ( "errors" "log" "net" "strconv" "github.com/jart/gosip/sip" "github.com/jart/gosip/util" ) type AddressRoute struct { Address string Next *AddressRoute } func PopulateMessage(via *sip.Via, contact *sip.Addr, msg *sip.Msg) { if !msg.IsResponse() { if msg.Via == nil { msg.Via = via } if msg.Contact == nil { msg.Contact = contact } if msg.To == nil { msg.To = &sip.Addr{Uri: msg.Request} } if msg.From == nil { msg.From = msg.Contact.Copy() msg.From.Uri.Param = nil } if msg.CallID == "" { msg.CallID = util.GenerateCallID() } if msg.CSeq == 0 { msg.CSeq = util.GenerateCSeq() } if msg.CSeqMethod == "" { msg.CSeqMethod = msg.Method } if msg.MaxForwards == 0 { msg.MaxForwards = 70 } if msg.UserAgent == "" { msg.UserAgent = GosipUA } if msg.Via.Param.Get("branch") == nil { msg.Via.Param = &sip.Param{ Name: "branch", Value: util.GenerateBranch(), Next: msg.Via.Param, } } if msg.From.Param.Get("tag") == nil { msg.From.Param = &sip.Param{ Name: "tag", Value: util.GenerateTag(), Next: msg.From.Param, } } } } 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 } host, port = msg.Via.Host, msg.Via.Port if received := msg.Via.Param.Get("received"); received != nil { host = received.Value } // fix: Get real port from rport field. // Request path like UAC->NAT->UAS will change port(according to NAT type) sometime, // we should use rport as real port in request-line if rport := msg.Via.Param.Get("rport"); rport != nil && len(rport.Value) > 0 { i, err := strconv.Atoi(rport.Value) if err != nil { return "", 0, err } port = uint16(i) } } else { if contact.CompareHostPort(msg.Route) { msg.Route = msg.Route.Next } if msg.Route != nil { if msg.Method == "REGISTER" { return "", 0, errors.New("Don't route REGISTER requests") } if msg.Route.Uri.Param.Get("lr") != nil { // RFC3261 16.12.1.1 Basic SIP Trapezoid host, port = msg.Route.Uri.Host, msg.Route.Uri.Port } else { // RFC3261 16.12.1.2: Traversing a Strict-Routing Proxy msg.Route = msg.Route.Copy() 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 } } else { host, port = msg.Request.Host, msg.Request.Port } } return } func RouteAddress(host string, port uint16, wantSRV bool) (routes *AddressRoute, err error) { if net.ParseIP(host) != nil { if port == 0 { port = 5060 } return &AddressRoute{Address: net.JoinHostPort(host, util.Portstr(port))}, nil } if port == 0 { if wantSRV { _, srvs, err := net.LookupSRV("sip", "udp", host) if err == nil && len(srvs) > 0 { s := "" for i := len(srvs) - 1; i >= 0; i-- { routes = &AddressRoute{ Address: net.JoinHostPort(srvs[i].Target, util.Portstr(srvs[i].Port)), Next: routes, } s = " " + routes.Address + s } log.Printf("%s routes to: %s\r\n", host, s) return routes, nil } log.Printf("net.LookupSRV(sip, udp, %s) failed: %s\r\n", host, err) } port = 5060 } addr, err := net.ResolveUDPAddr("udp", net.JoinHostPort(host, util.Portstr(port))) if err != nil { return nil, err } return &AddressRoute{Address: addr.String()}, nil }