]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[fdxhook] Complete LUA and add getHWAddr()
authorFrancis Dupont <fdupont@isc.org>
Wed, 22 Jun 2016 21:03:34 +0000 (23:03 +0200)
committerFrancis Dupont <fdupont@isc.org>
Wed, 22 Jun 2016 21:03:34 +0000 (23:03 +0200)
src/hooks/external/lua/NOTES
src/hooks/external/lua/loption.cc
src/hooks/external/lua/lpkt4.cc
src/hooks/external/ocaml/hook.ml
src/hooks/external/ocaml/hook.mli
src/hooks/external/ocaml/opt.c
src/hooks/external/ocaml/pkt4.c
src/hooks/external/ocaml/pkt4.h
src/hooks/external/python/poption.cc
src/hooks/external/python/ppkt4.cc

index 7aa22e31f28947193cf0a21f049e78370ce57f25..fc8613b423f7a94cfbea65e9e39732af564b4f5d 100644 (file)
@@ -2,10 +2,10 @@ Implementation notes for lua
 
 Manifest:
  - loption.h loption.cc: the C++ OptionPtr encapsulated into a lua full
-  userdata with a few methods ported.
+  userdata with some methods ported.
 
  - ppkt4.h ppkt4.cc: the C++ Pkt4Ptr encapsulated into a lua full userdata
-  with a few methods ported.
+  with some methods ported.
 
   one can complete these lua types or/and new lua type.
 
index d47c97685188f41ea2c5efdf1c45a911744c8bef..d36222c001beafe18202d3d74f1d8ab9cb5cd5ec 100644 (file)
@@ -19,23 +19,48 @@ l_option::l_option() {}
 
 namespace { // anonymous namespace
 
+// __gc
+int option__gc(lua_State* L) {
+    // This is a critical code to avoid memory leaks
+    cout << "option__gc called\n";
+    l_option* const self =
+        static_cast<l_option*>(luaL_checkudata(L, 1, LUA_KEAOPTION));
+    self->object.reset();
+    return (0);
+}
+
+// __tostring
+int option__tostring(lua_State* L) {
+    l_option* const self =
+        static_cast<l_option*>(luaL_checkudata(L, 1, LUA_KEAOPTION));
+    lua_pushstring(L, self->object->toText(0).c_str());
+    return (1);
+}
+
+// Method table
+const luaL_Reg option_method[] = {
+    { "__gc", option__gc },
+    { "__tostring", option__tostring },
+    { NULL, NULL }
+};
+
 // factory(universe, type, data)
 int factory(lua_State* L) {
-    // Require 3 arguments
-    if (lua_gettop(L) - 1 != 3) {
+    // Requires 3 arguments
+    if (lua_gettop(L) != 3) {
         return (luaL_error(L, "option.factory takes 3 arguments"));
     }
-    if (lua_type(L, -3) != LUA_TNUMBER) {
-        return (luaL_error(L, "universe must be a number"));
+    if (!lua_isinteger(L, 1)) {
+        return (luaL_error(L, "universe must be an integer"));
     }
-    if (lua_type(L, -2) != LUA_TNUMBER) {
-        return (luaL_error(L, "type must be a number"));
+    if (!lua_isinteger(L, 2)) {
+        return (luaL_error(L, "type must be an integer"));
     }
-    if (lua_type(L, -1) != LUA_TSTRING) {
+    if (!lua_isstring(L, 3)) {
         return (luaL_error(L, "data must be a string"));
     }
-    unsigned char u = static_cast<unsigned char>(lua_tonumber(L, -3));
-    unsigned short t = static_cast<unsigned short>(lua_tonumber(L, -2));
+    uint8_t u = static_cast<uint8_t>(lua_tointeger(L, 1));
+    uint16_t t = static_cast<uint16_t>(lua_tointeger(L, 2));
     Option::Universe universe;
     switch (u) {
     case 4:
@@ -54,7 +79,7 @@ int factory(lua_State* L) {
     }
 
     size_t len = 0;
-    const char* d = lua_tolstring(L, -1, &len);
+    const char* d = lua_tolstring(L, 3, &len);
     OptionBuffer data;
     data.resize(len);
     if (len) {
@@ -69,24 +94,6 @@ int factory(lua_State* L) {
     return (1);
 }
 
-// __gc
-int option__gc(lua_State* L) {
-    // This is a critical code to avoid memory leaks
-    cout << "option__gc called\n";
-    l_option* const self =
-        static_cast<l_option*>(luaL_checkudata(L, 1, LUA_KEAOPTION));
-    self->object.reset();
-    return (0);
-}
-
-// __tostring
-int option__tostring(lua_State* L) {
-    l_option* const self =
-        static_cast<l_option*>(luaL_checkudata(L, 1, LUA_KEAOPTION));
-    lua_pushstring(L, self->object->toText(0).c_str());
-    return (1);
-}
-
 // getUniverse() method
 int getUniverse(lua_State* L) {
     l_option* const self =
@@ -103,16 +110,167 @@ int getUniverse(lua_State* L) {
     }
 }
 
-// Method table
-const luaL_Reg option_method[] = {
-    { "__gc", option__gc },
-    { "__tostring", option__tostring },
-    { "getUniverse", getUniverse },
-    { NULL, NULL }
-};
+// toBinary(bool include_header = false) method
+int toBinary(lua_State* L) {
+    l_option* const self =
+        static_cast<l_option*>(luaL_checkudata(L, 1, LUA_KEAOPTION));
+    vector<uint8_t> bin = self->object->toBinary(true);
+    lua_pushlstring(L, reinterpret_cast<char*>(&bin[0]), bin.size());
+    return (1);
+}
+
+// getType() method
+int getType(lua_State* L) {
+    l_option* const self =
+        static_cast<l_option*>(luaL_checkudata(L, 1, LUA_KEAOPTION));
+    lua_pushinteger(L, static_cast<lua_Integer>(self->object->getType()));
+    return (1);
+}
+
+// len() method
+int len(lua_State* L) {
+    l_option* const self =
+        static_cast<l_option*>(luaL_checkudata(L, 1, LUA_KEAOPTION));
+    lua_pushinteger(L, static_cast<lua_Integer>(self->object->len()));
+    return (1);
+}
+
+// getHeaderLen() method
+int getHeaderLen(lua_State* L) {
+    l_option* const self =
+        static_cast<l_option*>(luaL_checkudata(L, 1, LUA_KEAOPTION));
+    lua_pushinteger(L, static_cast<lua_Integer>(self->object->getHeaderLen()));
+    return (1);
+}
+
+// getData() method
+int getData(lua_State* L) {
+    l_option* const self =
+        static_cast<l_option*>(luaL_checkudata(L, 1, LUA_KEAOPTION));
+    const OptionBuffer& data = self->object->getData();
+    lua_pushlstring(L, reinterpret_cast<const char*>(&data[0]), data.size());
+    return (1);
+}
+
+// addOption(OptionPtr opt) method
+int addOption(lua_State* L) {
+    // Requires 2 arguments
+    if (lua_gettop(L) != 2) {
+        return (luaL_error(L, "option.addOption takes 2 arguments"));
+    }
+    l_option* const self =
+        static_cast<l_option*>(luaL_checkudata(L, 1, LUA_KEAOPTION));
+    l_option* const sub =
+        static_cast<l_option*>(luaL_checkudata(L, 2, LUA_KEAOPTION));
+    self->object->addOption(sub->object);
+    return (0);
+}
+
+// getOption(uint16_t type) method
+int getOption(lua_State* L) {
+    // Requires 2 arguments
+    if (lua_gettop(L) != 2) {
+        return (luaL_error(L, "option.getOption takes 2 arguments"));
+    }
+    l_option* const self =
+        static_cast<l_option*>(luaL_checkudata(L, 1, LUA_KEAOPTION));
+    if (!lua_isinteger(L, 2)) {
+        return (luaL_error(L, "type must be an integer"));
+    }
+    uint16_t t = static_cast<uint16_t>(lua_tointeger(L, 2));
+    OptionPtr sub = self->object->getOption(t);
+    if (sub) {
+        void* ret =
+            static_cast<l_option*>(lua_newuserdata(L, sizeof(l_option)));
+        memset(ret, 0, sizeof(l_option));
+        (static_cast<l_option*>(ret))->object = sub;
+    } else {
+        lua_pushnil(L);
+    }
+    return (1);
+}
+
+// TODO: getOptions() method
+
+// delOption(uint16_t type) method
+int delOption(lua_State* L) {
+    // Requires 2 arguments
+    if (lua_gettop(L) != 2) {
+        return (luaL_error(L, "option.delOption takes 2 arguments"));
+    }
+    l_option* const self =
+        static_cast<l_option*>(luaL_checkudata(L, 1, LUA_KEAOPTION));
+    if (!lua_isinteger(L, 2)) {
+        return (luaL_error(L, "type must be an integer"));
+    }
+    uint16_t t = static_cast<uint16_t>(lua_tointeger(L, 2));
+    bool ret = self->object->delOption(t);
+    lua_pushboolean(L, ret ? 1 : 0);
+    return (1);
+}
+
+// setData(<byte>) method
+int setData(lua_State* L) {
+    // Requires 2 arguments
+    if (lua_gettop(L) != 2) {
+        return (luaL_error(L, "option.setData takes 2 arguments"));
+    }
+    l_option* const self =
+        static_cast<l_option*>(luaL_checkudata(L, 1, LUA_KEAOPTION));
+    if (!lua_isstring(L, 2)) {
+        return (luaL_error(L, "data must be a string"));
+    }
+    size_t len = 0;
+    const char* d = lua_tolstring(L, 2, &len);
+    OptionBuffer data;
+    data.resize(len);
+    if (len) {
+        memmove(&data[0], d, len);
+    }
+    self->object->setData(data.begin(), data.end());
+    return (0);
+}
+
+// setEncapsulatedSpace(const string& encapsulated_space) method
+int setEncapsulatedSpace(lua_State* L) {
+    // Requires 2 arguments
+    if (lua_gettop(L) != 2) {
+        return (luaL_error(L,
+                    "option.setEncapsulatedSpace takes 2 arguments"));
+    }
+    l_option* const self =
+        static_cast<l_option*>(luaL_checkudata(L, 1, LUA_KEAOPTION));
+    if (!lua_isstring(L, 2)) {
+        return (luaL_error(L, "encapsulated_state must be a string"));
+    }
+    string state(lua_tostring(L, 2));
+    self->object->setEncapsulatedSpace(state);
+    return (0);
+}
+
+// getEncapsulatedSpace() method
+int getEncapsulatedSpace(lua_State* L) {
+    l_option* const self =
+        static_cast<l_option*>(luaL_checkudata(L, 1, LUA_KEAOPTION));
+    lua_pushstring(L, self->object->getEncapsulatedSpace().c_str());
+    return (1);
+}
 
 // Function table
 const luaL_Reg option_function[] = {
+    { "factory", factory },
+    { "getUniverse", getUniverse },
+    { "toBinary", toBinary },
+    { "getType", getType },
+    { "len", len },
+    { "getHeaderLen", getHeaderLen },
+    { "getData", getData },
+    { "addOption", addOption },
+    { "getOption", getOption },
+    { "delOption", delOption },
+    { "setData", setData },
+    { "setEncapsulatedSpace", setEncapsulatedSpace },
+    { "getEncapsulatedSpace", getEncapsulatedSpace },
     { NULL, NULL }
 };
 
index d6ccd05a21c3e63c5a9c1841d188047a6d6232da..448a6c467d81355959f4120239d7e45750ab1058 100644 (file)
@@ -38,6 +38,13 @@ int pkt4__tostring(lua_State* L) {
     return (1);
 }
 
+// Method table
+const luaL_Reg pkt4_method[] = {
+    { "__gc", pkt4__gc },
+    { "__tostring", pkt4__tostring },
+    { NULL, NULL }
+};
+
 // addOption(const OptionPtr opt) method
 int addOption(lua_State* L) {
     l_pkt4* const self =
@@ -48,16 +55,222 @@ int addOption(lua_State* L) {
     return (0);
 }
 
-// Method table
-const luaL_Reg pkt4_method[] = {
-    { "__gc", pkt4__gc },
-    { "__tostring", pkt4__tostring },
-    { "addOption", addOption },
-    { NULL, NULL }
-};
+// delOption(uint16_t type) method
+int delOption(lua_State* L) {
+    // Requires 2 arguments
+    if (lua_gettop(L) != 2) {
+        return (luaL_error(L, "pkt4.delOption takes 2 arguments"));
+    }
+    l_pkt4* const self =
+        static_cast<l_pkt4*>(luaL_checkudata(L, 1, LUA_KEAPKT4));
+    if (!lua_isinteger(L, 2)) {
+        return (luaL_error(L, "type must be an integer"));
+    }
+    uint16_t t = static_cast<uint16_t>(lua_tointeger(L, 2));
+    bool ret = self->object->delOption(t);
+    lua_pushboolean(L, ret ? 1 : 0);
+    return (1);
+}
+
+// len() method
+int len(lua_State* L) {
+    l_pkt4* const self =
+        static_cast<l_pkt4*>(luaL_checkudata(L, 1, LUA_KEAPKT4));
+    lua_pushinteger(L, static_cast<lua_Integer>(self->object->len()));
+    return (1);
+}
+
+// getType() method
+int getType(lua_State* L) {
+    l_pkt4* const self =
+        static_cast<l_pkt4*>(luaL_checkudata(L, 1, LUA_KEAPKT4));
+    lua_pushinteger(L, static_cast<lua_Integer>(self->object->getType()));
+    return (1);
+}
+
+// setType(uint8_t type) method
+int setType(lua_State* L) {
+    // Requires 2 arguments
+    if (lua_gettop(L) != 2) {
+        return (luaL_error(L, "pkt4.setType takes 2 arguments"));
+    }
+    l_pkt4* const self =
+        static_cast<l_pkt4*>(luaL_checkudata(L, 1, LUA_KEAPKT4));
+    if (!lua_isinteger(L, 2)) {
+        return (luaL_error(L, "type must be an integer"));
+    }
+    uint16_t t = static_cast<uint16_t>(lua_tointeger(L, 2));
+    self->object->setType(t);
+    return (1);
+}
+
+// setTransid(uint32_t transid) method
+int setTransid(lua_State* L) {
+    // Requires 2 arguments
+    if (lua_gettop(L) != 2) {
+        return (luaL_error(L, "pkt4.setTransid takes 2 arguments"));
+    }
+    l_pkt4* const self =
+        static_cast<l_pkt4*>(luaL_checkudata(L, 1, LUA_KEAPKT4));
+    if (!lua_isinteger(L, 2)) {
+        return (luaL_error(L, "transid must be an integer"));
+    }
+    uint32_t t = static_cast<uint32_t>(lua_tointeger(L, 2));
+    self->object->setTransid(t);
+    return (1);
+}
+
+// getTransid() method
+int getTransid(lua_State* L) {
+    l_pkt4* const self =
+        static_cast<l_pkt4*>(luaL_checkudata(L, 1, LUA_KEAPKT4));
+    lua_pushinteger(L, static_cast<lua_Integer>(self->object->getTransid()));
+    return (1);
+}
+
+// inClass(const isc::dhcp::ClientClass& client_class) method
+int inClass(lua_State* L) {
+    // Requires 2 arguments
+    if (lua_gettop(L) != 2) {
+        return (luaL_error(L, "pkt4.inClass takes 2 arguments"));
+    }
+    l_pkt4* const self =
+        static_cast<l_pkt4*>(luaL_checkudata(L, 1, LUA_KEAPKT4));
+    if (!lua_isstring(L, 2)) {
+        return (luaL_error(L, "client_class must be a string"));
+    }
+    const ClientClass& cclass(lua_tostring(L, 2));
+    bool ret = self->object->inClass(cclass);
+    lua_pushboolean(L, ret ? 1 : 0);
+    return (1);
+}
+
+// addClass(const isc::dhcp::ClientClass& client_class) method
+int addClass(lua_State* L) {
+    // Requires 2 arguments
+    if (lua_gettop(L) != 2) {
+        return (luaL_error(L, "pkt4.addClass takes 2 arguments"));
+    }
+    l_pkt4* const self =
+        static_cast<l_pkt4*>(luaL_checkudata(L, 1, LUA_KEAPKT4));
+    if (!lua_isstring(L, 2)) {
+        return (luaL_error(L, "client_class must be a string"));
+    }
+    const ClientClass& cclass(lua_tostring(L, 2));
+    self->object->addClass(cclass);
+    return (0);
+}
+
+// TODO: getClasses() method
+
+// getOption(uint16_t type) method
+int getOption(lua_State* L) {
+    // Requires 2 arguments
+    if (lua_gettop(L) != 2) {
+        return (luaL_error(L, "pkt4.getOption takes 2 arguments"));
+    }
+    l_pkt4* const self =
+        static_cast<l_pkt4*>(luaL_checkudata(L, 1, LUA_KEAPKT4));
+    if (!lua_isinteger(L, 2)) {
+        return (luaL_error(L, "type must be an integer"));
+    }
+    uint16_t t = static_cast<uint16_t>(lua_tointeger(L, 2));
+    OptionPtr sub = self->object->getOption(t);
+    if (sub) {
+        void* ret =
+            static_cast<l_option*>(lua_newuserdata(L, sizeof(l_option)));
+        memset(ret, 0, sizeof(l_option));
+        (static_cast<l_option*>(ret))->object = sub;
+    } else {
+        lua_pushnil(L);
+    }
+    return (1);
+}
+
+// TODO: getTimestamp() method
+
+// TODO: set/getLocal/RemoteAddr/Port methods
+
+// setIndex(uint32_t ifindex) method
+int setIndex(lua_State* L) {
+    // Requires 2 arguments
+    if (lua_gettop(L) != 2) {
+        return (luaL_error(L, "pkt4.setIndex takes 2 arguments"));
+    }
+    l_pkt4* const self =
+        static_cast<l_pkt4*>(luaL_checkudata(L, 1, LUA_KEAPKT4));
+    if (!lua_isinteger(L, 2)) {
+        return (luaL_error(L, "ifindex must be an integer"));
+    }
+    uint32_t t = static_cast<uint32_t>(lua_tointeger(L, 2));
+    self->object->setIndex(t);
+    return (1);
+}
+
+// getIndex() method
+int getIndex(lua_State* L) {
+    l_pkt4* const self =
+        static_cast<l_pkt4*>(luaL_checkudata(L, 1, LUA_KEAPKT4));
+    lua_pushinteger(L, static_cast<lua_Integer>(self->object->getIndex()));
+    return (1);
+}
+
+// getIface() method
+int getIface(lua_State* L) {
+    l_pkt4* const self =
+        static_cast<l_pkt4*>(luaL_checkudata(L, 1, LUA_KEAPKT4));
+    lua_pushstring(L, self->object->getIface().c_str());
+    return (1);
+}
+
+// setIface(const std::string& iface) method
+int setIface(lua_State* L) {
+    // Requires 2 arguments
+    if (lua_gettop(L) != 2) {
+        return (luaL_error(L, "pkt4.setIface takes 2 arguments"));
+    }
+    l_pkt4* const self =
+        static_cast<l_pkt4*>(luaL_checkudata(L, 1, LUA_KEAPKT4));
+    if (!lua_isstring(L, 2)) {
+        return (luaL_error(L, "iface must be a string"));
+    }
+    const ClientClass& cclass(lua_tostring(L, 2));
+    self->object->setIface(cclass);
+    return (0);
+}
+
+// TODO many methods
+
+// getHWAddr() method
+int getHWAddr(lua_State* L) {
+    l_pkt4* const self =
+        static_cast<l_pkt4*>(luaL_checkudata(L, 1, LUA_KEAPKT4));
+    HWAddrPtr hwaddr = self->object->getHWAddr();
+    vector<uint8_t> bin;
+    if (hwaddr) {
+        bin = hwaddr->hwaddr_;
+    }
+    lua_pushlstring(L, reinterpret_cast<char*>(&bin[0]), bin.size());
+    return (1);
+}
 
 // Function table
 const luaL_Reg pkt4_function[] = {
+    { "addOption", addOption },
+    { "delOption", delOption },
+    { "len", len },
+    { "getType", getType },
+    { "setType", setType },
+    { "setTransid", setTransid },
+    { "getTransid", getTransid },
+    { "inClass", inClass },
+    { "addClass", addClass },
+    { "getOption", getOption },
+    { "setIndex", setIndex },
+    { "getIndex", getIndex },
+    { "getIface", getIface },
+    { "setIface", setIface },
+    { "getHWAddr", getHWAddr },
     { NULL, NULL }
 };
 
index 71c2b222cfbbd548037276975561e3599ea88ff8..91ea5970166df12ac94f565dbe68fd1ad18e7bdf 100644 (file)
@@ -86,6 +86,8 @@ module Packet4 = struct
     external getIface : pkt4 -> string = "pkt4_getIface"
 
     external setIface : pkt4 -> string -> unit = "pkt4_setIface"
+
+    external getHWAddr : pkt4 -> bytes = "pkt4_getHWAddr"
 end
 
 let _ = print_leave "pkt4"
index 4f7938d2d772f024522ae00c65240c3319edbb89..98be6bb23be8465dea8332dee5f43923f97f5f68 100644 (file)
@@ -80,6 +80,10 @@ module Packet4 : sig
     external getIface : pkt4 -> string = "pkt4_getIface"
 
     external setIface : pkt4 -> string -> unit = "pkt4_setIface"
+
+    (* TODO many *)
+
+    external getHWAddr : pkt4 -> bytes = "pkt4_getHWAddr"
 end
 
 val next_step_continue : int
index b4b33ac4092755637df2f19a644ce6f78c8c3315..01040c22633ef7f0c710e7a5ce8c5f7b1133ef8a 100644 (file)
@@ -121,7 +121,7 @@ extern "C" CAMLprim value opt_toBinary(value opt) {
     CAMLparam1(opt);
     CAMLlocal1(result);
     oc_opt* const self = static_cast<oc_opt*>(Data_custom_val(opt));
-    vector<uint8_t> bin = self->object->toBinary(0);
+    vector<uint8_t> bin = self->object->toBinary(true);
     result = caml_alloc_string(static_cast<mlsize_t>(bin.size()));
     memmove(String_val(result), &bin[0], bin.size());
     CAMLreturn (result);
index add46b01f10b680308adbfb11d0dcdf8a8e23f06..f3ae157eb8bc1401e729acc12de92bc0f62a6cfa 100644 (file)
@@ -182,5 +182,23 @@ extern "C" CAMLprim value pkt4_setIface(value pkt, value ifn) {
     CAMLreturn (Val_unit);
 }
 
+// TODO many
+
+extern "C" CAMLprim value pkt4_getHWAddr(value pkt) {
+    CAMLparam1(pkt);
+    CAMLlocal1(result);
+    oc_pkt4* const self = static_cast<oc_pkt4*>(Data_custom_val(pkt));
+    HWAddrPtr hwaddr = self->object->getHWAddr();
+    vector<uint8_t> bin;
+    if (hwaddr) {
+        bin = hwaddr->hwaddr_;
+    }
+    result = caml_alloc_string(static_cast<mlsize_t>(bin.size()));
+    if (!bin.empty()) {
+        memmove(String_val(result), &bin[0], bin.size());
+    }
+    CAMLreturn (result);
+}
+
 } // end of namespace ocaml
 } // end of namespace isc
index 3e844c435b055a6ed66efd0781a7f7aa39319838..d23e328cbc84a26b8463f9a78d75ba5af96a21be 100644 (file)
@@ -35,6 +35,7 @@ extern "C" CAMLprim value pkt4_setIndex(value pkt, value idx);
 extern "C" CAMLprim value pkt4_getIndex(value pkt);
 extern "C" CAMLprim value pkt4_getIface(value pkt);
 extern "C" CAMLprim value pkt4_setIface(value pkt, value ifn);
+extern "C" CAMLprim value pkt4_getHWAddr(value pkt);
 
 CAMLextern struct custom_operations* pkt4_ops;
 
index 9c5846106b348551adbd4872b243ef562503c017..5dc456c39fcb21bc22fcb91449f3b54287447cde 100644 (file)
@@ -53,7 +53,9 @@ option_init(PyObject* obj, PyObject* args, PyObject*) {
 
     OptionBuffer data;
     data.resize(PyBytes_GET_SIZE(d));
-    memmove(&data[0], PyBytes_AS_STRING(d), data.size());
+    if (!data.empty()) {
+        memmove(&data[0], PyBytes_AS_STRING(d), data.size());
+    }
 
     py_option* const self = static_cast<py_option*>(obj);
     self->object.reset(new Option(universe, t, data));
@@ -197,7 +199,9 @@ setData(PyObject* obj, PyObject* args) {
     }
     vector<uint8_t> data;
     data.resize(PyBytes_GET_SIZE(d));
-    memmove(&data[0], PyBytes_AS_STRING(d), data.size());
+    if (!data.empty()) {
+        memmove(&data[0], PyBytes_AS_STRING(d), data.size());
+    }
 
     py_option* const self = static_cast<py_option*>(obj);
     self->object->setData(data.begin(), data.end());
index bdad7d5327f18e063eec77b26cc40aebf0f6285f..90b90a1f12eb9e16ad1e0cb32a5d0287e6fe691a 100644 (file)
@@ -220,6 +220,21 @@ setIface(PyObject* obj, PyObject* args) {
     Py_RETURN_NONE;
 }
 
+// TODO many methods
+
+// getHWAddr() method
+PyObject*
+getHWAddr(PyObject* obj) {
+    py_pkt4* const self = static_cast<py_pkt4*>(obj);
+    HWAddrPtr hwaddr = self->object->getHWAddr();
+    vector<uint8_t> bin;
+    if (hwaddr) {
+        bin = hwaddr->hwaddr_;
+    }
+    return (PyBytes_FromStringAndSize(reinterpret_cast<char*>(&bin[0]),
+                                      static_cast<Py_ssize_t>(bin.size())));
+}
+
 // Method table
 PyMethodDef pkt4_method[] = {
     { "addOption", addOption, METH_VARARGS,
@@ -250,6 +265,8 @@ PyMethodDef pkt4_method[] = {
       "return interface name" },
     { "setIface", setIface, METH_VARARGS,
       "sets interface name" },
+    { "getHWAddr", (PyCFunction)getHWAddr, METH_NOARGS,
+      "returns hardware address information" },
     { NULL, NULL, 0, NULL }
 };