<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">After looking into this more deeply I suspect the only way I can provide a sensible wrapper for the Option class is to do a bunch of <span style="color: rgb(33, 33, 33); font-family: wf_segoe-ui_normal, "Segoe UI", "Segoe WP", Tahoma, Arial, sans-serif, serif, EmojiFont; font-size: 14.6667px;">dynamic_pointer_cast
operations in my Python wrapper constructor and save a type code. Then I can just perform a switch in each method that has the potential to fail when I have a reference to an Option sub-class rather than the generic Option super-class.</span></p>
<p style="margin-top:0;margin-bottom:0"><span style="color: rgb(33, 33, 33); font-family: wf_segoe-ui_normal, "Segoe UI", "Segoe WP", Tahoma, Arial, sans-serif, serif, EmojiFont; font-size: 14.6667px;"><br>
</span></p>
<p style="margin-top:0;margin-bottom:0"><span style="color: rgb(33, 33, 33); font-family: wf_segoe-ui_normal, "Segoe UI", "Segoe WP", Tahoma, Arial, sans-serif, serif, EmojiFont; font-size: 14.6667px;">I am not sure it makes sense to ever expose the ability
to construct an Option sub-class from Python.</span></p>
<p style="margin-top:0;margin-bottom:0"><span style="color: rgb(33, 33, 33); font-family: wf_segoe-ui_normal, "Segoe UI", "Segoe WP", Tahoma, Arial, sans-serif, serif, EmojiFont; font-size: 14.6667px;"><br>
</span></p>
<p style="margin-top:0;margin-bottom:0"><span style="color: rgb(33, 33, 33); font-family: wf_segoe-ui_normal, "Segoe UI", "Segoe WP", Tahoma, Arial, sans-serif, serif, EmojiFont; font-size: 14.6667px;">In any event, I am not going to bother doing this until
I have tests for all of the functionality currently implemented. You can quite happily do anything you need with just the Option class and methods. For example:<br>
<br>
</p>
<div>>>> from kea import *</div>
<div>>>> from ipaddress import IPv4Address</div>
<div>>>> name_servers = [IPv4Address(u'192.0.3.1'), IPv4Address(u'192.0.3.2')]</div>
<div>>>> packed_name_servers = ''.join([addr.packed for addr in name_servers])</div>
<div>>>> o = Option(DHO_DOMAIN_NAME_SERVERS).setString(packed_name_servers)</div>
<div>>>> o.getString()</div>
<div>'\xc0\x00\x03\x01\xc0\x00\x03\x02'</div>
<div><br>
</div>
<div>Hmm... On further investigation, I am going to have to do the funny dynamic cast thing - even though we will not use it here :-).</div>
<div><br>
</div>
<div>
<div>>>> from kea import *</div>
<div>>>> from pcapfile import savefile</div>
<div>
<div style="color: rgb(33, 33, 33); font-family: wf_segoe-ui_normal, "Segoe UI", "Segoe WP", Tahoma, Arial, sans-serif, serif, EmojiFont; font-size: 14.6667px;">
>>> </div>
<div>>>> def make_packet(frame):<br>
</div>
</div>
<div>... ll = frame.packet</div>
<div>... ip = ll.payload</div>
<div>... udp = ip.payload</div>
<div>... p = Pkt4(udp.payload.decode('hex'))</div>
<div>... p.setLocalAddr(ip.src)</div>
<div>... p.setRemoteAddr(ip.dst)</div>
<div>... p.setLocalPort(udp.src_port)</div>
<div>... p.setRemotePort(udp.dst_port)</div>
<div>... p.unpack()</div>
<div>... return p</div>
<div>... </div>
<div>>>> pcap = savefile.load_savefile(open('dhcp-trace.pcap'), layers=3)</div>
<div>>>> p = make_packet(pcap.packets[1])</div>
<div>>>> print p.toText()</div>
<div>local_address=172.20.0.4:67, remote_address=11.0.0.1:67, msg_type=DHCPOFFER (2), transid=0x566fcf25,</div>
<div>options:</div>
<div> type=001, len=004: 255.255.240.0 (ipv4-address)</div>
<div> type=003, len=004: 11.0.0.1</div>
<div> type=042, len=004: 10.10.3.10</div>
<div> type=043, len=058: 01:38:68:74:74:70:73:***private stuff***</div>
<div> type=051, len=004: 86400 (uint32)</div>
<div> type=053, len=001: 2 (uint8)</div>
<div> type=054, len=004: 172.20.0.4 (ipv4-address)</div>
<div> type=058, len=004: 43200 (uint32)</div>
<div> type=059, len=004: 75600 (uint32)</div>
<div> type=082, len=050:,</div>
<div>options:</div>
<div> type=001, len=033: 53:57<span style="color: rgb(33, 33, 33); font-family: wf_segoe-ui_normal, "Segoe UI", "Segoe WP", Tahoma, Arial, sans-serif, serif, EmojiFont; font-size: 14.6667px;">:</span><span style="color: rgb(33, 33, 33); font-family: wf_segoe-ui_normal, "Segoe UI", "Segoe WP", Tahoma, Arial, sans-serif, serif, EmojiFont; font-size: 14.6667px;">***private
stuff***</span></div>
<div> type=002, len=013: 55:4e<span style="color: rgb(33, 33, 33); font-family: wf_segoe-ui_normal, "Segoe UI", "Segoe WP", Tahoma, Arial, sans-serif, serif, EmojiFont; font-size: 14.6667px;">:</span><span style="color: rgb(33, 33, 33); font-family: wf_segoe-ui_normal, "Segoe UI", "Segoe WP", Tahoma, Arial, sans-serif, serif, EmojiFont; font-size: 14.6667px;">***private
stuff***</span></div>
<div>>>> </div>
<div>>>> o = p.getOption(3).getUint16()</div>
<div>Traceback (most recent call last):</div>
<div> File "<stdin>", line 1, in <module></div>
<div>TypeError: Length (0) of buffer is insufficient to read a uint16_t</div>
<div><br>
</div>
Oh well :-)</div>
</span>
<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> kea-dev <kea-dev-bounces@lists.isc.org> on behalf of Dave Cole <davecole@nbnco.com.au><br>
<b>Sent:</b> Tuesday, 30 January 2018 11:45:12 AM<br>
<b>To:</b> kea-dev@lists.isc.org<br>
<b>Subject:</b> [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">I have decided that before publishing my Python bindings I should add a bunch of unit tests. In the process I discovered something strange:<br>
<br>
>>> from kea import *<br>
>>> p = Pkt4(DHCPDISCOVER, 0)<br>
>>> o = 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>
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.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_TYPE is an instance of OptionInt which does not use the data_ member of Option, instead it has another member value_ of the type defined in the template argument.<br>
<br>
Is it a deliberate choice in the code to require application code to just know that getUint8 does not work for OptionInt (which subclasses Option)?<br>
<br>
Someone with more of a clue about c++ than me might be able to tell me an easy (and efficient) way I can make my code notice an OptionInt and internally use getValue() rather than getUint8(). Would a dynamic_pointer_cast<OptionUint8>(self->option_ptr) be the
way to go?<br>
_______________________________________________<br>
kea-dev mailing list<br>
kea-dev@lists.isc.org<br>
<a href="https://lists.isc.org/mailman/listinfo/kea-dev">https://lists.isc.org/mailman/listinfo/kea-dev</a><br>
</div>
</span></font></div>
</body>
</html>