Re: [Exim] RFC2920 and synchronization errors

Top Page
Delete this message
Reply to this message
Author: Edgar Lovecraft
Date:  
To: exim-users
Subject: Re: [Exim] RFC2920 and synchronization errors
Matthew Byng-Maddick wrote:
>
> While looking at PIPELINING support within SAUCE last night, the
> following issues were highlit by Ian Jackson. The RFC2920 (STD 60) spec
> for SMTP command pipelining includes no precise definition of a "command
> group",


How so? the RFC does not define 'what exactly is in a group', it does
however define quite clearly what commands ARE ONLY last command, no matter
what is in the group, these commands ARE ALWAYS defined as last.

Lets look at Section 3.1
<START OF RFC SNIPET>
3.1. Client use of pipelining
Once the client SMTP has confirmed that support exists for the
pipelining extension, the client SMTP may then elect to transmit
groups of SMTP commands in batches without waiting for a response to
each individual command. In particular, the commands RSET, MAIL FROM,
SEND FROM, SOML FROM, SAML FROM, and RCPT TO can all appear anywhere
in a pipelined command group. The EHLO, DATA, VRFY, EXPN, TURN,
QUIT, and NOOP commands can only appear as the last command in a
group since their success or failure produces a change of state which
the client SMTP must accommodate. (NOOP is included in this group so
it can be used as a synchronization point.)

Additional commands added by other SMTP extensions may only appear as
the last command in a group unless otherwise specified by the
extensions that define the commands.
</START OF RFC SNIPET>

That seems pretty clear to me, as there are some commands that MUST and
CAN ONLY be the last of a group (a group can be one command by the way).

Lets continue with Section 3.1...
<START OF RFC SNIPET>
The actual transfer of message content is explicitly allowed to be
the first "command" in a group. That is, a RSET/MAIL FROM sequence
used to initiate a new message transaction can be placed in the same
group as the final transfer of the headers and body of the previous
message.

Client SMTP implementations that employ pipelining MUST check ALL
statuses associated with each command in a group. For example, if
none of the RCPT TO recipient addresses were accepted the client must
then check the response to the DATA command -- the client cannot
assume that the DATA command will be rejected just because none of
the RCPT TO commands worked. If the DATA command was properly
rejected the client SMTP can just issue RSET, but if the DATA command
was accepted the client SMTP should send a single dot.

Command statuses MUST be coordinated with responses by counting each
separate response and correlating that count with the number of
commands known to have been issued. Multiline responses MUST be
supported. Matching on the basis of either the error code value or
associated text is expressly forbidden.
</START OF RFC SNIPET>

Here again, the 'what exactly is in a group' is not defined, but what
starts or ends the group is defined, as are the rules that the client must
follow in regard to response codes.

> and in particular, although it's implied that the "last command
> of a command group" is one that should wait for replies, the server:


Not just implied, the client MUST wait for all replies.

> | (9) MUST NOT flush or otherwise lose the contents of the TCP input
> |     buffer under any circumstances whatsoever.

>


That is to ensure that the server has seen the entire 'command group' sent
by the client, it has nothing to with the client not waiting for ALL
responses to the 'command group' which the client MUST do. There are also
things that the server must clearly NOT buffer, and the rules on when to
send responses to the client is very clear also.

Look at Section 3.2:
<START OF RFC SNIPET>
   (5) MUST NOT buffer responses to EHLO, DATA, VRFY, EXPN, TURN,
       QUIT, and NOOP.
   (6) MUST NOT buffer responses to unrecognized commands.
   (7) MUST send all pending responses immediately whenever the local
       TCP input buffer is emptied.
</START OF RFC SNIPET>


> Now, this means that it's quite reasonable to suggest pipelining
> violations in the situations where no pipelining has been advertised, but
> if it has, then it appears that the client can do pretty much what it
> wants (within the standard).


Not it cannot. If the client sends an 'ONLY LAST COMMAND' (EHLO or DATA
for example) then it MUST wait for all responses to the command group to be
returned, as the client MUST check all of the return codes before sending
the next command group.

>
> Other things about this standard appear to be totally braindead, (VRFY
> causing a change of state - you what!?) so it's not clear that a client
> can't believe that it's allowed to send other things, because of the
> unclearness between what goes in one TCP send operation and the places
> where it is pausing for a response.


There is nothing unclear about it, the client MUST check ALL statuses for
each command in the group.

> In particular, if one does several send operations one after the other,
> but without waiting for a response (having switched off Nagle, of
> course), then it would appear to be conformant to STD60 as specified,


Nope, this is just not true, on or off the client MUST wait for all
responses to commands given in a command group before continuing.

> but would cause a synchronization error in exim.


As it should.

Let us finish looking at Section 3.1...
<START OF RFC SNIPET>
Client SMTP implementations MAY elect to operate in a nonblocking
fashion, processing server responses immediately upon receipt, even
if there is still data pending transmission from the client's
previous TCP send operation. If nonblocking operation is not
supported, however, client SMTP implementations MUST also check the
TCP window size and make sure that each group of commands fits
entirely within the window. The window size is usually, but not
always, 4K octets. Failure to perform this check can lead to
deadlock conditions.

Clients MUST NOT confuse responses to multiple commands with
multiline responses. Each command requires one or more lines of
response, the last line not containing a dash between the response
code and the response string.
</START OF RFC SNIPET>

I believe that the 'Failure to perform this check can lead to deadlock
conditions' answers your question, if it does not wait, then the client
would not be conformant to the standard, thus, causing a 'synchronization
error'.

>
> So, is it a bug for exim to say "synchronization error" in those other
> situations?
>


I would say no, even if what exactly a 'group' is can be fuzzy, when a
group starts, and when a group ends is not.

MUST END A GROUP:
EHLO
DATA
VRFY
EXPN
TURN
QUIT
NOOP
any command added by other SMTP extensions, i.e. AUTH amongst others

With that definition of when a group ends (therefore anything else starts
a group), it is quite clear that the client MUST wait for ALL responses to
ALL commands before continuing with the next group.

--

--EAL--