Heads up - directory reorganization coming

Eric S. Raymond esr at thyrsus.com
Sat Nov 26 22:52:29 UTC 2016

Hal Murray <hmurray at megapathdsl.net>:
> esr at thyrsus.com said:
> >> Do you have sample code that calls libc and returns a big struct?
> > No, but I know exactly how to do it.  I'll put this on the to-do list at low
> > priority. 
> I have code that works using ctypes.  It doesn't give me that warm feeling.
> libc   = ctypes.CDLL("libc.so.6")
> class timex(ctypes.Structure):
>   _fields_ = [ ("modes",     ctypes.c_uint),
>                ("offset",    ctypes.c_long),
>                ("freq",      ctypes.c_long),
>                ("maxerror",  ctypes.c_long),
>                ("esterror",  ctypes.c_long),
> ...
>   libc.ntp_adjtime(ctypes.byref(ntp))
> On at least one system, I have to change that 6 to a 7.  It probably works 
> without the number,
> The other problem is that there is no check that the layout of the struct 
> matches what is on the system.
> Is there a preprocessor that would automate building the struct?

No.  And this should *absolutely not* give you a warm and fuzzy
feeling; it's a brittle, chancy way to do things which I have
summarily rejected for that reason.

The right way to do it would be to add a wrapper to libnp/pymodule.c
implementing Python access to adjtimex(2).  If you look at that code,
it will be pretty obvious how this is done for simple cases that don't
involve passing a struct to the C call being wrapped.

Here's the missing magic: for structs, you take arguments from Python-land
and pass them to Python's struct.pack(), giving it a format argument that
tells it to mock the C layout of the struct in the binary blob it hands
back.  Then you pass that blob to the underlying C call.

The trick works in the other direction with struct.unpack, so it's no
big deal to pass the elements of a C struct back out to Python-land.

In both cases, the way the format string is interpreted mimics the
same self-alignment rules for structure padding that NTP has been assuming
since the year zero in the protocol engine.

I use struct.unpack to analyze NTP packets in the back-end code for the
new Python tools.  As an example, here's the format that drives the
analysis of control (mode 6) packets.

    format = "!BBHHHHH"

That says: assume network byte order; peel off four bytes; peel off
four halfwords (16 bits each - this was designed in the 2-bit era).
The result is returned as a tuple.

The corresponding format for sync packets is

    format = "!BBBBIIIQQQQ"

where I requests a 32-bit word and Q a "quad" (64 bits). 

If you'd like to spread your wings a little, writing that adjtimex
wrapper would be a good way for you to begin acquiring some Python.
I could do it inside half an hour.  I'll be surprised if it takes you
more than three, even from a standing start and counting the time
to read the documentation for the struct module and Python extensions.
		<a href="http://www.catb.org/~esr/">Eric S. Raymond</a>

More information about the devel mailing list