Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

finding Replaces header Call-ID in dialog map #34

Closed
byoungdale opened this issue May 4, 2019 · 8 comments

Comments

Projects
None yet
2 participants
@byoungdale
Copy link

commented May 4, 2019

I am trying to figure the best way to find the Call-ID in the srf._dialogs map when I get an INVITE or REFER with a Replaces header. In an attended transfer scenario, the endpoint sets up a dialog with the transferTarget and then sends a REFER to the transferee with a Replaces header containing the Call-ID of the dialog with the transferTarget.

In this scenario, drachtio is acting as a B2BUA between all the endpoints (and media is just peer to peer for now), so I actually need to find the dialog of the other side of the call (UAS dialog if received on the UAC side, and vice versa).

I have a gist of a latter diagram and sip trace of a successful attended transfer through drachtio here.

I am wondering if there is a better way to find the dialog associated with the Call-ID in the replaces header than what I am doing below by looping through the map of dialogs:

// referParams has all the parsed elements of a refer header
findReplacesDialog(srf._dialogs, referParams.replacesCallId);

const findReplacesDialog = (dialogMap, replacesCallId) => {
  var replacesDialog;

  const dialogCallIds = Array.from(dialogMap.keys());
  debug('Dialog Keys');
  debug(dialogCallIds);
  dialogCallIds.every((dialog, i) => {
    const currentDialog = dialogMap.get(dialog);
    const previousDialog = dialogMap.get(dialogCallIds[i-1]);
    const nextDialog = dialogMap.get(dialogCallIds[i+1]);

    debug('replacesCallId');
    debug(replacesCallId);
    debug('currentDialog.sip.callId');
    debug(currentDialog.sip.callId);
    if (nextDialog) { debug('nextDialog.sip.callId'); debug(nextDialog.sip.callId); }
    if (previousDialog) { debug('previousDialog.sip.callId'); debug(previousDialog.sip.callId) }

    if (currentDialog.sip.callId == replacesCallId) {
      debug(`FOUND A MATCH!!!! ${dialog}`);
      // drachtio adds ';uas' when it's the UAS of the dialog
      if (dialog == `${replacesCallId};uas`) {
        debug('UAS dialog: setting repalcesDialog equal to previousDialog');
        replacesDialog = previousDialog;
        return false;
      } else {
        debug('UAC dialog: setting repalcesDialog equal to nextDialog');
        replacesDialog = nextDialog;
        return false;
      }
    }

    return true;
  });

  return replacesDialog;
};
@davehorton

This comment has been minimized.

Copy link
Owner

commented May 7, 2019

Thanks very much for the gist with the ladder diagram, that illustrates the problem clearly.

I'm not sure I totally follow the logic above (I think I'm confused by what seems the reverse use of 'every' instead of simply 'find'), but it seems like the issue is that we need to retrieve an existing dialog (the transferree dialog) from the internal map of dialogs that srf keeps. And we need to do that by Call-ID, is that correct?

Should we just add a public method to Srf to return a dialog by call-id?

Unfortunately, it is the case that a call-id could be used on two different dialogs, though that is undesirable and somewhat unlikely (the app would have to force the call-id on different legs).

Perhaps we could also add some standard implementation for attended transfer to https://github.com/davehorton/drachtio-fn-b2b-sugar ?

@davehorton

This comment has been minimized.

Copy link
Owner

commented May 7, 2019

also, let's try not to assume that the format of the dialog id is the calling =+[";uas"|";uac"] quite yet. I'm looking into changing that to be more correctly some combination of the callid and from tag

@davehorton

This comment has been minimized.

Copy link
Owner

commented May 7, 2019

I'm testing a new branch in drachtio-server called 'dialog-naming' to test a change in assigning dialog ids -- they will now be ${callid};from-tag=${fromTag}, which will be more strictly correct. So hold off on any hardcoding in your app of dialog id construction, and once I merge this branch I will add a public method in Srf to return a dialog given the call-id and the from tag, which I think will support the attended transfer scenario nicely

@byoungdale

This comment has been minimized.

Copy link
Author

commented May 8, 2019

Yeah, I think that will work since the Replaces headers includes the from-tag and to-tag. But, the hard part is that we actually need the dialog on the other side of the B2BUA call, since that is the dialog we need to update for the transfer.

Here is an example of the current dialog map:

srf._dialogs = [
121314, # call B
891011;uas, # call B
4567, # call A
1234;uas # call A
]

So, currently, if the Replaces header has the Call-ID 4567, I actually need to update the 1234;uas dialog.

@davehorton

This comment has been minimized.

Copy link
Owner

commented May 8, 2019

ah, ok, then here is what I think we do:

first, I've already merged the change to the develop branch of drachtio-server to format the dialog id as suggested above. This is in version v0.8.2-rc2, which you will need to test against once all of this is ready.

In upcoming drachtio-srf@4.4.7, I will add two methods:

Srf#findDialogById(stackDialogId)
Srf#findDialogByCallIDAndFromTag(callId, tag)

also, as part of createB2BUA the {uas, uac} SipDialogs that are returned will each have a reference to each other via the 'other' property, e.g.
uas.other === uac && uac.other === uas

So therefore, your code should (I think) only have to:

  • parse the Refer-To header in the REFER, get the call-id and from tag
  • call srf.findDialogByCallIDAndFromTag(callId, tag) to retrieve the dialog being replaced
  • then send the re-INVITE on dlg.other

Does that make sense?

I want to add a test case for this before I push the changes

@byoungdale

This comment has been minimized.

Copy link
Author

commented May 8, 2019

Yeah, that makes sense and will work great. Thanks!

@davehorton

This comment has been minimized.

Copy link
Owner

commented May 9, 2019

OK, just published drachtio-srf@4.4.7, which adds

findDialogById(stackDialogId), and
findDialogByCallIDAndFromTag(callId, tag)

Note: these functions require drachtio-server@v0.8.2-rc2 or above (currently the head of the 'develop' branch), which formats dialog ids as {Call-ID};from-tag={from-tag}.

additionally, if you have a reference to a dialog (uas or uac) that was created by Srf#createB2BUA then dialog.other will be a reference to the paired dialog.

So handling attended transfer should be a matter of:

  • parsing the Refer-To header (I think I need to add a utility function somewhere to make that easier, probably in drachtio-sip), then
  • calling findDialogByCallIDAndFromTag(callId, tag) to retrieve the dialog being replaced, then
  • reinviting the paired dialog by calling Dialog#modify on dialog.other.

I'll leave this issue open for now until you have time to test.

@byoungdale

This comment has been minimized.

Copy link
Author

commented May 14, 2019

I was able to test. This worked great! Thank you so much

@byoungdale byoungdale closed this May 14, 2019

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.