Subject: [SIP] Re: JAIN SIP Comments

From: Chris Harris <[email-masked]>
Date: Wed, 18 Oct 2000 15:02:53 +0100

Hi Billy,

Responses below in blue...

Chris

Billy Biggs wrote:

>   Hi,
>
>   I wondered why I still had no response to this message, when I
> realized that it never got sent! :)
> ==
>
>   Chris,
>
> > > [...]  Probably the largest part of the design that really shocked
> > > me was the extensive amount of parsing that the library seems to
> > > imply. [...]
> >
> > The first and foremost aim of the JAIN SIP API is application
> > portability.  It seems you are suggesting that a header value should
> > be simply defined as a String. This approach was considered to be
> > unacceptable by the expert group because allowing the API user to put
> > any String into a header seriously increases the risk of incorrect use
> > of the API, and applications which are not portable.
>
>   Now that I read over the API again, it doesn't seem so bad.  But
> still, I'm surprised you'd have such a comprehensive object to represent
> the User-Agent and Server headers, including the product name and
> version as separate values?  It seems that a straightforward
> implementation might end up having to parse alot more than it needs to.

That's a fair point - the API does assume that an implementation needs to parse
in as much detatil as the ABNF. The question is - where to draw the line. Some
headers will have a value that can reasonably represented by a String value, and
others will not. I suppose UserAgentHeader and ServerHeader could just have a
"Product" string value.

>
>
>   The same is true of the call-id.  Why bother having a method to
> extract the host portion of the call-id?  It's unlikely this will be
> required separately, and implementations are supposed to treat the
> call-id as an opaque string anyways.

Indeed CallIdHeader could uses a String value too. I am considering removing the
Challenge and Credential classes and replacing them in the
authenticate/authorization headers with just a scheme String and a
challenge/credentials String (or Parameters object mentioned below?). This will
mean the implementation won't have to understand the schemes. What do you think?

>
>
>   One thing I noticed was that the object hierarchy does not take into
> account the contents of the headers but rather the structure of a
> message.

I have removed GeneralHeader, EntityHeader, RequestHeader and ResponseHeader -
removing a layer in the header hierarchy. Now the API just relies on a header
type parameter to the Header constructor.

>
>
>   For example, there isn't much difference at all between the Contact,
> Record-Route, Route, and even the To and From in a SIP message.  Each of
> these contains a NameAddress along with some header parameters.  Why not
> have them inherit from a common base class?  I guess you're trying to
> just make the object as generic as possible without enforcing an object
> model on the stack behind it, but still, why not make a parametered uri
> object to represent this?

I have created a NameAddressParameters class - which is composed of a
NameAddress and a Hashtable for parameters (get, set, has and remove methods are
included for parameters). I have also created a NameAddressHeader base class for
all the headers you mention above - so the generic parameter and NameAddress
methods are avilable to all subclasses - FromHeader, ToHeader, ContactHeader,
RecordRouteHeader and RouteHeader.

>
>   Why have both a ToHeader and a FromHeader object if they're exactly
> the same?

I could add a superclass for these two classes - with the classes only differing
in option tag. Can you think of an appropriate name for such a class?

>
>
>   Also, it's interesting to see how you have a ContentTypeHeader object
> instead of a more general MimeContentType object.  It seems to me that
> something so generic should be outside of the scope of a SIP stack.
>
>   The last object I'd think would be useful would be some sort of
> ParameterList object.  It would help to avoid problems like your
> ViaHeader object, which is missing calls to set or retrieve extension
> parameters.

This is so obvious it was bound to be be overlooked :) This Parameters object
could be used in SipURL and Header class - making NameAddressParameters class
obsolete. I'm just thinking about parameters for the encryption and response key
headers - they use a comma as a delimiter not a semi-colon and need a space
before them - should they be treated independently, or should the Parameters
object know which delimiter type it uses and whether it needs spaces in front?
Also the via header allows a comment between via params and extension params -
so should the ViaHeader class have another Parameters object specifically for
via params? Wouldn't SIP have been so much easier if the parameters all used the
same syntax? :)

>
>
> > >   Also, the Header object should really contain the concept of a list of
> > > headers. [...]
> >
> > It was decided that the API would be simpler if we did not allow a
> > Header to include a list. We adopted the canonical form here, so if a
> > header list is received by the implementation, it simply creates a
> > list of Header objects and adds them to the Message in the same order
> > - which is semantically equivalent.
>
>   Yes, now that I look at the API again, I see how you have a
> getHeaders() call which handles stuff very nicely.
>
>   Another thing I'm concerned about is how only a string key is passed
> in to unencrypt a message.  Is this sufficient?  As well, how do you
> check if a message is encrypted: if it has an encryption header?

I am beginning to think that the decryptMessage and encryptMessage methods are a
bad idea - Is it really fair to expect an implementation to handle this?

>
>
> > >   There also seems to be some confusion in the API about SIP calls
> > > and the scope of a call-id.  [...]
> > >
> > >   This confusion is completely rampant through the entire
> > > documentation as well.  For example, call-leg-ends and Call-IDs
> > > are confused in the description of an InviteMessage.
> >
> > This is absolutely true - The method for getting CSeq numbers should
> > take a from and a to parameter as well as the CallIdHeader. (It would
> > also be more convenient if the method returned a CSeqHeader rather
> > than just a CSeq number.)
>
>   Careful though.  I'd argue: why have a CSeq header object at all?  It
> seems like you're letting the user have alot of power, being able to put
> mis-matching methods in the CSeq and in the start line.  If you're
> worried about having a safe API this seems surprising.  Why not just be
> able to get and set the sequence numbers on messages?

I could do that - but remeber there's nothing stopping the user adding a CSeq
header via the Header class. I think if it is made clear in the API
documentation that CSeqHeaders must be generated through the Provider, and that
if the method is incorrect the Provider will fix it to match the Message method
it should be OK?

>
>
>   Also regarding call-leg end matching, I'm confused about how you
> intend to keep things straight between which call-leg end you're talking
> about in communication with the stack.
>
>   For example, let's say I send an Invite request and I receive four 200
> OK response, creating four active calls.  I accept all of them, and then
> later I want to disconnect one of them.
>
>   If I call sendBye( listener, originalinvite ), what happens?  This
> seems odd.

The Provider will send BYEs to all call legs

>
>
>   If I call sendBye( listener, one_of_the_responses ), is the provider
> supposed to keep track of the sequence numbers for that call-leg to know
> which one to use?

The Provider will send BYE to call leg response corresponds to

>
>
>   I guess I'm really asking, if you're asking the provider to keep track
> of the call-legs, provide the necessary calls to query and see which are
> active, and perform operations on the legs directly, not through
> inference by what messages get passed in from the calling code.  If you
> let the user send create messages from scratch and send them out, and
> reply to messages using responses they created, then it means that you
> have both layers struggling to keep track of all active legs, without
> any common method of referencing them.

I could create a CallLeg object comprised of a CallIdHeader, FromHeader and
ToHeader, and have a method: public CallLeg[] getCallLegs(CallIdHeader
callIdHeader) on the Provider, and also a method: public sendBye(CallLeg
callLeg) throws SipException - but won't this imply that the implementation has
to maintain call state?

>
>
>   Another suggestion: when talking about call-legs, it's probably best
> to have a concept of the near-end and far-end URIs, since you end up
> having to flip the To and the From when you send local requests to
> remote calls etc.  Otherwise, things just get really confusing,
> especially when you try and call yourself.

I'm not quite sure what you mean by this - what is a near and far URI if you not
the UAC or UAS - i.e. a proxy in the middle?

>
>
> --
> Billy Biggs, 3Com               Email: [email-masked]
> http://www.div8.net/billy/      Phone: [email-masked]

---

From: Gethin Liddell <[email-masked]>
Date: Wed, 18 Oct 2000 15:15:01 +0100

> mean the implementation won't have to understand the schemes. What do you think?

Will this work for WWWAuthentication and the other multi valued
authentication headers?  Unfortunately the challenge and credential
values use a `,' separated parameter list so if two different values are
in the same header there will be no way of knowing where the first
stops and the second starts.  So any implemenetation will have to know
and understand the different schemes.

> in option tag. Can you think of an appropriate name for such a class?

I'm a bit concerened that we are going down the path here of specifying
an implementation as opposed to an API.  Is it not acceptable to define
that the To and From headers have certain methods, even if they are
actually provided by some common base class?

Don't forget, the API is supposed to be a thin wrapper around existing
implmentations and not a re-write.

> via params? Wouldn't SIP have been so much easier if the parameters all used the

Absolutely!!!!!! Unfortunately, the authentication is just grabbed
from the HTTP spec with no modifications so we're just lumbered with it.
However, the questions you ask here again, i feel are getting far too
implementation specific.  I think that the access to the parameters
should remiain solely in the form of access calls to the header.  So to
grab future parameters, we just need a 

"public String getParameter(String paramName)"

method.  In fact I see no need for a getTag(), getTTL() etc... would
the getParameter(String) not suffice.  And i definitely do not think we
should be throwing Eexceptions if a getParameter() is made and it does
not exist.  just return null.  IMHO it is a lot more elegant than
having a lot of try catchs everywhere and more efficient as no Exception
classes have to be created.  Also is there a real need for hasBranch()?
just check for null.  It is easy enough and perfectly acceptable and
cuts down drastically on the number of methods.  in fact taking via as
an example, we could cut the number of methods by 19 if we got rid of
all the remove methods as well.

So could we not replace all the getPARAMETER() with a single
getParameter(String name), all the hasPARAMETER() with the fact that
null defines no parameter exists and the removePARAMETER() with a
setPARAMETER(null) (although i accept this last suggestion may be a
little off the wall)

I'm also tempted to get rid off all the setPARAMETER(String) methods
and replace with a single setParameter(String name, String value)
although i can't find an acceptable way to enforce type checking.

Talking of which, how is type checking handled when read from the
network?  What if we receive a message with an invalid Authentication
header for example?  How is the stack supposed to relay that
information back to the user when they ask for the Authentication
header?

Going onto another topic, I really, really, don't think it is a good
idea to use InetAddress within the parsing of the message.

Take the SipURL object, it has a "public InetAddress getHost()" method.
This seems a bit bizarre to me as creating an InetAddress forces the
JVM to do a DNS lookup.  So if say we have a proxy that is using this
stack and it recieves a request-uri with an address sip:[email-masked]
then just trying to get at the host will cause a blocking dns lookup.
The proxy may well have its own asynchronous dns solution and never use
InetAddress until it has obtained an IPAddress itself.  So using
InetAddress seriously hampers the performance of the proxy.

Also it may be the case that host.com is not actually a valid
resolvable domain but is really intended to mean something to the proxy
server to force some action.  If it fails with an UnknownHostException
what then?

I think InetAddress should be removed from all getXXX() methods, eg.
Via - getMAddr() getHost() getReceived().  Using it to set say the
SipUrl in the To is valid but should not be the only constructor.  We
need a SipURL(String name, String host) constructor.

-- 
Gethin Liddell
Ubiquity Software Corporation

http://www.ubiquity.net
mailto:[email-masked]

_______________________________________________
SIP mailing list
[email-masked]
http://lists.bell-labs.com/mailman/listinfo/sip