Tuesday Sep 29, 2009

Sip Message Inspection in SailFin

SipMessageInspection(SMI) feature is intended as a way of troubleshooting Sip traffic through SailFin. SMI in SailFin is implemented as logging of requests and responses in the server log. Together with the contextual log information in the server logs, Sip messages helps in tracing and debugging. SMI was first introduced in SailFin 1.0, but it had few limitations such as outgoing requests and responses are not accounted for.

SMI is enhanced in SailFin 2.0 to overcome the short comings in 1.0 and in addition, ability to add user defined message adapters is provided to customize the information logged as part of SMI.

SailFin's sip stack is based on layered architecture and by default SMI logs messages at network layer and application dispatcher/servlet dispatcher, reasoning behind these two are that they are important interception points both from the application and infrastructure developer point of views. Logging at network layer will take care of incoming and outgoing messages from the container and logging at servlet dispatcher takes care of incoming and outgoing messages from or to the applications, which includes the messages generated in the container and stayed back in the container, for example application composition. Users could configure the log message adapters at each layer.

SMI can be configured with the help of properties under sip-service element in the domain.xml and they can be set either using admin GUI or asadmin command line.

By default an adapter is configured at GrizzlyNetworkManager layer and one for servlet invocation on application dispatcher. Users could configure their adapters using on of the following three properties: smiServletAdapter, smiLayerAdapter, smiNetworkManagerAdapter and their values should be in the following format:
(specified class should be available with container class loader)
(specified class should be available at supplied external class root)

User defined adapters should implement org.jvnet.glassfish.comms.admin.reporter.SMILogMessageAdapter interface.

For the default adapters, it is possible to control the amount of records logged by setting smi log level ( e.g. server-config.log-service.module-log-levels.property.smi=FINE ).

When smi log level is

FINE: messages are logged at SERVLET interception in the Application Dispatcher layer

FINER: SERVLET interception and NetworkManager from/to cluster (i.e excluding Loadbalancer network hops)

FINEST:SERVLET interception and NetworkManager including Loadbalancer network hops

If the intent is to log messages only at NetworkManager thus bypassing messages at servlet invocation, there is a work around to achieve the same. There is a NullAdapter implementation in SailFin, which can be set as an adapter implementation for smiServletAdapter property.

Access logging, where SIP messages are logged into a different file is implemented on top of SMI.

Cut and paster from the server logs to when a simple invite UAS application is run:

[#|2009-09-27T23:21:03.509+0530|FINE|sun-glassfish-comms-server2.0|javax.enterprise.system.container.sip.smi|_ThreadID=16;_ThreadName=SipContainer-serversWorkerThread-5060-9;ClassName=org.jvnet.glassfish.comms.admin.reporter.SMIBaseReporter;MethodName=log;_RequestID=fc6596b6-87ec-4304-b423-76425085c98c;|SMI -->IN Request INVITE At: inviteuas/TestSipServlet -->

INVITE sip:sailfin-AT-inviteuas-DOT-com;transport=UDP SIP/2.0

Content-Length: 127

Max-Forwards: 70

From: "sipp";tag=10460SIPpTag001

Cseq: 1 INVITE

Contact:

Subject: inviteuas Test

To: "sailfin"

Content-Type: application/sdp

Test-Type: uas

Call-Id: 1-10460-AT-127.0.0-DOT-1

Via: SIP/2.0/UDP 127.0.0-DOT-1:5090;branch=z9hG4bK-10460-1-0

v=0

o=user1 53655765 2353687637 IN IP4 127.0.0-DOT-1

s=-

c=IN IP4 127.0.0-DOT-1

t=0 0

m=audio 6000 RTP/AVP 0

a=rtpmap:0 PCMU/8000|#]

[#|2009-09-27T23:21:03.533+0530|FINE|sun-glassfish-comms-server2.0|javax.enterprise.system.container.sip.smi|_ThreadID=16;_ThreadName=SipContainer-serversWorkerThread-5060-9;ClassName=org.jvnet.glassfish.comms.admin.reporter.SMIBaseReporter;MethodName=log;_RequestID=fc6596b6-87ec-4304-b423-76425085c98c;|SMI <--OUT Response 200 (INVITE) At: inviteuas/TestSipServlet -->

SIP/2.0 200 OK

From: "sipp";tag=10460SIPpTag001

Cseq: 1 INVITE

Contact:

To: "sailfin";tag=g043761z-1

Server: Glassfish_SIP_2.0.0

Call-Id: 1-10460-AT-127.0.0-DOT-1

Via: SIP/2.0/UDP 127.0.0-DOT-1:5090;branch=z9hG4bK-10460-1-0

|#]
[#|2009-09-27T23:21:03.578+0530|FINE|sun-glassfish-comms-server2.0|javax.enterprise.system.container.sip.smi|_ThreadID=17;_ThreadName=SipContainer-serversWorkerThread-5060-7;ClassName=org.jvnet.glassfish.comms.admin.reporter.SMIBaseReporter;MethodName=log;_RequestID=6dd574b5-0f5a-4857-8e85-0a805d6e02e8;|SMI -->IN Request ACK At: inviteuas/TestSipServlet -->

ACK sip:sailfin-AT-inviteuas-DOT-com;transport=UDP;fid=server_1 SIP/2.0

Content-Length: 0

Max-Forwards: 69

From: "sipp";tag=10460SIPpTag001

Cseq: 1 ACK

Contact: sip:sipp-AT-127.0.0-DOT-1:5090

Subject: inviteuas Test

To: "sailfin";tag=g043761z-1

Call-Id: 1-10460-AT-127.0.0-DOT-1

Via: SIP/2.0/UDP 127.0.0-DOT-1:5090;branch=z9hG4bK-10460-1-5

|#]#|2009-09-27T23:21:04.073+0530|FINE|sun-glassfish-comms-server2.0|javax.enterprise.system.container.sip.smi|_ThreadID=18;_ThreadName=SipContainer-serversWorkerThread-5060-6;ClassName=org.jvnet.glassfish.comms.admin.reporter.SMIBaseReporter;MethodName=log;_RequestID=c88e7c7c-18a1-4632-9994-1e12d6a52d8c;|SMI -->IN Request BYE At: inviteuas/TestSipServlet -->

BYE sip:sailfin-AT-inviteuas-DOT-com;transport=UDP;fid=server_1 SIP/2.0

Content-Length: 0

Max-Forwards: 69

From: "sipp";tag=10460SIPpTag001

Cseq: 2 BYE

Contact: sip:sipp-AT-127.0.0.1:5090

Subject: inviteuas Test

To: "sailfin";tag=g043761z-1

Call-Id: 1-10460-AT-127.0.0.1

Via: SIP/2.0/UDP 127.0.0.1:5090;branch=z9hG4bK-10460-1-7

|#]

[#|2009-09-27T23:21:04.087+0530|FINE|sun-glassfish-comms-server2.0|javax.enterprise.system.container.sip.smi|_ThreadID=18;_ThreadName=SipContainer-serversWorkerThread-5060-6;ClassName=org.jvnet.glassfish.comms.admin.reporter.SMIBaseReporter;MethodName=log;_RequestID=c88e7c7c-18a1-4632-9994-1e12d6a52d8c;|SMI <--OUT Response 200 (BYE) At: inviteuas/TestSipServlet -->

SIP/2.0 200 OK

From: "sipp";tag=10460SIPpTag001

Cseq: 2 BYE

To: "sailfin";tag=g043761z-1

Server: Glassfish_SIP_2.0.0

Call-Id: 1-10460-AT-127.0.0.1

Via: SIP/2.0/UDP 127.0.0.1:5090;branch=z9hG4bK-10460-1-7

|#]

Tuesday Feb 10, 2009

SIP Extension Headers in SailFin

Interpretation of extension-headers as specified in the RFC 3261 is confusing and the extension-headers may be treated as multi valued or single value based on how implementation choose to implement it.

According to RFC 3261 25.1 Basic Rules:

extension-header = header-name HCOLON header-value
header-name = token
header-value = \*(TEXT-UTF8char / UTF8-CONT / LWS)
message-body = \*OCTET

According to the above grammar, extension-headers (user defined headers), which are also not defined by any known RFCs may be treated as single valued headers but most of the applications use the extension-headers as multi valued headers and that puts the implementors in doubt. If the implementation choose either way, some applications may not behave as they intended. One such example is, should "My-Header : Foo,Bar" be treated as as My-Header having Foo and Bar as values? or what if the user wanted it as as single value "Foo,Bar", where comma is a part of value not a value separator. I have looked for guidance from RFC authors on this issue, but with out success.

Mattias from Ericsson has explained in detail, in his own words

\*\*\*\*
IMHO an implementation that is unaware of the exact (BNF) definition of an extension header cannot know whether a comma in its value is intended as just another byte in the value or as a value separator. Further, it cannot know whether any double-quote character in the value is intended as just another byte in the value or as a quoting character, which could, but does not necessarily, imply that any subsequent comma should be interpreted differently. The same goes for any other character (for example single quote, angle or square brackets, etc) that may or may not be used as a quoting character by the extension. In fact, since it's impossible to know _what_ characters an extension may define for quoting, it's completely impossible to even guess at how to interpret a comma.

In short, an unaware implementation cannot be expected to interpret the values of extension headers. The only safe way to define an API is to treat the rest of the (possibly folded) line as a single value.

This does not imply that multiple values are not possible. For example, an unaware proxy that forwards the header unaltered will of course not know whether there is one or more values, but if the ultimately receiving UA is aware of the extension, it will still correctly interpret the contents as one or more values. The important thing here is for the unaware proxy to forward the header _unaltered_!

I also believe that you are correct in your interpretation of the BNF. From a strict BNF perspective, it indeed allows multiple To, From and other well-known single-value-only headers. To maintain a level of simplicity in the BNF, many such semantic rules are instead defined in the text of the RFC. Thus, the argument that the BNF allows multiple
instances of "extension-header" is worthless. For the record, it would be virtually impossible to define a BNF that allows for an arbitrary number of (different) extension headers but limits the number of each header to one, at least without enumerating all possible extension header names (which, of course, would be an infinitely long list given
that there are no length restrictions on such names). Further, it would be impossible to define it such that some extension headers would be allowed in multiple instances but others would not (which, as we've seen in _actual_ extensions, is a perfectly legitimate requirement). The only reasonable way is to keep the BNF "flexible" in this sense, and, as you point out, define for each extension, as it is defined in its own RFC, whether it's allowed one or more times, and, in the latter case, whether comma separation is allowed.

In conclusion, an unaware implementation cannot possibly know whether to allow an extension header name only once or more than one time, even on separate lines. Again, the only safe bet is to be tolerant and assume that whoever sent the extension knows what they're doing and forward any and all such extension headers, again unaltered (and to make them available on the API, accessible as one header instance per line, with a single value per such instance). It has to be left to a node (another proxy or the ultimate UA) that _is_ aware of the extension to judge whether the occurrence of one or more header instances, on a single line with comma separation or on multiple lines, or indeed on a combination of both, makes the SIP message valid.

On a final note: The above outline allows perfectly well for an application built on top of the unaware API to add awareness of the extension. It will just have to parse each "single" value given from the API according to the specific rules of the extension, to see if that "single" value needs to be "split" into several values. Further, the application may use its extension awareness to judge whether additional values on separate lines are permissible. The application, with its additional extension awareness, can do this but the API implementor/provider could never do it correctly. The API implementation would have to choose either to always split at commas or never to do it, and either to always allow multiple separate lines are never to do it. Regardless of which path is taken, some (possibly not yet defined)
extensions would be handled the wrong way.

Cheers,
Mattias
\*\*\*\*\*\*

By taking the spirit from the above explanation, SailFin treats extension-headers as multi valued headers by default and provides configurable mechanism to specify the headers which should take comma as part of value.
org.glassfish.sip.commaisnotaseperator system property can be specified with header names as a comma separated list. For example -Dorg.glassfish.sip.commaisnotaseperator=Header1,Header2, then Header1 and Header2 are interpreted as single valued headers.

Thursday Nov 20, 2008

Parameterable Headers in SailFin

Headers which have "field-name: field-value \*(;parameter-name=parameter-value)" have a direct support for manipulating headers in JSR 289 and referred as Parameterable Headers. javax.servlet.sip.Parameterable interface defines the contract for Parameterable header, javax.servlet.sip.SipFactory.createParameterable(String) helps in creating a Parameterable and javax.servlet.sip.ServletMessage getters and setters helps in adding and retrieves headers in Parameterable form.

According to the JSR 289, a Parameterable header should be interpreted as "field-value \*(;parameter-name[=parameter-value])"
where the field-value may be in name-addr or addr-spec format as defined in RFC 3261 or may be any sequence of tokens till the first semicolon.

With the above interpretation, almost all the headers would be qualified as Parameterable headers, and there is away to create Parameterable but then there is a restriction while adding the created Parameterable to the message as the JSR 289 disallows any header, whose form is not the form in its BNF.


SipServletMessage.addParameterableHeader(..)
java.lang.IllegalArgumentException - if the specified header is not defined to hold Parameterable values or if the specified header field is a system header

With this the implementation is in a tricky situation and it has to know before hand, what are all the headers which have Parameterable header form, if not for the extension headers, this task is not overly complex. Since some of the extension headers defined by other RFCs might have Parameterable form, there should be a way of extending the list of headers, which takes Parameterable form.

SailFin's Parameterable implementation has been extended so that there is a configurable way of allowing any header to be added to SipServletMessage as a Parameterable. Two system properties which effect this behaviour are:
1) org.glassfish.sip.parameterablecheck : This property can be set to to false to allow any header name to be added to the message as a Parameterable as long as it follows Parameterable's BNF.

Example, the domain.xml:
-Dorg.glassfish.sip.parameterablecheck=false

2) org.glassfish.sip.parameterablelist : This property can be used to specify the explicit list of header names to be considered as Parameterable headers. Union of predefined Parameterable headers as specified in the 4.2.1 of the JSR 289 spec
and this list will be considered as the list of Parameterable headers.

Example, in the domain.xml:
-Dorg.glassfish.sip.parameterablelist=Header1,Header2

We hope, predefined parameterable headers are good enough for most users and where it is not sufficient, above mechanism can be used.

About

bsankararao

Search

Categories
Archives
« July 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
  
       
Today