Skip to main content

SIP RA new event types and dialog activity

24 replies [Last post]
baranowb
Offline
Joined: 2006-01-09
Points: 0

There is one issue that we cant solve with Ranga ( or rather we are not certain which aproach would be the best ).

We cant figure out how Dialog should be handled as activity. DialogID of dialog is undetermined until final responce with toTag is sent or provisional with toTag. We cant be sure when this happens.
So, refering to wiki:

JainSipResourceAdaptorSbbInterface intf = ...
SipActivityContextInterfaceFactory factory = ...
SbbLocalObject myLocalObject = ...
ClientTransaction tx = ....
SipProvider provider = intf.getSipProvider();
Dialog dialog = provider.getNewDialog(tx);
ActivitiyContextInterface aci = factory.getActivityContextInterface(dialog);
aci.attach(myLocalObject);

Cant be done until sbb sends response (any, provisional or final). Until than we have to postpone craetion of dialog as acitivty object, otherwise we get NPE as dialogID is undetermined.

But it gets worse if we get to new events for dialog AO, like SetupEarly.
We had some brainstorming moments on this with Ranga but as for now we couldnt find clean, non hacky way.

LEt me introduce code which generates error:

This is form test sbb which receives invite:

public void onInvite(javax.sip.RequestEvent event,
ActivityContextInterface aci) {
logger
.info("''''''''''''''''''''INVITE ''''''''''''''''''''''''''''''''''''");
logger.info("\n" + event.getRequest());
logger
.info("'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''");
try {
// Dialog
// dial=fp.getSipProvider().getNewDialog((Transaction)aci.getActivity());
// ActivityContextInterface
// dialACI=SIPACIF.getActivityContextInterface(dial);
// SbbLocalObject SLO=this.sbbContext.getSbbLocalObject();
// dialACI.attach(SLO);

try {
Response okResponse = messageFactory.createResponse(
Response.OK, event.getRequest());
ServerTransaction ST = (ServerTransaction) aci.getActivity();
ToHeader toHeader = (ToHeader) okResponse
.getHeader(ToHeader.NAME);
toHeader.setTag("LOCAL TAG - NEEDED TO COMPUTE DIALOG ID");
okResponse.setHeader(toHeader);
ContactHeader contactHeader = headerFactory
.createContactHeader(toHeader.getAddress());
okResponse.addHeader(contactHeader);
ST.sendResponse(okResponse);

Dialog dial = fp.getSipProvider().getNewDialog(
(Transaction) aci.getActivity());
ActivityContextInterface dialACI = SIPACIF
.getActivityContextInterface(dial);
SbbLocalObject SLO = this.sbbContext.getSbbLocalObject();
dialACI.attach(SLO);

(if we comment out last line and uncoment first ones with dialog creation then NPE is thrown since dialogID is undetermined)

This is code from SipProviderProxy where error arises:

public Dialog getNewDialog(Transaction transaction) throws SipException {

Dialog dial=this.provider.getNewDialog(transaction);
String dialID=dial.getDialogId();
logger.info("==================== "+dial+" : "+dialID+" ===============");
this.sipResourceAdaptor.getActivities().put(dialID,dial);
try {
sipResourceAdaptor.getSleeEndpoint().activityStartedSuspended(
new SipActivityHandle(dialID));
} catch (ActivityAlreadyExistsException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (CouldNotStartActivityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return dial;

}

Logger prints dialog object ( what Object.toString() returns) and null;

Message was edited by: baranowb
Sorry had to edit message, it was 4 am when I posted it.

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
niklasuhrberg
Offline
Joined: 2004-11-02
Points: 0

> To keep everything in one place.
> Ivelin pointed me out that we took slightly wrong
> approach, or maybe different, not entirelly wrong as
> one might think.
> According to wiki ( as I understand it ) If dialog is
> created and sbb attaches to its activity context all
> messages should be delivered to dialog activity, no
> Tx should be created as by RA as activity

This is not true according to the discussion I and Ben Evans had as to get a common understanding of the workings.

We stated that the transaction based activities are indeed created by the RA but this does not mean that there is an ACI created for all the activities.

An example:

A dialog is established.
When later the BYE is sent to the SLEE there is an SBB attached to the corresponding Dialog ACI.
Now the BYE is fired on the Dialog ACI as a DialogTerminatedEvent (the most common case where the BYE actually terminates the dialog).
At this moment there is a ServerTransaction activity that the Sbb can obtain and if it wishes also create an ACI for.

Because there is no ACI for the ServerTransaction activity the 1.1 events will not be fired, the 1.2 event replaces the 1.1 BYE event.

> Events fired should be in-dialog types - v1.2.
> Otherwise Tx should be created as activity object and
> all event fired to it should be out of dialog type -
> v1.1.
>
> Ivelin suggested that 1.1 event types should always
> be fired and 1.2 if dialog AO exists.
>
> Both approaches have its flaws and ofcourse "better
> sides".
> Ivelins:
> + back compatibility is not completly ruined, only
> dialog stateful apps have to be slighlty recoded
> (right)
> - apps have to ignore some 1.1 types of messages if
> they are using Dialogs - RA becomes noisy...
> Wikis:
> -back compatibility seems to be gone forever, just
> new begining
> + RA is not so noisy, apps dont have to check
> anything, just subscribe to events
>
>
> Which would be better?

niklasuhrberg
Offline
Joined: 2004-11-02
Points: 0

I don't know what "hacky" solutions to the DialogID problem you have come up with.

Could you briefly summarize the best candidate?

I actually gave this some thought (a pretty long time ago now...) and then I considered a mechanism that basically changes the id when the dialog changes state.
This should be possible given that you have control over the concurrency mechanism, i.e. if there is a forking situation the dialogs must be handled sequentially in a controlled way.

Without having gone into details yet it seems that the most interesting case is for a client transaction, right?

Is the following viable?

1. Sbb obtains Dialog and attached to corresponding ACI before any response is received.
2. RA maps Dialog ACI without using the To tag since it is not present. It also does not use Dialog.getDialogID
3. The first response containing a To tag arrives. At this moment the RA discovers that there is no Dialog activity mapped using the DialogID of the dialog and it falls back on checking among the mappings for dialogs done in (2).
There is a match and the mapping is updated to contain also the To tag.

I suspect that this is one of the hacks you've already considered but given the nature of the DialogID and the constraints in Jain SIP there is probably some work that has to be done :=)

eduardomartins
Offline
Joined: 2005-10-10
Points: 0

Since they have a SIP RA that supports dialogs as activities (not sure if it's the one with the OC or JAIN stack), anyone tried to know what's the solution that OpenCloud uses?

Eduardo Martins
PT Inovação

niklasuhrberg
Offline
Joined: 2004-11-02
Points: 0

> Since they have a SIP RA that supports dialogs as
> activities (not sure if it's the one with the OC or
> JAIN stack), anyone tried to know what's the solution
> that OpenCloud uses?
>
> Eduardo Martins
> PT Inovação

Solution to what problem? There are a few different questions in the postings above...

The RA Type discussed here is very much inspired by the OC SIP RA Type. In fact it is their RA Type with a few enhancements designed in close cooperation with OC (Ben Evans).
Their implementation is closed though so there is no clue to the implemenation issue raised in the first post in the thread.

eduardomartins
Offline
Joined: 2005-10-10
Points: 0

The solution for the whole SIP RA 1.2. I'm glad the answer to my question is yes, OC and Mobicents are cooperating.

Eduardo Martins
PT Inovação

ben_evans
Offline
Joined: 2003-08-14
Points: 0

You guys seem to be on the right track but since people are curious here's what we did in the OC SIP RA, I think it is similar to what Niklas had in mind above.

Problem:
SBB has created a dialog activity, but the full dialogID is not known yet, we don't know the remote tag. I call it a "half-dialogID". The RA needs to assign an ActivityHandle to this activity (which the SLEE maps to an ACI), but the ActivityHandle must be immutable, so we can't use the dialogID which is going to change.

Solution:
When the dialog activity is created, the RA creates an ActivityHandle, and also stores a mapping from half-dialogID -> ActivityHandle. The actual value of the ActivityHandle does not matter as long as it is unique.
When the dialog is established (ie. a dialog-creating response is sent or received), check to see if the response matches a half-dialogID, and if so, update the mapping so the full dialogID (now containing the remote tag) maps to the ActivityHandle.

Now if future mid-dialog requests arrive, the RA can use the dialogID to lookup the ActivityHandle, and then fires the event using the correct ActivityHandle.

baranowb
Offline
Joined: 2006-01-09
Points: 0

Here is what we did.
We have created wrappers for events, TXs and dialog objects. Each wrapper implements same interface as object it wraps.
Those wrappers are introduced to slee and sbbs. dialog wrapper takes care of generating dialog id ( local dialog id ) which will be constant and unique localy.
When sbb creates dialog it is wrapped and wrapper object is presented to sbb.

niklasuhrberg
Offline
Joined: 2004-11-02
Points: 0

> Here is what we did.
> We have created wrappers for events, TXs and dialog
> objects. Each wrapper implements same interface as
> object it wraps.
> Those wrappers are introduced to slee and sbbs.
> dialog wrapper takes care of generating dialog id (
> local dialog id ) which will be constant and unique
> localy.
> When sbb creates dialog it is wrapped and wrapper
> object is presented to sbb.

Have you ensured that this solution permits forked dialogs?
I.e. will you be able to handle multiple dialogs with the same local tag?

The wrappers themselves do not explain how the core problem is solved, you must fill in some more to have me understand the solution...

baranowb
Offline
Joined: 2006-01-09
Points: 0

Llocal tag is never the same for two different dialogs, it will have common part though. Forked dialogs are supported, or atleast I dont see any thing that would stand as obstacle.
if sbb creates dialog ( forked one ) it has to respond with ok to forked invite, simple as it is.

ivelin
Offline
Joined: 2003-07-13
Points: 0

...
> if sbb creates dialog ( forked one ) it has to
> respond with ok to forked invite, simple as it is.

Is the forked dialog a separate dialog activity? If so, is it related to the original dialog activity in any way and how?

baranowb
Offline
Joined: 2006-01-09
Points: 0

Yes, its different activity. No special link between forked dialogs exists as for now, should there be one?

ivelin
Offline
Joined: 2003-07-13
Points: 0

> Yes, its different activity. No special link between
> forked dialogs exists as for now, should there be one?

I can't think of a use case at this point, just wanted to understand the implementation.

Is there a unintrusive way to tag a forked dialog with the ID of the original dialog. Maybe a reference to the activity of the original dialog can be provided with the first event on the forked activity.

Can you please post a status update of the new SIP RA work?

baranowb
Offline
Joined: 2006-01-09
Points: 0

uh I thought that I have sent it already as I did before. strange.

Well work is almost done, all that has to be done:
- add CANCEL behaviour
- maybe some kind of a link between forked dialogs
- write some TCKs
- test SIPRA as UAC - it will fit into tcks

I cant see any reason to add that forked dialog linking, nor I am not able to say right now if there is any simple way to add it.

Currently I have moved all tests we had to TCks but I cant run them. It's strange because everything passed to jvm looks ok, classpath points to directory with test classes but I keep geting ClassNotFoundEx

Message was edited by: baranowb

Message was edited by: baranowb

jbemmel
Offline
Joined: 2005-03-01
Points: 0

(At the risk of stating the obvious) For a UAS, all related forked dialogs will have the same call-id and from-tag. So you can provide a link by providing a dialog lookup function, indexed by call-id + from-tag

Regards,

Jeroen

baranowb
Offline
Joined: 2006-01-09
Points: 0

I took some time reading into extension memo and rfc 3261 and looking best place in code to put CANCEL behaviour of new RA.
After a while I stumbled on few sentences I missed after first 2 times I read rfc:
"The processing of a CANCEL request at a server depends on the type of
server. A stateless proxy will forward it, a stateful proxy might
respond to it and generate some CANCEL requests of its own, and a UAS
will respond to it. See Section 16.10 for proxy treatment of CANCEL."

With this taken into consideration I am not sure if putting cancel logic into RA is a good idea.

Any comments? Maybe Im missing something, please, be cruel.

Besides there is one small "bug"
Since we use branchID as id for siphandles, handles for INVITE and CANCEL TX are equal right (since for both tx getBranch return the same String)? This way we leak INVITE Tx as activity dont we?

Bartek

jbemmel
Offline
Joined: 2005-03-01
Points: 0

Yes, you are right. And moreover, older SIP clients might not fill in the branchID

For RFC3261-only mode, a solution would be to use {branchID+method} (or first char of the method). This matches with what is described in section 17.1.3

You can also calculate a hash function over those two elements, and use the resulting String as id (such that empty branches hash to something usable too)

Regards,
Jeroen

ivelin
Offline
Joined: 2003-07-13
Points: 0

CANCEL handling for stateless proxy vs stateful proxy (and end point) cases has been discussed earlier on the forum. For Dialog activities its better for the RA to handle CANCEL as much as possible on send higher level activity end events. SBBs that need pass through behavior in the RA can use the regular SIP Transaction activities.

http://wiki.java.net/bin/view/Communications/SipRADiscussionBase#Cancel
http://wiki.java.net/bin/view/Communications/DialogExtensionMemo#Cancell...
http://wiki.java.net/bin/view/Communications/DialogExtensionMemo#Cancell...

jbemmel
Offline
Joined: 2005-03-01
Points: 0

A note on RFC3261: it says (in section 16.10) that a proxy MUST statelessly forward a CANCEL if no INVITE transaction matched, because it might have forwarded the INVITE statelessly.

However, if the application always uses stateful forwarding, IMHO it would be better to respond with 481 instead of forwarding statelessly.

niklasuhrberg
Offline
Joined: 2004-11-02
Points: 0

On the DialogID issue I don't have any clear thoughts at the moment except what follows - I'll think about this more.

In Jain Sip it is defined that (for a server transaction) the Dialog must be created [i]before[/i] any response is sent.
(See the javadocs for SipProvider.getNewDialog)

From what I can see in the code it should not qualify as legal according to the constraint referred to above.

Comment?

torosvi
Offline
Joined: 2005-07-20
Points: 0

> LEt me introduce code which generates error:
>
> This is form test sbb which receives invite:
>
> public void onInvite(javax.sip.RequestEvent event,
> ActivityContextInterface aci) {
> logger
> .info("''''''''''''''''''''INVITE
> VITE ''''''''''''''''''''''''''''''''''''");
> logger.info("\n" + event.getRequest());
> logger
> .info("'''''''''''''''''''''''''''''''''''''''''''
> ''''''''''''''''''''''");
> try {
> // Dialog
> //
> //
> /
> dial=fp.getSipProvider().getNewDialog((Transaction)aci
> .getActivity());
> // ActivityContextInterface
> //
> //
> / dialACI=SIPACIF.getActivityContextInterface(dial);
> // SbbLocalObject
> ect SLO=this.sbbContext.getSbbLocalObject();
> // dialACI.attach(SLO);
>
> try {
> Response okResponse =
> se = messageFactory.createResponse(
> Response.OK, event.getRequest());
> ServerTransaction ST = (ServerTransaction)
> ion) aci.getActivity();
> ToHeader toHeader = (ToHeader) okResponse
> .getHeader(ToHeader.NAME);
> toHeader.setTag("LOCAL TAG - NEEDED TO COMPUTE
> PUTE DIALOG ID");
> okResponse.setHeader(toHeader);
> ContactHeader contactHeader = headerFactory
> .createContactHeader(toHeader.getAddress());
> okResponse.addHeader(contactHeader);
> ST.sendResponse(okResponse);
>
> Dialog dial = fp.getSipProvider().getNewDialog(
> (Transaction) aci.getActivity());

[b]NOTES[/b]

Debugging the code I have noticed that it is necessary to do the folowing change:

public void onInvite(javax.sip.RequestEvent event, ActivityContextInterface aci) {

...

try {

...

try {

[b][i]Object activity = aci.getActivity();[/i][/b]
Response okResponse = messageFactory.createResponse(Response.OK, event.getRequest());
[b][i]ServerTransaction ST = (ServerTransaction) activity;[/i][/b]

...

[b][i]
Dialog dial = fp.getSipProvider().getNewDialog((Transaction) activity);[/i][/b]

...

These simple changes are due to the fact that I noticed that using the other code (Dialog dial = fp.getSipProvider().getNewDialog((Transaction) aci.getActivity())) we were giving a null argument to the getNewDialog method because [i]aci.getActivity()[/i] was returning [b]null[/b]

> This is code from SipProviderProxy where error
> arises:
>
> public Dialog getNewDialog(Transaction transaction)
> throws SipException {
>
> Dialog dial=this.provider.getNewDialog(transaction);
> String dialID=dial.getDialogId();

As Bartek said, dialID will be null and as a result we will have a NPI.

Victor

baranowb
Offline
Joined: 2006-01-09
Points: 0

To keep everything in one place.
Ivelin pointed me out that we took slightly wrong approach, or maybe different, not entirelly wrong as one might think.
According to wiki ( as I understand it ) If dialog is created and sbb attaches to its activity context all messages should be delivered to dialog activity, no Tx should be created as by RA as activity.
Events fired should be in-dialog types - v1.2.
Otherwise Tx should be created as activity object and all event fired to it should be out of dialog type - v1.1.

Ivelin suggested that 1.1 event types should always be fired and 1.2 if dialog AO exists.

Both approaches have its flaws and ofcourse "better sides".
Ivelins:
+ back compatibility is not completly ruined, only dialog stateful apps have to be slighlty recoded (right)
- apps have to ignore some 1.1 types of messages if they are using Dialogs - RA becomes noisy...
Wikis:
-back compatibility seems to be gone forever, just new begining
+ RA is not so noisy, apps dont have to check anything, just subscribe to events

Which would be better?

eduardomartins
Offline
Joined: 2005-10-10
Points: 0

Why should you say that the RA is noisy? 1.1 Events does not need to be "always" fired, the RA can manage a counter of how many services that are activated are registred for those event types and if the counter is 0 then those events are discarded. This is event filtering and those RA methods regarding service activation and deactivation were created for that. And if there is a service that is really interested in 1.1 you need to fire those events, the service may lack the interest in dialogs.

Eduardo Martins

baranowb
Offline
Joined: 2006-01-09
Points: 0

By noisy I mean that if app moves to dialog activity it will still receiver out of dialog events

Besides firing both event types breakes wikis
"If Trying comes for INVITE we have sent , fire SetupEarly"

Message was edited by: baranowb

niklasuhrberg
Offline
Joined: 2004-11-02
Points: 0

> By noisy I mean that if app moves to dialog activity
> it will still receiver out of dialog events
>
> Besides firing both event types breakes wikis
> "If Trying comes for INVITE we have sent , fire
> SetupEarly"
>
>
> Message was edited by: baranowb

If my memory doesn't let me down I think there are cases where a Trying response does not contain a To tag and therefore does not cause the dialog to enter early state.

Therefore Trying does not automatically mean that a SetupEarly event should be fired.

I may have been misinformed on this one, I haven't checked RFC3261 on this one.