JINMEI Tatuya / 神明達哉 wrote:

After thinking about it again, I now tend to feel AI_PREFERENCE does
not sound so ad-hoc.  Sine getaddrinfo() is typically expected to
return multiple addresses (of multiple families), ordering among them
is its inherent concern.  So, I think I can live with AI_PREFERENCE
(and the corresponding additional field(s) of addrinfo{}).

ok

I'm not really sure what "to only define a single AI flag", but yes,
I'm still concerned about having separate flags for both PUBLIC and
TMP (and so on).

FWIW I don't understand the first part of that sentence. Missing "means"
before the comma? Or something else?

I've been thinking over it again, and I guess the main concerns are as
follows:

1. having separate flags cause invalid cases and make sanity checks in
   implementations more complex (as I mentioned in the comment
   message).

But for getaddrinfo I think is an inherent issue. For instance, I don't
see how your proposed list of preferences below (in ai_selections) makes
it any easier to detect conflicts; it might actually make it harder for
all I can tell.

2. rephrasing this point differently, these are actually not "flags",
   but multi(more than 2)-value options.  For example, what we are
   going to define with IPV6_PREFER_SRC_HOME and IPV6_PREFER_SRC_COA
   is the source address selection policy from
     - prefer home address
     - prefer care-of-address
     - (perhaps implicitly) use system (or administrator's) default

The 3rd is actually the semantics of "leave unchanged". In the case of
getaddrinfo this would always mean the system default. But in the case
of setsockopt, it would mean to not change the current setting for that
preference on the socket.

   (I admit this might sound just a "philosophical" argument.)

As far as I know, in the traditional API design we have been using a
separate socket option type for each optional notion (in this case the
address selection policy).  Examples include the IPV6_MULTICAST_LOOP
option (while it does not have a specific "use default" value) and the
IPV6_{UNICAST,MULTICAST}_HOPS options (while these have more than two
possible values).

Yes, one can produce a functional setsockopt setting of preferences by
using a separate socket option for each preference.
Thus
        int on = 1;

        setsockopt(s, IPPROTO_IPV6, IPV6_PREFER_COA, &on, sizeof(on));
to prefer CoA over HOA and
        int off = 0;

        setsockopt(s, IPPROTO_IPV6, IPV6_PREFER_COA, &off, sizeof(off));
to turn it off, and likewise for the separate socket options for
IPV6_PREFER_TMP, IPV6_PREFER_CGA, etc.

That would imply a large number of separate socket options.

But the important thing is that such a change could have no impact on
how we specify getaddrinfo(), since there we have to be able to specify
everything in a single call.

I speculate one of the reasons why we've been adhering to the use of
"flags" is because we need to do the similar thing for getaddrinfo()
and the only available field to pass this information was a "flag"
field at that time.  If my understanding is correct, and if we agree
on some (more flexible) extensions to the addrinfo structure, we may
be able to take a different approach.

For example, we'd be able to specify each policy as an integer
encoding a type-value pair, and specify the set of policies as an
array of the pairs.  The following describes one possible
implementation of this idea.

typedef struct {
        u_int32_t policyname : 30;
        u_int32_t policyvalue : 2;
} ai_selection_t;

struct addrinfo {
  int     ai_flags;     /* AI_PASSIVE, AI_CANONNAME,
                           AI_NUMERICHOST, .. */
  (snip)
  ai_selection_t *ai_selection; /* examined only when AI_PREFERENCE is
                                   set and ai_selection is non NULL */
};

An application that prefers care-of-address over home-address would
do:

        struct addrinfo hints;
        ai_selection_t ai_selections[2];

        ai_selections[0].policyname = AI_SELECTION_MIP;
        ai_selections[0].policyvalue = AI_SELECTION_PREFER_COA;

        /* AI_SELECTION_NULL is a terminating marker */
        ai_selections[1].policyname = AI_SELECTION_NULL;
        ai_selections[1].policyvalue = 0;

        hints.ai_flags |= AI_PREFERENCE;
        hints.ai_selection = ai_selections;

How about something like this?  One may regard this as an
overly-generalized solution, but I believe this solves all technical
concerns pointed out so far.

I don't see how this is any simpler. The implementation becomes more
complex because it needs to handle an array of preferences instead of a
single value. And the implementation still need to have checks against
specifying different values for the same preference, doesn't it?
For example, if the application does
        ai_selections[0].policyname = AI_SELECTION_MIP;
        ai_selections[0].policyvalue = AI_SELECTION_PREFER_COA;
        ai_selections[1].policyname = AI_SELECTION_MIP;
        ai_selections[1].policyvalue = AI_SELECTION_PREFER_HOME;
        /* AI_SELECTION_NULL is a terminating marker */
        ai_selections[2].policyname = AI_SELECTION_NULL;
        ai_selections[2].policyvalue = 0;


So I don't see the gain in such added generality over a single
ai_preference field.

And I see a disadvantage in having getaddrinfo preferences and
setsockopt preferences working in a different way, since it is the
application programmer that needs to deal with that.

The simplest approach for the application programmer would be to define
a single name space for IPV6_ADDR_PREFER_*, and use that both in
ai_preferences and with setsockopt. In such a case the application code
would be along the lines of
        int preferences = IPV6_PREFER_COA | IPV6_PREFER_TMP;

        hints.ai_flags |= AI_PREFERENCE;
        hints.ai_preferences = preferences;
        getaddrinfo(...);
        /* Loop over all returned addresses */
        while (ai != NULL) {
                s = socket(ai->ai_family, ...);
                setsockopt(s, IPV^_PREFERENCES, &preferences,
                    sizeof (preferences));
                if (connect(s, ai->ai_addr, ai->ai_addrlen) == -1)
                        continue;
                break;
        }
                

Such code would be more complex for all the other approaches we've
discussed. And the single preference name space would make it easier to
provide a
        int connect_by_name(char *hostname, int port, int preferences);
library function (which would help move the complexity of trying
multiple addresses out of the applications).

   Erik





--------------------------------------------------------------------
IETF IPv6 working group mailing list
[email protected]
Administrative Requests: https://www1.ietf.org/mailman/listinfo/ipv6
--------------------------------------------------------------------

Reply via email to