[Standards-JIG] rfc3920bis: Stanza Acknowledgements

Justin Karneges justin-keyword-jabber.093179 at affinix.com
Mon Nov 6 22:50:59 UTC 2006


On Monday 06 November 2006 8:41 am, Dave Cridland wrote:
> On Sun Nov  5 02:12:41 2006, Justin Karneges wrote:
> > When an initiating entity activates the acknowledgement feature
> > with a
> > receiving entity, the steps involved are as follows:
>
> I'd be tempted to seperate out initial connection from reconnection,
> here.

How so?

> Bruce Fitzsimmons's comments make it clear that a sender might want
> to send unacked stanzas anyway, here, in order to reduce the
> round-trip count, and have the receiver drop duplicates. This is
> quite reasonable on some links - it's a trade-off of round-trips to
> latency, however I think it only works when all stanzas have a 'c'
> attribute. (Although I freely admit to not having thought of this
> before, and not having thought it through).

I don't follow this.  How does it reduce round-trips?

In both cases of session resumption, you need a sequence number.  Either you 
know the last number you got, and you ignore any re-sent stanzas with a lower 
number, or you tell the peer the last number you got, and then the peer won't 
send the lower numbered stanzas at all.

Now, one possible advantage of the first way is that stanzas won't be lost if 
the client doesn't have the previous sequencing state (for example, if the 
client lost the information or if the user logged in from a different 
machine).  However, the server could also be clever here, and re-send 
un-acked stanzas if the client doesn't resume a session.  If the client does 
resume a session, then it knows the sequence number, the server knows the 
sequence number, and there's no need to do any pointless re-sends.

> Finally, the server might not realize the client's been disconnected
> before it reconnects. What needs to happen here is that the server
> essentially replays unacked stanzas and ditches the old session, but
> I've yet to remind myself what RFC3920 says about that.

Technically, the old session wouldn't go away until the client binds to the 
same resource as before (this is pretty standard XMPP/Jabber behavior, as far 
as I know).  However, I think if a session is being resumed, the server 
should get rid of the old one immediately.  No sense it it lingering around, 
especially if the client binds to a different resource than before.

> I would state that the value of "c" MUST be strictly increasing (not
> "monotonically increasing", that means "strictly non-decreasing",
> which'd be bad). I can't see any use-case for anything else.

Bruce mentioned this as well, but I don't understand why it needs to be 
specified.  Couldn't I even say that the value is an opaque string to the 
receiver?  To the receiver, it doesn't matter that it is a number.  It is 
just a cookie for the sender to read during a resume.

> Furthermore, I would state that any stanza with an "r" attribute MUST
> have a "c" attribute - see below for why.

Following the trail...

> Okay, here I diverge more... I would say that a receiver MAY send an
> ack even if not requested, if it is also sending other stanzas. I'm
> not wedded to this by any means, but it might be nice. The intention
> here is to allow a receiver to plonk an <a/> onto the end of a packet
> if it's sending.

This didn't make any sense at all, until I read the rest of your message. :)

> Acks SHOULD be sent in a timely manner, however receivers MAY delay
> sending an ack for a short period in order to increase efficiency.
> Receivers MUST NOT delay sending an ack for more than 15 seconds,
> allowing the requesting peer to timeout the connection after 30
> seconds.
>
> Rationale is that you want mandatory timeouts here, and I too was a
> little confused by what you meant there. Feel free to adjust the
> mandatory timeout figures. The idea is that a client gets to be
> assured that if it asks for an ack, if it hasn't had one for 30
> seconds (in this case) the connection is dead.

Do we want mandatory timeouts?  Classic Jabber "karma" throttling could last 
more than 30 seconds.  I was planning to leave timeouts out of the ack 
picture.  If it takes 10 minutes for the server to ack, then you wait 10 
minutes for it.

This is why my original Ack proposal has both acking and pinging, with 
different purposes.  The idea is that pings should be responded to 
immediately, as they are used to determine if the connection is alive.  Acks, 
by contrast, are not used to detect if the connection is alive.  They are 
only used to tell you if a stanza has been "accepted".  Indeed, you could 
send a stanza, send a ping, receive a pong, and then wait a minute before you 
get an ack.  While the pong would indicate your TCP connection is running, 
and all data prior to, and including, the ping was received by the other 
side, it wouldn't mean the stanza was "accepted" yet.  The specific problem 
I'm addressing in this explanation is server karma/throttling.

> Finally, I'd add in a mandatory prevc attribute in the <a/> element,
> to match the mandatory 'c' attribute in an 'r'-enabled stanza. This
> does mean that stanzas MUST be accepted in sequence, which I don't
> think is unreasonable. In turn, this renders the 'n' attribute
> obsolete.

Again, this makes no sense at first, but when I read the rest of your message, 
it will make sense. :)  You are almost subliminally creating a protocol here, 
as you go.

> 1) A 'c' or 'r' attribute only makes sense on the last stanza in a
> TCP packet. In general, any time you write any stanzas, you may well
> only care about 'c'/'r' attributes on the last one.

Agreed.

> 2) We need some mechanism for obtaining an ack when we've nothing to
> send. You could, of course, send an unrequested ack here, with 'c'
> and 'r' attributes.

We don't need this to solve a stanza-loss problem.

Acking when there are no outstanding stanzas would just be a form of pinging, 
and pings (when we already have stanza acks) would only be useful if we want 
to end a TCP connection early (e.g. before the natural OS retransmission 
timeout) or do a latency diagnostic or something.

That said, I'm not opposed to having a "free" ping (as you say below), if it 
works out that way.  Actually I'm not even opposed to having a non-free 
ping. :)  I just see acking and pings as solving separate problems.  There 
can be overlap, of course, depending on what meanings you give to the two.

> 3) But given (1) and (2), that implies that we could stick all the
> 'c' and 'r' attributes onto only the <a/>, and append an <a/> to
> flushes to indicate synch points and request acks.
>
> Point (3) is interesting, because it avoids servers having to rewrite
> stanzas (which was complained about, IIRC), *and* gives you a free
> hop-to-hop ping. So maybe that's worth discussing too.

You essentially mean this:

C: <message/>
C: <message/>
C: <message/>
C: <ping/>
S: <pong/>
[all 3 messages are now "acked"]

If we forget about "acceptance" for a moment, at least in terms of 
karma/throttling, and we simply want to know if data has reached the remote 
application, then a ping can double as an ack.

So you want to go beyond this, and add sequence numbers into the pings, so 
that they act as "sync points".

C: <message/>
C: <message/>
C: <message/>
C: <ping c='1'/>
[session tagged up to this point, can be resumed later.  no pong.]

And required pongs would still be useful:

C: <message/>
C: <message/>
C: <message/>
C: <ping r='true'/>
S: <pong/>
[all 3 messages are now acked]

Basically, this just means moving the attributes from the stanza and into an 
element at the end.  Now, pings aren't really the right word for what we're 
doing, especially since 'r' is optional.

So let's rename them, but stay with two elements (request and response).  If 
we have two elements, then we don't have to use 'prevc' anywhere.

C: <message/>
C: <message/>
C: <message/>
C: <r/> (request ack)
S: <a/> (ack)
[request ack, and ack]

C: <message/>
C: <message/>
C: <message/>
C: <a c='1'/>
["gratuitous ack", to indicate a sync point]

Now, if we DO provide a 'prevc', and have just one kind of element, then we 
can get some of the benefits of acks, without having to do any round-trips.  
Ack replies would simply be sent the next time there is other data to send 
along with it.  In keeping with the single-letter convention, I'll 
call 'prevc' as 'b', but whatever. :)

C: <message/>
C: <a c='1'/>
[...time passes...]
S: <message/>
S: <a c='1' b='1'/>
[server acks client's message, but with no hurry, and no extra round trips.]

Of course, it should still be possible request an ack:

C: <message/>
C: <a c='1' r='true'/>
S: <a b='1'/>

For compactness, we could go back to having two elements:

C: <message/>
C: <r c='1'/>
S: <a b='1'/>

But with a difference in behavior: when 'r' is sent, an 'a' must be sent back, 
however an 'a' can also be sent unsolicited.

I suppose one could also just ping:

C: <r/>
S: <a/>

And, unless used as an answer, this would be useless:

C: <a/>

In short, the above proposal is similar to what I've already written, but 
better.  At the basic level, we've just moved attributes from the stanzas 
into outside elements.  However, additional changes allow for passive acking, 
and we even got a free ping.

Regarding the ping, I think the same rules as my original ack proposal should 
apply.  That is, if 'r' is sent with no attributes, then the server MUST 
immediately respond with 'a'.

For example, here is a client with a 1-minute penalty sending a message.  The 
client pings every 50 seconds to make sure the connection is alive.

C: <message/>
C: <r c='1'/> (request ack)
[... 50 seconds pass ...]
C: <r/> (ping)
S: <a/> (pong)
[... 10 seconds pass ...]
S: <a b='1'/> (ack)

Thoughts?

-Justin



More information about the Standards mailing list