At 2021-04-08 09:26:22 +0200, [email protected] wrote:
>
> Something changed in NetBSD-current last year, to make it no longer
> safe to assume that communication over a Unix domain stream socket
> would make the entire contents of a write() available to read() on
> the other side in one go.

I don't think the code means to assume that, though:

    case Read:
        while ( d->active && hasMessage( readBuffer() ) ) {
            /* We call a function to process every message we receive.
               This function is expected to parse and remove a message
               from the readBuffer, throwing an exception for malformed
               messages, and setting d->unknownMessage for messages that
               it can't or won't handle. */

            char msg = (*readBuffer())[0];
            try {
                if ( d->startup ) {
                    if ( !d->authenticated )
                        authentication( msg );
                    else
                        backendStartup( msg );
                }
                else {
                    process( msg );
                }

                if ( d->unknownMessage )
                    unknown( msg );
            }
            catch ( PgServerMessage::Error e ) {
                error( "Malformed " + EString( &msg, 1 ).quoted() +
                       " message received." );
            }
        }

…and hasMessage() returns false if we don't have the required number of
bytes available (every message starts with a type byte, followed by a
four-byte length):

    static bool hasMessage( Buffer *b )
    {
        if ( b->size() < 5 ||
             b->size() < 1+( (uint)((*b)[1]<<24)|((*b)[2]<<16)|
                                   ((*b)[3]<<8)|((*b)[4]) ) )
            return false;
        return true;
    }

So we should clearly be parsing a 'D' message (or any message) only when
all of the bytes in the message are available, no matter how many reads
that takes.

-- Abhijit

Reply via email to