Skip to main content

Re: B2B proposal

  • From: "Strickland, Tom" < >
  • To:
  • Subject: Re: B2B proposal
  • Date: Fri, 14 Jun 2013 12:11:39 +0100

My comments inline.

---------- Forwarded message ----------
From: Jonas Borjesson < "> >
Date: 13 June 2013 19:16
Subject: Re: B2B proposal
To: ">
Good morning,
See my response inline
/Jonas

>> --------- Forwarded message ----------
>> From: Jonas Borjesson < "> >
>> Date: Wed, Jun 12, 2013 at 7:28 PM
>> Subject: Re: B2B proposal
>> To: ">
>>
>>
>> Hi all,
>> I agree with George – i.e., 1A is my preferred solution since as I'm
>> sure you know by now that I like interfaces, things become more
>> explicit. Apart from that, I do have a few other questions/comments:
>>
>> === Consistency ===
>> The suggestion calls for a lot of new very specific methods, such as
>> SipInviteRequest.
>> getUnacknowlegedProvisionalResponse(s),
>> SipFactory.createContinuationRequest and
>> SipSession.getActiveInvites(UAMode).
>>
>> The first two ones are very specific but the third one has two
>> meanings, incoming and outgoing which is defined by the UAMode. Going
>> with the rest of the methods and the overall intent of the proposal
>> should they just be renamed to
>> SipSession.getActiveIncoming/OutgoingInvites? I can go both ways but
>> just wanted to ask. I think consistency is super important in an API.
>> However, from a simplicity point of view I have some other concerns
>> about these every specific methods...
>
>
> I like the idea of having SipSession.getActiveIncoming/OutgoingInvites
>
>> Also, we often returns Collection but sometimes pass in Set. If the
>> intent is indeed to e.g. not allow duplicates then sure, use a Set but
>> then I would ask if that really matters for the proposed changes? So
>> is the useage of Set deliberate?
>
> Yes createContinuationRequest could take a Collection.
>
>> And finally, in 289 Iterators are what is typically returned so if
>> nothing else the return values from these new proposals should
>> probably do the same (even though there are some inconsistencies in
>> 289 as well – SipApplicationSession.getTimers() e.g.) .
>
> But Collections are more useful - I would prefer utility over consistency.
> We can find out what others think.

In what way are the more useful? I think the big question here is
whether or not we are returning a streamed response. Iterators
actually give more flexibility for the implementors (even though our
first priority should not be the implementors but rather the users but
I think there is a big difference between the intent of collections vs
iterators). E.g., if you do not have everything in memory, such as
reading from a file, database or perhaps something across the network,
an iterator is what you want. Otherwise you have to suck down
everything first before returning the result. In our case, in a
distributed scenario you may actually have the stuff you are asking
for in your local JVM, which is where iterators excel. Anyway, I can
go either way but I think this aspect is worth considering before
making a final decision.

I will respond to this by, at first, ignoring anything to do with maintaining consistency with the rest of the API - but I will address that at the end of this comment.
I have just had to write an app component that copies the route headers from one message to another. To do this, I had to get the route header using msg.getHeaders, which returns a ListIterator... which then has to be reversed to push the routes into the other message; this is where our notion of pushRoutes(...) (search up for this) came from. I find the ListIterator irritating: for example, I cannot call isEmpty and it was irritating having to write reversal code.
When it comes to returning data from an API: I think that you can return the relevant collection type, where relevant, typically as a delegating read-only or snapshot view of the underlying data. I wish that the SipServlet API returned an immutable snapshot List view when you call getHeaders(). This could be efficiently implemented as a Copy-On-Write structure. I would like more useful header specific utilities that return useful collections: if I could call Set<String> getRequired(), then I could ask:
if (msg.getRequired().contains("100rel"))
Collections are more useful than iterators: this seems obvious. I would suggest that you need a good reason to use an iterator (or iterable) over a Collection. Reasons to use iterator/Iterable, as Jonas has stated:
1) It's easier for the implementer, as the contract is less rigid.
2) It's easier to write a lazy-load iterator than a lazy-load collection.

I'm not sure that (1) is a sufficiently good reason for us: our focus should be on the user of the API (as Jonas points out).
I'm not sure that we need lazy-loading in most of the places that we use iterators in the SipServlet API.

I would also point out that, where a method returns iterator, it is usually better to return iterable, as that is nice to use in a for...each loop. If you want to look at a library that has given the whole issue of Collections vs Iterators/Iterables, look at Google's Guava.

As for consistency: I think that the API should, over time, move away from using iterators. Which is more broadly useful of the following?
ListIterator<Locale> getAcceptLanguages()
Set<Locale> getAcceptLanguages() - where the iterator of Set is guaranteed to return items the order of the headers

With the second option, I can call methods such as contains().

Furthermore, we have used collections in some places:
Set<Map.Entry<String,String>> Parameterable.getParameters

>> === Simplicity ===
>>
>> In general, we should certainly make the life of the developers easy
>> but I don't always think creating a bunch of different very special
>> purpose methods will actually help. If we end up creating methods such
>> as SipFactory.createContinuationRequest then I believe that the API is
>> broken as it is and patching it is only going to make developers more
>> confused.
>>
>> --- CreateContinuationRequest ---
>>
>> So, createContinuationRequest, apart from making that particular use
>> case just slightly easier, is it a good idea? Perhaps the routing
>> directive should be added to the SipFactory.createRequest methods
>> instead? If we decide to keep the createContinuationRequest, why not a
>> createReverseRequest too?
>>
>>
>> I guess I personally do not like the createContinuationRequest because
>> for consistency sake we should then also add all the other
>> possibilities but the API becomes really cluttered, which is even
>> worse. So, I'm voting for not including this method and if really
>> needed enhance the SipFactory.createRequest ones instead, which I
>> believe is also what Binod suggested.
>
> I included createContinuationRequest as a lightweight version of the
> B2BuaHelper.createRequest() methods which may be deprecated. You are right
> we could just remove it.

Ok, sounds good to me...

> If a B2B application is sequenced in by a remote container that used
> ROUTE-BACK it should copy route headers. If the same app is to work well
> with a local app router it should use the CONTINUE directive. I was thinking
> that there may be some merit in doing both in the same method but not much
> would be lost by removing the method and having these two actions performed
> separately.
>
> (I note that it is quite cumbersome to copy route headers in the correct
> order so a pushRoutes() method might be helpful for creating B2B apps).
>
> Also, on a separate note, the javadoc isn't super clear what the
> directive is for the newly created request. I assume is is NEW, which
> makes sense but the only reference I have found regarding this is the
> javadoc on SipServletRequest.setRoutingDirective, which is referring
> to the deprecated SipFactory.createRequest. Perhaps we should improve
> the javadoc here...
>
>
> (side note2: for a beautiful API that gets stuff done, check out the
> Python Requests API (though http is way simpler protocol but this API
> is what I try and strive for)
> http://docs.python-requests.org/en/latest/)
>
>
> --- SipInviteRequest.getUnacknowledgedProvisionalResponse ---
>
> Why do we need to pass in the SipSession? If we do, it seems like this
> method should be on the SipSession as opposed to the request. Since it
> is on the request, I would assume this method would only return
> responses for this particular transaction, correct? And if so, the
> SipSession is not needed since the request you are operating on
> explicitly is associated with a SipSession, or perhaps I'm missing
> something...
>
> Version 2 of my proposal did have this method on the SipSession. I realised
> a problem with that as explained in the email that accompanied version 3.
>
> The rseq value in a reliable provisional is only unique for that dialog. Due
> to forking there can be several dialogs which return provisional responses.
> In order to locate a specific response at a UAC which is downstream of a
> forking proxy we need to pass the session (or derived session) along with
> the rseq to the method on SipInviteRequest.
>
> If we put the method on the SipSession there is still a problem with the
> uniqueness of the rseq value. PRACK can arrive after the corresponding ACK
> by which time a new INVITE transaction can be in progress which also has
> provisional responses. To retrieve the correct response we would need to
> pass it the requestId of the INVITE transaction as well as the rseq.
>
> It seems best to avoid cluttering the SipSession interface with methods such
> as this one.
Ok, I think you lost me but I guess my original question was also that
the request itself is uniquely associated with a particular sip
session (it cannot have two) so if you ask the request, the sip
session is implied. Right?

A SIP request is uniquely associated with a SIP dialog, which is uniquely associated with a SipSession. This all seems simple enough, until you consider forking. When downstream forking occurs, you will have more than one SipSession, but still only have one SipServletRequest. This is not so bad when you are acting as a UAC, but when you are running a B2BUA and acting as a UAS, what happens when you want to "fork back" to the caller?

    Alice          B2BUA          Proxy          Bob1          Bob2
 1. INV(a1)---------->
 2.                   INV(b1)------->
 3.                                 INV(b1)------->
 4.                                 INV(b2)--------------------->
 5.                                 <-------180(b1)
 6.                   <-------180(b1)
 7. <----------180(a1)
 8.                                 <---------------------180(b2)
 9.                   <-------180(b2)
10. <----------180(a2)

Here we have an example of parallel downstream forking. Assume that the B2BUA is an app running on a SipServlet container. Everything else is a normal SIP actor outside of the container. At step (9), the response from Bob2 leads the container to realise that forking has occurred, and so it creates a derived SipSession from the session used to send the initial INVITE to Bob in step (2). When we need to send the first response to Alice in (7), then the existing SipSession is used, but to create the second response in (10) requires a new SipSession to be created. After all this forking: Alice has two SipSessions, but only one INVITE SipServletRequest - when that SipServletRequest is queried for Alice each has one INVITE. When you call getSession() on the INVITE SipServletRequest, it will return the original SipSession. All quite weird.


Anyway, I suck at the prack stuff so I'm going to go with whatever you
want as long as we make sure that the methods are clear, the
documentation is there and we don't run the risk of confusing
container implementors as well as users.
 
As for the PRACK stuff, we are discussing this and Keith is writing up a further proposal that is hopefully a little more clear when it comes to handling PRACK transactions from one INVITE transaction overlapping with a different INVITE transaction (and thus possibly overlapping with its PRACK transactions).

Tom

>>
>> --- SipSession.getActiveInvites ---
>>
>> What about getActiveXXX? i.e., what about all the other methods?
>
> Only INVITE transactions require an ACK, other transactions are complete
> once the final response is sent/received. Similarly only INVITES can have
> reliable provisional responses.

Sure, but until you get a final response the "other" type of requests
are still "active". And if you are after only whether or not you have
received an ACK or not, wouldn't a method following the other
getUnacknowledgedXXXX methods be more appropriate?

--
Tom Strickland, Software Developer, Thrupoint Software. Tel: +44 (0) 2920 005110
 
--------------------
Note: The information contained in this message may be privileged and confidential 
and protected from disclosure. If the reader of this message is not the intended 
recipient, or an employee or agent responsible for delivering this message to the 
intended recipient, you are hereby notified that any dissemination, distribution or 
copying of this communication is strictly prohibited. If you have received this 
communication in error, please notify us immediately by replying to the message and 
deleting it from your computer. Thank you. Thrupoint, Inc.
nXaR2cC3






Re: B2B proposal

Jonas Borjesson 06/12/2013

Re: B2B proposal

Binod 06/13/2013

Message not available

Message not available

Fwd: B2B proposal

Strickland, Tom 06/13/2013

Re: B2B proposal

Jonas Borjesson 06/13/2013

Re: B2B proposal

Strickland, Tom 06/14/2013

Re: B2B proposal

Binod 06/14/2013

Re: B2B proposal

Strickland, Tom 06/14/2013

Re: B2B proposal

Binod 06/17/2013

Re: B2B proposal

Nitzan Nissim 06/17/2013

Re: B2B proposal

Strickland, Tom 06/17/2013

Re: B2B proposal

Jonas Borjesson 06/14/2013

Re: B2B proposal

Lewis, Keith 06/15/2013
 
 
Close
loading
Please Confirm
Close