mirror of
https://github.com/ossrs/srs.git
synced 2025-03-09 15:49:59 +00:00
GB28181: Support GB28181-2016 protocol. v5.0.74 (#3201)
01. Support GB config as StreamCaster. 02. Support disable GB by --gb28181=off. 03. Add utests for SIP examples. 04. Wireshark plugin to decode TCP/9000 as rtp.rfc4571 05. Support MPEGPS program stream codec. 06. Add utest for PS stream codec. 07. Decode MPEGPS packet stream. 08. Carry RTP and PS packet as helper in PS message. 09. Support recover from error mode. 10. Support process by a pack of PS/TS messages. 11. Add statistic for recovered and msgs dropped. 12. Recover from err position fastly. 13. Define state machine for GB session. 14. Bind context to GB session. 15. Re-invite when media disconnected. 16. Update GitHub actions with GB28181. 17. Support parse CANDIDATE by env or pip. 18. Support mux GB28181 to RTMP. 19. Support regression test by srs-bench.
This commit is contained in:
parent
9c81a0e1bd
commit
5a420ece3b
298 changed files with 43343 additions and 763 deletions
279
trunk/3rdparty/srs-bench/vendor/github.com/ghettovoice/gosip/sip/auth.go
generated
vendored
Normal file
279
trunk/3rdparty/srs-bench/vendor/github.com/ghettovoice/gosip/sip/auth.go
generated
vendored
Normal file
|
@ -0,0 +1,279 @@
|
|||
package sip
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// currently only Digest and MD5
|
||||
type Authorization struct {
|
||||
realm string
|
||||
nonce string
|
||||
algorithm string
|
||||
username string
|
||||
password string
|
||||
uri string
|
||||
response string
|
||||
method string
|
||||
qop string
|
||||
nc string
|
||||
cnonce string
|
||||
other map[string]string
|
||||
}
|
||||
|
||||
func AuthFromValue(value string) *Authorization {
|
||||
auth := &Authorization{
|
||||
algorithm: "MD5",
|
||||
other: make(map[string]string),
|
||||
}
|
||||
|
||||
re := regexp.MustCompile(`([\w]+)="([^"]+)"`)
|
||||
matches := re.FindAllStringSubmatch(value, -1)
|
||||
for _, match := range matches {
|
||||
switch match[1] {
|
||||
case "realm":
|
||||
auth.realm = match[2]
|
||||
case "algorithm":
|
||||
auth.algorithm = match[2]
|
||||
case "nonce":
|
||||
auth.nonce = match[2]
|
||||
case "username":
|
||||
auth.username = match[2]
|
||||
case "uri":
|
||||
auth.uri = match[2]
|
||||
case "response":
|
||||
auth.response = match[2]
|
||||
case "qop":
|
||||
for _, v := range strings.Split(match[2], ",") {
|
||||
v = strings.Trim(v, " ")
|
||||
if v == "auth" || v == "auth-int" {
|
||||
auth.qop = "auth"
|
||||
break
|
||||
}
|
||||
}
|
||||
case "nc":
|
||||
auth.nc = match[2]
|
||||
case "cnonce":
|
||||
auth.cnonce = match[2]
|
||||
default:
|
||||
auth.other[match[1]] = match[2]
|
||||
}
|
||||
}
|
||||
|
||||
return auth
|
||||
}
|
||||
|
||||
func (auth *Authorization) Realm() string {
|
||||
return auth.realm
|
||||
}
|
||||
|
||||
func (auth *Authorization) Nonce() string {
|
||||
return auth.nonce
|
||||
}
|
||||
|
||||
func (auth *Authorization) Algorithm() string {
|
||||
return auth.algorithm
|
||||
}
|
||||
|
||||
func (auth *Authorization) Username() string {
|
||||
return auth.username
|
||||
}
|
||||
|
||||
func (auth *Authorization) SetUsername(username string) *Authorization {
|
||||
auth.username = username
|
||||
|
||||
return auth
|
||||
}
|
||||
|
||||
func (auth *Authorization) SetPassword(password string) *Authorization {
|
||||
auth.password = password
|
||||
|
||||
return auth
|
||||
}
|
||||
|
||||
func (auth *Authorization) Uri() string {
|
||||
return auth.uri
|
||||
}
|
||||
|
||||
func (auth *Authorization) SetUri(uri string) *Authorization {
|
||||
auth.uri = uri
|
||||
|
||||
return auth
|
||||
}
|
||||
|
||||
func (auth *Authorization) SetMethod(method string) *Authorization {
|
||||
auth.method = method
|
||||
|
||||
return auth
|
||||
}
|
||||
|
||||
func (auth *Authorization) Response() string {
|
||||
return auth.response
|
||||
}
|
||||
|
||||
func (auth *Authorization) SetResponse(response string) {
|
||||
auth.response = response
|
||||
}
|
||||
|
||||
func (auth *Authorization) Qop() string {
|
||||
return auth.qop
|
||||
}
|
||||
|
||||
func (auth *Authorization) SetQop(qop string) {
|
||||
auth.qop = qop
|
||||
}
|
||||
|
||||
func (auth *Authorization) Nc() string {
|
||||
return auth.nc
|
||||
}
|
||||
|
||||
func (auth *Authorization) SetNc(nc string) {
|
||||
auth.nc = nc
|
||||
}
|
||||
|
||||
func (auth *Authorization) CNonce() string {
|
||||
return auth.cnonce
|
||||
}
|
||||
|
||||
func (auth *Authorization) SetCNonce(cnonce string) {
|
||||
auth.cnonce = cnonce
|
||||
}
|
||||
|
||||
func (auth *Authorization) CalcResponse() string {
|
||||
return calcResponse(
|
||||
auth.username,
|
||||
auth.realm,
|
||||
auth.password,
|
||||
auth.method,
|
||||
auth.uri,
|
||||
auth.nonce,
|
||||
auth.qop,
|
||||
auth.cnonce,
|
||||
auth.nc,
|
||||
)
|
||||
}
|
||||
|
||||
func (auth *Authorization) String() string {
|
||||
if auth == nil {
|
||||
return "<nil>"
|
||||
}
|
||||
|
||||
str := fmt.Sprintf(
|
||||
`Digest realm="%s",algorithm=%s,nonce="%s",username="%s",uri="%s",response="%s"`,
|
||||
auth.realm,
|
||||
auth.algorithm,
|
||||
auth.nonce,
|
||||
auth.username,
|
||||
auth.uri,
|
||||
auth.response,
|
||||
)
|
||||
if auth.qop == "auth" {
|
||||
str += fmt.Sprintf(`,qop=%s,nc=%s,cnonce="%s"`, auth.qop, auth.nc, auth.cnonce)
|
||||
}
|
||||
|
||||
return str
|
||||
}
|
||||
|
||||
// calculates Authorization response https://www.ietf.org/rfc/rfc2617.txt
|
||||
func calcResponse(username, realm, password, method, uri, nonce, qop, cnonce, nc string) string {
|
||||
calcA1 := func() string {
|
||||
encoder := md5.New()
|
||||
encoder.Write([]byte(username + ":" + realm + ":" + password))
|
||||
|
||||
return hex.EncodeToString(encoder.Sum(nil))
|
||||
}
|
||||
calcA2 := func() string {
|
||||
encoder := md5.New()
|
||||
encoder.Write([]byte(method + ":" + uri))
|
||||
|
||||
return hex.EncodeToString(encoder.Sum(nil))
|
||||
}
|
||||
|
||||
encoder := md5.New()
|
||||
encoder.Write([]byte(calcA1() + ":" + nonce + ":"))
|
||||
if qop != "" {
|
||||
encoder.Write([]byte(nc + ":" + cnonce + ":" + qop + ":"))
|
||||
}
|
||||
encoder.Write([]byte(calcA2()))
|
||||
|
||||
return hex.EncodeToString(encoder.Sum(nil))
|
||||
}
|
||||
|
||||
func AuthorizeRequest(request Request, response Response, user, password MaybeString) error {
|
||||
if user == nil {
|
||||
return fmt.Errorf("authorize request: user is nil")
|
||||
}
|
||||
|
||||
var authenticateHeaderName, authorizeHeaderName string
|
||||
if response.StatusCode() == 401 {
|
||||
// on 401 Unauthorized increase request seq num, add Authorization header and send once again
|
||||
authenticateHeaderName = "WWW-Authenticate"
|
||||
authorizeHeaderName = "Authorization"
|
||||
} else {
|
||||
// 407 Proxy authentication
|
||||
authenticateHeaderName = "Proxy-Authenticate"
|
||||
authorizeHeaderName = "Proxy-Authorization"
|
||||
}
|
||||
|
||||
if hdrs := response.GetHeaders(authenticateHeaderName); len(hdrs) > 0 {
|
||||
authenticateHeader := hdrs[0].(*GenericHeader)
|
||||
auth := AuthFromValue(authenticateHeader.Contents).
|
||||
SetMethod(string(request.Method())).
|
||||
SetUri(request.Recipient().String()).
|
||||
SetUsername(user.String())
|
||||
if password != nil {
|
||||
auth.SetPassword(password.String())
|
||||
}
|
||||
if auth.Qop() == "auth" {
|
||||
auth.SetNc("00000001")
|
||||
encoder := md5.New()
|
||||
encoder.Write([]byte(user.String() + request.Recipient().String()))
|
||||
if password != nil {
|
||||
encoder.Write([]byte(password.String()))
|
||||
}
|
||||
auth.SetCNonce(hex.EncodeToString(encoder.Sum(nil)))
|
||||
}
|
||||
auth.SetResponse(auth.CalcResponse())
|
||||
|
||||
if hdrs = request.GetHeaders(authorizeHeaderName); len(hdrs) > 0 {
|
||||
authorizationHeader := hdrs[0].Clone().(*GenericHeader)
|
||||
authorizationHeader.Contents = auth.String()
|
||||
request.ReplaceHeaders(authorizationHeader.Name(), []Header{authorizationHeader})
|
||||
} else {
|
||||
request.AppendHeader(&GenericHeader{
|
||||
HeaderName: authorizeHeaderName,
|
||||
Contents: auth.String(),
|
||||
})
|
||||
}
|
||||
} else {
|
||||
return fmt.Errorf("authorize request: header '%s' not found in response", authenticateHeaderName)
|
||||
}
|
||||
|
||||
if viaHop, ok := request.ViaHop(); ok {
|
||||
viaHop.Params.Add("branch", String{Str: GenerateBranch()})
|
||||
}
|
||||
|
||||
if cseq, ok := request.CSeq(); ok {
|
||||
cseq := cseq.Clone().(*CSeq)
|
||||
cseq.SeqNo++
|
||||
request.ReplaceHeaders(cseq.Name(), []Header{cseq})
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type Authorizer interface {
|
||||
AuthorizeRequest(request Request, response Response) error
|
||||
}
|
||||
|
||||
type DefaultAuthorizer struct {
|
||||
User MaybeString
|
||||
Password MaybeString
|
||||
}
|
||||
|
||||
func (auth *DefaultAuthorizer) AuthorizeRequest(request Request, response Response) error {
|
||||
return AuthorizeRequest(request, response, auth.User, auth.Password)
|
||||
}
|
336
trunk/3rdparty/srs-bench/vendor/github.com/ghettovoice/gosip/sip/builder.go
generated
vendored
Normal file
336
trunk/3rdparty/srs-bench/vendor/github.com/ghettovoice/gosip/sip/builder.go
generated
vendored
Normal file
|
@ -0,0 +1,336 @@
|
|||
package sip
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/ghettovoice/gosip/util"
|
||||
)
|
||||
|
||||
type RequestBuilder struct {
|
||||
protocol string
|
||||
protocolVersion string
|
||||
transport string
|
||||
host string
|
||||
method RequestMethod
|
||||
cseq *CSeq
|
||||
recipient Uri
|
||||
body string
|
||||
callID *CallID
|
||||
via ViaHeader
|
||||
from *FromHeader
|
||||
to *ToHeader
|
||||
contact *ContactHeader
|
||||
expires *Expires
|
||||
userAgent *UserAgentHeader
|
||||
maxForwards *MaxForwards
|
||||
supported *SupportedHeader
|
||||
require *RequireHeader
|
||||
allow AllowHeader
|
||||
contentType *ContentType
|
||||
accept *Accept
|
||||
route *RouteHeader
|
||||
generic map[string]Header
|
||||
}
|
||||
|
||||
func NewRequestBuilder() *RequestBuilder {
|
||||
callID := CallID(util.RandString(32))
|
||||
maxForwards := MaxForwards(70)
|
||||
userAgent := UserAgentHeader("GoSIP")
|
||||
rb := &RequestBuilder{
|
||||
protocol: "SIP",
|
||||
protocolVersion: "2.0",
|
||||
transport: "UDP",
|
||||
host: "localhost",
|
||||
cseq: &CSeq{SeqNo: 1},
|
||||
body: "",
|
||||
via: make(ViaHeader, 0),
|
||||
callID: &callID,
|
||||
userAgent: &userAgent,
|
||||
maxForwards: &maxForwards,
|
||||
generic: make(map[string]Header),
|
||||
}
|
||||
|
||||
return rb
|
||||
}
|
||||
|
||||
func (rb *RequestBuilder) SetTransport(transport string) *RequestBuilder {
|
||||
if transport == "" {
|
||||
rb.transport = "UDP"
|
||||
} else {
|
||||
rb.transport = transport
|
||||
}
|
||||
|
||||
return rb
|
||||
}
|
||||
|
||||
func (rb *RequestBuilder) SetHost(host string) *RequestBuilder {
|
||||
if host == "" {
|
||||
rb.host = "localhost"
|
||||
} else {
|
||||
rb.host = host
|
||||
}
|
||||
|
||||
return rb
|
||||
}
|
||||
|
||||
func (rb *RequestBuilder) SetMethod(method RequestMethod) *RequestBuilder {
|
||||
rb.method = method
|
||||
rb.cseq.MethodName = method
|
||||
|
||||
return rb
|
||||
}
|
||||
|
||||
func (rb *RequestBuilder) SetSeqNo(seqNo uint) *RequestBuilder {
|
||||
rb.cseq.SeqNo = uint32(seqNo)
|
||||
|
||||
return rb
|
||||
}
|
||||
|
||||
func (rb *RequestBuilder) SetRecipient(uri Uri) *RequestBuilder {
|
||||
rb.recipient = uri.Clone()
|
||||
|
||||
return rb
|
||||
}
|
||||
|
||||
func (rb *RequestBuilder) SetBody(body string) *RequestBuilder {
|
||||
rb.body = body
|
||||
|
||||
return rb
|
||||
}
|
||||
|
||||
func (rb *RequestBuilder) SetCallID(callID *CallID) *RequestBuilder {
|
||||
if callID != nil {
|
||||
rb.callID = callID
|
||||
}
|
||||
|
||||
return rb
|
||||
}
|
||||
|
||||
func (rb *RequestBuilder) AddVia(via *ViaHop) *RequestBuilder {
|
||||
if via.ProtocolName == "" {
|
||||
via.ProtocolName = rb.protocol
|
||||
}
|
||||
if via.ProtocolVersion == "" {
|
||||
via.ProtocolVersion = rb.protocolVersion
|
||||
}
|
||||
if via.Transport == "" {
|
||||
via.Transport = rb.transport
|
||||
}
|
||||
if via.Host == "" {
|
||||
via.Host = rb.host
|
||||
}
|
||||
if via.Params == nil {
|
||||
via.Params = NewParams()
|
||||
}
|
||||
|
||||
rb.via = append(rb.via, via)
|
||||
|
||||
return rb
|
||||
}
|
||||
|
||||
func (rb *RequestBuilder) SetFrom(address *Address) *RequestBuilder {
|
||||
if address == nil {
|
||||
rb.from = nil
|
||||
} else {
|
||||
address = address.Clone()
|
||||
if address.Uri.Host() == "" {
|
||||
address.Uri.SetHost(rb.host)
|
||||
}
|
||||
rb.from = &FromHeader{
|
||||
DisplayName: address.DisplayName,
|
||||
Address: address.Uri,
|
||||
Params: address.Params,
|
||||
}
|
||||
}
|
||||
|
||||
return rb
|
||||
}
|
||||
|
||||
func (rb *RequestBuilder) SetTo(address *Address) *RequestBuilder {
|
||||
if address == nil {
|
||||
rb.to = nil
|
||||
} else {
|
||||
address = address.Clone()
|
||||
if address.Uri.Host() == "" {
|
||||
address.Uri.SetHost(rb.host)
|
||||
}
|
||||
rb.to = &ToHeader{
|
||||
DisplayName: address.DisplayName,
|
||||
Address: address.Uri,
|
||||
Params: address.Params,
|
||||
}
|
||||
}
|
||||
|
||||
return rb
|
||||
}
|
||||
|
||||
func (rb *RequestBuilder) SetContact(address *Address) *RequestBuilder {
|
||||
if address == nil {
|
||||
rb.contact = nil
|
||||
} else {
|
||||
address = address.Clone()
|
||||
if address.Uri.Host() == "" {
|
||||
address.Uri.SetHost(rb.host)
|
||||
}
|
||||
rb.contact = &ContactHeader{
|
||||
DisplayName: address.DisplayName,
|
||||
Address: address.Uri,
|
||||
Params: address.Params,
|
||||
}
|
||||
}
|
||||
|
||||
return rb
|
||||
}
|
||||
|
||||
func (rb *RequestBuilder) SetExpires(expires *Expires) *RequestBuilder {
|
||||
rb.expires = expires
|
||||
|
||||
return rb
|
||||
}
|
||||
|
||||
func (rb *RequestBuilder) SetUserAgent(userAgent *UserAgentHeader) *RequestBuilder {
|
||||
rb.userAgent = userAgent
|
||||
|
||||
return rb
|
||||
}
|
||||
|
||||
func (rb *RequestBuilder) SetMaxForwards(maxForwards *MaxForwards) *RequestBuilder {
|
||||
rb.maxForwards = maxForwards
|
||||
|
||||
return rb
|
||||
}
|
||||
|
||||
func (rb *RequestBuilder) SetAllow(methods []RequestMethod) *RequestBuilder {
|
||||
rb.allow = methods
|
||||
|
||||
return rb
|
||||
}
|
||||
|
||||
func (rb *RequestBuilder) SetSupported(options []string) *RequestBuilder {
|
||||
if len(options) == 0 {
|
||||
rb.supported = nil
|
||||
} else {
|
||||
rb.supported = &SupportedHeader{
|
||||
Options: options,
|
||||
}
|
||||
}
|
||||
|
||||
return rb
|
||||
}
|
||||
|
||||
func (rb *RequestBuilder) SetRequire(options []string) *RequestBuilder {
|
||||
if len(options) == 0 {
|
||||
rb.require = nil
|
||||
} else {
|
||||
rb.require = &RequireHeader{
|
||||
Options: options,
|
||||
}
|
||||
}
|
||||
|
||||
return rb
|
||||
}
|
||||
|
||||
func (rb *RequestBuilder) SetContentType(contentType *ContentType) *RequestBuilder {
|
||||
rb.contentType = contentType
|
||||
|
||||
return rb
|
||||
}
|
||||
|
||||
func (rb *RequestBuilder) SetAccept(accept *Accept) *RequestBuilder {
|
||||
rb.accept = accept
|
||||
|
||||
return rb
|
||||
}
|
||||
|
||||
func (rb *RequestBuilder) SetRoutes(routes []Uri) *RequestBuilder {
|
||||
if len(routes) == 0 {
|
||||
rb.route = nil
|
||||
} else {
|
||||
rb.route = &RouteHeader{
|
||||
Addresses: routes,
|
||||
}
|
||||
}
|
||||
|
||||
return rb
|
||||
}
|
||||
|
||||
func (rb *RequestBuilder) AddHeader(header Header) *RequestBuilder {
|
||||
rb.generic[header.Name()] = header
|
||||
|
||||
return rb
|
||||
}
|
||||
|
||||
func (rb *RequestBuilder) RemoveHeader(headerName string) *RequestBuilder {
|
||||
if _, ok := rb.generic[headerName]; ok {
|
||||
delete(rb.generic, headerName)
|
||||
}
|
||||
|
||||
return rb
|
||||
}
|
||||
|
||||
func (rb *RequestBuilder) Build() (Request, error) {
|
||||
if rb.method == "" {
|
||||
return nil, fmt.Errorf("undefined method name")
|
||||
}
|
||||
if rb.recipient == nil {
|
||||
return nil, fmt.Errorf("empty recipient")
|
||||
}
|
||||
if rb.from == nil {
|
||||
return nil, fmt.Errorf("empty 'From' header")
|
||||
}
|
||||
if rb.to == nil {
|
||||
return nil, fmt.Errorf("empty 'From' header")
|
||||
}
|
||||
|
||||
hdrs := make([]Header, 0)
|
||||
|
||||
if rb.route != nil {
|
||||
hdrs = append(hdrs, rb.route)
|
||||
}
|
||||
|
||||
if len(rb.via) != 0 {
|
||||
via := make(ViaHeader, 0)
|
||||
for _, viaHop := range rb.via {
|
||||
via = append(via, viaHop)
|
||||
}
|
||||
hdrs = append(hdrs, via)
|
||||
}
|
||||
|
||||
hdrs = append(hdrs, rb.cseq, rb.from, rb.to, rb.callID)
|
||||
|
||||
if rb.contact != nil {
|
||||
hdrs = append(hdrs, rb.contact)
|
||||
}
|
||||
if rb.maxForwards != nil {
|
||||
hdrs = append(hdrs, rb.maxForwards)
|
||||
}
|
||||
if rb.expires != nil {
|
||||
hdrs = append(hdrs, rb.expires)
|
||||
}
|
||||
if rb.supported != nil {
|
||||
hdrs = append(hdrs, rb.supported)
|
||||
}
|
||||
if rb.allow != nil {
|
||||
hdrs = append(hdrs, rb.allow)
|
||||
}
|
||||
if rb.contentType != nil {
|
||||
hdrs = append(hdrs, rb.contentType)
|
||||
}
|
||||
if rb.accept != nil {
|
||||
hdrs = append(hdrs, rb.accept)
|
||||
}
|
||||
if rb.userAgent != nil {
|
||||
hdrs = append(hdrs, rb.userAgent)
|
||||
}
|
||||
|
||||
for _, header := range rb.generic {
|
||||
hdrs = append(hdrs, header)
|
||||
}
|
||||
|
||||
sipVersion := rb.protocol + "/" + rb.protocolVersion
|
||||
// basic request
|
||||
req := NewRequest("", rb.method, rb.recipient, sipVersion, hdrs, "", nil)
|
||||
req.SetBody(rb.body, true)
|
||||
|
||||
return req, nil
|
||||
}
|
412
trunk/3rdparty/srs-bench/vendor/github.com/ghettovoice/gosip/sip/core.go
generated
vendored
Normal file
412
trunk/3rdparty/srs-bench/vendor/github.com/ghettovoice/gosip/sip/core.go
generated
vendored
Normal file
|
@ -0,0 +1,412 @@
|
|||
package sip
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/ghettovoice/gosip/util"
|
||||
)
|
||||
|
||||
const (
|
||||
MTU uint = 1500
|
||||
|
||||
DefaultHost = "127.0.0.1"
|
||||
DefaultProtocol = "UDP"
|
||||
|
||||
DefaultUdpPort Port = 5060
|
||||
DefaultTcpPort Port = 5060
|
||||
DefaultTlsPort Port = 5061
|
||||
DefaultWsPort Port = 80
|
||||
DefaultWssPort Port = 443
|
||||
)
|
||||
|
||||
// TODO should be refactored, currently here the pit
|
||||
|
||||
type Address struct {
|
||||
DisplayName MaybeString
|
||||
Uri Uri
|
||||
Params Params
|
||||
}
|
||||
|
||||
func NewAddressFromFromHeader(from *FromHeader) *Address {
|
||||
addr := &Address{
|
||||
DisplayName: from.DisplayName,
|
||||
}
|
||||
if from.Address != nil {
|
||||
addr.Uri = from.Address.Clone()
|
||||
}
|
||||
if from.Params != nil {
|
||||
addr.Params = from.Params.Clone()
|
||||
}
|
||||
|
||||
return addr
|
||||
}
|
||||
|
||||
func NewAddressFromToHeader(to *ToHeader) *Address {
|
||||
addr := &Address{
|
||||
DisplayName: to.DisplayName,
|
||||
}
|
||||
if to.Address != nil {
|
||||
addr.Uri = to.Address.Clone()
|
||||
}
|
||||
if to.Params != nil {
|
||||
addr.Params = to.Params.Clone()
|
||||
}
|
||||
|
||||
return addr
|
||||
}
|
||||
|
||||
func NewAddressFromContactHeader(cnt *ContactHeader) *Address {
|
||||
addr := &Address{
|
||||
DisplayName: cnt.DisplayName,
|
||||
}
|
||||
if cnt.Address != nil {
|
||||
addr.Uri = cnt.Address.Clone()
|
||||
}
|
||||
if cnt.Params != nil {
|
||||
addr.Params = cnt.Params.Clone()
|
||||
}
|
||||
|
||||
return addr
|
||||
}
|
||||
|
||||
func (addr *Address) String() string {
|
||||
var buffer bytes.Buffer
|
||||
|
||||
if addr == nil {
|
||||
return "<nil>"
|
||||
}
|
||||
|
||||
if addr.DisplayName != nil {
|
||||
if displayName, ok := addr.DisplayName.(String); ok && displayName.String() != "" {
|
||||
buffer.WriteString(fmt.Sprintf("\"%s\" ", displayName))
|
||||
}
|
||||
}
|
||||
|
||||
buffer.WriteString(fmt.Sprintf("<%s>", addr.Uri))
|
||||
|
||||
if addr.Params != nil && addr.Params.Length() > 0 {
|
||||
buffer.WriteString(";")
|
||||
buffer.WriteString(addr.Params.ToString(';'))
|
||||
}
|
||||
|
||||
return buffer.String()
|
||||
}
|
||||
|
||||
func (addr *Address) Clone() *Address {
|
||||
var name MaybeString
|
||||
var uri Uri
|
||||
var params Params
|
||||
|
||||
if addr.DisplayName != nil {
|
||||
name = String{Str: addr.DisplayName.String()}
|
||||
}
|
||||
if addr.Uri != nil {
|
||||
uri = addr.Uri.Clone()
|
||||
}
|
||||
if addr.Params != nil {
|
||||
params = addr.Params.Clone()
|
||||
}
|
||||
|
||||
return &Address{
|
||||
DisplayName: name,
|
||||
Uri: uri,
|
||||
Params: params,
|
||||
}
|
||||
}
|
||||
|
||||
func (addr *Address) Equals(other interface{}) bool {
|
||||
otherPtr, ok := other.(*Address)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
if addr == otherPtr {
|
||||
return true
|
||||
}
|
||||
if addr == nil && otherPtr != nil || addr != nil && otherPtr == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
res := true
|
||||
|
||||
if addr.DisplayName != otherPtr.DisplayName {
|
||||
if addr.DisplayName == nil {
|
||||
res = res && otherPtr.DisplayName == nil
|
||||
} else {
|
||||
res = res && addr.DisplayName.Equals(otherPtr.DisplayName)
|
||||
}
|
||||
}
|
||||
|
||||
if addr.Uri != otherPtr.Uri {
|
||||
if addr.Uri == nil {
|
||||
res = res && otherPtr.Uri == nil
|
||||
} else {
|
||||
res = res && addr.Uri.Equals(otherPtr.Uri)
|
||||
}
|
||||
}
|
||||
|
||||
if addr.Params != otherPtr.Params {
|
||||
if addr.Params == nil {
|
||||
res = res && otherPtr.Params == nil
|
||||
} else {
|
||||
res = res && addr.Params.Equals(otherPtr.Params)
|
||||
}
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
func (addr *Address) AsToHeader() *ToHeader {
|
||||
to := &ToHeader{
|
||||
DisplayName: addr.DisplayName,
|
||||
}
|
||||
if addr.Uri != nil {
|
||||
to.Address = addr.Uri.Clone()
|
||||
}
|
||||
if addr.Params != nil {
|
||||
to.Params = addr.Params.Clone()
|
||||
}
|
||||
|
||||
return to
|
||||
}
|
||||
|
||||
func (addr *Address) AsFromHeader() *FromHeader {
|
||||
from := &FromHeader{
|
||||
DisplayName: addr.DisplayName,
|
||||
}
|
||||
if addr.Uri != nil {
|
||||
from.Address = addr.Uri.Clone()
|
||||
}
|
||||
if addr.Params != nil {
|
||||
from.Params = addr.Params.Clone()
|
||||
}
|
||||
|
||||
return from
|
||||
}
|
||||
|
||||
func (addr *Address) AsContactHeader() *ContactHeader {
|
||||
cnt := &ContactHeader{
|
||||
DisplayName: addr.DisplayName,
|
||||
}
|
||||
if addr.Uri != nil {
|
||||
cnt.Address = addr.Uri.Clone()
|
||||
}
|
||||
if addr.Params != nil {
|
||||
cnt.Params = addr.Params.Clone()
|
||||
}
|
||||
|
||||
return cnt
|
||||
}
|
||||
|
||||
// Port number
|
||||
type Port uint16
|
||||
|
||||
func (port *Port) Clone() *Port {
|
||||
if port == nil {
|
||||
return nil
|
||||
}
|
||||
newPort := *port
|
||||
return &newPort
|
||||
}
|
||||
|
||||
func (port *Port) String() string {
|
||||
if port == nil {
|
||||
return ""
|
||||
}
|
||||
return fmt.Sprintf("%d", *port)
|
||||
}
|
||||
|
||||
func (port *Port) Equals(other interface{}) bool {
|
||||
if p, ok := other.(*Port); ok {
|
||||
return util.Uint16PtrEq((*uint16)(port), (*uint16)(p))
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// String wrapper
|
||||
type MaybeString interface {
|
||||
String() string
|
||||
Equals(other interface{}) bool
|
||||
}
|
||||
|
||||
type String struct {
|
||||
Str string
|
||||
}
|
||||
|
||||
func (str String) String() string {
|
||||
return str.Str
|
||||
}
|
||||
|
||||
func (str String) Equals(other interface{}) bool {
|
||||
if v, ok := other.(string); ok {
|
||||
return str.Str == v
|
||||
}
|
||||
if v, ok := other.(String); ok {
|
||||
return str.Str == v.Str
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
type CancelError interface {
|
||||
Canceled() bool
|
||||
}
|
||||
|
||||
type ExpireError interface {
|
||||
Expired() bool
|
||||
}
|
||||
|
||||
type MessageError interface {
|
||||
error
|
||||
// Malformed indicates that message is syntactically valid but has invalid headers, or
|
||||
// without required headers.
|
||||
Malformed() bool
|
||||
// Broken or incomplete message, or not a SIP message
|
||||
Broken() bool
|
||||
}
|
||||
|
||||
// Broken or incomplete messages, or not a SIP message.
|
||||
type BrokenMessageError struct {
|
||||
Err error
|
||||
Msg string
|
||||
}
|
||||
|
||||
func (err *BrokenMessageError) Malformed() bool { return false }
|
||||
func (err *BrokenMessageError) Broken() bool { return true }
|
||||
func (err *BrokenMessageError) Error() string {
|
||||
if err == nil {
|
||||
return "<nil>"
|
||||
}
|
||||
|
||||
s := "BrokenMessageError: " + err.Err.Error()
|
||||
if err.Msg != "" {
|
||||
s += fmt.Sprintf("\nMessage dump:\n%s", err.Msg)
|
||||
}
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
// syntactically valid but logically invalid message
|
||||
type MalformedMessageError struct {
|
||||
Err error
|
||||
Msg string
|
||||
}
|
||||
|
||||
func (err *MalformedMessageError) Malformed() bool { return true }
|
||||
func (err *MalformedMessageError) Broken() bool { return false }
|
||||
func (err *MalformedMessageError) Error() string {
|
||||
if err == nil {
|
||||
return "<nil>"
|
||||
}
|
||||
|
||||
s := "MalformedMessageError: " + err.Err.Error()
|
||||
if err.Msg != "" {
|
||||
s += fmt.Sprintf("\nMessage dump:\n%s", err.Msg)
|
||||
}
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
type UnsupportedMessageError struct {
|
||||
Err error
|
||||
Msg string
|
||||
}
|
||||
|
||||
func (err *UnsupportedMessageError) Malformed() bool { return true }
|
||||
func (err *UnsupportedMessageError) Broken() bool { return false }
|
||||
func (err *UnsupportedMessageError) Error() string {
|
||||
if err == nil {
|
||||
return "<nil>"
|
||||
}
|
||||
|
||||
s := "UnsupportedMessageError: " + err.Err.Error()
|
||||
if err.Msg != "" {
|
||||
s += fmt.Sprintf("\nMessage dump:\n%s", err.Msg)
|
||||
}
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
type UnexpectedMessageError struct {
|
||||
Err error
|
||||
Msg string
|
||||
}
|
||||
|
||||
func (err *UnexpectedMessageError) Broken() bool { return false }
|
||||
func (err *UnexpectedMessageError) Malformed() bool { return false }
|
||||
func (err *UnexpectedMessageError) Error() string {
|
||||
if err == nil {
|
||||
return "<nil>"
|
||||
}
|
||||
|
||||
s := "UnexpectedMessageError: " + err.Err.Error()
|
||||
if err.Msg != "" {
|
||||
s += fmt.Sprintf("\nMessage dump:\n%s", err.Msg)
|
||||
}
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
const RFC3261BranchMagicCookie = "z9hG4bK"
|
||||
|
||||
// GenerateBranch returns random unique branch ID.
|
||||
func GenerateBranch() string {
|
||||
return strings.Join([]string{
|
||||
RFC3261BranchMagicCookie,
|
||||
util.RandString(32),
|
||||
}, ".")
|
||||
}
|
||||
|
||||
// DefaultPort returns protocol default port by network.
|
||||
func DefaultPort(protocol string) Port {
|
||||
switch strings.ToLower(protocol) {
|
||||
case "tls":
|
||||
return DefaultTlsPort
|
||||
case "tcp":
|
||||
return DefaultTcpPort
|
||||
case "udp":
|
||||
return DefaultUdpPort
|
||||
case "ws":
|
||||
return DefaultWsPort
|
||||
case "wss":
|
||||
return DefaultWssPort
|
||||
default:
|
||||
return DefaultTcpPort
|
||||
}
|
||||
}
|
||||
|
||||
func MakeDialogIDFromMessage(msg Message) (string, error) {
|
||||
callID, ok := msg.CallID()
|
||||
if !ok {
|
||||
return "", fmt.Errorf("missing Call-ID header")
|
||||
}
|
||||
|
||||
to, ok := msg.To()
|
||||
if !ok {
|
||||
return "", fmt.Errorf("missing To header")
|
||||
}
|
||||
|
||||
toTag, ok := to.Params.Get("tag")
|
||||
if !ok {
|
||||
return "", fmt.Errorf("missing tag param in To header")
|
||||
}
|
||||
|
||||
from, ok := msg.From()
|
||||
if !ok {
|
||||
return "", fmt.Errorf("missing To header")
|
||||
}
|
||||
|
||||
fromTag, ok := from.Params.Get("tag")
|
||||
if !ok {
|
||||
return "", fmt.Errorf("missing tag param in From header")
|
||||
}
|
||||
|
||||
return MakeDialogID(string(*callID), toTag.String(), fromTag.String()), nil
|
||||
}
|
||||
|
||||
func MakeDialogID(callID, innerID, externalID string) string {
|
||||
return strings.Join([]string{callID, innerID, externalID}, "__")
|
||||
}
|
37
trunk/3rdparty/srs-bench/vendor/github.com/ghettovoice/gosip/sip/error.go
generated
vendored
Normal file
37
trunk/3rdparty/srs-bench/vendor/github.com/ghettovoice/gosip/sip/error.go
generated
vendored
Normal file
|
@ -0,0 +1,37 @@
|
|||
package sip
|
||||
|
||||
import "fmt"
|
||||
|
||||
type RequestError struct {
|
||||
Request Request
|
||||
Response Response
|
||||
Code uint
|
||||
Reason string
|
||||
}
|
||||
|
||||
func NewRequestError(code uint, reason string, request Request, response Response) *RequestError {
|
||||
err := &RequestError{
|
||||
Code: code,
|
||||
Reason: reason,
|
||||
}
|
||||
if request != nil {
|
||||
err.Request = CopyRequest(request)
|
||||
}
|
||||
if response != nil {
|
||||
err.Response = CopyResponse(response)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (err *RequestError) Error() string {
|
||||
if err == nil {
|
||||
return "<nil>"
|
||||
}
|
||||
|
||||
reason := err.Reason
|
||||
if err.Code != 0 {
|
||||
reason += fmt.Sprintf(" (Code %d)", err.Code)
|
||||
}
|
||||
|
||||
return fmt.Sprintf("sip.RequestError: request failed with reason '%s'", reason)
|
||||
}
|
230
trunk/3rdparty/srs-bench/vendor/github.com/ghettovoice/gosip/sip/escape.go
generated
vendored
Normal file
230
trunk/3rdparty/srs-bench/vendor/github.com/ghettovoice/gosip/sip/escape.go
generated
vendored
Normal file
|
@ -0,0 +1,230 @@
|
|||
package sip
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// This is actually shorten copy of escape/unescape helpers of the net/url package.
|
||||
|
||||
type encoding int
|
||||
|
||||
const (
|
||||
EncodeUserPassword encoding = 1 + iota
|
||||
EncodeHost
|
||||
EncodeZone
|
||||
EncodeQueryComponent
|
||||
)
|
||||
|
||||
type EscapeError string
|
||||
|
||||
func (e EscapeError) Error() string {
|
||||
return "invalid URL escape " + strconv.Quote(string(e))
|
||||
}
|
||||
|
||||
type InvalidHostError string
|
||||
|
||||
func (e InvalidHostError) Error() string {
|
||||
return "invalid character " + strconv.Quote(string(e)) + " in host name"
|
||||
}
|
||||
|
||||
// unescape unescapes a string; the mode specifies
|
||||
// which section of the URL string is being unescaped.
|
||||
func Unescape(s string, mode encoding) (string, error) {
|
||||
// Count %, check that they're well-formed.
|
||||
n := 0
|
||||
hasPlus := false
|
||||
for i := 0; i < len(s); {
|
||||
switch s[i] {
|
||||
case '%':
|
||||
n++
|
||||
if i+2 >= len(s) || !ishex(s[i+1]) || !ishex(s[i+2]) {
|
||||
s = s[i:]
|
||||
if len(s) > 3 {
|
||||
s = s[:3]
|
||||
}
|
||||
return "", EscapeError(s)
|
||||
}
|
||||
// Per https://tools.ietf.org/html/rfc3986#page-21
|
||||
// in the host component %-encoding can only be used
|
||||
// for non-ASCII bytes.
|
||||
// But https://tools.ietf.org/html/rfc6874#section-2
|
||||
// introduces %25 being allowed to escape a percent sign
|
||||
// in IPv6 scoped-address literals. Yay.
|
||||
if mode == EncodeHost && unhex(s[i+1]) < 8 && s[i:i+3] != "%25" {
|
||||
return "", EscapeError(s[i : i+3])
|
||||
}
|
||||
if mode == EncodeZone {
|
||||
// RFC 6874 says basically "anything goes" for zone identifiers
|
||||
// and that even non-ASCII can be redundantly escaped,
|
||||
// but it seems prudent to restrict %-escaped bytes here to those
|
||||
// that are valid host name bytes in their unescaped form.
|
||||
// That is, you can use escaping in the zone identifier but not
|
||||
// to introduce bytes you couldn't just write directly.
|
||||
// But Windows puts spaces here! Yay.
|
||||
v := unhex(s[i+1])<<4 | unhex(s[i+2])
|
||||
if s[i:i+3] != "%25" && v != ' ' && shouldEscape(v, EncodeHost) {
|
||||
return "", EscapeError(s[i : i+3])
|
||||
}
|
||||
}
|
||||
i += 3
|
||||
case '+':
|
||||
hasPlus = mode == EncodeQueryComponent
|
||||
i++
|
||||
default:
|
||||
if (mode == EncodeHost || mode == EncodeZone) && s[i] < 0x80 && shouldEscape(s[i], mode) {
|
||||
return "", InvalidHostError(s[i : i+1])
|
||||
}
|
||||
i++
|
||||
}
|
||||
}
|
||||
|
||||
if n == 0 && !hasPlus {
|
||||
return s, nil
|
||||
}
|
||||
|
||||
var t strings.Builder
|
||||
t.Grow(len(s) - 2*n)
|
||||
for i := 0; i < len(s); i++ {
|
||||
switch s[i] {
|
||||
case '%':
|
||||
t.WriteByte(unhex(s[i+1])<<4 | unhex(s[i+2]))
|
||||
i += 2
|
||||
case '+':
|
||||
t.WriteByte('+')
|
||||
default:
|
||||
t.WriteByte(s[i])
|
||||
}
|
||||
}
|
||||
return t.String(), nil
|
||||
}
|
||||
|
||||
func ishex(c byte) bool {
|
||||
switch {
|
||||
case '0' <= c && c <= '9':
|
||||
return true
|
||||
case 'a' <= c && c <= 'f':
|
||||
return true
|
||||
case 'A' <= c && c <= 'F':
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func unhex(c byte) byte {
|
||||
switch {
|
||||
case '0' <= c && c <= '9':
|
||||
return c - '0'
|
||||
case 'a' <= c && c <= 'f':
|
||||
return c - 'a' + 10
|
||||
case 'A' <= c && c <= 'F':
|
||||
return c - 'A' + 10
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// Return true if the specified character should be escaped when
|
||||
// appearing in a URL string, according to RFC 3986.
|
||||
//
|
||||
// Please be informed that for now shouldEscape does not check all
|
||||
// reserved characters correctly. See golang.org/issue/5684.
|
||||
func shouldEscape(c byte, mode encoding) bool {
|
||||
// §2.3 Unreserved characters (alphanum)
|
||||
if 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || '0' <= c && c <= '9' {
|
||||
return false
|
||||
}
|
||||
|
||||
if mode == EncodeHost || mode == EncodeZone {
|
||||
// §3.2.2 Host allows
|
||||
// sub-delims = "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / ";" / "="
|
||||
// as part of reg-name.
|
||||
// We add : because we include :port as part of host.
|
||||
// We add [ ] because we include [ipv6]:port as part of host.
|
||||
// We add < > because they're the only characters left that
|
||||
// we could possibly allow, and Parse will reject them if we
|
||||
// escape them (because hosts can't use %-encoding for
|
||||
// ASCII bytes).
|
||||
switch c {
|
||||
case '!', '$', '&', '\'', '(', ')', '*', '+', ',', ';', '=', ':', '[', ']', '<', '>', '"':
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
switch c {
|
||||
case '-', '_', '.', '~': // §2.3 Unreserved characters (mark)
|
||||
return false
|
||||
|
||||
case '$', '&', '+', ',', '/', ':', ';', '=', '?', '@': // §2.2 Reserved characters (reserved)
|
||||
// Different sections of the URL allow a few of
|
||||
// the reserved characters to appear unescaped.
|
||||
switch mode {
|
||||
case EncodeUserPassword: // §3.2.1
|
||||
// The RFC allows ';', ':', '&', '=', '+', '$', and ',' in
|
||||
// userinfo, so we must escape only '@', '/', and '?'.
|
||||
// The parsing of userinfo treats ':' as special so we must escape
|
||||
// that too.
|
||||
return c == '@' || c == '/' || c == '?' || c == ':'
|
||||
|
||||
case EncodeQueryComponent: // §3.4
|
||||
// The RFC reserves (so we must escape) everything.
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// Everything else must be escaped.
|
||||
return true
|
||||
}
|
||||
|
||||
const upperhex = "0123456789ABCDEF"
|
||||
|
||||
func Escape(s string, mode encoding) string {
|
||||
spaceCount, hexCount := 0, 0
|
||||
for i := 0; i < len(s); i++ {
|
||||
c := s[i]
|
||||
if shouldEscape(c, mode) {
|
||||
if c == ' ' && mode == EncodeQueryComponent {
|
||||
spaceCount++
|
||||
} else {
|
||||
hexCount++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if spaceCount == 0 && hexCount == 0 {
|
||||
return s
|
||||
}
|
||||
|
||||
var buf [64]byte
|
||||
var t []byte
|
||||
|
||||
required := len(s) + 2*hexCount
|
||||
if required <= len(buf) {
|
||||
t = buf[:required]
|
||||
} else {
|
||||
t = make([]byte, required)
|
||||
}
|
||||
|
||||
if hexCount == 0 {
|
||||
copy(t, s)
|
||||
return string(t)
|
||||
}
|
||||
|
||||
j := 0
|
||||
for i := 0; i < len(s); i++ {
|
||||
switch c := s[i]; {
|
||||
case c == ' ' && mode == EncodeQueryComponent:
|
||||
t[j] = c
|
||||
j++
|
||||
case shouldEscape(c, mode):
|
||||
t[j] = '%'
|
||||
t[j+1] = upperhex[c>>4]
|
||||
t[j+2] = upperhex[c&15]
|
||||
j += 3
|
||||
default:
|
||||
t[j] = s[i]
|
||||
j++
|
||||
}
|
||||
}
|
||||
return string(t)
|
||||
}
|
1655
trunk/3rdparty/srs-bench/vendor/github.com/ghettovoice/gosip/sip/headers.go
generated
vendored
Normal file
1655
trunk/3rdparty/srs-bench/vendor/github.com/ghettovoice/gosip/sip/headers.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
542
trunk/3rdparty/srs-bench/vendor/github.com/ghettovoice/gosip/sip/message.go
generated
vendored
Normal file
542
trunk/3rdparty/srs-bench/vendor/github.com/ghettovoice/gosip/sip/message.go
generated
vendored
Normal file
|
@ -0,0 +1,542 @@
|
|||
package sip
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
uuid "github.com/satori/go.uuid"
|
||||
|
||||
"github.com/ghettovoice/gosip/log"
|
||||
)
|
||||
|
||||
// A representation of a SIP method.
|
||||
// This is syntactic sugar around the string type, so make sure to use
|
||||
// the Equals method rather than built-in equality, or you'll fall foul of case differences.
|
||||
// If you're defining your own Method, uppercase is preferred but not compulsory.
|
||||
type RequestMethod string
|
||||
|
||||
// StatusCode - response status code: 1xx - 6xx
|
||||
type StatusCode uint16
|
||||
|
||||
// Determine if the given method equals some other given method.
|
||||
// This is syntactic sugar for case insensitive equality checking.
|
||||
func (method *RequestMethod) Equals(other *RequestMethod) bool {
|
||||
if method != nil && other != nil {
|
||||
return strings.EqualFold(string(*method), string(*other))
|
||||
} else {
|
||||
return method == other
|
||||
}
|
||||
}
|
||||
|
||||
// It's nicer to avoid using raw strings to represent methods, so the following standard
|
||||
// method names are defined here as constants for convenience.
|
||||
const (
|
||||
INVITE RequestMethod = "INVITE"
|
||||
ACK RequestMethod = "ACK"
|
||||
CANCEL RequestMethod = "CANCEL"
|
||||
BYE RequestMethod = "BYE"
|
||||
REGISTER RequestMethod = "REGISTER"
|
||||
OPTIONS RequestMethod = "OPTIONS"
|
||||
SUBSCRIBE RequestMethod = "SUBSCRIBE"
|
||||
NOTIFY RequestMethod = "NOTIFY"
|
||||
REFER RequestMethod = "REFER"
|
||||
INFO RequestMethod = "INFO"
|
||||
MESSAGE RequestMethod = "MESSAGE"
|
||||
PRACK RequestMethod = "PRACK"
|
||||
UPDATE RequestMethod = "UPDATE"
|
||||
PUBLISH RequestMethod = "PUBLISH"
|
||||
)
|
||||
|
||||
type MessageID string
|
||||
|
||||
func NextMessageID() MessageID {
|
||||
return MessageID(uuid.Must(uuid.NewV4()).String())
|
||||
}
|
||||
|
||||
// Message introduces common SIP message RFC 3261 - 7.
|
||||
type Message interface {
|
||||
MessageID() MessageID
|
||||
|
||||
Clone() Message
|
||||
// Start line returns message start line.
|
||||
StartLine() string
|
||||
// String returns string representation of SIP message in RFC 3261 form.
|
||||
String() string
|
||||
// Short returns short string info about message.
|
||||
Short() string
|
||||
// SipVersion returns SIP protocol version.
|
||||
SipVersion() string
|
||||
// SetSipVersion sets SIP protocol version.
|
||||
SetSipVersion(version string)
|
||||
|
||||
// Headers returns all message headers.
|
||||
Headers() []Header
|
||||
// GetHeaders returns slice of headers of the given type.
|
||||
GetHeaders(name string) []Header
|
||||
// AppendHeader appends header to message.
|
||||
AppendHeader(header Header)
|
||||
// PrependHeader prepends header to message.
|
||||
PrependHeader(header Header)
|
||||
PrependHeaderAfter(header Header, afterName string)
|
||||
// RemoveHeader removes header from message.
|
||||
RemoveHeader(name string)
|
||||
ReplaceHeaders(name string, headers []Header)
|
||||
|
||||
// Body returns message body.
|
||||
Body() string
|
||||
// SetBody sets message body.
|
||||
SetBody(body string, setContentLength bool)
|
||||
|
||||
/* Helper getters for common headers */
|
||||
// CallID returns 'Call-ID' header.
|
||||
CallID() (*CallID, bool)
|
||||
// Via returns the top 'Via' header field.
|
||||
Via() (ViaHeader, bool)
|
||||
// ViaHop returns the first segment of the top 'Via' header.
|
||||
ViaHop() (*ViaHop, bool)
|
||||
// From returns 'From' header field.
|
||||
From() (*FromHeader, bool)
|
||||
// To returns 'To' header field.
|
||||
To() (*ToHeader, bool)
|
||||
// CSeq returns 'CSeq' header field.
|
||||
CSeq() (*CSeq, bool)
|
||||
ContentLength() (*ContentLength, bool)
|
||||
ContentType() (*ContentType, bool)
|
||||
Contact() (*ContactHeader, bool)
|
||||
|
||||
Transport() string
|
||||
SetTransport(tp string)
|
||||
Source() string
|
||||
SetSource(src string)
|
||||
Destination() string
|
||||
SetDestination(dest string)
|
||||
|
||||
IsCancel() bool
|
||||
IsAck() bool
|
||||
|
||||
Fields() log.Fields
|
||||
WithFields(fields log.Fields) Message
|
||||
}
|
||||
|
||||
// headers is a struct with methods to work with SIP headers.
|
||||
type headers struct {
|
||||
mu sync.RWMutex
|
||||
// The logical SIP headers attached to this message.
|
||||
headers map[string][]Header
|
||||
// The order the headers should be displayed in.
|
||||
headerOrder []string
|
||||
}
|
||||
|
||||
func newHeaders(hdrs []Header) *headers {
|
||||
hs := new(headers)
|
||||
hs.headers = make(map[string][]Header)
|
||||
hs.headerOrder = make([]string, 0)
|
||||
for _, header := range hdrs {
|
||||
hs.AppendHeader(header)
|
||||
}
|
||||
return hs
|
||||
}
|
||||
|
||||
func (hs *headers) String() string {
|
||||
buffer := bytes.Buffer{}
|
||||
hs.mu.RLock()
|
||||
// Construct each header in turn and add it to the message.
|
||||
for typeIdx, name := range hs.headerOrder {
|
||||
headers := hs.headers[name]
|
||||
for idx, header := range headers {
|
||||
buffer.WriteString(header.String())
|
||||
if typeIdx < len(hs.headerOrder) || idx < len(headers) {
|
||||
buffer.WriteString("\r\n")
|
||||
}
|
||||
}
|
||||
}
|
||||
hs.mu.RUnlock()
|
||||
return buffer.String()
|
||||
}
|
||||
|
||||
// Add the given header.
|
||||
func (hs *headers) AppendHeader(header Header) {
|
||||
name := strings.ToLower(header.Name())
|
||||
hs.mu.Lock()
|
||||
if _, ok := hs.headers[name]; ok {
|
||||
hs.headers[name] = append(hs.headers[name], header)
|
||||
} else {
|
||||
hs.headers[name] = []Header{header}
|
||||
hs.headerOrder = append(hs.headerOrder, name)
|
||||
}
|
||||
hs.mu.Unlock()
|
||||
}
|
||||
|
||||
// AddFrontHeader adds header to the front of header list
|
||||
// if there is no header has h's name, add h to the font of all headers
|
||||
// if there are some headers have h's name, add h to front of the sublist
|
||||
func (hs *headers) PrependHeader(header Header) {
|
||||
name := strings.ToLower(header.Name())
|
||||
hs.mu.Lock()
|
||||
if hdrs, ok := hs.headers[name]; ok {
|
||||
hs.headers[name] = append([]Header{header}, hdrs...)
|
||||
} else {
|
||||
hs.headers[name] = []Header{header}
|
||||
newOrder := make([]string, 1, len(hs.headerOrder)+1)
|
||||
newOrder[0] = name
|
||||
hs.headerOrder = append(newOrder, hs.headerOrder...)
|
||||
}
|
||||
hs.mu.Unlock()
|
||||
}
|
||||
|
||||
func (hs *headers) PrependHeaderAfter(header Header, afterName string) {
|
||||
headerName := strings.ToLower(header.Name())
|
||||
afterName = strings.ToLower(afterName)
|
||||
hs.mu.Lock()
|
||||
if _, ok := hs.headers[afterName]; ok {
|
||||
afterIdx := -1
|
||||
headerIdx := -1
|
||||
for i, name := range hs.headerOrder {
|
||||
if name == afterName {
|
||||
afterIdx = i
|
||||
}
|
||||
if name == headerName {
|
||||
headerIdx = i
|
||||
}
|
||||
}
|
||||
|
||||
if headerIdx == -1 {
|
||||
hs.headers[headerName] = []Header{header}
|
||||
newOrder := make([]string, 0)
|
||||
newOrder = append(newOrder, hs.headerOrder[:afterIdx+1]...)
|
||||
newOrder = append(newOrder, headerName)
|
||||
newOrder = append(newOrder, hs.headerOrder[afterIdx+1:]...)
|
||||
hs.headerOrder = newOrder
|
||||
} else {
|
||||
hs.headers[headerName] = append([]Header{header}, hs.headers[headerName]...)
|
||||
newOrder := make([]string, 0)
|
||||
if afterIdx < headerIdx {
|
||||
newOrder = append(newOrder, hs.headerOrder[:afterIdx+1]...)
|
||||
newOrder = append(newOrder, headerName)
|
||||
newOrder = append(newOrder, hs.headerOrder[afterIdx+1:headerIdx]...)
|
||||
newOrder = append(newOrder, hs.headerOrder[headerIdx+1:]...)
|
||||
} else {
|
||||
newOrder = append(newOrder, hs.headerOrder[:headerIdx]...)
|
||||
newOrder = append(newOrder, hs.headerOrder[headerIdx+1:afterIdx+1]...)
|
||||
newOrder = append(newOrder, headerName)
|
||||
newOrder = append(newOrder, hs.headerOrder[afterIdx+1:]...)
|
||||
}
|
||||
hs.headerOrder = newOrder
|
||||
}
|
||||
hs.mu.Unlock()
|
||||
} else {
|
||||
hs.mu.Unlock()
|
||||
hs.PrependHeader(header)
|
||||
}
|
||||
}
|
||||
|
||||
func (hs *headers) ReplaceHeaders(name string, headers []Header) {
|
||||
name = strings.ToLower(name)
|
||||
hs.mu.Lock()
|
||||
if _, ok := hs.headers[name]; ok {
|
||||
hs.headers[name] = headers
|
||||
}
|
||||
hs.mu.Unlock()
|
||||
}
|
||||
|
||||
// Gets some headers.
|
||||
func (hs *headers) Headers() []Header {
|
||||
hdrs := make([]Header, 0)
|
||||
hs.mu.RLock()
|
||||
for _, key := range hs.headerOrder {
|
||||
hdrs = append(hdrs, hs.headers[key]...)
|
||||
}
|
||||
hs.mu.RUnlock()
|
||||
|
||||
return hdrs
|
||||
}
|
||||
|
||||
func (hs *headers) GetHeaders(name string) []Header {
|
||||
name = strings.ToLower(name)
|
||||
hs.mu.RLock()
|
||||
defer hs.mu.RUnlock()
|
||||
if hs.headers == nil {
|
||||
hs.headers = map[string][]Header{}
|
||||
hs.headerOrder = []string{}
|
||||
}
|
||||
if headers, ok := hs.headers[name]; ok {
|
||||
return headers
|
||||
}
|
||||
|
||||
return []Header{}
|
||||
}
|
||||
|
||||
func (hs *headers) RemoveHeader(name string) {
|
||||
name = strings.ToLower(name)
|
||||
hs.mu.Lock()
|
||||
delete(hs.headers, name)
|
||||
// update order slice
|
||||
for idx, entry := range hs.headerOrder {
|
||||
if entry == name {
|
||||
hs.headerOrder = append(hs.headerOrder[:idx], hs.headerOrder[idx+1:]...)
|
||||
break
|
||||
}
|
||||
}
|
||||
hs.mu.Unlock()
|
||||
}
|
||||
|
||||
// CloneHeaders returns all cloned headers in slice.
|
||||
func (hs *headers) CloneHeaders() []Header {
|
||||
return cloneHeaders(hs)
|
||||
}
|
||||
|
||||
func cloneHeaders(msg interface{ Headers() []Header }) []Header {
|
||||
hdrs := make([]Header, 0)
|
||||
for _, header := range msg.Headers() {
|
||||
hdrs = append(hdrs, header.Clone())
|
||||
}
|
||||
return hdrs
|
||||
}
|
||||
|
||||
func (hs *headers) CallID() (*CallID, bool) {
|
||||
hdrs := hs.GetHeaders("Call-ID")
|
||||
if len(hdrs) == 0 {
|
||||
return nil, false
|
||||
}
|
||||
callId, ok := hdrs[0].(*CallID)
|
||||
if !ok {
|
||||
return nil, false
|
||||
}
|
||||
return callId, true
|
||||
}
|
||||
|
||||
func (hs *headers) Via() (ViaHeader, bool) {
|
||||
hdrs := hs.GetHeaders("Via")
|
||||
if len(hdrs) == 0 {
|
||||
return nil, false
|
||||
}
|
||||
via, ok := (hdrs[0]).(ViaHeader)
|
||||
if !ok {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
return via, true
|
||||
}
|
||||
|
||||
func (hs *headers) ViaHop() (*ViaHop, bool) {
|
||||
via, ok := hs.Via()
|
||||
if !ok {
|
||||
return nil, false
|
||||
}
|
||||
hops := []*ViaHop(via)
|
||||
if len(hops) == 0 {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
return hops[0], true
|
||||
}
|
||||
|
||||
func (hs *headers) From() (*FromHeader, bool) {
|
||||
hdrs := hs.GetHeaders("From")
|
||||
if len(hdrs) == 0 {
|
||||
return nil, false
|
||||
}
|
||||
from, ok := hdrs[0].(*FromHeader)
|
||||
if !ok {
|
||||
return nil, false
|
||||
}
|
||||
return from, true
|
||||
}
|
||||
|
||||
func (hs *headers) To() (*ToHeader, bool) {
|
||||
hdrs := hs.GetHeaders("To")
|
||||
if len(hdrs) == 0 {
|
||||
return nil, false
|
||||
}
|
||||
to, ok := hdrs[0].(*ToHeader)
|
||||
if !ok {
|
||||
return nil, false
|
||||
}
|
||||
return to, true
|
||||
}
|
||||
|
||||
func (hs *headers) CSeq() (*CSeq, bool) {
|
||||
hdrs := hs.GetHeaders("CSeq")
|
||||
if len(hdrs) == 0 {
|
||||
return nil, false
|
||||
}
|
||||
cseq, ok := hdrs[0].(*CSeq)
|
||||
if !ok {
|
||||
return nil, false
|
||||
}
|
||||
return cseq, true
|
||||
}
|
||||
|
||||
func (hs *headers) ContentLength() (*ContentLength, bool) {
|
||||
hdrs := hs.GetHeaders("Content-Length")
|
||||
if len(hdrs) == 0 {
|
||||
return nil, false
|
||||
}
|
||||
contentLength, ok := hdrs[0].(*ContentLength)
|
||||
if !ok {
|
||||
return nil, false
|
||||
}
|
||||
return contentLength, true
|
||||
}
|
||||
|
||||
func (hs *headers) ContentType() (*ContentType, bool) {
|
||||
hdrs := hs.GetHeaders("Content-Type")
|
||||
if len(hdrs) == 0 {
|
||||
return nil, false
|
||||
}
|
||||
contentType, ok := hdrs[0].(*ContentType)
|
||||
if !ok {
|
||||
return nil, false
|
||||
}
|
||||
return contentType, true
|
||||
}
|
||||
|
||||
func (hs *headers) Contact() (*ContactHeader, bool) {
|
||||
hdrs := hs.GetHeaders("Contact")
|
||||
if len(hdrs) == 0 {
|
||||
return nil, false
|
||||
}
|
||||
contactHeader, ok := hdrs[0].(*ContactHeader)
|
||||
if !ok {
|
||||
return nil, false
|
||||
}
|
||||
return contactHeader, true
|
||||
}
|
||||
|
||||
// basic message implementation
|
||||
type message struct {
|
||||
// message headers
|
||||
*headers
|
||||
mu sync.RWMutex
|
||||
messID MessageID
|
||||
sipVersion string
|
||||
body string
|
||||
startLine func() string
|
||||
tp string
|
||||
src string
|
||||
dest string
|
||||
fields log.Fields
|
||||
}
|
||||
|
||||
func (msg *message) MessageID() MessageID {
|
||||
return msg.messID
|
||||
}
|
||||
|
||||
func (msg *message) StartLine() string {
|
||||
return msg.startLine()
|
||||
}
|
||||
|
||||
func (msg *message) Fields() log.Fields {
|
||||
msg.mu.RLock()
|
||||
defer msg.mu.RUnlock()
|
||||
return msg.fields.WithFields(log.Fields{
|
||||
"transport": msg.tp,
|
||||
"source": msg.src,
|
||||
"destination": msg.dest,
|
||||
})
|
||||
}
|
||||
|
||||
func (msg *message) String() string {
|
||||
var buffer bytes.Buffer
|
||||
|
||||
// write message start line
|
||||
buffer.WriteString(msg.StartLine() + "\r\n")
|
||||
// Write the headers.
|
||||
msg.mu.RLock()
|
||||
buffer.WriteString(msg.headers.String())
|
||||
msg.mu.RUnlock()
|
||||
// message body
|
||||
buffer.WriteString("\r\n" + msg.Body())
|
||||
|
||||
return buffer.String()
|
||||
}
|
||||
|
||||
func (msg *message) SipVersion() string {
|
||||
msg.mu.RLock()
|
||||
defer msg.mu.RUnlock()
|
||||
return msg.sipVersion
|
||||
}
|
||||
|
||||
func (msg *message) SetSipVersion(version string) {
|
||||
msg.mu.Lock()
|
||||
msg.sipVersion = version
|
||||
msg.mu.Unlock()
|
||||
}
|
||||
|
||||
func (msg *message) Body() string {
|
||||
msg.mu.RLock()
|
||||
defer msg.mu.RUnlock()
|
||||
return msg.body
|
||||
}
|
||||
|
||||
// SetBody sets message body, calculates it length and add 'Content-Length' header.
|
||||
func (msg *message) SetBody(body string, setContentLength bool) {
|
||||
msg.mu.Lock()
|
||||
msg.body = body
|
||||
msg.mu.Unlock()
|
||||
if setContentLength {
|
||||
hdrs := msg.GetHeaders("Content-Length")
|
||||
if len(hdrs) == 0 {
|
||||
length := ContentLength(len(body))
|
||||
msg.AppendHeader(&length)
|
||||
} else {
|
||||
length := ContentLength(len(body))
|
||||
msg.ReplaceHeaders("Content-Length", []Header{&length})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (msg *message) Transport() string {
|
||||
msg.mu.RLock()
|
||||
defer msg.mu.RUnlock()
|
||||
return msg.tp
|
||||
}
|
||||
|
||||
func (msg *message) SetTransport(tp string) {
|
||||
msg.mu.Lock()
|
||||
msg.tp = strings.ToUpper(tp)
|
||||
msg.mu.Unlock()
|
||||
}
|
||||
|
||||
func (msg *message) Source() string {
|
||||
msg.mu.RLock()
|
||||
defer msg.mu.RUnlock()
|
||||
return msg.src
|
||||
}
|
||||
|
||||
func (msg *message) SetSource(src string) {
|
||||
msg.mu.Lock()
|
||||
msg.src = src
|
||||
msg.mu.Unlock()
|
||||
}
|
||||
|
||||
func (msg *message) Destination() string {
|
||||
msg.mu.RLock()
|
||||
defer msg.mu.RUnlock()
|
||||
return msg.dest
|
||||
}
|
||||
|
||||
func (msg *message) SetDestination(dest string) {
|
||||
msg.mu.Lock()
|
||||
msg.dest = dest
|
||||
msg.mu.Unlock()
|
||||
}
|
||||
|
||||
// Copy all headers of one type from one message to another.
|
||||
// Appending to any headers that were already there.
|
||||
func CopyHeaders(name string, from, to Message) {
|
||||
name = strings.ToLower(name)
|
||||
for _, h := range from.GetHeaders(name) {
|
||||
to.AppendHeader(h.Clone())
|
||||
}
|
||||
}
|
||||
|
||||
func PrependCopyHeaders(name string, from, to Message) {
|
||||
name = strings.ToLower(name)
|
||||
for _, h := range from.GetHeaders(name) {
|
||||
to.PrependHeader(h.Clone())
|
||||
}
|
||||
}
|
||||
|
||||
type MessageMapper func(msg Message) Message
|
5
trunk/3rdparty/srs-bench/vendor/github.com/ghettovoice/gosip/sip/parser/README.md
generated
vendored
Normal file
5
trunk/3rdparty/srs-bench/vendor/github.com/ghettovoice/gosip/sip/parser/README.md
generated
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
# SIP parser
|
||||
|
||||
> Package implements SIP protocol parser compatible with [RFC 3261](https://tools.ietf.org/html/rfc3261)
|
||||
|
||||
Originally forked from [gossip](https://github.com/StefanKopieczek/gossip) library by @StefanKopieczek.
|
26
trunk/3rdparty/srs-bench/vendor/github.com/ghettovoice/gosip/sip/parser/error.go
generated
vendored
Normal file
26
trunk/3rdparty/srs-bench/vendor/github.com/ghettovoice/gosip/sip/parser/error.go
generated
vendored
Normal file
|
@ -0,0 +1,26 @@
|
|||
package parser
|
||||
|
||||
type Error interface {
|
||||
error
|
||||
// Syntax indicates that this is syntax error
|
||||
Syntax() bool
|
||||
}
|
||||
|
||||
type InvalidStartLineError string
|
||||
|
||||
func (err InvalidStartLineError) Syntax() bool { return true }
|
||||
func (err InvalidStartLineError) Malformed() bool { return false }
|
||||
func (err InvalidStartLineError) Broken() bool { return true }
|
||||
func (err InvalidStartLineError) Error() string { return "parser.InvalidStartLineError: " + string(err) }
|
||||
|
||||
type InvalidMessageFormat string
|
||||
|
||||
func (err InvalidMessageFormat) Syntax() bool { return true }
|
||||
func (err InvalidMessageFormat) Malformed() bool { return true }
|
||||
func (err InvalidMessageFormat) Broken() bool { return true }
|
||||
func (err InvalidMessageFormat) Error() string { return "parser.InvalidMessageFormat: " + string(err) }
|
||||
|
||||
type WriteError string
|
||||
|
||||
func (err WriteError) Syntax() bool { return false }
|
||||
func (err WriteError) Error() string { return "parser.WriteError: " + string(err) }
|
1685
trunk/3rdparty/srs-bench/vendor/github.com/ghettovoice/gosip/sip/parser/parser.go
generated
vendored
Normal file
1685
trunk/3rdparty/srs-bench/vendor/github.com/ghettovoice/gosip/sip/parser/parser.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
131
trunk/3rdparty/srs-bench/vendor/github.com/ghettovoice/gosip/sip/parser/parserbuffer.go
generated
vendored
Normal file
131
trunk/3rdparty/srs-bench/vendor/github.com/ghettovoice/gosip/sip/parser/parserbuffer.go
generated
vendored
Normal file
|
@ -0,0 +1,131 @@
|
|||
// Forked from github.com/StefanKopieczek/gossip by @StefanKopieczek
|
||||
package parser
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"sync"
|
||||
|
||||
"github.com/ghettovoice/gosip/log"
|
||||
)
|
||||
|
||||
// parserBuffer is a specialized buffer for use in the parser.
|
||||
// It is written to via the non-blocking Write.
|
||||
// It exposes various blocking read methods, which wait until the requested
|
||||
// data is available, and then return it.
|
||||
type parserBuffer struct {
|
||||
mu sync.RWMutex
|
||||
|
||||
writer io.Writer
|
||||
buffer bytes.Buffer
|
||||
|
||||
// Wraps parserBuffer.pipeReader
|
||||
reader *bufio.Reader
|
||||
|
||||
// Don't access this directly except when closing.
|
||||
pipeReader *io.PipeReader
|
||||
|
||||
log log.Logger
|
||||
}
|
||||
|
||||
// Create a new parserBuffer object (see struct comment for object details).
|
||||
// Note that resources owned by the parserBuffer may not be able to be GCed
|
||||
// until the Dispose() method is called.
|
||||
func newParserBuffer(logger log.Logger) *parserBuffer {
|
||||
var pb parserBuffer
|
||||
pb.pipeReader, pb.writer = io.Pipe()
|
||||
pb.reader = bufio.NewReader(pb.pipeReader)
|
||||
pb.log = logger.
|
||||
WithPrefix("parser.parserBuffer").
|
||||
WithFields(log.Fields{
|
||||
"parser_buffer_ptr": fmt.Sprintf("%p", &pb),
|
||||
})
|
||||
|
||||
return &pb
|
||||
}
|
||||
|
||||
func (pb *parserBuffer) Log() log.Logger {
|
||||
return pb.log
|
||||
}
|
||||
|
||||
func (pb *parserBuffer) Write(p []byte) (n int, err error) {
|
||||
pb.mu.RLock()
|
||||
defer pb.mu.RUnlock()
|
||||
|
||||
return pb.writer.Write(p)
|
||||
}
|
||||
|
||||
// Block until the buffer contains at least one CRLF-terminated line.
|
||||
// Return the line, excluding the terminal CRLF, and delete it from the buffer.
|
||||
// Returns an error if the parserbuffer has been stopped.
|
||||
func (pb *parserBuffer) NextLine() (response string, err error) {
|
||||
var buffer bytes.Buffer
|
||||
var data string
|
||||
var b byte
|
||||
|
||||
// There has to be a better way!
|
||||
for {
|
||||
data, err = pb.reader.ReadString('\r')
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
buffer.WriteString(data)
|
||||
|
||||
b, err = pb.reader.ReadByte()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
buffer.WriteByte(b)
|
||||
if b == '\n' {
|
||||
response = buffer.String()
|
||||
response = response[:len(response)-2]
|
||||
|
||||
pb.Log().Tracef("return line '%s'", response)
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Block until the buffer contains at least n characters.
|
||||
// Return precisely those n characters, then delete them from the buffer.
|
||||
func (pb *parserBuffer) NextChunk(n int) (response string, err error) {
|
||||
var data = make([]byte, n)
|
||||
|
||||
var read int
|
||||
for total := 0; total < n; {
|
||||
read, err = pb.reader.Read(data[total:])
|
||||
total += read
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
response = string(data)
|
||||
|
||||
pb.Log().Tracef("return chunk:\n%s", response)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Stop the parser buffer.
|
||||
func (pb *parserBuffer) Stop() {
|
||||
pb.mu.RLock()
|
||||
if err := pb.pipeReader.Close(); err != nil {
|
||||
pb.Log().Errorf("parser pipe reader close failed: %s", err)
|
||||
}
|
||||
pb.mu.RUnlock()
|
||||
|
||||
pb.Log().Trace("parser buffer stopped")
|
||||
}
|
||||
|
||||
func (pb *parserBuffer) Reset() {
|
||||
pb.mu.Lock()
|
||||
pb.pipeReader, pb.writer = io.Pipe()
|
||||
pb.reader.Reset(pb.pipeReader)
|
||||
pb.mu.Unlock()
|
||||
}
|
382
trunk/3rdparty/srs-bench/vendor/github.com/ghettovoice/gosip/sip/request.go
generated
vendored
Normal file
382
trunk/3rdparty/srs-bench/vendor/github.com/ghettovoice/gosip/sip/request.go
generated
vendored
Normal file
|
@ -0,0 +1,382 @@
|
|||
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)
|
||||
}
|
310
trunk/3rdparty/srs-bench/vendor/github.com/ghettovoice/gosip/sip/response.go
generated
vendored
Normal file
310
trunk/3rdparty/srs-bench/vendor/github.com/ghettovoice/gosip/sip/response.go
generated
vendored
Normal file
|
@ -0,0 +1,310 @@
|
|||
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)
|
||||
}
|
28
trunk/3rdparty/srs-bench/vendor/github.com/ghettovoice/gosip/sip/transaction.go
generated
vendored
Normal file
28
trunk/3rdparty/srs-bench/vendor/github.com/ghettovoice/gosip/sip/transaction.go
generated
vendored
Normal file
|
@ -0,0 +1,28 @@
|
|||
package sip
|
||||
|
||||
type TransactionKey string
|
||||
|
||||
func (key TransactionKey) String() string {
|
||||
return string(key)
|
||||
}
|
||||
|
||||
type Transaction interface {
|
||||
Origin() Request
|
||||
Key() TransactionKey
|
||||
String() string
|
||||
Errors() <-chan error
|
||||
Done() <-chan bool
|
||||
}
|
||||
|
||||
type ServerTransaction interface {
|
||||
Transaction
|
||||
Respond(res Response) error
|
||||
Acks() <-chan Request
|
||||
Cancels() <-chan Request
|
||||
}
|
||||
|
||||
type ClientTransaction interface {
|
||||
Transaction
|
||||
Responses() <-chan Response
|
||||
Cancel() error
|
||||
}
|
8
trunk/3rdparty/srs-bench/vendor/github.com/ghettovoice/gosip/sip/transport.go
generated
vendored
Normal file
8
trunk/3rdparty/srs-bench/vendor/github.com/ghettovoice/gosip/sip/transport.go
generated
vendored
Normal file
|
@ -0,0 +1,8 @@
|
|||
package sip
|
||||
|
||||
type Transport interface {
|
||||
Messages() <-chan Message
|
||||
Send(msg Message) error
|
||||
IsReliable(network string) bool
|
||||
IsStreamed(network string) bool
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue