Home > Java, SIP, Telecom > Lost layer of SIP

Lost layer of SIP

SIP is defined by RFC as a layered protocol. This means that all the functionality is grouped into several layers, which have “entry points” where they accept data from other layers. Whole protocol is described as internals of each layer and inter-layer communication. Layers are not organized in strict sequence: for example, transaction user layer sometimes interacts with transport layer directly, like when sending ACK.

Implementations of SIP usually follow layered model. However, since layers defined as “functional”, it is possible to move an implementation of a layer upper or lower, as long as result will be the same. For example, parser layer by definition is located below transport layer. If implementation follows this approach, then it first opens a socket, then encodes a message and writes resulting bytes into that socket, possibly in streaming mode. But other implementations first encode a message, then pass a byte array to common network code which will send those bytes, possibly re-using some existing connection. It is even possible to store a result of encoding in a transaction, thus avoiding encoding a message for each retransmission.

Unfortunatelly, a layered model of SIP is not perfect. It seems to me that there is an additional layer lost in a spec. This article is an attemt to point this fact out, and to show how existing SIP implementations deal with it.

A chapter 12.2.1.1 explains how to populate an outgoing request based on route set of a Dialog. A chapter 8.1.2 of RFC 3261 describes actions UAC should take to send an outgoing request. To find out which URI should be used to define a request destination, it is not enough to have just a request, but it is also should be known if a first element of a route set was a strict or loose router. When a URI is chosen, it should be converted to a list of IP addresses using a procedures described in RFC 3263. After that a request together with IP+port+transport should be passed to transaction layer for sending, unless a request method is ACK. Chapter 8.1.3 describes response processing.

Exactly the same steps are descibed for Proxies in chapter 16.6, steps 6 and 7. My observation is that there should be an additional layer called “Client”. This layer whould be common for proxies and UACs. There are also other pieces of functionality which naturally fit into this layer, like sending a CANCEL.

Sailfin, an open source SIP servlet container, has a layer called “ResolverManager” which is located above TransactionManager and below DialogManager. This layer partially implemens my logical “client layer”. When sending a request it does IP/port/transport resolution, which is stored in “_remote” field of a request and later used on transport layer. ResolverManager also handles 503 responses by re-trying another IP address, if exists. Treating client timeouts as “408” responses is done entirely on transaction layer. Strict routing is not supported by Sailfin.

Reference implementation of JAIN SIP API is much more obscure. There are two methods for sending requests: through SipProvider, and through ClientTransaction. Both methods use “Router” to determine IP address. If application doesn’t define any special Router, a DefaultRouter will be used, which does route info post-processing and URI determination. Address resolution is not performed as described in RFC 3263, instead they just use standard Java facility. So, “client layer” here is hidden inside transaction layer. Well, as I said at the beginning of this article, re-ordering of layers is possible if whole picture is the same. But this implementation makes it impossible to implement high availability by trying several client transactions, if hostname has several IP addresses.

I wish RFC 3261 whould be more clear. I also wish JAIN SIP API whould be much better than it is. ClientTransaction interface already suitable to be used as interface for “client layer” , we just need to throw away all methods like getBranchId(), getState(), createAck(). However, a proposal for new, better and cleaner SIP API is a subject for another article. I’m open for suggestions!

Advertisements
Categories: Java, SIP, Telecom Tags: , ,
  1. October 14, 2008 at 1:37 am

    I am one of the spec leads of JAIN-SIP. A friend of mine pointed me at your article some time ago and I have been meaning to find the time to respond. Some comments on your article:

    I cannot agree with some of the comments you make. First, about the SIP RFC itself. The SIP RFC is in fact one of the better RFCs around. I do not agree at all that it is unclear.

    Next, your comments about JAIN-SIP. The motivation for JAIN-SIP was to provide a stack library for programmers who understand SIP pretty well. If you want something higher layer, you have SIP-SERVLETS and SLEE. There are some things that are much harder to build using one of these. If what you are looking for is a simple, flexible and powerful SIP Stack, JAIN-SIP fits that bill.

    As for your specific comments on JAIN-SIP, here are a few things that you did not quite understand, perhaps:

    1. The reason why there is a stateless send and a stateful send message ( i.e. one that uses the SipProvider and one that uses the Transaction object) is that the latter has under lyingly, a transaction state machine that is updated. When you send using the Transaction Object, you are updating the transaction state machine; whereas, in the stateless case you are not. The fact that you use the Router object in both cases is not relevant. The Router is used for out of dialog messages.. Does not matter if the send is Stateful or Stateless. Also note that there is also a Dialog.sendMessage(Transaction). This updates both the dialog and the transaction state. It all depends upon what you are trying to build.

    Why do you need these different methods? The reason is that not all sip components keep the same state around. User Agents are DIalog Stateful and Proxy servers are either stateless or transaction stateful.

    Finally, note that the Router is a pluggable class. You can add RFC 3263 (DNS SRV) support easily using DNS JAVA and implementing the Router Interface. Why was this not part of the RI? Well, first the RI was meant to be just a Reference Implementation. Its primary purpose *was* reference testing. It grew to be something more than that — which is fine. However, what you are asking for is not hard to do. Note Mobicents SIP Servlets and SIPXBRIDGE Both those projects do DNS SRV lookup and return a Hop on that basis. Its really quite simple. You can also do other non-standard mapping schemes ( I have implemented some of those ).

    All these mechanisms offer you enough flexibility to easily build failover mechanisms. Take a look at how mobicents sip servlets does that.

    The flexibility of the API allows you to build anything from proxy servers to user agents to test tools. With all this flexibility comes the inevitability of allowing you to shoot yourself in the foot. I accept that as a valid criticism but then that was not the purpose of the API and neither was it an explicit goal to make the RI full featured.

  2. kmatveev
    October 14, 2008 at 7:11 am

    Hello, Mr. Ranganathan! Your name is well known to me. It is an honor to me (seriously!) to see your comments in my humble blog.

    When I’m saying that I wish RFC 3261 to be more clear I always mean something specific, like in this article. I know that RFC 3261 is considered to be one of the clearest RFCs (and one of the biggest), but this only means that other RFCs are just less clear. I never meant to offend authors of this RFC, I believe that it is a very good document, and if some novice asks me “what can I read about SIP ?”, I always respond: “read an RFC, it is a best thing available”. But it is not perfect, that’s just what I wanted to say.

    When you say that JAIN-SIP was designed for programmers who understand SIP pretty well, I totally agree. The learning curve for JAIN-SIP is steepper than of SIP Servlets. Just look: JAIN SIP has 3 ways of sending a request and 2 ways of sending a response, comparing with single method send() of SIP Servlets. JAIN SIP sacrifices simplicity of API to simplicity of implementation. I also agree that JAIN-SIP is more flexible than SIP Servlets, because the latter is intended for server-side applications. It is also quite hard to develop some API on top of SIP Servlets API.

    Believe me, I certainly know the difference between stateless and statefull sending of messages. You say that the fact they both use Router is not relevant, but this fact is exactly the point of my article! This router class is used for converting URI to IP+port, and it is hidden inside transaction or tranport layer, but RFC 3261 says that it should be done on TU layer. I see that as a drawback not because I just want stack to perfectly reflect the layered structure of RFC. There are other reasons. For example, RFC 3263 explains how several transactions should be used sequentially if DNS lookup returns several IP addresses for some host name. But, if Router is inside transaction layer, that is impossible, even if Router is pluggable. So, JAIN SIP is not compatible with RFC 3263.

    I admit that this article doesn’t explain my another complaint, that a transaction layer cannot be built on top of a transport layer. My impression of JAIN SIP was that you can use the only layers of SIP that you need, so you can take just parser+transport layer (SipProvider), and build your own transaction layer. What should custom implementation do in this case: to use Router or not ? If it should use Router, then it will be used twice: first on a transaction layer, and then on a transport layer. I don’t think this is a correct way of working.

    I’ll take a look at mobicents, but I doubt that they have found a way to fix this.

    Anyway, thank you very much for your attention. I agree that JAIN SIP has some virtues, and it is certainly better than nothing. But I strongly suspect that main attraction of JAIN SIP is availability of free stack.

    I think that JAIN SIP is far from being perfect. I’ll keep publishing my thoughts on it, and on SIP Servlets also. And I will also keep publishing on all unclear parts of RFC 3261. I was not very active later, but it will change. Please come back, I promise it will be interesting reading!

  3. Anonymous
    October 14, 2008 at 9:21 pm

    You are right in that everything can stand improvement and clearly that includes JAIN-SIP.

    Regarding your comments on RFC 3263. One point to note about trying sequential transactions – this is quite possible. Nothing prevents you from communicating from your application layer to your Router implementation. You can instantiate your Router and get the instantiated Router from the Stack object. After that, if you wish, you can set up a method in your Router class to communicate with it from the application layer. Hence, you can indeed try sequentially, if thats what you wish to do. For example, if you do Transaction.sendRequest() and that fails, you set a flag in your Router and in your getNextHop() return the next address. It allows you to have different routing policies this way.

    Of course JAIN-SIP is far from being perfect. It was meant for a purpose and I believe serves that purpose. I have not come across a SIP signaling application that cannot be built with it. Its tricky to use but it was not intended for the non-expert. Many things can be added to it ( look at the Ext interfaces for an inkling of things to come). Many complex applications have been built with it and yes there is more than one implementation of the standard. Finally, there is another reason for the use of the Router which you did not identify. It can be used for routing tel: URLS and for non-standard routing schemes.

    A criticism on what you have written thus far — you have not identified its major pitfalls of JAIN-SIP correctly IMO. So let me help you with that : here is what I think is wrong with JAIN-SIP. There are some things which are not very well defined — for example the “split of responsibility” between “application” and stack and the lack of a clear statement of what the threading model is. These are things that affect the semantics of programs and hence should be clearly defined. I do not buy that having three different send methods is a shortcoming. If you know which one to use, thats what you will use. If you don’t know which one to use, then your program will not work as expected and you will discover when your Dialog times out or your transaction times out. Which, by the way, will happen every time. However if your concurrency model is not clearly defined, it will work some of the time.

    Disclaimer – I am not an API Smith. API beautification is not my game. I like to build stuff that works. If JAIN-SIP is ugly but does the job then I prefer that to something pretty that cannot be used everywhere.

  4. M.Ranganathan
    October 14, 2008 at 9:25 pm

    Forgot to sign the previous note…

  5. kmatveev
    October 15, 2008 at 3:50 pm

    Thanks for your reply. I agree with mostly everything that you say. But I am a perfectionist. I want to design an API which whould be best. Definition of stack responsibility will certainly be a part of that API. And I will strive for this API to have all virtues of JAIN SIP without it’s drawbacks. It will even include threading model!

  6. Frederic Tardif
    November 22, 2012 at 2:48 pm

    I got the same need regarding 3263 redundancy in jain-sip. Here are details about how we implemented it:
    http://java.net/projects/jsip/lists/users/archive/2012-11/message/0

  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: