< Previous by Date Date Index Next by Date >
< Previous in Thread Thread Index Next in Thread >

Re: [reSIProcate] How to answer a refer that was cancelled


On Thu, Sep 22, 2011 at 9:27 AM, Robert Szokovacs
<rszokovacs@xxxxxxxxxxxxxxx> wrote:
> On 2011 September 21, Wednesday 16:34:42 you wrote:
>
> Hello,
>
>> I wonder if you could send a 100 Trying right after getting the first
>> REFER and before starting your internal async. request?
>> ServerSubscription::send and Helper::makeResponse(..., 100) could be
>> used to do that.
>>
>> That way, you will indicate to the peer UA that you are in the process
>> of handling the request and that might prevent it from transmitting
>> another REFER.
>
> I will definately pressure the developer to fix his app, but I'd like to
> create a robust solution that can handle irregular clients as well :)
>
>> Also, by quickly looking at the code of Dialog.cxx/hxx, I don't think
>> the second REFER overwrites the first one: you could probably cache
>> the ServerSubscriptionHandle of the first one in your application
>> (i.e. your own AppDialogSet) or either try to find it using
>> Dialog::getServerSubscriptions. Maintaining the handles as such should
>> enable you to answer them independently.
>
> I'm afraid it's not like that:
>
> (resiprocate 1.7) Dialog.cxx:549
>
>                ServerSubscription* server = findMatchingServerSub(request);
>                 ServerSubscriptionHandle serverHandle;
>                  if (server)
>                  {
>                     serverHandle = server->getHandle();
>                     server->dispatch(request);
>                  }
>                  else
>                  {
>                     server = makeServerSubscription(request);
>                     mServerSubscriptions.push_back(server);
>                     serverHandle = server->getHandle();
>                     server->dispatch(request);
>                  }
>
> This will match the second request's subscription with the first one's, so
> when I reply to the cached ServerSubscriptionHandle, it will get the second
> one's CSeq, so this is no way to reply to the first request :(
>
> br
>
> Szo
> _______________________________________________
> resiprocate-devel mailing list
> resiprocate-devel@xxxxxxxxxxxxxxx
> https://list.resiprocate.org/mailman/listinfo/resiprocate-devel
>

Hi,

I was able to reproduce the issue using a test application. I
originally thought it might have been a bug with reSIProcate (DUM),
but I don't think it is a bug anymore...

This is the test I've done:

- Create a call between 2 UAs
- UAS sends first REFER
- UAC's DUM onRefer callback gets called, cache the ServerSubscriptionHandle
- UAS sends second REFER (identical to first one, but different
transaction id and CSeq = 2)
- UAC's DUM onRefer callback gets called, cache the ServerSubscriptionHandle
- It turns out that the same ServerSubscriptionHandle is used in the
second callback.

Because the same handle is used for the two REFER, any response
generated using handle->accept/reject will use the CSeq/transaction
from the second REFER. This will make the sender retransmit its first
REFER until it times out.

The code that verifies whether or not to reuse the handle is in
BaseSubscription::matches. Originally I thought there was a bug in
there for the special case of a REFER implied subscription. But...

Here's what RFC 3515 says about multiple REFERs in the same dialog:

2.4.6 Multiple REFER Requests in a Dialog

   A REFER creates an implicit subscription sharing the dialog
   identifiers in the REFER request.  If more than one REFER is issued
   in the same dialog (a second attempt at transferring a call for
   example), the dialog identifiers do not provide enough information to
   associate the resulting NOTIFYs with the proper REFER.

   Thus, for the second and subsequent REFER requests a UA receives in a
   given dialog, it MUST include an id parameter[2] in the Event header
   field of each NOTIFY containing the sequence number (the number from
   the CSeq header field value) of the REFER this NOTIFY is associated
   with.  This id parameter MAY be included in NOTIFYs to the first
   REFER a UA receives in a given dialog.  A SUBSCRIBE sent to refresh
   or terminate this subscription MUST contain this id parameter.

Note the MUST regarding the usage of the id parameter if subsequent
REFERs are issued.

When I modified my test application to include the following header in
the second REFER: Event: refer;id=2, then two separate
ServerSubscriptionHandles were created, which enabled me to
independently answer them.

So... the RFC is pretty clear that subsequent REFER requests must have
the id parameter, which seems to indicate that the UA you are
interacting with is not compliant to RFC 3515. Hopefully this UA can
be changed to become compliant (at least, the RFC is crystal clear)...

If changing the peer UA is simply not an option, then I suppose some
magic could be conjured (it wouldn't be clean) to cache the SipMessage
(and not the ServerSubscriptionHandle) so that a response (to the
first REFER) can be manually forged and sent when needed... I wouldn't
recommend that ;) Another option would be to "hack" your own version
of BaseSubscription::matches so that it works in your case, but this
patch will most likely not make it back in the reSIProcate code
line...

Regards,
Francis