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),
> 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