<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=us-ascii">
<style type="text/css" style="display:none;"><!-- P {margin-top:0;margin-bottom:0;} --></style>
</head>
<body dir="ltr">
<div id="divtagdefaultwrapper" style="font-size:12pt;color:#000000;font-family:Calibri,Helvetica,sans-serif;" dir="ltr">
<p style="margin-top:0;margin-bottom:0">I was hoping to be able to minimise the amount of extra work done by the binding, so eliminating unnecessary object allocation / destruction would be a good thing. I recently had a play with exposing the shared_ptr use_count
to confirm a behaviour I was seeking. It turns out that the shared_ptr works very nicely with Python wrapping. I would like to be able to create constant options once at module load time and then poke them into response packets as required. This will completely
eliminate heap activity for those objects.</p>
<p style="margin-top:0;margin-bottom:0"><br>
</p>
<p style="margin-top:0;margin-bottom:0">All of my Python classes are just simple proxies for the wrapped Kea class. They just act as vehicles for delivering the Kea object to Kea code and are never retained by any object reference from Kea. The only exception
to this rule is the CalloutHandle setContext() method where the roles are reversed :-).</p>
<p style="margin-top:0;margin-bottom:0"><br>
</p>
<p style="margin-top:0;margin-bottom:0"></p>
<div>>>> from kea import *</div>
<div>>>> o = Option(1).setUint8(3)</div>
<div>>>> o.use_count</div>
<div>1</div>
<div>>>> p = Pkt4(DHCPDISCOVER, 1)</div>
<div>>>> p.addOption(o)</div>
<div>>>> o.use_count</div>
<div>2</div>
<div>>>> p = None</div>
<div>>>> o.use_count</div>
<div>1</div>
<div><span style="font-size: 12pt;">>>> p = Pkt4(DHCPDISCOVER, 1)</span><br>
</div>
<div>>>> p.addOption(o)</div>
<div>>>> o.use_count</div>
<div>2</div>
<div>>>> p.pack()</div>
<div>>>> o.use_count</div>
<div>2</div>
<div>>>> p = None</div>
<div>>>> o.use_count</div>
<div>1</div>
<div>>>> p = Pkt4(DHCPDISCOVER, 1)</div>
<div>>>> p.addOption(o)</div>
<div>>>> q = Pkt4(DHCPDISCOVER, 1)</div>
<div>>>> q.addOption(o)</div>
<div>>>> o.use_count</div>
<div>3</div>
<div>>>> p = q = None</div>
<div>>>> o.use_count</div>
<div>1</div>
<div>>>> import sys</div>
<div>>>> sys.getrefcount(o)</div>
<div>2</div>
<div>>>> p = Pkt4(DHCPDISCOVER, 1)</div>
<div>>>> p.addOption(o)</div>
<div>>>> sys.getrefcount(o)</div>
<div>2</div>
<div>>>> sys.getrefcount(Option(1))</div>
<div>1</div>
<div><br>
</div>
<br>
<p></p>
</div>
<hr style="display:inline-block;width:98%" tabindex="-1">
<div id="divRplyFwdMsg" dir="ltr"><font face="Calibri, sans-serif" style="font-size:11pt" color="#000000"><b>From:</b> Francis Dupont <fdupont@isc.org><br>
<b>Sent:</b> Tuesday, 30 January 2018 7:34:07 PM<br>
<b>To:</b> Dave Cole<br>
<b>Cc:</b> kea-dev@lists.isc.org<br>
<b>Subject:</b> Re: [kea-dev] Strange behaviour with Option 53 - what am I missing?</font>
<div> </div>
</div>
<div class="BodyFragment"><font size="2"><span style="font-size:11pt;">
<div class="PlainText">Dave Cole writes:<br>
> >>> from kea import *<br>
> >>> p =3D Pkt4(DHCPDISCOVER, 0)<br>
> >>> o =3D p.getOptions()[DHO_DHCP_MESSAGE_TYPE]<br>
> >>> o.getUint8()<br>
> Traceback (most recent call last):<br>
> File "<stdin>", line 1, in <module><br>
> TypeError: Attempt to read uint8 from option 53 that has size 0<br>
> >>> o.getString()<br>
> '\x01'<br>
> <br>
> The implementation of getUint8 is:<br>
> <br>
> static PyObject *<br>
> Option_getUint8(OptionObj *self, PyObject *args) {<br>
> try {<br>
> return (PyInt_FromLong(self->option_ptr->getUint8()));<br>
> } catch (const exception &e) {<br>
> return (raisePythonError(PyExc_TypeError, e.what()));<br>
> }<br>
> }<br>
<br>
=> you don't use the right method: the option 53 dhcp-message-type is<br>
decoded as an OptionInt<uint8_t> not as an Option so its content is<br>
available by getValue().<br>
If you look at the option_int.h file you can see the constructor<br>
with begin/end content iterators does not pass them to the super class<br>
but only to unpack.<br>
You have the same for most of derived classes from Option, I believe<br>
the idea is to save memory: as the content is decoded there is no need<br>
to save it also in the super class object.<br>
Of course this means you have to use a dynamic cast to the derived class<br>
and specialized methods. Or you can repack the option in wire format<br>
using toBinary() and works on the result.<br>
<br>
> Whereas the getString is:<br>
> <br>
> static PyObject *<br>
> Option_getString(OptionObj *self, PyObject *args) {<br>
> try {<br>
> vector<uint8_t> value = self->option_ptr->toBinary();<br>
> return (PyString_FromStringAndSize((const char *) &value[0], value.=<br>
> size()));<br>
> } catch (const exception &e) {<br>
> return (raisePythonError(PyExc_TypeError, e.what()));<br>
> }<br>
> }<br>
> <br>
> So when I step through the code with gdb it appears that DHO_DHCP_MESSAGE_T=<br>
> YPE is an instance of OptionInt which does not use the data_ member of Opti=<br>
> on, instead it has another member value_ of the type defined in the templat=<br>
> e argument.<br>
> <br>
> Is it a deliberate choice in the code to require application code to just k=<br>
> now that getUint8 does not work for OptionInt (which subclasses Option)?<br>
<br>
=> it is.<br>
<br>
> Someone with more of a clue about c++ than me might be able to tell me an e=<br>
> asy (and efficient) way I can make my code notice an OptionInt and internal=<br>
> ly use getValue() rather than getUint8(). Would a dynamic_pointer_cast<Opt=<br>
> ionUint8>(self->option_ptr) be the way to go?<br>
<br>
=> you should get the definition from either std_option_defs.h or<br>
runtime libdhcp++ structures and work with it. Or simply repack the<br>
option with toBinary(). In fact it depends on the option format: if it<br>
is simple repacking is easier, if it is complex the OptionCustom provides<br>
tools which makes redecoding useless.<br>
<br>
Thanks<br>
<br>
Francis Dupont <fdupont@isc.org><br>
</div>
</span></font></div>
</body>
</html>