From 87392f417d8bc7381633f4505e539ed121f3ef44 Mon Sep 17 00:00:00 2001 From: Denys Smirnov Date: Thu, 31 Oct 2024 20:00:06 +0200 Subject: [PATCH] Pass remote SIP tag and SIP call ID to attrs. (#217) --- pkg/sip/inbound.go | 9 ++++++++- pkg/sip/outbound.go | 26 +++++++++++++++++--------- pkg/sip/participant.go | 5 +++++ pkg/sip/protocol.go | 1 + pkg/sip/types.go | 6 ++++++ test/lktest/sip.go | 36 ++++++++++++++++++++++++++++++++---- 6 files changed, 69 insertions(+), 14 deletions(-) diff --git a/pkg/sip/inbound.go b/pkg/sip/inbound.go index 809c53d..00223d5 100644 --- a/pkg/sip/inbound.go +++ b/pkg/sip/inbound.go @@ -840,7 +840,9 @@ func (s *Server) newInbound(id LocalTag, contact URI, invite *sip.Request, invit if h != nil { c.nextRequestCSeq = h.SeqNo + 1 } - + if callID, _ := invite.CallID(); callID != nil { + c.callID = callID.Value() + } return c } @@ -848,6 +850,7 @@ type sipInbound struct { s *Server id LocalTag tag RemoteTag + callID string invite *sip.Request inviteTx sip.ServerTransaction contact *sip.ContactHeader @@ -934,6 +937,10 @@ func (c *sipInbound) Tag() RemoteTag { return c.tag } +func (c *sipInbound) CallID() string { + return c.callID +} + func (c *sipInbound) RemoteHeaders() Headers { c.mu.RLock() defer c.mu.RUnlock() diff --git a/pkg/sip/outbound.go b/pkg/sip/outbound.go index a0b8cc5..9ddc57d 100644 --- a/pkg/sip/outbound.go +++ b/pkg/sip/outbound.go @@ -422,15 +422,13 @@ func (c *outboundCall) sipSignal(ctx context.Context) error { } joinDur() - if len(c.cc.RemoteHeaders()) != 0 { - extra := HeadersToAttrs(nil, c.sipConf.headersToAttrs, c.cc) - if c.lkRoom != nil && len(extra) != 0 { - room := c.lkRoom.Room() - if room != nil { - room.LocalParticipant.SetAttributes(extra) - } else { - c.log.Warnw("could not set attributes on nil room", nil, "attrs", extra) - } + extra := HeadersToAttrs(nil, c.sipConf.headersToAttrs, c.cc) + if c.lkRoom != nil && len(extra) != 0 { + room := c.lkRoom.Room() + if room != nil { + room.LocalParticipant.SetAttributes(extra) + } else { + c.log.Warnw("could not set attributes on nil room", nil, "attrs", extra) } } return nil @@ -512,6 +510,7 @@ type sipOutbound struct { mu sync.RWMutex tag RemoteTag + callID string invite *sip.Request inviteOk *sip.Response to *sip.ToHeader @@ -544,6 +543,12 @@ func (c *sipOutbound) Tag() RemoteTag { return c.tag } +func (c *sipOutbound) CallID() string { + c.mu.RLock() + defer c.mu.RUnlock() + return c.callID +} + func (c *sipOutbound) RemoteHeaders() Headers { c.mu.RLock() defer c.mu.RUnlock() @@ -647,6 +652,9 @@ authLoop: if !ok { return nil, errors.New("no tag in To header in INVITE response") } + if callID, _ := c.invite.CallID(); callID != nil { + c.callID = callID.Value() + } h, _ := c.invite.CSeq() if h != nil { c.nextRequestCSeq = h.SeqNo + 1 diff --git a/pkg/sip/participant.go b/pkg/sip/participant.go index 6350762..1597e28 100644 --- a/pkg/sip/participant.go +++ b/pkg/sip/participant.go @@ -31,6 +31,11 @@ const ( defaultRingingTimeout = 3 * time.Minute ) +const ( + AttrSIPCallIDFull = livekit.AttrSIPPrefix + "callIDFull" + AttrSIPCallTag = livekit.AttrSIPPrefix + "callTag" +) + var headerToLog = map[string]string{ "X-Twilio-AccountSid": "twilioAccSID", "X-Twilio-CallSid": "twilioCallSID", diff --git a/pkg/sip/protocol.go b/pkg/sip/protocol.go index 0c18c16..20aabca 100644 --- a/pkg/sip/protocol.go +++ b/pkg/sip/protocol.go @@ -56,6 +56,7 @@ type Signaling interface { To() sip.Uri ID() LocalTag Tag() RemoteTag + CallID() string RemoteHeaders() Headers WriteRequest(req *sip.Request) error diff --git a/pkg/sip/types.go b/pkg/sip/types.go index fffa5f1..6c476da 100644 --- a/pkg/sip/types.go +++ b/pkg/sip/types.go @@ -213,5 +213,11 @@ func HeadersToAttrs(attrs, hdrToAttr map[string]string, c Signaling) map[string] attrs[name] = h.Value() } } + if tag := c.Tag(); tag != "" { + attrs[AttrSIPCallTag] = string(tag) + } + if cid := c.CallID(); cid != "" { + attrs[AttrSIPCallIDFull] = cid + } return attrs } diff --git a/test/lktest/sip.go b/test/lktest/sip.go index 705d953..8c5ccce 100644 --- a/test/lktest/sip.go +++ b/test/lktest/sip.go @@ -17,6 +17,7 @@ package lktest import ( "context" "maps" + "slices" "strings" "github.com/livekit/protocol/livekit" @@ -27,13 +28,36 @@ import ( func checkSIPAttrs(t TB, exp, got map[string]string) (_, _ map[string]string) { exp, got = maps.Clone(exp), maps.Clone(got) - if _, ok := exp[livekit.AttrSIPCallID]; ok { - require.True(t, strings.HasPrefix(got[livekit.AttrSIPCallID], guid.SIPCallPrefix)) - delete(exp, livekit.AttrSIPCallID) - delete(got, livekit.AttrSIPCallID) + + var keepKeys []string + for _, a := range []string{ + livekit.AttrSIPCallID, + livekit.AttrSIPPrefix + "callIDFull", + livekit.AttrSIPPrefix + "callTag", + } { + if _, ok := exp[a]; !ok { + continue + } + v, ok := got[a] + if !ok { + // let the caller fail + keepKeys = append(keepKeys, a) + continue + } + require.True(t, ok, "missing attribute %q", a) + require.NotEmpty(t, v, "empty attribute %q", a) + switch a { + case livekit.AttrSIPCallID: + require.True(t, strings.HasPrefix(v, guid.SIPCallPrefix)) + } + delete(exp, a) + delete(got, a) } // remove extra attributes from comparison for key := range got { + if slices.Contains(keepKeys, key) { + continue + } if _, ok := exp[key]; !ok { delete(got, key) } @@ -129,6 +153,8 @@ func TestSIPOutbound(t TB, ctx context.Context, lkOut, lkIn *LiveKit, params SIP t.Log("checking rooms (outbound)") expAttrsOut := map[string]string{ "sip.callID": "", // special case + "sip.callTag": "", // special case + "sip.callIDFull": "", // special case "sip.callStatus": "active", "sip.trunkPhoneNumber": params.NumberOut, "sip.phoneNumber": params.NumberIn, @@ -150,6 +176,8 @@ func TestSIPOutbound(t TB, ctx context.Context, lkOut, lkIn *LiveKit, params SIP t.Log("checking rooms (inbound)") expAttrsIn := map[string]string{ "sip.callID": "", // special case + "sip.callTag": "", // special case + "sip.callIDFull": "", // special case "sip.callStatus": "active", "sip.trunkPhoneNumber": params.NumberIn, "sip.phoneNumber": params.NumberOut,