123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382 |
- package sip
- import (
- "bytes"
- "fmt"
- "strconv"
- "strings"
- "github.com/ghettovoice/gosip/log"
- )
- // Request RFC 3261 - 7.1.
- type Request interface {
- Message
- Method() RequestMethod
- SetMethod(method RequestMethod)
- Recipient() Uri
- SetRecipient(recipient Uri)
- /* Common Helpers */
- IsInvite() bool
- }
- type request struct {
- message
- method RequestMethod
- recipient Uri
- }
- func NewRequest(
- messID MessageID,
- method RequestMethod,
- recipient Uri,
- sipVersion string,
- hdrs []Header,
- body string,
- fields log.Fields,
- ) Request {
- req := new(request)
- if messID == "" {
- req.messID = NextMessageID()
- } else {
- req.messID = messID
- }
- req.startLine = req.StartLine
- req.sipVersion = sipVersion
- req.headers = newHeaders(hdrs)
- req.method = method
- req.recipient = recipient
- req.body = body
- req.fields = fields.WithFields(log.Fields{
- "request_id": req.messID,
- })
- return req
- }
- func (req *request) Short() string {
- if req == nil {
- return "<nil>"
- }
- fields := log.Fields{
- "method": req.Method(),
- "recipient": req.Recipient(),
- "transport": req.Transport(),
- "source": req.Source(),
- "destination": req.Destination(),
- }
- if cseq, ok := req.CSeq(); ok {
- fields["sequence"] = cseq.SeqNo
- }
- fields = req.Fields().WithFields(fields)
- return fmt.Sprintf("sip.Request<%s>", fields)
- }
- func (req *request) Method() RequestMethod {
- req.mu.RLock()
- defer req.mu.RUnlock()
- return req.method
- }
- func (req *request) SetMethod(method RequestMethod) {
- req.mu.Lock()
- req.method = method
- req.mu.Unlock()
- }
- func (req *request) Recipient() Uri {
- req.mu.RLock()
- defer req.mu.RUnlock()
- return req.recipient
- }
- func (req *request) SetRecipient(recipient Uri) {
- req.mu.Lock()
- req.recipient = recipient
- req.mu.Unlock()
- }
- // StartLine returns Request Line - RFC 2361 7.1.
- func (req *request) StartLine() string {
- var buffer bytes.Buffer
- // Every SIP request starts with a Request Line - RFC 2361 7.1.
- buffer.WriteString(
- fmt.Sprintf(
- "%s %s %s",
- string(req.Method()),
- req.Recipient(),
- req.SipVersion(),
- ),
- )
- return buffer.String()
- }
- func (req *request) Clone() Message {
- return cloneRequest(req, "", nil)
- }
- func (req *request) Fields() log.Fields {
- return req.fields.WithFields(log.Fields{
- "transport": req.Transport(),
- "source": req.Source(),
- "destination": req.Destination(),
- })
- }
- func (req *request) WithFields(fields log.Fields) Message {
- req.mu.Lock()
- req.fields = req.fields.WithFields(fields)
- req.mu.Unlock()
- return req
- }
- func (req *request) IsInvite() bool {
- return req.Method() == INVITE
- }
- func (req *request) IsAck() bool {
- return req.Method() == ACK
- }
- func (req *request) IsCancel() bool {
- return req.Method() == CANCEL
- }
- func (req *request) Transport() string {
- if tp := req.message.Transport(); tp != "" {
- return strings.ToUpper(tp)
- }
- var tp string
- if viaHop, ok := req.ViaHop(); ok && viaHop.Transport != "" {
- tp = viaHop.Transport
- } else {
- tp = DefaultProtocol
- }
- uri := req.Recipient()
- if hdrs := req.GetHeaders("Route"); len(hdrs) > 0 {
- routeHeader, ok := hdrs[0].(*RouteHeader)
- if ok && len(routeHeader.Addresses) > 0 {
- uri = routeHeader.Addresses[0]
- }
- }
- if uri != nil {
- if uri.UriParams() != nil {
- if val, ok := uri.UriParams().Get("transport"); ok && !val.Equals("") {
- tp = strings.ToUpper(val.String())
- }
- }
- if uri.IsEncrypted() {
- if tp == "TCP" {
- tp = "TLS"
- } else if tp == "WS" {
- tp = "WSS"
- }
- }
- }
- if tp == "UDP" && len(req.String()) > int(MTU)-200 {
- tp = "TCP"
- }
- return tp
- }
- func (req *request) Source() string {
- if src := req.message.Source(); src != "" {
- return src
- }
- viaHop, ok := req.ViaHop()
- if !ok {
- return ""
- }
- var (
- host string
- port Port
- )
- host = viaHop.Host
- if viaHop.Port != nil {
- port = *viaHop.Port
- } else {
- port = DefaultPort(req.Transport())
- }
- if viaHop.Params != nil {
- if received, ok := viaHop.Params.Get("received"); ok && received.String() != "" {
- host = received.String()
- }
- if rport, ok := viaHop.Params.Get("rport"); ok && rport != nil && rport.String() != "" {
- if p, err := strconv.Atoi(rport.String()); err == nil {
- port = Port(uint16(p))
- }
- }
- }
- return fmt.Sprintf("%v:%v", host, port)
- }
- func (req *request) Destination() string {
- if dest := req.message.Destination(); dest != "" {
- return dest
- }
- var uri *SipUri
- if hdrs := req.GetHeaders("Route"); len(hdrs) > 0 {
- routeHeader, ok := hdrs[0].(*RouteHeader)
- if ok && len(routeHeader.Addresses) > 0 {
- uri = routeHeader.Addresses[0].(*SipUri)
- }
- }
- if uri == nil {
- if u, ok := req.Recipient().(*SipUri); ok {
- uri = u
- } else {
- return ""
- }
- }
- host := uri.FHost
- var port Port
- if uri.FPort != nil {
- port = *uri.FPort
- } else {
- port = DefaultPort(req.Transport())
- }
- return fmt.Sprintf("%v:%v", host, port)
- }
- // NewAckRequest creates ACK request for 2xx INVITE
- // https://tools.ietf.org/html/rfc3261#section-13.2.2.4
- func NewAckRequest(ackID MessageID, inviteRequest Request, inviteResponse Response, body string, fields log.Fields) Request {
- recipient := inviteRequest.Recipient()
- if contact, ok := inviteResponse.Contact(); ok {
- // For ws and wss (like clients in browser), don't use Contact
- if strings.Index(strings.ToLower(recipient.String()), "transport=ws") == -1 {
- recipient = contact.Address
- }
- }
- ackRequest := NewRequest(
- ackID,
- ACK,
- recipient,
- inviteRequest.SipVersion(),
- []Header{},
- body,
- inviteRequest.Fields().
- WithFields(fields).
- WithFields(log.Fields{
- "invite_request_id": inviteRequest.MessageID(),
- "invite_response_id": inviteResponse.MessageID(),
- }),
- )
- CopyHeaders("Via", inviteRequest, ackRequest)
- if inviteResponse.IsSuccess() {
- // update branch, 2xx ACK is separate Tx
- viaHop, _ := ackRequest.ViaHop()
- viaHop.Params.Add("branch", String{Str: GenerateBranch()})
- }
- if len(inviteRequest.GetHeaders("Route")) > 0 {
- CopyHeaders("Route", inviteRequest, ackRequest)
- } else {
- hdrs := inviteResponse.GetHeaders("Record-Route")
- for i := len(hdrs) - 1; i >= 0; i-- {
- h := hdrs[i]
- uris := make([]Uri, 0)
- for j := len(h.(*RecordRouteHeader).Addresses) - 1; j >= 0; j-- {
- uris = append(uris, h.(*RecordRouteHeader).Addresses[j].Clone())
- }
- ackRequest.AppendHeader(&RouteHeader{
- Addresses: uris,
- })
- }
- }
- maxForwardsHeader := MaxForwards(70)
- ackRequest.AppendHeader(&maxForwardsHeader)
- CopyHeaders("From", inviteRequest, ackRequest)
- CopyHeaders("To", inviteResponse, ackRequest)
- CopyHeaders("Call-ID", inviteRequest, ackRequest)
- CopyHeaders("CSeq", inviteRequest, ackRequest)
- cseq, _ := ackRequest.CSeq()
- cseq.MethodName = ACK
- ackRequest.SetBody("", true)
- ackRequest.SetTransport(inviteRequest.Transport())
- ackRequest.SetSource(inviteRequest.Source())
- ackRequest.SetDestination(inviteRequest.Destination())
- return ackRequest
- }
- func NewCancelRequest(cancelID MessageID, requestForCancel Request, fields log.Fields) Request {
- cancelReq := NewRequest(
- cancelID,
- CANCEL,
- requestForCancel.Recipient(),
- requestForCancel.SipVersion(),
- []Header{},
- "",
- requestForCancel.Fields().
- WithFields(fields).
- WithFields(log.Fields{
- "cancelling_request_id": requestForCancel.MessageID(),
- }),
- )
- viaHop, _ := requestForCancel.ViaHop()
- cancelReq.AppendHeader(ViaHeader{viaHop.Clone()})
- CopyHeaders("Route", requestForCancel, cancelReq)
- maxForwardsHeader := MaxForwards(70)
- cancelReq.AppendHeader(&maxForwardsHeader)
- CopyHeaders("From", requestForCancel, cancelReq)
- CopyHeaders("To", requestForCancel, cancelReq)
- CopyHeaders("Call-ID", requestForCancel, cancelReq)
- CopyHeaders("CSeq", requestForCancel, cancelReq)
- cseq, _ := cancelReq.CSeq()
- cseq.MethodName = CANCEL
- cancelReq.SetBody("", true)
- cancelReq.SetTransport(requestForCancel.Transport())
- cancelReq.SetSource(requestForCancel.Source())
- cancelReq.SetDestination(requestForCancel.Destination())
- return cancelReq
- }
- func cloneRequest(req Request, id MessageID, fields log.Fields) Request {
- newFields := req.Fields()
- if fields != nil {
- newFields = newFields.WithFields(fields)
- }
- newReq := NewRequest(
- id,
- req.Method(),
- req.Recipient().Clone(),
- req.SipVersion(),
- cloneHeaders(req),
- req.Body(),
- newFields,
- )
- newReq.SetTransport(req.Transport())
- newReq.SetSource(req.Source())
- newReq.SetDestination(req.Destination())
- return newReq
- }
- func CopyRequest(req Request) Request {
- return cloneRequest(req, req.MessageID(), nil)
- }
|