MIDLC IDL Compiler

Michael B Allen mba2000 at ioplex.com
Fri Jan 14 00:29:54 GMT 2005


Andrew,

I have the MIDLC C emitter working. At least I've tested the marshalling
routines for some lsarpc operations (e.g. LsarLookupSids) by running a
little test program on raw NDR data obtained using the "export bytes"
feature of Ethereal. So I rsync'd the latest Samba4 and started looked
at your PIDL stubs for a spot to splice in.

However, as you anticipated there is a problem with the different I/O
strategies. PIDL stubs read/write data directly from/to the named pipe
in leaf operations. MIDLC stubs currently expect to be provided with the
entire raw NDR data buffer and a buffer into which to write the raw NDR
response [1]. Unfortunately both methods have problems.

First, the problem with the PIDL stubs. Consider the following IDL:

    typedef struct {
        [length_is(len)] char buf[BIGMAX];
        int len;
    } foo0;

or:

    int SomeOp([in,out,size_is(*len)] char *buf, [in,out] int *len);

I don't know exactly how PIDL would handle these but I think I know in
advance that it just doesn't. MIDLC produces (for the foo0 struct anyway):

    int
    dec_foo0(struct ndr *_ndr,
                foo0 *_obj,
                unsigned char **_src,
                unsigned char **_deferred,
                unsigned char *_slim)
    {
        unsigned char *_start = *_src;

        uint32_t _bufl;
        uint32_t _bufs;
        unsigned char *_bufi;
        uint32_t _i;

        dec_ndr_align(_ndr, 4, _src, _slim);
        _bufl = _obj->len;
        _bufs = 0xFFFFF;
        dec_ndr_long(_ndr, &_bufl, _src, _slim);
        dec_ndr_long(_ndr, &_bufl, _src, _slim);
        _bufi = *_src;
        *_src += 1 * _bufl;                       <-- skip buffer
        dec_ndr_long(_ndr, &_obj->len, _src, _slim);

        _src = &_bufi;            <-- go back and decode elements
        for (_i = 0; _i < _bufl; _i++) {
            dec_ndr_small(_ndr, &_obj->buf[_i], _src, _slim);
        }

        (void)_deferred;
        return *_src - _start;
    }

The point here is that to decode this we must temporarily skip the array
to get to 'len' and *then go back* to decode the elements. To the best
of my knowledge this is the only way to do it. That means that when
reading data you might need to skip stuff and then go back. AFAICT this
is not practical with the current approach in Samba.

Yes, these scenarios are highly unusual but MIDLC is supposed to be a
general purpose IDL compiler so minus compatible extensions I must code
to spec.

The problem with the current MIDLC I/O strategy is that, as you have
observed, it is inefficient to preallocate buffers of the correct size.

One possible solution to remedy this problem would be to simply reuse the
same buffer for all marshalling input and output and resize the buffer
to be larger on demand. In practice the buffer would be relatively small
unless a large RPC was processed after which the buffer could be resized
to a smaller maximum size. If I/O multiplexing is important (not sure
how Samba4 handles that) then a buffer pool might be employed. Etc.

Any thoughts? Problems?

Mike

[1] Although the same buffer can be used for decoding and encoding
a single RPC provided it's large enough for both.



More information about the samba-technical mailing list