Hi,

2011/8/27 Peter Saint-Andre <[email protected]>:
> Yes I am reviewing all of the messages about this proposal before
> publishing it as a XEP.

Ok. Good! I saw you indeed changed several parts.
Two remarks:

1/ I still think we should get rid of all the <features/> though,
which can be done only if the client announces from the start it wants
to try a "quickstart" stream negotiation. This is why I proposed in a
previous email that the client would add a dedicated attribute to the
stream hearder:
<stream:stream
    from='[email protected]'
    to='im.example.com'
    version='1.0'
    pipe:pipeline='true'
    xml:lang='en'
    xmlns='jabber:client'
    xmlns:stream='http://etherx.jabber.org/streams'
    xmlns:pipe='urn:xmpp:pipelining:0'>

Basically by starting like this, the client says "I know what you
propose, don't announce your features, let's make this quick!".
So obviously I know that *normally* announcing the features is
mandatory after every feature negotiation. I mean, after all, I was
the one who proposed to make this whole part an automatism in
RFC-6120! But here the goal is like a special "fast" negotiation,
where you take the risk that once in a while (when the server changed
something in its configuration) it may fail and you'll have to retry
"normally", but that most of the time, you will be so faster. Isn't
it? Then in such a case, processing features is just useless and a
waste of time. That's why I think we could really make this case a
special exception with a stream attribute to announce such a special
stream. No?

Also I think this way of doing (announcing you do quickstart with a
<stream/> attribute) is much clearer for the server which otherwise
may not be that sure it is dealing with a client which is actually
doing a real organized "quickstart" methodology or which is just a
little in a hurry, because it has never been said in RFC6120 that 1
TCP packet = 1 command, and TCP provides normally no "notion" of
whether it received X commands in X packets, or less, or even more
(like 1 command broken into several packets). This is normally
supposed to be transparent to the upper protocol.

2/ About caching DNS, I think there is much to say to make it efficient.

Here is how I am caching DNS in my plugin for Wordpress (the whole
caching is still partly implemented, but that's the finale goal):

(1) First you'll want to order/randomize the SRV records according to
the algorithm in RFC-2782 (SRV records).
You need to keep a TTL for the whole caching, which will be the
minimum of all the TTL of each records. I do this because I consider
that if one of the SRV record expires, I may want to check all the
records again. But if the domain has many other valid records in
cache, this may be useless though. This is up to client policy.
Also limit any TTL to a maximal value, as proposed in RFC-1035
(section 7.3 Processing responses). RFC-1035 proposes for instance a
maximum value of 1 week, though this value may be subject to your own
policy as well.

(2) Then for each SRV record that you try, you must query, then cache
the A and AAAA records as well.
Keep their TTL as well with a similar policy as the SRV records.

(3) Finally you have an initial order of caching, but this order might
be reordered while actually trying to connect:

- If for a given SRV record, one or more connections to IPs
corresponding to your list of A/AAAA records fail, move these records
to the end of your list and set the record of the succeeding IP as the
first to try for next time. Then cache the records in this new order.
Hence at each connection, in case of failure, the order of caching may
change (even though you don't do new DNS query as long as the TTL is
not expired).

- If for a given SRV record, all the connection to A/AAAA records
failed, move the SRV record to the end of the SRV cached list.

Example:
** First Connection **

- You do 1 DNS SRV query _xmpp-client._tcp.example.com -> it returns
you X SRV records.
You order them as of RFC-2782.

- For the 1st SRV records only (after ordering), you do A and/or AAAA
query (1 or 2 additional queries, depending of IPv4/6 preference).

- You try to connect to each A/AAAA record in any order, and you move
any record which fails to the end.

- If all the A/AAAA records failed for the 1st SRV, you move this SRV
record to the end of the SRV list, and you query A/AAAA for the 2nd
SRV.

- And so on. You stop at the first successful connection and you cache
the SRV for the main domain and the A/AAAA for each SRV in the current
order.

** Subsequent connections **

- You use cached SRV and cached A/AAAA records and try them in the
same order as you cached them (no reordering at first), *if* their TTL
is not expired. Otherwise, you query the records which are expired.

- If some connection failed again, you may reorder the cached records
and re-cache them in the new order. Otherwise, keep the current cache.

And that's it.
This way, you ensure that the IP you successfully managed to connect
is always the first you try the next time, and the IPs which failed
(hence less reliable) will be tried last. This should hopefully make
next connections faster.
This is at least my current algorithm.

Jehan

> On 8/26/11 6:57 AM, Jehan Pagès wrote:
>> Hi,
>>
>> I wrote 2 unanswered emails about this XEP proposal, one about the
>> fact the quickstart can be improved, hence skipping one step and also
>> sending a lot less unecessary data (basically all the <features/>) in
>> "quickstart mode" as we could consider the initiating entity already
>> "registered" its authentication "path" during a previous connection;
>> and one about stream resumption, which I think is slightly
>> contradictory to XEP-0198.
>>
>> So as I think they may have been "lost" amongst the many emails on the
>> list, I allow myself to up this. :-)
>> Thanks.
>>
>> Jehan
>>
>> 2011/8/13 Jehan Pagès <[email protected]>:
>>> Hi,
>>>
>>> On Thu, Aug 11, 2011 at 10:46 AM, Waqas Hussain <[email protected]> wrote:
>>>> On Thu, Aug 11, 2011 at 2:28 AM, XMPP Extensions Editor <[email protected]> 
>>>> wrote:
>>>>> The XMPP Extensions Editor has received a proposal for a new XEP.
>>>>>
>>>>> Title: XMPP Quickstart
>>>>>
>>>>> Abstract: This document defines methods for speeding the process of 
>>>>> connecting or reconnecting to an XMPP.
>>>>>
>>>>> URL: http://www.xmpp.org/extensions/inbox/quickstart.html
>>>>>
>>>
>>> I find this XEP very interesting. I would typically use this in
>>> "simple" web implementations where I cannot keep a live client
>>> connection, hence do often short connections.
>>>
>>>>> The XMPP Council will decide at its next meeting whether to accept this 
>>>>> proposal as an official XEP.
>>>>>
>>>>>
>>>>
>>>> Example 1 doesn't take things to their logical extreme.
>>>>
>>>> STEP 1 can be merged with the TLS ClientHello message.
>>>> STEP 4 can be merged with the server's TLS Finished message.
>>>> STEP 5 can be merged with the client's TLS Finished message.
>>>> STEP 9 can be merged with STEP 7.
>>>> If the server handles it just right, STEP 8 and 10 could be merged
>>>> into one TCP packet (in response to 7+9).
>>>>
>>>> If you are not negotiating TLS in the middle, you can start a stream,
>>>> do PLAIN or ANONYMOUS login, request roster, set presence, join a
>>>> chatroom, and send messages, all in the first TCP packet. This makes
>>>> legacy SSL somewhat attractive. The same can be done with BOSH, if you
>>>> skip the stream restart on SASL (which virtually all existing clients
>>>> do?).
>>>>
>>>> Moving on...
>>>>
>>>> Does the client even need to pay attention to the pipelining stream
>>>> feature? When connecting to any server, it can first attempt to use
>>>> full pipelining. If that fails, it can simply reconnect without
>>>> pipelining. It can cache the failures. It would need to do this even
>>>> if the server indicates it can support pipelining, as the server may
>>>> be lying/buggy and e.g., might not support merging TLS negotiation and
>>>> XMPP data in the same TCP packet.
>>>>
>>>> Looking at Example 1 closely, the client pipelined <starttls/> before
>>>> looking at the stream feature, so what's the stream feature for? Is
>>>> the client expected to not pipeline unless it has seen the feature in
>>>> a previous connection to the host? Why? Given that the failure case is
>>>> harmless, and that pipelining might work on many existing servers, why
>>>> wouldn't it want to use it on first connect? Would using it violate
>>>> any specification?
>>>
>>> Actually I think it can be very interesting to have done a "normal"
>>> connection first (where you saw that pipelining feature), in order to
>>> further optimize any further connections. Hence the client could
>>> already know what are the features of the server, what will be the one
>>> it will want to negotiate, and in which order.
>>> In particular, you know there is TLS, which SASL mechanism you will
>>> want to use, if there is compression, and if so, which compression
>>> scheme to use, and so on. What we "earn" here is that, first of all,
>>> the server would never have to send its list of features and the
>>> client would thus never have to process it (even if it skips it when
>>> it sees it while pipelining, that's still useless processing in the
>>> "quickstart" use case).
>>> For instance, in the example 1, because you have done once the whole
>>> normal negotiation and you saw that the server supports pipelining,
>>> you cache that next time you will "quickstart" with TLS+SASL
>>> SCRAM-SHA1+bind. So the example could be like this:
>>>
>>> STEP 1: *same*
>>> C: <stream:stream
>>>     from='[email protected]'
>>>     to='im.example.com'
>>>     version='1.0'
>>>     xml:lang='en'
>>>     xmlns='jabber:client'
>>>     xmlns:stream='http://etherx.jabber.org/streams'>
>>>   <starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>
>>>
>>> STEP 2: *no need to send features. That's a lot "thinner" packet!*
>>> S: <proceed xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>
>>>
>>> STEP 3: *same*
>>> [client and server complete TLS negotiation over the existing TCP 
>>> connection]
>>>
>>> STEP 4: *your example was somewhat "bad"! The initiating identity has
>>> to restart the stream, not the receiving one (cf. RFC 6120), though we
>>> could imagine in quickstart, it does not matter much.*
>>> C: <stream:stream
>>>     from='[email protected]'
>>>     to='im.example.com'
>>>     version='1.0'
>>>     xml:lang='en'
>>>     xmlns='jabber:client'
>>>     xmlns:stream='http://etherx.jabber.org/streams'>
>>>   <auth xmlns="urn:ietf:params:xml:ns:xmpp-sasl"
>>>         mechanism="SCRAM-SHA-1">
>>> biwsbj1qdWxpZXQscj1vTXNUQUF3QUFBQU1BQUFBTlAwVEFBQUFBQUJQVTBBQQ==
>>>   </auth>
>>>
>>> STEP 5: *server restarts as well and directly responds the SASL auth,
>>> no features!*
>>> S: <stream:stream
>>>     from='im.example.com'
>>>     id='vgKi/bkYME8OAj4rlXMkpucAqe4='
>>>     to='[email protected]'
>>>     version='1.0'
>>>     xml:lang='en'
>>>     xmlns='jabber:client'
>>>     xmlns:stream='http://etherx.jabber.org/streams'>
>>> <challenge xmlns="urn:ietf:params:xml:ns:xmpp-sasl">
>>>     cj1vTXNUQUF3QUFBQU1BQUFBTlAwVEFBQUFBQUJQVTBBQWUxMjQ2OTViLTY5Y
>>>     TktNGRlNi05YzMwLWI1MWIzODA4YzU5ZSxzPU5qaGtZVE0wTURndE5HWTBaaT
>>>     AwTmpkbUxUa3hNbVV0TkRsbU5UTm1ORE5rTURNeixpPTQwOTY=
>>>   </challenge>
>>>
>>> STEP 6:
>>> C: <response xmlns="urn:ietf:params:xml:ns:xmpp-sasl">
>>>     Yz1iaXdzLHI9b01zVEFBd0FBQUFNQUFBQU5QMFRBQUFBQUFCUFUwQUFlMTI0N
>>>     jk1Yi02OWE5LTRkZTYtOWMzMC1iNTFiMzgwOGM1OWUscD1VQTU3dE0vU3ZwQV
>>>     RCa0gyRlhzMFdEWHZKWXc9
>>>   </response>
>>>
>>> STEP 7: *ok here the server could restart the stream because it knows
>>> first the success of the negotiation (but it does not change much. It
>>> could restart its side at step 9). Still no features sent!*
>>> S: <success xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>
>>>     dj1wTk5ERlZFUXh1WHhDb1NFaVc4R0VaKzFSU289
>>>   </success>
>>>   <stream:stream
>>>     from='im.example.com'
>>>     id='gPybzaOzBmaADgxKXu9UClbprp0='
>>>     to='[email protected]'
>>>     version='1.0'
>>>     xml:lang='en'
>>>     xmlns='jabber:client'
>>>     xmlns:stream='http://etherx.jabber.org/streams'>
>>>
>>> STEP 8:
>>> C: <stream:stream
>>>     from='[email protected]'
>>>     to='im.example.com'
>>>     version='1.0'
>>>     xml:lang='en'
>>>     xmlns='jabber:client'
>>>     xmlns:stream='http://etherx.jabber.org/streams'>
>>>   <iq id='yhc13a95' type='set'>
>>>     <bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'>
>>>       <resource>balcony</resource>
>>>     </bind>
>>>   </iq>
>>>
>>> STEP 9:
>>> S: <iq id='yhc13a95' type='result'>
>>>     <bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'>
>>>       <jid>
>>>         [email protected]/balcony
>>>       </jid>
>>>     </bind>
>>>   </iq>
>>>
>>> So here we have 1 step less and in particular, the server never sends
>>> any features, which spare some useless data processing on both side.
>>>
>>> NOTE: actually if the client is *sure* the authentication will work,
>>> it can merge steps 6 and 8. As a consequence, the server can merge 7
>>> and 9, saving, in all, 2 additional round trips! The whole process
>>> would be only 7 roundtrips. Of course the downside of this is that a
>>> failed authentication cannot be saved (as you already sent "wrongly"
>>> the restarted stream headers, which would hence make a stream error,
>>> and a stream must re-negotiated from the start). I would say that
>>> could be 2 cases:
>>> 1/ if the client is user-driven, then you might want to do the 9-steps
>>> process. Indeed in case of auth-error, you might want to pop-up the
>>> user and ask him to type again its password to retry authentication
>>> without having to redo the whole negotiation.
>>> 2/ if the client is a bot, you can just imagine that a failed
>>> negotiation has no solution right now. So you do the 7-steps process
>>> by assuming it will go all right.
>>>
>>> So I guess you provided the stream features here because RFC-6120
>>> writes that the receiving entity MUST send a <features/>. But as we
>>> are in a special case of quickstart stream, we could imagine new
>>> characteristics, couldn't we?
>>>
>>> Actually I think the more logical would be to have a dedicated stream
>>> attribute prefixed by the pipelining namespace. Then if the client
>>> wants to pipeline, it adds this attribute to its initial stream
>>> header:
>>> <stream:stream
>>>     from='[email protected]'
>>>     to='im.example.com'
>>>     version='1.0'
>>>     pipe:pipeline='true'
>>>     xml:lang='en'
>>>     xmlns='jabber:client'
>>>     xmlns:stream='http://etherx.jabber.org/streams'
>>>     xmlns:pipe='urn:xmpp:pipelining:0'>
>>>
>>> Then the server knows for sure it is in "pipeline" mode and does not
>>> need to send any features, hence saving many roundtrips (up to 9 steps
>>> in our example!) and much processing of features. In any other case,
>>> the server can "guess" the client is trying to pipeline (by checking
>>> how many "commands" are in the single first TCP packet), but that
>>> implies first to check at the lower (TCP) level (which I don't find
>>> nice here), and second it implies that 2 commands in a single TCP
>>> packet are necessarily an attempt to pipeline while nothing forbids an
>>> entity to have several commands in a single packet, or at the opposite
>>> "break" into several packets (that's how TCP works after all). So as
>>> this is in fact not necessarily true, that makes pipelining either
>>> limited or unreliable. With an additional stream attribute here, we
>>> make this reliable, hence we allow additional optimizations (like
>>> removing all the <features/>).
>>>
>>> What do you think? This way, I think this would make such a feature
>>> extremely more interesting.
>>>
>>> Jehan
>>>
>
>
> --
> Peter Saint-Andre
> https://stpeter.im/
>
>
>

Reply via email to