123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310 |
- package sip
- import (
- "bytes"
- "fmt"
- "strconv"
- "strings"
- "github.com/ghettovoice/gosip/log"
- )
- // Response RFC 3261 - 7.2.
- type Response interface {
- Message
- StatusCode() StatusCode
- SetStatusCode(code StatusCode)
- Reason() string
- SetReason(reason string)
- // Previous returns previous provisional responses
- Previous() []Response
- SetPrevious(responses []Response)
- /* Common helpers */
- IsProvisional() bool
- IsSuccess() bool
- IsRedirection() bool
- IsClientError() bool
- IsServerError() bool
- IsGlobalError() bool
- }
- type response struct {
- message
- status StatusCode
- reason string
- previous []Response
- }
- func NewResponse(
- messID MessageID,
- sipVersion string,
- statusCode StatusCode,
- reason string,
- hdrs []Header,
- body string,
- fields log.Fields,
- ) Response {
- res := new(response)
- if messID == "" {
- res.messID = NextMessageID()
- } else {
- res.messID = messID
- }
- res.startLine = res.StartLine
- res.sipVersion = sipVersion
- res.headers = newHeaders(hdrs)
- res.status = statusCode
- res.reason = reason
- res.body = body
- res.fields = fields.WithFields(log.Fields{
- "response_id": res.messID,
- })
- res.previous = make([]Response, 0)
- return res
- }
- func (res *response) Short() string {
- if res == nil {
- return "<nil>"
- }
- fields := log.Fields{
- "status": res.StatusCode(),
- "reason": res.Reason(),
- "transport": res.Transport(),
- "source": res.Source(),
- "destination": res.Destination(),
- }
- if cseq, ok := res.CSeq(); ok {
- fields["method"] = cseq.MethodName
- fields["sequence"] = cseq.SeqNo
- }
- fields = res.Fields().WithFields(fields)
- return fmt.Sprintf("sip.Response<%s>", fields)
- }
- func (res *response) StatusCode() StatusCode {
- res.mu.RLock()
- defer res.mu.RUnlock()
- return res.status
- }
- func (res *response) SetStatusCode(code StatusCode) {
- res.mu.Lock()
- res.status = code
- res.mu.Unlock()
- }
- func (res *response) Reason() string {
- res.mu.RLock()
- defer res.mu.RUnlock()
- return res.reason
- }
- func (res *response) SetReason(reason string) {
- res.mu.Lock()
- res.reason = reason
- res.mu.Unlock()
- }
- func (res *response) Previous() []Response {
- res.mu.RLock()
- defer res.mu.RUnlock()
- return res.previous
- }
- func (res *response) SetPrevious(responses []Response) {
- res.mu.Lock()
- res.previous = responses
- res.mu.Unlock()
- }
- // StartLine returns Response Status Line - RFC 2361 7.2.
- func (res *response) StartLine() string {
- var buffer bytes.Buffer
- // Every SIP response starts with a Status Line - RFC 2361 7.2.
- buffer.WriteString(
- fmt.Sprintf(
- "%s %d %s",
- res.SipVersion(),
- res.StatusCode(),
- res.Reason(),
- ),
- )
- return buffer.String()
- }
- func (res *response) Clone() Message {
- return cloneResponse(res, "", nil)
- }
- func (res *response) Fields() log.Fields {
- return res.fields.WithFields(log.Fields{
- "transport": res.Transport(),
- "source": res.Source(),
- "destination": res.Destination(),
- })
- }
- func (res *response) WithFields(fields log.Fields) Message {
- res.mu.Lock()
- res.fields = res.fields.WithFields(fields)
- res.mu.Unlock()
- return res
- }
- func (res *response) IsProvisional() bool {
- return res.StatusCode() < 200
- }
- func (res *response) IsSuccess() bool {
- return res.StatusCode() >= 200 && res.StatusCode() < 300
- }
- func (res *response) IsRedirection() bool {
- return res.StatusCode() >= 300 && res.StatusCode() < 400
- }
- func (res *response) IsClientError() bool {
- return res.StatusCode() >= 400 && res.StatusCode() < 500
- }
- func (res *response) IsServerError() bool {
- return res.StatusCode() >= 500 && res.StatusCode() < 600
- }
- func (res *response) IsGlobalError() bool {
- return res.StatusCode() >= 600
- }
- func (res *response) IsAck() bool {
- if cseq, ok := res.CSeq(); ok {
- return cseq.MethodName == ACK
- }
- return false
- }
- func (res *response) IsCancel() bool {
- if cseq, ok := res.CSeq(); ok {
- return cseq.MethodName == CANCEL
- }
- return false
- }
- func (res *response) Transport() string {
- if tp := res.message.Transport(); tp != "" {
- return strings.ToUpper(tp)
- }
- var tp string
- if viaHop, ok := res.ViaHop(); ok && viaHop.Transport != "" {
- tp = viaHop.Transport
- } else {
- tp = DefaultProtocol
- }
- return tp
- }
- func (res *response) Destination() string {
- if dest := res.message.Destination(); dest != "" {
- return dest
- }
- viaHop, ok := res.ViaHop()
- if !ok {
- return ""
- }
- var (
- host string
- port Port
- )
- host = viaHop.Host
- if viaHop.Port != nil {
- port = *viaHop.Port
- } else {
- port = DefaultPort(res.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)
- }
- // RFC 3261 - 8.2.6
- func NewResponseFromRequest(
- resID MessageID,
- req Request,
- statusCode StatusCode,
- reason string,
- body string,
- ) Response {
- res := NewResponse(
- resID,
- req.SipVersion(),
- statusCode,
- reason,
- []Header{},
- "",
- req.Fields(),
- )
- CopyHeaders("Record-Route", req, res)
- CopyHeaders("Via", req, res)
- CopyHeaders("From", req, res)
- CopyHeaders("To", req, res)
- CopyHeaders("Call-ID", req, res)
- CopyHeaders("CSeq", req, res)
- if statusCode == 100 {
- CopyHeaders("Timestamp", req, res)
- }
- res.SetBody(body, true)
- res.SetTransport(req.Transport())
- res.SetSource(req.Destination())
- res.SetDestination(req.Source())
- return res
- }
- func cloneResponse(res Response, id MessageID, fields log.Fields) Response {
- newFields := res.Fields()
- if fields != nil {
- newFields = newFields.WithFields(fields)
- }
- newRes := NewResponse(
- id,
- res.SipVersion(),
- res.StatusCode(),
- res.Reason(),
- cloneHeaders(res),
- res.Body(),
- newFields,
- )
- newRes.SetPrevious(res.Previous())
- newRes.SetTransport(res.Transport())
- newRes.SetSource(res.Source())
- newRes.SetDestination(res.Destination())
- return newRes
- }
- func CopyResponse(res Response) Response {
- return cloneResponse(res, res.MessageID(), nil)
- }
|