diff --git a/pkg/auth/server.go b/pkg/auth/server.go index e3ab3c7..8929f6a 100644 --- a/pkg/auth/server.go +++ b/pkg/auth/server.go @@ -8,7 +8,6 @@ import ( "strings" "time" - "github.com/cloudwebrtc/go-sip-ua/pkg/util" "github.com/ghettovoice/gosip/log" "github.com/ghettovoice/gosip/sip" ) @@ -108,9 +107,7 @@ func (auth *ServerAuthorizer) requestAuthentication(request sip.Request, tx sip. created: time.Now(), } response.SetBody("", true) - util.BuildContactHeader("Contact", request, response, nil) tx.Respond(response) - return } func (auth *ServerAuthorizer) checkAuthorization(request sip.Request, tx sip.ServerTransaction, diff --git a/pkg/session/session.go b/pkg/session/session.go index 070e60e..0646de0 100644 --- a/pkg/session/session.go +++ b/pkg/session/session.go @@ -10,7 +10,7 @@ import ( gosip_util "github.com/ghettovoice/gosip/util" ) -type RequestCallback func(ctx context.Context, request sip.Request, authorizer sip.Authorizer, waitForResult bool) (sip.Response, error) +type RequestCallback func(ctx context.Context, request sip.Request, authorizer sip.Authorizer, waitForResult bool, attempt int) (sip.Response, error) type Session struct { lock sync.Mutex @@ -240,7 +240,7 @@ func (s *Session) Bye() { func (s *Session) sendRequest(req sip.Request) (sip.Response, error) { s.Log().Debugf(s.uaType+" send request: %v => \n%v", req.Method(), req) - return s.requestCallbck(context.TODO(), req, nil, false) + return s.requestCallbck(context.TODO(), req, nil, false, 1) } // Reject Reject incoming call or for re-INVITE or UPDATE, @@ -249,6 +249,7 @@ func (s *Session) Reject(statusCode sip.StatusCode, reason string) { request := s.request s.Log().Debugf("Reject: Request => %s, body => %s", request.Short(), request.Body()) response := sip.NewResponseFromRequest(request.MessageID(), request, statusCode, reason, "") + response.AppendHeader(s.localURI.AsContactHeader()) tx.Respond(response) } @@ -346,7 +347,7 @@ func (s *Session) Provisional(statusCode sip.StatusCode, reason string) { } else { response = sip.NewResponseFromRequest(request.MessageID(), request, statusCode, reason, "") } - + response.AppendHeader(s.localURI.AsContactHeader()) s.response = response tx.Respond(response) } @@ -370,14 +371,21 @@ func (s *Session) makeRequest(uaType string, method sip.RequestMethod, msgID sip to := s.remoteURI.Clone().AsToHeader() newRequest.AppendHeader(to) newRequest.SetRecipient(s.request.Recipient()) + sip.CopyHeaders("Via", inviteRequest, newRequest) if uaType == "UAC" { - sip.CopyHeaders("Via", inviteRequest, newRequest) + if contact, ok := s.request.Contact(); ok { + newRequest.AppendHeader(contact) + } + if len(inviteRequest.GetHeaders("Route")) > 0 { sip.CopyHeaders("Route", inviteRequest, newRequest) } } else if uaType == "UAS" { - sip.CopyHeaders("Via", inviteRequest, newRequest) + if contact, ok := s.response.Contact(); ok { + newRequest.AppendHeader(contact) + } + if len(inviteResponse.GetHeaders("Route")) > 0 { sip.CopyHeaders("Route", inviteResponse, newRequest) } @@ -389,6 +397,7 @@ func (s *Session) makeRequest(uaType string, method sip.RequestMethod, msgID sip newRequest.AppendHeader(&maxForwardsHeader) sip.CopyHeaders("Call-ID", inviteRequest, newRequest) sip.CopyHeaders("CSeq", inviteRequest, newRequest) + cseq, _ := newRequest.CSeq() cseq.SeqNo++ cseq.MethodName = method diff --git a/pkg/stack/stack.go b/pkg/stack/stack.go index a7f003f..7d1d3cc 100644 --- a/pkg/stack/stack.go +++ b/pkg/stack/stack.go @@ -334,7 +334,6 @@ func (s *SipStack) AckInviteRequest(request sip.Request, response sip.Response) ackRequest := sip.NewAckRequest("", request, response, "", log.Fields{ "sent_at": time.Now(), }) - ackRequest.SetRecipient(request.Recipient()) if err := s.Send(ackRequest); err != nil { s.Log().WithFields(map[string]interface{}{ "invite_request": request.Short(), @@ -348,7 +347,6 @@ func (s *SipStack) CancelRequest(request sip.Request, response sip.Response) { cancelRequest := sip.NewCancelRequest("", request, log.Fields{ "sent_at": time.Now(), }) - cancelRequest.SetRecipient(request.Recipient()) if err := s.Send(cancelRequest); err != nil { s.Log().WithFields(map[string]interface{}{ "invite_request": request.Short(), diff --git a/pkg/ua/register.go b/pkg/ua/register.go index 463c5b6..2fdd138 100644 --- a/pkg/ua/register.go +++ b/pkg/ua/register.go @@ -76,7 +76,7 @@ func (r *Register) SendRegister(expires uint32) error { r.authorizer = auth.NewClientAuthorizer(profile.AuthInfo.AuthUser, profile.AuthInfo.Password) } - resp, err := ua.RequestWithContext(r.ctx, *r.request, r.authorizer, true) + resp, err := ua.RequestWithContext(r.ctx, *r.request, r.authorizer, true, 1) if err != nil { ua.Log().Errorf("Request [%s] failed, err => %v", sip.REGISTER, err) diff --git a/pkg/ua/ua.go b/pkg/ua/ua.go index 2d39891..e4f06aa 100644 --- a/pkg/ua/ua.go +++ b/pkg/ua/ua.go @@ -3,7 +3,7 @@ package ua import ( "context" "fmt" - "net" + "strconv" "sync" "github.com/cloudwebrtc/go-sip-ua/pkg/account" @@ -102,32 +102,6 @@ func (ua *UserAgent) buildRequest( return &req, nil } -func (ua *UserAgent) buildViaHopHeader(target sip.SipUri) *sip.ViaHop { - protocol := "udp" - if nt, ok := target.UriParams().Get("transport"); ok { - protocol = nt.String() - } - s := ua.config.SipStack - netinfo := s.GetNetworkInfo(protocol) - - var host string = netinfo.Host - if net.ParseIP(target.Host()).IsLoopback() { - host = "127.0.0.1" - } - - port := netinfo.Port - - viaHop := &sip.ViaHop{ - ProtocolName: "SIP", - ProtocolVersion: "2.0", - Transport: protocol, - Host: host, - Port: port, - Params: sip.NewParams().Add("branch", sip.String{Str: sip.GenerateBranch()}), - } - return viaHop -} - func (ua *UserAgent) SendRegister(profile *account.Profile, recipient sip.SipUri, expires uint32, userdata interface{}) (*Register, error) { register := NewRegister(ua, profile, recipient, userdata) err := register.SendRegister(expires) @@ -169,7 +143,7 @@ func (ua *UserAgent) Invite(profile *account.Profile, target sip.Uri, recipient authorizer = auth.NewClientAuthorizer(profile.AuthInfo.AuthUser, profile.AuthInfo.Password) } - resp, err := ua.RequestWithContext(context.TODO(), *request, authorizer, false) + resp, err := ua.RequestWithContext(context.TODO(), *request, authorizer, false, 1) if err != nil { ua.Log().Errorf("INVITE: Request [INVITE] failed, err => %v", err) return nil, err @@ -188,7 +162,7 @@ func (ua *UserAgent) Invite(profile *account.Profile, target sip.Uri, recipient } } - return nil, fmt.Errorf("Invite session not found, unknown errors.") + return nil, fmt.Errorf("invite session not found, unknown errors") } func (ua *UserAgent) Request(req *sip.Request) (sip.ClientTransaction, error) { @@ -198,6 +172,32 @@ func (ua *UserAgent) Request(req *sip.Request) (sip.ClientTransaction, error) { func (ua *UserAgent) handleBye(request sip.Request, tx sip.ServerTransaction) { ua.Log().Debugf("handleBye: Request => %s, body => %s", request.Short(), request.Body()) response := sip.NewResponseFromRequest(request.MessageID(), request, 200, "OK", "") + + if viaHop, ok := request.ViaHop(); ok { + var ( + host string + port sip.Port + ) + host = viaHop.Host + 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 = sip.Port(uint16(p)) + } + } else if request.Recipient().Port() != nil { + port = *request.Recipient().Port() + } else { + port = sip.DefaultPort(request.Transport()) + } + } + + dest := fmt.Sprintf("%v:%v", host, port) + response.SetDestination(dest) + } + tx.Respond(response) callID, ok := request.CallID() if ok { @@ -290,7 +290,7 @@ func (ua *UserAgent) handleInvite(request sip.Request, tx sip.ServerTransaction) } // RequestWithContext . -func (ua *UserAgent) RequestWithContext(ctx context.Context, request sip.Request, authorizer sip.Authorizer, waitForResult bool) (sip.Response, error) { +func (ua *UserAgent) RequestWithContext(ctx context.Context, request sip.Request, authorizer sip.Authorizer, waitForResult bool, attempt int) (sip.Response, error) { s := ua.config.SipStack tx, err := s.Request(request) if err != nil { @@ -401,12 +401,13 @@ func (ua *UserAgent) RequestWithContext(ctx context.Context, request sip.Request } // unauth request - if (response.StatusCode() == 401 || response.StatusCode() == 407) && authorizer != nil { + needAuth := (response.StatusCode() == 401 || response.StatusCode() == 407) && attempt < 2 + if needAuth && authorizer != nil { if err := authorizer.AuthorizeRequest(request, response); err != nil { errs <- err return } - if response, err := ua.RequestWithContext(ctx, request, nil, true); err == nil { + if response, err := ua.RequestWithContext(ctx, request, authorizer, true, attempt+1); err == nil { responses <- response } else { errs <- err @@ -455,7 +456,6 @@ func (ua *UserAgent) RequestWithContext(ctx context.Context, request sip.Request if v, found := ua.iss.Load(*callID); found { is := v.(*session.Session) ua.iss.Delete(*callID) - // handle Ringing or Processing with sdp is.SetState(session.Failure) ua.handleInviteState(is, &request, &response, session.Failure, nil) } @@ -466,7 +466,6 @@ func (ua *UserAgent) RequestWithContext(ctx context.Context, request sip.Request if ok { if v, found := ua.iss.Load(*callID); found { if request.IsInvite() { - // handle Ringing or Processing with sdp is := v.(*session.Session) is.SetState(session.Confirmed) ua.handleInviteState(is, &request, &response, session.Confirmed, nil)