Subject: [Tsvwg] sctp_bindx to port 0 needs clarification in sctpsocket

From: "Thomas Steffen" <[email-masked]>
Date: Tue, 13 Jun 2006 15:41:26 +0200

Hi

I found a problem with the SCTP Socket API as defined in
http://www.ietf.org/internet-drafts/draft-ietf-tsvwg-sctpsocket-13.txt.
I try to:

1. open a new SCTP socket (socket)
2. bind it to the local primary IP address, but not to a port (bind)
3. bind it to a local alternative IP address (sctp_bindx)
4. connect to a remove destination

Step 3 fails, because sctp_bindx() does not seem to like the wildcard
port number 0. Since I could verify this behaviour on two
implementations (Linux 2.6 and Solaris 10), I had a look at the API
specification. It seems to be not clear enough on this case.

In Section 8.1 on sctp_bindx, it says:

> Note that the wildcard addresses cannot be used with this function, doing so will result in an error.

(you could try to interpret port 0 as a "wildcard address"), but also

> For SCTP, the port given in each socket address must be the same, or sctp_bindx() will fail, setting errno to EINVAL.

(which could be interpreted to mean that port 0 is ok, as long as it
is used consistently).

I am not the first person to encounter this problem, and the typical
work around seems to be the use of getsockname():

...
   sin.sin_addr = <first IP>;
   sin.sin_port = htons(0);
   bind(fd, (struct sockaddr*)&sin, sizeof(sin));
   getsockname(fd, &sin, &sin_len); /* this sets sin.sin_port */
   sin.sin_addr = <second IP>;
   sctp_bindx(fd, (struct sockaddr*)&sin, 1, SCTP_BINDX_ADD_ADDR);
...

However, this is not intuitive. A strict interpretation of the
specification might even refuse the port number, because it differs
from the initial port number.

So I would like to see a statement added to the document that
explicitly states port 0 as a valid argument to sctp_bindx(), as long
as bind() had this port number. For convenience it might even be nice
to accept a port number of 0 unconditionally.

I also noticed that the relation between bind() and sctp_bindx() seem
to be not quite a explicit as could be hoped. On Linux 2.6,
sctp_bindx() can be used without bind(), but on Solaris 10 that fails.
In the interest of compatibility, it might be nice to specify one of
the two behaviours as standard.

I intend to submit a patch to the Linux lksctp project to rectify the
problem in the way outlined above, and I can also file a bug with
Solaris 10.

Thomas

---

From: Peter Lei <[email-masked]>
Date: Tue, 13 Jun 2006 10:10:39 -0500

> (you could try to interpret port 0 as a "wildcard address"), but also

No, these are different.

Binding port 0 means bind an ephemeral port where the OS provides
the port number.

Binding wildcard address 0 means bind all local IP addresses to this
socket.

If you have bound all addresses to the socket, binding the wildcard
address with an ADD or DELETE parameter should return an error
because you cannot add or delete addresses to that socket.

>> For SCTP, the port given in each socket address must be the same, or 
>> sctp_bindx() will fail, setting errno to EINVAL.
> 
> 

No, because as soon as you do the first bind, a ephemeral port
number has been assigned by the OS.  You should use that new
port number in future bindx() calls.

> to accept a port number of 0 unconditionally.

I disagree.  Port 0 does already have specific semantics as an
ephemeral port.  Note that similar code to the above is also
necessary in any TCP application that say wants to pass it's
local port number to the peer... If you require the local port
number after a bind to port 0, then using getsockname is the
socket API way to get the local port.

> the two behaviours as standard.

I agree, we may need to clarify the text here as the existing
text only makes reference to using bindx() after a bind() call.

thanks,
--peter

---

From: Randall Stewart <[email-masked]>
Date: Tue, 13 Jun 2006 17:34:46 -0400

Thomas:

I have to agree 100% with Peter here.. and we will need
to touch up the wording to make it clear..

Port 0 has specific symantics that have ALWAYS been in
the socket-api.. If you use Port 0 with a bind.. you end
up getting a ephemiral port.. this then is the port you
would need to use with subsequent bindx calls. Of course
TCP does not have such a thing as bindx.. so we need
to be a bit more explicit in the wording I think :-D

R

-- 
Randall Stewart
803-345-0369 <or> 815-342-5222(cell)

---

From: "Sridhar Samudrala" <[email-masked]>
Date: Tue, 13 Jun 2006 23:09:50 -0700

> to be a bit more explicit in the wording I think :-D

Specifically because TCP doesn't have bindx() and this is
a new API, we could define the behavior that makes it easy
for SCTP apps.
So bindx() with 0 port could mean
- the stack will assign an an ephemeral port if it is not bound  or
- use the port that the socket is already bound to.

With this semantics, suppose you want to bind 2 addresses,
you will be able to do
     bindx(addr1, addr2, 0)
or
     bind(addr1)
     bindx(addr2, 0)

Thanks
Sridhar

---

From: "Thomas Steffen" <[email-masked]>
Date: Wed, 14 Jun 2006 09:08:11 +0200

> With this semantics, suppose you want to bind 2 addresses,

Thanks, Sridhar. This is exactly what I mean. I know that port 0 has a
special semantics, but I would like to have it as consistently as
possible.

In my project, I have a function that binds an SCTP socket to the
configured interfaces and a port number given as a function argument.
I would expect that I can just write:

    inet_pton(AF_INET, ip1, &sin.sin_addr);
    sin.sin_port = ntohs(port);
    bind(fd, (struct sockaddr*)&sin, sizeof(sin));
    inet_pton(AF_INET, ip2, &sin.sin_addr);
    sctp_bindx(fd, (struct sockaddr*)&sin, 1, SCTP_BINDX_ADD_ADDR);

But this is not possible, because bind() does interpret 0 as an
ephemeral port, and sctp_bindx() does not. Instead I have to code a
special code path for port 0.

I think this is a pretty normal situation, given the following assumptions:

 * multihoming is essential
 * binding to IPADDR_ANY is not acceptable
 * an ephemeral port is used for performance reasons

and the piece of code given above seems to be the intuitive solution.
Using getsockname() would break the flow (but it is currently
necessary).

Thomas

---

From: "Brian F. G. Bidulock" <[email-masked]>
Date: Wed, 14 Jun 2006 02:41:48 -0600

Thomas,

Thomas Steffen wrote:                       (Wed, 14 Jun 2006 09:08:11)
>     bind(fd, (struct sockaddr*)&sin, sizeof(sin));
      getsockname(fd, (struct sockaddr *)&sin, sizeof(sin));
> special code path for port 0.

Well, no you don't need a special code path for port 0: calling
getsockname() will always return the assigned port, whether 0
was issued to bind() or not (see above).

You are arguing over 1 line of code?

-- 
Brian F. G. Bidulock
[email-masked]
http://www.openss7.org/

---

From: "Thomas Steffen" <[email-masked]>
Date: Thu, 15 Jun 2006 16:42:09 +0200

> was issued to bind() or not (see above).

You are right, I can use the same code in all cases. So I still think
it is inconvenient, but it does not seem to bad, as long as the
documentation is updated to be conclusive on this issue.

Thomas

---

From: Randall Stewart <[email-masked]>
Date: Thu, 15 Jun 2006 22:58:06 -0400

> documentation is updated to be conclusive on this issue.
I am no API expert.. by any means.. but usually
having something mean two things is not very desireable..

So if I do

sctp_bindx(...);

with port=0...

If its the first call and no bind() as been done I get
one set of behavior..

And if its a subsequent call.. I get a different behavior... aka
use the port I already have...

This is really a bit inconsistent..  Its easy to implement
but is it the right thing... I am adding Kacheong.. to wake him
up from his sleepy observing of this list :-D

Phil Conrad.. who I don't know if he still listens to this
list.. and is probably on summer vacation.. but is very very
good with API's and such (having to teach them all the time
to new students)...

And also Paul Amer.. who is often in the same boat :-D

Comments please???

For those not following and to be clear... the proposal is to have
a sctp_bindx() have two meanings for port=0

1) If its the first call to sctp_bindx() and no other bind() call
    has been done, it means .. please pick an ephemeral port.

or

2) If its NOT the first call.. and a port has been picked it means
    please use the port I have been assigned (or previously bound).

R

R

---

From: Vlad Yasevich <[email-masked]>
Date: Mon, 19 Jun 2006 13:33:38 -0400

Hi Randy

>     please use the port I have been assigned (or previously bound).

Originally I didn't have a problem with this, especially since
implementing this is so easy.  After thinking some more about this
issue, there are are some interesting permutations that get introduced
that make the matter more complicated.

First, a question I am not sure about is if standalone sctp_bindx(),
without a prior bind(), should be allowed.  This needs to be clarified.
This would also clarify if the lone sctp_bindx() will all ports set 0
should work or not.

Secondly, if sctp_bindx() not the first call, then port 0 stops being
ephemeral, especially if the first bind() explicitly set a port.   That
changes the whole meaning of port 0, and I am not sure I like it.

-vlad

---

From: "Thomas Steffen" <[email-masked]>
Date: Mon, 19 Jun 2006 20:06:16 +0200

> This would also clarify if the lone sctp_bindx() will all ports set 0

Yes, this is an interesting question for this problem. On Linux it
works, on Solaris it does not (unless I made mistake in testing). So
my code does bind() first, then getsockname(), and then I loop over
sctp_bindx() with the remaining addresses.

Having just sctp_bindx() would make the code a lot shorter, easier and
clearer. I guess the same would be true for a lot of other user code
that uses SCTP.

If sctp_bindx() can only be used after bind(), I wonder why
sctp_bindx() requires a port at all.  There is no obvious need for it.

> changes the whole meaning of port 0, and I am not sure I like it.

The following argument is not very stringent, but I want to show that
there are two perspectives:

On the implementation side I agree. 0 means ephemeral port for the
first call, and every implementation already has the logic to
distinguish the first port from any later port number.

On the (API) user side, I usually read port 0 as "don't care". In many
cases (before connect) the user does not care which port is used, and
whether it is the same for all addresses (which it is of course). In
this light, the first and the second port 0 have the same meaning.

Thomas

---

From: Vlad Yasevich <[email-masked]>
Date: Mon, 19 Jun 2006 15:14:26 -0400

> distinguish the first port from any later port number.

But this proposal can potentially change this.  Should an sctp_bindx()
with all first port set and the rest 0 be allowed? 

> this light, the first and the second port 0 have the same meaning.

Well, with all the attacks on port space, this now is starting to mean
"pick something for me that's not easily guessed".  With that semantic,
what does it mean when application explicitly binds to a port, and then
uses 0 with sctp_bindx()?  Is it saying pick something for me, or I
"don't care, use what I have"?

This is what concerns me.

-vlad

---

From: Randall Stewart <[email-masked]>
Date: Thu, 22 Jun 2006 11:41:42 -0400

> sctp_bindx() with the remaining addresses.

And on BSD sctp_bindx() by itself also works :-D

I seem to remember Michael Tuexen and I having an discussion
about this and I can't remember what the outcome was (except
for me implementing the ability to bindx as the first
bind... BSD used to be like solaris :-0)

> sctp_bindx() requires a port at all.  There is no obvious need for it.
Yes.. this would be true.. other than the fact that the
socket address structure just happens to have a sin_port
or sin6_port in it :-D

R