Browse Source

[1540] Huge (29 files changed) Option6 and Pkt6 refactoring in DHCP.

- Migrated from boost::shared_array to std::vector<uint8>
- Pkt6 now have all fields private, getters/setters implemented
- Many smaller clean-ups
- Tests updated to follow new procedure
- isc::util::OutputBuffer is now used
Tomek Mrugalski 13 years ago
parent
commit
219324e66e

+ 6 - 0
ChangeLog

@@ -1,3 +1,9 @@
+3XX.	[func]		tomek
+	libdhcp++: Option6 and Pkt6 now follow the same design as
+	options and packet for DHCPv4. General code refactoring after
+	end of 2011 year release.
+	(Trac #1540, git TBD)
+
 359.	[bug]		kevin
 359.	[bug]		kevin
 	Corrected SOA serial check in xfrout.  It now compares the SOA
 	Corrected SOA serial check in xfrout.  It now compares the SOA
 	serial of an IXFR query with that of the server based serial
 	serial of an IXFR query with that of the server based serial

+ 25 - 31
src/bin/dhcp4/dhcp4_srv.cc

@@ -1,4 +1,4 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011-2012 Internet Systems Consortium, Inc. ("ISC")
 //
 //
 // Permission to use, copy, modify, and/or distribute this software for any
 // Permission to use, copy, modify, and/or distribute this software for any
 // purpose with or without fee is hereby granted, provided that the above
 // purpose with or without fee is hereby granted, provided that the above
@@ -59,8 +59,8 @@ Dhcpv4Srv::~Dhcpv4Srv() {
 bool
 bool
 Dhcpv4Srv::run() {
 Dhcpv4Srv::run() {
     while (!shutdown_) {
     while (!shutdown_) {
-        boost::shared_ptr<Pkt4> query; // client's message
+        Pkt4Ptr query; // client's message
-        boost::shared_ptr<Pkt4> rsp;   // server's response
+        Pkt4Ptr rsp;   // server's response
 
 
         query = IfaceMgr::instance().receive4();
         query = IfaceMgr::instance().receive4();
 
 
@@ -141,14 +141,13 @@ Dhcpv4Srv::setServerID() {
 #if 0
 #if 0
     // uncomment this once ticket 1350 is merged.
     // uncomment this once ticket 1350 is merged.
     IOAddress srvId("127.0.0.1");
     IOAddress srvId("127.0.0.1");
-    serverid_ = boost::shared_ptr<Option>(
+    serverid_ = OptionPtr(
       new Option4AddrLst(Option::V4, DHO_DHCP_SERVER_IDENTIFIER, srvId));
       new Option4AddrLst(Option::V4, DHO_DHCP_SERVER_IDENTIFIER, srvId));
 #endif
 #endif
 }
 }
 
 
 
 
-void Dhcpv4Srv::copyDefaultFields(const boost::shared_ptr<Pkt4>& question,
+void Dhcpv4Srv::copyDefaultFields(const Pkt4Ptr& question, Pkt4Ptr& answer) {
-                                  boost::shared_ptr<Pkt4>& answer) {
     answer->setIface(question->getIface());
     answer->setIface(question->getIface());
     answer->setIndex(question->getIndex());
     answer->setIndex(question->getIndex());
     answer->setCiaddr(question->getCiaddr());
     answer->setCiaddr(question->getCiaddr());
@@ -174,17 +173,17 @@ void Dhcpv4Srv::copyDefaultFields(const boost::shared_ptr<Pkt4>& question,
 
 
 }
 }
 
 
-void Dhcpv4Srv::appendDefaultOptions(boost::shared_ptr<Pkt4>& msg, uint8_t msg_type) {
+void Dhcpv4Srv::appendDefaultOptions(Pkt4Ptr& msg, uint8_t msg_type) {
-    boost::shared_ptr<Option> opt;
+    OptionPtr opt;
 
 
     // add Message Type Option (type 53)
     // add Message Type Option (type 53)
     std::vector<uint8_t> tmp;
     std::vector<uint8_t> tmp;
     tmp.push_back(static_cast<uint8_t>(msg_type));
     tmp.push_back(static_cast<uint8_t>(msg_type));
-    opt = boost::shared_ptr<Option>(new Option(Option::V4, DHO_DHCP_MESSAGE_TYPE, tmp));
+    opt = OptionPtr(new Option(Option::V4, DHO_DHCP_MESSAGE_TYPE, tmp));
     msg->addOption(opt);
     msg->addOption(opt);
 
 
     // DHCP Server Identifier (type 54)
     // DHCP Server Identifier (type 54)
-    opt = boost::shared_ptr<Option>
+    opt = OptionPtr
         (new Option4AddrLst(DHO_DHCP_SERVER_IDENTIFIER, IOAddress(HARDCODED_SERVER_ID)));
         (new Option4AddrLst(DHO_DHCP_SERVER_IDENTIFIER, IOAddress(HARDCODED_SERVER_ID)));
     msg->addOption(opt);
     msg->addOption(opt);
 
 
@@ -192,47 +191,43 @@ void Dhcpv4Srv::appendDefaultOptions(boost::shared_ptr<Pkt4>& msg, uint8_t msg_t
 }
 }
 
 
 
 
-void Dhcpv4Srv::appendRequestedOptions(boost::shared_ptr<Pkt4>& msg) {
+void Dhcpv4Srv::appendRequestedOptions(Pkt4Ptr& msg) {
-    boost::shared_ptr<Option> opt;
+    OptionPtr opt;
 
 
     // Domain name (type 15)
     // Domain name (type 15)
     vector<uint8_t> domain(HARDCODED_DOMAIN_NAME.begin(), HARDCODED_DOMAIN_NAME.end());
     vector<uint8_t> domain(HARDCODED_DOMAIN_NAME.begin(), HARDCODED_DOMAIN_NAME.end());
-    opt = boost::shared_ptr<Option>(new Option(Option::V4, DHO_DOMAIN_NAME, domain));
+    opt = OptionPtr(new Option(Option::V4, DHO_DOMAIN_NAME, domain));
     msg->addOption(opt);
     msg->addOption(opt);
     // TODO: Add Option_String class
     // TODO: Add Option_String class
 
 
     // DNS servers (type 6)
     // DNS servers (type 6)
-    opt = boost::shared_ptr<Option>
+    opt = OptionPtr(new Option4AddrLst(DHO_DOMAIN_NAME_SERVERS, IOAddress(HARDCODED_DNS_SERVER)));
-        (new Option4AddrLst(DHO_DOMAIN_NAME_SERVERS, IOAddress(HARDCODED_DNS_SERVER)));
     msg->addOption(opt);
     msg->addOption(opt);
 }
 }
 
 
-void Dhcpv4Srv::tryAssignLease(boost::shared_ptr<Pkt4>& msg) {
+void Dhcpv4Srv::tryAssignLease(Pkt4Ptr& msg) {
-    boost::shared_ptr<Option> opt;
+    OptionPtr opt;
 
 
     // TODO: Implement actual lease assignment here
     // TODO: Implement actual lease assignment here
     msg->setYiaddr(IOAddress(HARDCODED_LEASE));
     msg->setYiaddr(IOAddress(HARDCODED_LEASE));
 
 
     // IP Address Lease time (type 51)
     // IP Address Lease time (type 51)
-    opt = boost::shared_ptr<Option>(new Option(Option::V4, DHO_DHCP_LEASE_TIME));
+    opt = OptionPtr(new Option(Option::V4, DHO_DHCP_LEASE_TIME));
     opt->setUint32(HARDCODED_LEASE_TIME);
     opt->setUint32(HARDCODED_LEASE_TIME);
     msg->addOption(opt);
     msg->addOption(opt);
     // TODO: create Option_IntArray that holds list of integers, similar to Option4_AddrLst
     // TODO: create Option_IntArray that holds list of integers, similar to Option4_AddrLst
 
 
     // Subnet mask (type 1)
     // Subnet mask (type 1)
-    opt = boost::shared_ptr<Option>
+    opt = OptionPtr(new Option4AddrLst(DHO_SUBNET_MASK, IOAddress(HARDCODED_NETMASK)));
-        (new Option4AddrLst(DHO_SUBNET_MASK, IOAddress(HARDCODED_NETMASK)));
     msg->addOption(opt);
     msg->addOption(opt);
 
 
     // Router (type 3)
     // Router (type 3)
-    opt = boost::shared_ptr<Option>
+    opt = OptionPtr(new Option4AddrLst(DHO_ROUTERS, IOAddress(HARDCODED_GATEWAY)));
-        (new Option4AddrLst(DHO_ROUTERS, IOAddress(HARDCODED_GATEWAY)));
     msg->addOption(opt);
     msg->addOption(opt);
 }
 }
 
 
-boost::shared_ptr<Pkt4>
+Pkt4Ptr Dhcpv4Srv::processDiscover(Pkt4Ptr& discover) {
-Dhcpv4Srv::processDiscover(boost::shared_ptr<Pkt4>& discover) {
+    Pkt4Ptr offer = Pkt4Ptr
-    boost::shared_ptr<Pkt4> offer = boost::shared_ptr<Pkt4>
         (new Pkt4(DHCPOFFER, discover->getTransid()));
         (new Pkt4(DHCPOFFER, discover->getTransid()));
 
 
     copyDefaultFields(discover, offer);
     copyDefaultFields(discover, offer);
@@ -244,9 +239,8 @@ Dhcpv4Srv::processDiscover(boost::shared_ptr<Pkt4>& discover) {
     return (offer);
     return (offer);
 }
 }
 
 
-boost::shared_ptr<Pkt4>
+Pkt4Ptr Dhcpv4Srv::processRequest(Pkt4Ptr& request) {
-Dhcpv4Srv::processRequest(boost::shared_ptr<Pkt4>& request) {
+    Pkt4Ptr ack = Pkt4Ptr
-    boost::shared_ptr<Pkt4> ack = boost::shared_ptr<Pkt4>
         (new Pkt4(DHCPACK, request->getTransid()));
         (new Pkt4(DHCPACK, request->getTransid()));
 
 
     copyDefaultFields(request, ack);
     copyDefaultFields(request, ack);
@@ -258,17 +252,17 @@ Dhcpv4Srv::processRequest(boost::shared_ptr<Pkt4>& request) {
     return (ack);
     return (ack);
 }
 }
 
 
-void Dhcpv4Srv::processRelease(boost::shared_ptr<Pkt4>& release) {
+void Dhcpv4Srv::processRelease(Pkt4Ptr& release) {
     /// TODO: Implement this.
     /// TODO: Implement this.
     cout << "Received RELEASE on " << release->getIface() << " interface." << endl;
     cout << "Received RELEASE on " << release->getIface() << " interface." << endl;
 }
 }
 
 
-void Dhcpv4Srv::processDecline(boost::shared_ptr<Pkt4>& decline) {
+void Dhcpv4Srv::processDecline(Pkt4Ptr& decline) {
     /// TODO: Implement this.
     /// TODO: Implement this.
     cout << "Received DECLINE on " << decline->getIface() << " interface." << endl;
     cout << "Received DECLINE on " << decline->getIface() << " interface." << endl;
 }
 }
 
 
-boost::shared_ptr<Pkt4> Dhcpv4Srv::processInform(boost::shared_ptr<Pkt4>& inform) {
+Pkt4Ptr Dhcpv4Srv::processInform(Pkt4Ptr& inform) {
     /// TODO: Currently implemented echo mode. Implement this for real
     /// TODO: Currently implemented echo mode. Implement this for real
     return (inform);
     return (inform);
 }
 }

+ 12 - 19
src/bin/dhcp4/dhcp4_srv.h

@@ -1,4 +1,4 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011-2012 Internet Systems Consortium, Inc. ("ISC")
 //
 //
 // Permission to use, copy, modify, and/or distribute this software for any
 // Permission to use, copy, modify, and/or distribute this software for any
 // purpose with or without fee is hereby granted, provided that the above
 // purpose with or without fee is hereby granted, provided that the above
@@ -15,7 +15,6 @@
 #ifndef DHCPV4_SRV_H
 #ifndef DHCPV4_SRV_H
 #define DHCPV4_SRV_H
 #define DHCPV4_SRV_H
 
 
-#include <boost/shared_ptr.hpp>
 #include <boost/noncopyable.hpp>
 #include <boost/noncopyable.hpp>
 #include <dhcp/dhcp4.h>
 #include <dhcp/dhcp4.h>
 #include <dhcp/pkt4.h>
 #include <dhcp/pkt4.h>
@@ -71,8 +70,7 @@ protected:
     /// @param solicit DISCOVER message received from client
     /// @param solicit DISCOVER message received from client
     ///
     ///
     /// @return OFFER message or NULL
     /// @return OFFER message or NULL
-    boost::shared_ptr<Pkt4>
+    Pkt4Ptr processDiscover(Pkt4Ptr& discover);
-    processDiscover(boost::shared_ptr<Pkt4>& discover);
 
 
     /// @brief Processes incoming REQUEST and returns REPLY response.
     /// @brief Processes incoming REQUEST and returns REPLY response.
     ///
     ///
@@ -86,7 +84,7 @@ protected:
     /// @param request a message received from client
     /// @param request a message received from client
     ///
     ///
     /// @return ACK or NACK message
     /// @return ACK or NACK message
-    boost::shared_ptr<Pkt4> processRequest(boost::shared_ptr<Pkt4>& request);
+    Pkt4Ptr processRequest(Pkt4Ptr& request);
 
 
     /// @brief Stub function that will handle incoming RELEASE messages.
     /// @brief Stub function that will handle incoming RELEASE messages.
     ///
     ///
@@ -94,17 +92,17 @@ protected:
     /// this function does not return anything.
     /// this function does not return anything.
     ///
     ///
     /// @param release message received from client
     /// @param release message received from client
-    void processRelease(boost::shared_ptr<Pkt4>& release);
+    void processRelease(Pkt4Ptr& release);
 
 
     /// @brief Stub function that will handle incoming DHCPDECLINE messages.
     /// @brief Stub function that will handle incoming DHCPDECLINE messages.
     ///
     ///
     /// @param decline message received from client
     /// @param decline message received from client
-    void processDecline(boost::shared_ptr<Pkt4>& decline);
+    void processDecline(Pkt4Ptr& decline);
 
 
     /// @brief Stub function that will handle incoming INFORM messages.
     /// @brief Stub function that will handle incoming INFORM messages.
     ///
     ///
     /// @param infRequest message received from client
     /// @param infRequest message received from client
-    boost::shared_ptr<Pkt4> processInform(boost::shared_ptr<Pkt4>& inform);
+    Pkt4Ptr processInform(Pkt4Ptr& inform);
 
 
     /// @brief Copies default parameters from client's to server's message
     /// @brief Copies default parameters from client's to server's message
     ///
     ///
@@ -113,9 +111,7 @@ protected:
     ///
     ///
     /// @param question any message sent by client
     /// @param question any message sent by client
     /// @param answer any message server is going to send as response
     /// @param answer any message server is going to send as response
-    void copyDefaultFields(const boost::shared_ptr<Pkt4>& question,
+    void copyDefaultFields(const Pkt4Ptr& question, Pkt4Ptr& answer);
-                           boost::shared_ptr<Pkt4>& answer);
-
 
 
     /// @brief Appends options requested by client.
     /// @brief Appends options requested by client.
     ///
     ///
@@ -123,8 +119,7 @@ protected:
     /// (sent in PRL) or are enforced by server.
     /// (sent in PRL) or are enforced by server.
     ///
     ///
     /// @param msg outgoing message (options will be added here)
     /// @param msg outgoing message (options will be added here)
-    void appendRequestedOptions(boost::shared_ptr<Pkt4>& msg);
+    void appendRequestedOptions(Pkt4Ptr& msg);
-
 
 
     /// @brief Assigns a lease and appends corresponding options
     /// @brief Assigns a lease and appends corresponding options
     ///
     ///
@@ -136,20 +131,18 @@ protected:
     /// used fixed, hardcoded lease.
     /// used fixed, hardcoded lease.
     ///
     ///
     /// @param msg OFFER or ACK message (lease options will be added here)
     /// @param msg OFFER or ACK message (lease options will be added here)
-    void tryAssignLease(boost::shared_ptr<Pkt4>& msg);
+    void tryAssignLease(Pkt4Ptr& msg);
-
 
 
     /// @brief Appends default options to a message
     /// @brief Appends default options to a message
     ///
     ///
     /// @param msg message object (options will be added to it)
     /// @param msg message object (options will be added to it)
     /// @param msg_type specifies message type
     /// @param msg_type specifies message type
-    void appendDefaultOptions(boost::shared_ptr<Pkt4>& msg, uint8_t msg_type);
+    void appendDefaultOptions(Pkt4Ptr& msg, uint8_t msg_type);
 
 
     /// @brief Returns server-intentifier option
     /// @brief Returns server-intentifier option
     ///
     ///
     /// @return server-id option
     /// @return server-id option
-    boost::shared_ptr<isc::dhcp::Option>
+    OptionPtr getServerID() { return serverid_; }
-    getServerID() { return serverid_; }
 
 
     /// @brief Sets server-identifier.
     /// @brief Sets server-identifier.
     ///
     ///
@@ -163,7 +156,7 @@ protected:
     void setServerID();
     void setServerID();
 
 
     /// server DUID (to be sent in server-identifier option)
     /// server DUID (to be sent in server-identifier option)
-    boost::shared_ptr<isc::dhcp::Option> serverid_;
+    OptionPtr serverid_;
 
 
     /// indicates if shutdown is in progress. Setting it to true will
     /// indicates if shutdown is in progress. Setting it to true will
     /// initiate server shutdown procedure.
     /// initiate server shutdown procedure.

+ 33 - 57
src/bin/dhcp6/dhcp6_srv.cc

@@ -1,4 +1,4 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011-2012 Internet Systems Consortium, Inc. ("ISC")
 //
 //
 // Permission to use, copy, modify, and/or distribute this software for any
 // Permission to use, copy, modify, and/or distribute this software for any
 // purpose with or without fee is hereby granted, provided that the above
 // purpose with or without fee is hereby granted, provided that the above
@@ -70,8 +70,8 @@ Dhcpv6Srv::~Dhcpv6Srv() {
 bool
 bool
 Dhcpv6Srv::run() {
 Dhcpv6Srv::run() {
     while (!shutdown) {
     while (!shutdown) {
-        boost::shared_ptr<Pkt6> query; // client's message
+        Pkt6Ptr query; // client's message
-        boost::shared_ptr<Pkt6> rsp;   // server's response
+        Pkt6Ptr rsp;   // server's response
 
 
         query = IfaceMgr::instance().receive6();
         query = IfaceMgr::instance().receive6();
 
 
@@ -110,16 +110,16 @@ Dhcpv6Srv::run() {
                      << query->getType() << endl;
                      << query->getType() << endl;
             }
             }
 
 
-            cout << "Received " << query->data_len_ << " bytes packet type="
+            cout << "Received " << query->getBuffer().getLength() << " bytes packet type="
                  << query->getType() << endl;
                  << query->getType() << endl;
             cout << query->toText();
             cout << query->toText();
             if (rsp) {
             if (rsp) {
-                rsp->remote_addr_ = query->remote_addr_;
+                rsp->setRemoteAddr(query->getRemoteAddr());
-                rsp->local_addr_ = query->local_addr_;
+                rsp->setLocalAddr(query->getLocalAddr());
-                rsp->remote_port_ = DHCP6_CLIENT_PORT;
+                rsp->setRemotePort(DHCP6_CLIENT_PORT);
-                rsp->local_port_ = DHCP6_SERVER_PORT;
+                rsp->setLocalPort(DHCP6_SERVER_PORT);
-                rsp->ifindex_ = query->ifindex_;
+                rsp->setIndex(query->getIndex());
-                rsp->iface_ = query->iface_;
+                rsp->setIface(query->getIface());
                 cout << "Replying with:" << rsp->getType() << endl;
                 cout << "Replying with:" << rsp->getType() << endl;
                 cout << rsp->toText();
                 cout << rsp->toText();
                 cout << "----" << endl;
                 cout << "----" << endl;
@@ -143,7 +143,7 @@ Dhcpv6Srv::setServerID() {
     /// TODO implement this for real once interface detection is done.
     /// TODO implement this for real once interface detection is done.
     /// Use hardcoded server-id for now
     /// Use hardcoded server-id for now
 
 
-    boost::shared_array<uint8_t> srvid(new uint8_t[14]);
+    OptionBuffer srvid(14);
     srvid[0] = 0;
     srvid[0] = 0;
     srvid[1] = 1; // DUID type 1 = DUID-LLT (see section 9.2 of RFC3315)
     srvid[1] = 1; // DUID type 1 = DUID-LLT (see section 9.2 of RFC3315)
     srvid[2] = 0;
     srvid[2] = 0;
@@ -154,12 +154,11 @@ Dhcpv6Srv::setServerID() {
     }
     }
     serverid_ = boost::shared_ptr<Option>(new Option(Option::V6,
     serverid_ = boost::shared_ptr<Option>(new Option(Option::V6,
                                                      D6O_SERVERID,
                                                      D6O_SERVERID,
-                                                     srvid,
+                                                     srvid.begin(),
-                                                     0, 14));
+                                                     srvid.end()));
 }
 }
 
 
-void Dhcpv6Srv::copyDefaultOptions(const boost::shared_ptr<Pkt6>& question,
+void Dhcpv6Srv::copyDefaultOptions(const Pkt6Ptr& question, Pkt6Ptr& answer) {
-                                   boost::shared_ptr<Pkt6>& answer) {
     // add client-id
     // add client-id
     boost::shared_ptr<Option> clientid = question->getOption(D6O_CLIENTID);
     boost::shared_ptr<Option> clientid = question->getOption(D6O_CLIENTID);
     if (clientid) {
     if (clientid) {
@@ -169,8 +168,7 @@ void Dhcpv6Srv::copyDefaultOptions(const boost::shared_ptr<Pkt6>& question,
     // TODO: Should throw if there is no client-id (except anonymous INF-REQUEST)
     // TODO: Should throw if there is no client-id (except anonymous INF-REQUEST)
 }
 }
 
 
-void Dhcpv6Srv::appendDefaultOptions(const boost::shared_ptr<Pkt6>& /*question*/,
+void Dhcpv6Srv::appendDefaultOptions(const Pkt6Ptr& /*question*/, Pkt6Ptr& answer) {
-                                   boost::shared_ptr<Pkt6>& answer) {
     // TODO: question is currently unused, but we need it at least to know
     // TODO: question is currently unused, but we need it at least to know
     // message type we are answering
     // message type we are answering
 
 
@@ -179,8 +177,7 @@ void Dhcpv6Srv::appendDefaultOptions(const boost::shared_ptr<Pkt6>& /*question*/
 }
 }
 
 
 
 
-void Dhcpv6Srv::appendRequestedOptions(const boost::shared_ptr<Pkt6>& /*question*/,
+void Dhcpv6Srv::appendRequestedOptions(const Pkt6Ptr& /*question*/, Pkt6Ptr& answer) {
-                                       boost::shared_ptr<Pkt6>& answer) {
     // TODO: question is currently unused, but we need to extract ORO from it
     // TODO: question is currently unused, but we need to extract ORO from it
     // and act on its content. Now we just send DNS-SERVERS option.
     // and act on its content. Now we just send DNS-SERVERS option.
 
 
@@ -190,8 +187,7 @@ void Dhcpv6Srv::appendRequestedOptions(const boost::shared_ptr<Pkt6>& /*question
     answer->addOption(dnsservers);
     answer->addOption(dnsservers);
 }
 }
 
 
-void Dhcpv6Srv::assignLeases(const boost::shared_ptr<Pkt6>& question,
+void Dhcpv6Srv::assignLeases(const Pkt6Ptr& question, Pkt6Ptr& answer) {
-                             boost::shared_ptr<Pkt6>& answer) {
     /// TODO Rewrite this once LeaseManager is implemented.
     /// TODO Rewrite this once LeaseManager is implemented.
 
 
     // answer client's IA (this is mostly a dummy,
     // answer client's IA (this is mostly a dummy,
@@ -217,11 +213,9 @@ void Dhcpv6Srv::assignLeases(const boost::shared_ptr<Pkt6>& question,
     }
     }
 }
 }
 
 
-boost::shared_ptr<Pkt6>
+Pkt6Ptr Dhcpv6Srv::processSolicit(const Pkt6Ptr& solicit) {
-Dhcpv6Srv::processSolicit(const boost::shared_ptr<Pkt6>& solicit) {
 
 
-    boost::shared_ptr<Pkt6> advertise(new Pkt6(DHCPV6_ADVERTISE,
+    Pkt6Ptr advertise(new Pkt6(DHCPV6_ADVERTISE, solicit->getTransid()));
-                                               solicit->getTransid()));
 
 
     copyDefaultOptions(solicit, advertise);
     copyDefaultOptions(solicit, advertise);
     appendDefaultOptions(solicit, advertise);
     appendDefaultOptions(solicit, advertise);
@@ -232,11 +226,9 @@ Dhcpv6Srv::processSolicit(const boost::shared_ptr<Pkt6>& solicit) {
     return (advertise);
     return (advertise);
 }
 }
 
 
-boost::shared_ptr<Pkt6>
+Pkt6Ptr Dhcpv6Srv::processRequest(const Pkt6Ptr& request) {
-Dhcpv6Srv::processRequest(const boost::shared_ptr<Pkt6>& request) {
 
 
-    boost::shared_ptr<Pkt6> reply(new Pkt6(DHCPV6_REPLY,
+    Pkt6Ptr reply(new Pkt6(DHCPV6_REPLY, request->getTransid()));
-                                           request->getTransid()));
 
 
     copyDefaultOptions(request, reply);
     copyDefaultOptions(request, reply);
     appendDefaultOptions(request, reply);
     appendDefaultOptions(request, reply);
@@ -247,50 +239,34 @@ Dhcpv6Srv::processRequest(const boost::shared_ptr<Pkt6>& request) {
     return (reply);
     return (reply);
 }
 }
 
 
-boost::shared_ptr<Pkt6>
+Pkt6Ptr Dhcpv6Srv::processRenew(const Pkt6Ptr& renew) {
-Dhcpv6Srv::processRenew(const boost::shared_ptr<Pkt6>& renew) {
+    Pkt6Ptr reply(new Pkt6(DHCPV6_REPLY, renew->getTransid()));
-    boost::shared_ptr<Pkt6> reply(new Pkt6(DHCPV6_REPLY,
-                                           renew->getTransid(),
-                                           Pkt6::UDP));
     return reply;
     return reply;
 }
 }
 
 
-boost::shared_ptr<Pkt6>
+Pkt6Ptr Dhcpv6Srv::processRebind(const Pkt6Ptr& rebind) {
-Dhcpv6Srv::processRebind(const boost::shared_ptr<Pkt6>& rebind) {
+    Pkt6Ptr reply(new Pkt6(DHCPV6_REPLY,
-    boost::shared_ptr<Pkt6> reply(new Pkt6(DHCPV6_REPLY,
                                            rebind->getTransid(),
                                            rebind->getTransid(),
                                            Pkt6::UDP));
                                            Pkt6::UDP));
     return reply;
     return reply;
 }
 }
 
 
-boost::shared_ptr<Pkt6>
+Pkt6Ptr Dhcpv6Srv::processConfirm(const Pkt6Ptr& confirm) {
-Dhcpv6Srv::processConfirm(const boost::shared_ptr<Pkt6>& confirm) {
+    Pkt6Ptr reply(new Pkt6(DHCPV6_REPLY, confirm->getTransid()));
-    boost::shared_ptr<Pkt6> reply(new Pkt6(DHCPV6_REPLY,
-                                           confirm->getTransid(),
-                                           Pkt6::UDP));
     return reply;
     return reply;
 }
 }
 
 
-boost::shared_ptr<Pkt6>
+Pkt6Ptr Dhcpv6Srv::processRelease(const Pkt6Ptr& release) {
-Dhcpv6Srv::processRelease(const boost::shared_ptr<Pkt6>& release) {
+    Pkt6Ptr reply(new Pkt6(DHCPV6_REPLY, release->getTransid()));
-    boost::shared_ptr<Pkt6> reply(new Pkt6(DHCPV6_REPLY,
-                                           release->getTransid(),
-                                           Pkt6::UDP));
     return reply;
     return reply;
 }
 }
 
 
-boost::shared_ptr<Pkt6>
+Pkt6Ptr Dhcpv6Srv::processDecline(const Pkt6Ptr& decline) {
-Dhcpv6Srv::processDecline(const boost::shared_ptr<Pkt6>& decline) {
+    Pkt6Ptr reply(new Pkt6(DHCPV6_REPLY, decline->getTransid()));
-    boost::shared_ptr<Pkt6> reply(new Pkt6(DHCPV6_REPLY,
-                                           decline->getTransid(),
-                                           Pkt6::UDP));
     return reply;
     return reply;
 }
 }
 
 
-boost::shared_ptr<Pkt6>
+Pkt6Ptr Dhcpv6Srv::processInfRequest(const Pkt6Ptr& infRequest) {
-Dhcpv6Srv::processInfRequest(const boost::shared_ptr<Pkt6>& infRequest) {
+    Pkt6Ptr reply(new Pkt6(DHCPV6_REPLY, infRequest->getTransid()));
-    boost::shared_ptr<Pkt6> reply(new Pkt6(DHCPV6_REPLY,
-                                           infRequest->getTransid(),
-                                           Pkt6::UDP));
     return reply;
     return reply;
 }
 }

+ 14 - 28
src/bin/dhcp6/dhcp6_srv.h

@@ -1,4 +1,4 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011-2012 Internet Systems Consortium, Inc. ("ISC")
 //
 //
 // Permission to use, copy, modify, and/or distribute this software for any
 // Permission to use, copy, modify, and/or distribute this software for any
 // purpose with or without fee is hereby granted, provided that the above
 // purpose with or without fee is hereby granted, provided that the above
@@ -15,7 +15,6 @@
 #ifndef DHCPV6_SRV_H
 #ifndef DHCPV6_SRV_H
 #define DHCPV6_SRV_H
 #define DHCPV6_SRV_H
 
 
-#include <boost/shared_ptr.hpp>
 #include <boost/noncopyable.hpp>
 #include <boost/noncopyable.hpp>
 #include <dhcp/dhcp6.h>
 #include <dhcp/dhcp6.h>
 #include <dhcp/pkt6.h>
 #include <dhcp/pkt6.h>
@@ -52,8 +51,7 @@ public:
     /// @brief Returns server-intentifier option
     /// @brief Returns server-intentifier option
     ///
     ///
     /// @return server-id option
     /// @return server-id option
-    boost::shared_ptr<isc::dhcp::Option>
+    OptionPtr getServerID() { return serverid_; }
-    getServerID() { return serverid_; }
 
 
     /// @brief Main server processing loop.
     /// @brief Main server processing loop.
     ///
     ///
@@ -80,8 +78,7 @@ protected:
     /// @param solicit SOLICIT message received from client
     /// @param solicit SOLICIT message received from client
     ///
     ///
     /// @return ADVERTISE, REPLY message or NULL
     /// @return ADVERTISE, REPLY message or NULL
-    boost::shared_ptr<Pkt6>
+    Pkt6Ptr processSolicit(const Pkt6Ptr& solicit);
-    processSolicit(const boost::shared_ptr<Pkt6>& solicit);
 
 
     /// @brief Processes incoming REQUEST and returns REPLY response.
     /// @brief Processes incoming REQUEST and returns REPLY response.
     ///
     ///
@@ -94,44 +91,37 @@ protected:
     /// @param request a message received from client
     /// @param request a message received from client
     ///
     ///
     /// @return REPLY message or NULL
     /// @return REPLY message or NULL
-    boost::shared_ptr<Pkt6>
+    Pkt6Ptr processRequest(const Pkt6Ptr& request);
-    processRequest(const boost::shared_ptr<Pkt6>& request);
 
 
     /// @brief Stub function that will handle incoming RENEW messages.
     /// @brief Stub function that will handle incoming RENEW messages.
     ///
     ///
     /// @param renew message received from client
     /// @param renew message received from client
-    boost::shared_ptr<Pkt6>
+    Pkt6Ptr processRenew(const Pkt6Ptr& renew);
-    processRenew(const boost::shared_ptr<Pkt6>& renew);
 
 
     /// @brief Stub function that will handle incoming REBIND messages.
     /// @brief Stub function that will handle incoming REBIND messages.
     ///
     ///
     /// @param rebind message received from client
     /// @param rebind message received from client
-    boost::shared_ptr<Pkt6>
+    Pkt6Ptr processRebind(const Pkt6Ptr& rebind);
-    processRebind(const boost::shared_ptr<Pkt6>& rebind);
 
 
     /// @brief Stub function that will handle incoming CONFIRM messages.
     /// @brief Stub function that will handle incoming CONFIRM messages.
     ///
     ///
     /// @param confirm message received from client
     /// @param confirm message received from client
-    boost::shared_ptr<Pkt6>
+    Pkt6Ptr processConfirm(const Pkt6Ptr& confirm);
-    processConfirm(const boost::shared_ptr<Pkt6>& confirm);
 
 
     /// @brief Stub function that will handle incoming RELEASE messages.
     /// @brief Stub function that will handle incoming RELEASE messages.
     ///
     ///
     /// @param release message received from client
     /// @param release message received from client
-    boost::shared_ptr<Pkt6>
+    Pkt6Ptr processRelease(const Pkt6Ptr& release);
-    processRelease(const boost::shared_ptr<Pkt6>& release);
 
 
     /// @brief Stub function that will handle incoming DECLINE messages.
     /// @brief Stub function that will handle incoming DECLINE messages.
     ///
     ///
     /// @param decline message received from client
     /// @param decline message received from client
-    boost::shared_ptr<Pkt6>
+    Pkt6Ptr processDecline(const Pkt6Ptr& decline);
-    processDecline(const boost::shared_ptr<Pkt6>& decline);
 
 
     /// @brief Stub function that will handle incoming INF-REQUEST messages.
     /// @brief Stub function that will handle incoming INF-REQUEST messages.
     ///
     ///
     /// @param infRequest message received from client
     /// @param infRequest message received from client
-    boost::shared_ptr<Pkt6>
+    Pkt6Ptr processInfRequest(const Pkt6Ptr& infRequest);
-    processInfRequest(const boost::shared_ptr<Pkt6>& infRequest);
 
 
     /// @brief Copies required options from client message to server answer
     /// @brief Copies required options from client message to server answer
     ///
     ///
@@ -141,8 +131,7 @@ protected:
     ///
     ///
     /// @param question client's message (options will be copied from here)
     /// @param question client's message (options will be copied from here)
     /// @param answer server's message (options will be copied here)
     /// @param answer server's message (options will be copied here)
-    void copyDefaultOptions(const boost::shared_ptr<Pkt6>& question,
+    void copyDefaultOptions(const Pkt6Ptr& question, Pkt6Ptr& answer);
-                            boost::shared_ptr<Pkt6>& answer);
 
 
     /// @brief Appends default options to server's answer.
     /// @brief Appends default options to server's answer.
     ///
     ///
@@ -152,8 +141,7 @@ protected:
     ///
     ///
     /// @param question client's message
     /// @param question client's message
     /// @param answer server's message (options will be added here)
     /// @param answer server's message (options will be added here)
-    void appendDefaultOptions(const boost::shared_ptr<Pkt6>& question,
+    void appendDefaultOptions(const Pkt6Ptr& question, Pkt6Ptr& answer);
-                              boost::shared_ptr<Pkt6>& answer);
 
 
     /// @brief Appends requested options to server's answer.
     /// @brief Appends requested options to server's answer.
     ///
     ///
@@ -163,8 +151,7 @@ protected:
     ///
     ///
     /// @param question client's message
     /// @param question client's message
     /// @param answer server's message (options will be added here)
     /// @param answer server's message (options will be added here)
-    void appendRequestedOptions(const boost::shared_ptr<Pkt6>& question,
+    void appendRequestedOptions(const Pkt6Ptr& question, Pkt6Ptr& answer);
-                                boost::shared_ptr<Pkt6>& answer);
 
 
     /// @brief Assigns leases.
     /// @brief Assigns leases.
     ///
     ///
@@ -174,8 +161,7 @@ protected:
     ///
     ///
     /// @param question client's message (with requested IA_NA)
     /// @param question client's message (with requested IA_NA)
     /// @param answer server's message (IA_NA options will be added here)
     /// @param answer server's message (IA_NA options will be added here)
-    void assignLeases(const boost::shared_ptr<Pkt6>& question,
+    void assignLeases(const Pkt6Ptr& question, Pkt6Ptr& answer);
-                      boost::shared_ptr<Pkt6>& answer);
 
 
     /// @brief Sets server-identifier.
     /// @brief Sets server-identifier.
     ///
     ///

+ 6 - 8
src/bin/dhcp6/tests/dhcp6_srv_unittest.cc

@@ -84,13 +84,11 @@ TEST_F(Dhcpv6SrvTest, Solicit_basic) {
     ASSERT_NO_THROW( srv = new NakedDhcpv6Srv(); );
     ASSERT_NO_THROW( srv = new NakedDhcpv6Srv(); );
 
 
     // a dummy content for client-id
     // a dummy content for client-id
-    boost::shared_array<uint8_t> clntDuid(new uint8_t[32]);
+    OptionBuffer clntDuid(32);
     for (int i = 0; i < 32; i++)
     for (int i = 0; i < 32; i++)
         clntDuid[i] = 100 + i;
         clntDuid[i] = 100 + i;
 
 
-    boost::shared_ptr<Pkt6> sol =
+    Pkt6Ptr sol = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 1234, Pkt6::UDP));
-        boost::shared_ptr<Pkt6>(new Pkt6(DHCPV6_SOLICIT,
-                                         1234, Pkt6::UDP));
 
 
     boost::shared_ptr<Option6IA> ia =
     boost::shared_ptr<Option6IA> ia =
         boost::shared_ptr<Option6IA>(new Option6IA(D6O_IA_NA, 234));
         boost::shared_ptr<Option6IA>(new Option6IA(D6O_IA_NA, 234));
@@ -113,9 +111,9 @@ TEST_F(Dhcpv6SrvTest, Solicit_basic) {
     // - server-id
     // - server-id
     // - IA that includes IAADDR
     // - IA that includes IAADDR
 
 
-    boost::shared_ptr<Option> clientid =
+    OptionPtr clientid = OptionPtr(new Option(Option::V6, D6O_CLIENTID,
-        boost::shared_ptr<Option>(new Option(Option::V6, D6O_CLIENTID,
+                                              clntDuid.begin(),
-                                             clntDuid, 0, 16));
+                                              clntDuid.begin()+16));
     sol->addOption(clientid);
     sol->addOption(clientid);
 
 
     boost::shared_ptr<Pkt6> reply = srv->processSolicit(sol);
     boost::shared_ptr<Pkt6> reply = srv->processSolicit(sol);
@@ -126,7 +124,7 @@ TEST_F(Dhcpv6SrvTest, Solicit_basic) {
     EXPECT_EQ( DHCPV6_ADVERTISE, reply->getType() );
     EXPECT_EQ( DHCPV6_ADVERTISE, reply->getType() );
     EXPECT_EQ( 1234, reply->getTransid() );
     EXPECT_EQ( 1234, reply->getTransid() );
 
 
-    boost::shared_ptr<Option> tmp = reply->getOption(D6O_IA_NA);
+    OptionPtr tmp = reply->getOption(D6O_IA_NA);
     ASSERT_TRUE( tmp );
     ASSERT_TRUE( tmp );
 
 
     Option6IA* reply_ia = dynamic_cast<Option6IA*>(tmp.get());
     Option6IA* reply_ia = dynamic_cast<Option6IA*>(tmp.get());

+ 67 - 83
src/lib/dhcp/iface_mgr.cc

@@ -437,8 +437,8 @@ int IfaceMgr::openSocket6(Iface& iface, const IOAddress& addr, int port) {
         isc_throw(Unexpected, "Failed to create UDP6 socket.");
         isc_throw(Unexpected, "Failed to create UDP6 socket.");
     }
     }
 
 
-    /* Set the REUSEADDR option so that we don't fail to start if
+    // Set the REUSEADDR option so that we don't fail to start if
-       we're being restarted. */
+    // we're being restarted.
     int flag = 1;
     int flag = 1;
     if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
     if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
                    (char *)&flag, sizeof(flag)) < 0) {
                    (char *)&flag, sizeof(flag)) < 0) {
@@ -452,14 +452,14 @@ int IfaceMgr::openSocket6(Iface& iface, const IOAddress& addr, int port) {
                   << "/port=" << port);
                   << "/port=" << port);
     }
     }
 #ifdef IPV6_RECVPKTINFO
 #ifdef IPV6_RECVPKTINFO
-    /* RFC3542 - a new way */
+    // RFC3542 - a new way
     if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO,
     if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO,
                    &flag, sizeof(flag)) != 0) {
                    &flag, sizeof(flag)) != 0) {
         close(sock);
         close(sock);
         isc_throw(Unexpected, "setsockopt: IPV6_RECVPKTINFO failed.");
         isc_throw(Unexpected, "setsockopt: IPV6_RECVPKTINFO failed.");
     }
     }
 #else
 #else
-    /* RFC2292 - an old way */
+    // RFC2292 - an old way
     if (setsockopt(sock, IPPROTO_IPV6, IPV6_PKTINFO,
     if (setsockopt(sock, IPPROTO_IPV6, IPV6_PKTINFO,
                    &flag, sizeof(flag)) != 0) {
                    &flag, sizeof(flag)) != 0) {
         close(sock);
         close(sock);
@@ -523,10 +523,10 @@ IfaceMgr::send(boost::shared_ptr<Pkt6>& pkt) {
     struct in6_pktinfo *pktinfo;
     struct in6_pktinfo *pktinfo;
     struct cmsghdr *cmsg;
     struct cmsghdr *cmsg;
 
 
-    Iface* iface = getIface(pkt->iface_);
+    Iface* iface = getIface(pkt->getIface());
     if (!iface) {
     if (!iface) {
         isc_throw(BadValue, "Unable to send Pkt6. Invalid interface ("
         isc_throw(BadValue, "Unable to send Pkt6. Invalid interface ("
-                  << pkt->iface_ << ") specified.");
+                  << pkt->getIface() << ") specified.");
     }
     }
 
 
     memset(&control_buf_[0], 0, control_buf_len_);
     memset(&control_buf_[0], 0, control_buf_len_);
@@ -538,11 +538,11 @@ IfaceMgr::send(boost::shared_ptr<Pkt6>& pkt) {
     sockaddr_in6 to;
     sockaddr_in6 to;
     memset(&to, 0, sizeof(to));
     memset(&to, 0, sizeof(to));
     to.sin6_family = AF_INET6;
     to.sin6_family = AF_INET6;
-    to.sin6_port = htons(pkt->remote_port_);
+    to.sin6_port = htons(pkt->getRemotePort());
     memcpy(&to.sin6_addr,
     memcpy(&to.sin6_addr,
-           pkt->remote_addr_.getAddress().to_v6().to_bytes().data(),
+           pkt->getRemoteAddr().getAddress().to_v6().to_bytes().data(),
            16);
            16);
-    to.sin6_scope_id = pkt->ifindex_;
+    to.sin6_scope_id = pkt->getIndex();
 
 
     m.msg_name = &to;
     m.msg_name = &to;
     m.msg_namelen = sizeof(to);
     m.msg_namelen = sizeof(to);
@@ -550,8 +550,8 @@ IfaceMgr::send(boost::shared_ptr<Pkt6>& pkt) {
     // Set the data buffer we're sending. (Using this wacky
     // Set the data buffer we're sending. (Using this wacky
     // "scatter-gather" stuff... we only have a single chunk
     // "scatter-gather" stuff... we only have a single chunk
     // of data to send, so we declare a single vector entry.)
     // of data to send, so we declare a single vector entry.)
-    v.iov_base = (char *) &pkt->data_[0];
+    v.iov_base = (char *) pkt->getBuffer().getData();
-    v.iov_len = pkt->data_len_;
+    v.iov_len = pkt->getBuffer().getLength();
     m.msg_iov = &v;
     m.msg_iov = &v;
     m.msg_iovlen = 1;
     m.msg_iovlen = 1;
 
 
@@ -569,17 +569,17 @@ IfaceMgr::send(boost::shared_ptr<Pkt6>& pkt) {
     cmsg->cmsg_len = CMSG_LEN(sizeof(*pktinfo));
     cmsg->cmsg_len = CMSG_LEN(sizeof(*pktinfo));
     pktinfo = (struct in6_pktinfo *)CMSG_DATA(cmsg);
     pktinfo = (struct in6_pktinfo *)CMSG_DATA(cmsg);
     memset(pktinfo, 0, sizeof(*pktinfo));
     memset(pktinfo, 0, sizeof(*pktinfo));
-    pktinfo->ipi6_ifindex = pkt->ifindex_;
+    pktinfo->ipi6_ifindex = pkt->getIndex();
     m.msg_controllen = cmsg->cmsg_len;
     m.msg_controllen = cmsg->cmsg_len;
 
 
     result = sendmsg(getSocket(*pkt), &m, 0);
     result = sendmsg(getSocket(*pkt), &m, 0);
     if (result < 0) {
     if (result < 0) {
         isc_throw(Unexpected, "Pkt6 send failed: sendmsg() returned " << result);
         isc_throw(Unexpected, "Pkt6 send failed: sendmsg() returned " << result);
     }
     }
-    cout << "Sent " << pkt->data_len_ << " bytes over socket " << getSocket(*pkt)
+    cout << "Sent " << pkt->getBuffer().getLength() << " bytes over socket " << getSocket(*pkt)
          << " on " << iface->getFullName() << " interface: "
          << " on " << iface->getFullName() << " interface: "
-         << " dst=[" << pkt->remote_addr_.toText() << "]:" << pkt->remote_port_
+         << " dst=[" << pkt->getRemoteAddr().toText() << "]:" << pkt->getRemotePort()
-         << ", src=" << pkt->local_addr_.toText() << "]:" << pkt->remote_port_
+         << ", src=" << pkt->getLocalAddr().toText() << "]:" << pkt->getLocalPort()
          << endl;
          << endl;
 
 
     return (result);
     return (result);
@@ -813,8 +813,7 @@ IfaceMgr::receive4() {
     return (pkt);
     return (pkt);
 }
 }
 
 
-boost::shared_ptr<Pkt6>
+Pkt6Ptr IfaceMgr::receive6() {
-IfaceMgr::receive6() {
     struct msghdr m;
     struct msghdr m;
     struct iovec v;
     struct iovec v;
     int result;
     int result;
@@ -822,57 +821,43 @@ IfaceMgr::receive6() {
     struct in6_pktinfo* pktinfo;
     struct in6_pktinfo* pktinfo;
     struct sockaddr_in6 from;
     struct sockaddr_in6 from;
     struct in6_addr to_addr;
     struct in6_addr to_addr;
-    boost::shared_ptr<Pkt6> pkt;
+    int ifindex;
-    char addr_str[INET6_ADDRSTRLEN];
+    Pkt6Ptr pkt;
-
+
-    try {
+    // RFC3315 states that server responses may be
-        // RFC3315 states that server responses may be
+    // fragmented if they are over MTU. There is no
-        // fragmented if they are over MTU. There is no
+    // text whether client's packets may be larger
-        // text whether client's packets may be larger
+    // than 1500. For now, we can assume that
-        // than 1500. Nevertheless to be on the safe side
+    // we don't support packets larger than 1500.
-        // we use larger buffer. This buffer limit is checked
+    const uint32_t RCVBUFSIZE = 1500;
-        // during reception (see iov_len below), so we are
+    static uint8_t buf[RCVBUFSIZE];
-        // safe
-        pkt = boost::shared_ptr<Pkt6>(new Pkt6(65536));
-    } catch (const std::exception& ex) {
-        cout << "Failed to create new packet." << endl;
-        return (boost::shared_ptr<Pkt6>()); // NULL
-    }
 
 
     memset(&control_buf_[0], 0, control_buf_len_);
     memset(&control_buf_[0], 0, control_buf_len_);
 
 
     memset(&from, 0, sizeof(from));
     memset(&from, 0, sizeof(from));
     memset(&to_addr, 0, sizeof(to_addr));
     memset(&to_addr, 0, sizeof(to_addr));
 
 
-    /*
+    // Initialize our message header structure.
-     * Initialize our message header structure.
-     */
     memset(&m, 0, sizeof(m));
     memset(&m, 0, sizeof(m));
 
 
-    /*
+    // Point so we can get the from address.
-     * Point so we can get the from address.
-     */
     m.msg_name = &from;
     m.msg_name = &from;
     m.msg_namelen = sizeof(from);
     m.msg_namelen = sizeof(from);
 
 
-    /*
+    // Set the data buffer we're receiving. (Using this wacky
-     * Set the data buffer we're receiving. (Using this wacky
+    // "scatter-gather" stuff... but we that doesn't really make
-     * "scatter-gather" stuff... but we that doesn't really make
+    // sense for us, so we use a single vector entry.)
-     * sense for us, so we use a single vector entry.)
+    v.iov_base = (void*)buf;
-     */
+    v.iov_len = RCVBUFSIZE;
-    v.iov_base = (void*)&pkt->data_[0];
-    v.iov_len = pkt->data_len_;
     m.msg_iov = &v;
     m.msg_iov = &v;
     m.msg_iovlen = 1;
     m.msg_iovlen = 1;
 
 
-    /*
+    // Getting the interface is a bit more involved.
-     * Getting the interface is a bit more involved.
+    //
-     *
+    // We set up some space for a "control message". We have
-     * We set up some space for a "control message". We have
+    // previously asked the kernel to give us packet
-     * previously asked the kernel to give us packet
+    // information (when we initialized the interface), so we
-     * information (when we initialized the interface), so we
+    // should get the destination address from that.
-     * should get the destination address from that.
-     */
     m.msg_control = &control_buf_[0];
     m.msg_control = &control_buf_[0];
     m.msg_controllen = control_buf_len_;
     m.msg_controllen = control_buf_len_;
 
 
@@ -917,14 +902,12 @@ IfaceMgr::receive6() {
     result = recvmsg(candidate->sockfd_, &m, 0);
     result = recvmsg(candidate->sockfd_, &m, 0);
 
 
     if (result >= 0) {
     if (result >= 0) {
-        /*
+        // If we did read successfully, then we need to loop
-         * If we did read successfully, then we need to loop
+        // through the control messages we received and
-         * through the control messages we received and
+        // find the one with our destination address.
-         * find the one with our destination address.
+        //
-         *
+        // We also keep a flag to see if we found it. If we
-         * We also keep a flag to see if we found it. If we
+        // didn't, then we consider this to be an error.
-         * didn't, then we consider this to be an error.
-         */
         int found_pktinfo = 0;
         int found_pktinfo = 0;
         cmsg = CMSG_FIRSTHDR(&m);
         cmsg = CMSG_FIRSTHDR(&m);
         while (cmsg != NULL) {
         while (cmsg != NULL) {
@@ -932,7 +915,7 @@ IfaceMgr::receive6() {
                 (cmsg->cmsg_type == IPV6_PKTINFO)) {
                 (cmsg->cmsg_type == IPV6_PKTINFO)) {
                 pktinfo = (struct in6_pktinfo*)CMSG_DATA(cmsg);
                 pktinfo = (struct in6_pktinfo*)CMSG_DATA(cmsg);
                 to_addr = pktinfo->ipi6_addr;
                 to_addr = pktinfo->ipi6_addr;
-                pkt->ifindex_ = pktinfo->ipi6_ifindex;
+                ifindex = pktinfo->ipi6_ifindex;
                 found_pktinfo = 1;
                 found_pktinfo = 1;
             }
             }
             cmsg = CMSG_NXTHDR(&m, cmsg);
             cmsg = CMSG_NXTHDR(&m, cmsg);
@@ -946,34 +929,35 @@ IfaceMgr::receive6() {
         return (boost::shared_ptr<Pkt6>()); // NULL
         return (boost::shared_ptr<Pkt6>()); // NULL
     }
     }
 
 
-    // That's ugly.
-    // TODO add IOAddress constructor that will take struct in6_addr*
-    // TODO: there's from_bytes() method added in IOAddress. Use it!
-    inet_ntop(AF_INET6, &to_addr, addr_str,INET6_ADDRSTRLEN);
-    pkt->local_addr_ = IOAddress(string(addr_str));
 
 
-    // TODO: there's from_bytes() method added in IOAddress. Use it!
+    try {
-    inet_ntop(AF_INET6, &from.sin6_addr, addr_str, INET6_ADDRSTRLEN);
+        pkt = Pkt6Ptr(new Pkt6(buf, result));
-    pkt->remote_addr_ = IOAddress(string(addr_str));
+    } catch (const std::exception& ex) {
+        cout << "Failed to create new packet." << endl;
+        return (boost::shared_ptr<Pkt6>()); // NULL
+    }
+
+    pkt->setLocalAddr(IOAddress::from_bytes(AF_INET6, (const uint8_t*)&to_addr));
+    pkt->setRemoteAddr(IOAddress::from_bytes(AF_INET6, (const uint8_t*)&from.sin6_addr));
+
+    pkt->setRemotePort(ntohs(from.sin6_port));
 
 
-    pkt->remote_port_ = ntohs(from.sin6_port);
+    pkt->setIndex(ifindex);
 
 
-    Iface* received = getIface(pkt->ifindex_);
+    Iface* received = getIface(pkt->getIndex());
     if (received) {
     if (received) {
-        pkt->iface_ = received->getName();
+        pkt->setIface(received->getName());
     } else {
     } else {
         cout << "Received packet over unknown interface (ifindex="
         cout << "Received packet over unknown interface (ifindex="
-             << pkt->ifindex_ << ")." << endl;
+             << pkt->getIndex() << ")." << endl;
         return (boost::shared_ptr<Pkt6>()); // NULL
         return (boost::shared_ptr<Pkt6>()); // NULL
     }
     }
 
 
-    pkt->data_len_ = result;
-
     // TODO Move this to LOG_DEBUG
     // TODO Move this to LOG_DEBUG
-    cout << "Received " << pkt->data_len_ << " bytes over "
+    cout << "Received " << pkt->getBuffer().getLength() << " bytes over "
-         << pkt->iface_ << "/" << pkt->ifindex_ << " interface: "
+         << pkt->getIface() << "/" << pkt->getIndex() << " interface: "
-         << " src=" << pkt->remote_addr_.toText()
+         << " src=" << pkt->getRemoteAddr().toText()
-         << ", dst=" << pkt->local_addr_.toText()
+         << ", dst=" << pkt->getLocalAddr().toText()
          << endl;
          << endl;
 
 
     return (pkt);
     return (pkt);
@@ -981,10 +965,10 @@ IfaceMgr::receive6() {
 
 
 uint16_t
 uint16_t
 IfaceMgr::getSocket(isc::dhcp::Pkt6 const& pkt) {
 IfaceMgr::getSocket(isc::dhcp::Pkt6 const& pkt) {
-    Iface* iface = getIface(pkt.iface_);
+    Iface* iface = getIface(pkt.getIface());
     if (!iface) {
     if (!iface) {
         isc_throw(BadValue, "Tried to find socket for non-existent interface "
         isc_throw(BadValue, "Tried to find socket for non-existent interface "
-                  << pkt.iface_);
+                  << pkt.getIface());
     }
     }
 
 
     SocketCollection::const_iterator s;
     SocketCollection::const_iterator s;

+ 51 - 58
src/lib/dhcp/libdhcp++.cc

@@ -1,4 +1,4 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011-2012 Internet Systems Consortium, Inc. ("ISC")
 //
 //
 // Permission to use, copy, modify, and/or distribute this software for any
 // Permission to use, copy, modify, and/or distribute this software for any
 // purpose with or without fee is hereby granted, provided that the above
 // purpose with or without fee is hereby granted, provided that the above
@@ -28,19 +28,16 @@ using namespace isc::dhcp;
 using namespace isc::util;
 using namespace isc::util;
 
 
 // static array with factories for options
 // static array with factories for options
+std::map<unsigned short, Option::Factory*> LibDHCP::v4factories_;
+
+// static array with factories for options
 std::map<unsigned short, Option::Factory*> LibDHCP::v6factories_;
 std::map<unsigned short, Option::Factory*> LibDHCP::v6factories_;
 
 
-unsigned int
+
-LibDHCP::unpackOptions6(const boost::shared_array<uint8_t> buf,
+uint32_t LibDHCP::unpackOptions6(const OptionBuffer& buf,
-                        unsigned int buf_len,
+                                 isc::dhcp::Option::OptionCollection& options) {
-                        unsigned int offset, unsigned int parse_len,
+    uint32_t offset = 0;
-                        isc::dhcp::Option::OptionCollection& options) {
+    unsigned int end = buf.size();
-    if (offset + parse_len > buf_len) {
-        isc_throw(OutOfRange, "Option parse failed. Tried to parse "
-                  << parse_len << " bytes at offset " << offset
-                  << ":  out of buffer");
-    }
-    unsigned int end = offset + parse_len;
 
 
     while (offset +4 <= end) {
     while (offset +4 <= end) {
         uint16_t opt_type = buf[offset]*256 + buf[offset+1];
         uint16_t opt_type = buf[offset]*256 + buf[offset+1];
@@ -52,29 +49,27 @@ LibDHCP::unpackOptions6(const boost::shared_array<uint8_t> buf,
             cout << "Option " << opt_type << " truncated." << endl;
             cout << "Option " << opt_type << " truncated." << endl;
             return (offset);
             return (offset);
         }
         }
-        boost::shared_ptr<Option> opt;
+        OptionPtr opt;
         switch (opt_type) {
         switch (opt_type) {
         case D6O_IA_NA:
         case D6O_IA_NA:
         case D6O_IA_PD:
         case D6O_IA_PD:
             // cout << "Creating Option6IA" << endl;
             // cout << "Creating Option6IA" << endl;
-            opt = boost::shared_ptr<Option>(new Option6IA(opt_type,
+            opt = OptionPtr(new Option6IA(opt_type,
-                                                          buf, buf_len,
+                                          buf.begin() + offset,
-                                                          offset,
+                                          buf.begin() + offset + opt_len));
-                                                          opt_len));
             break;
             break;
         case D6O_IAADDR:
         case D6O_IAADDR:
             // cout << "Creating Option6IAAddr" << endl;
             // cout << "Creating Option6IAAddr" << endl;
-            opt = boost::shared_ptr<Option>(new Option6IAAddr(opt_type,
+            opt = OptionPtr(new Option6IAAddr(opt_type,
-                                                              buf, buf_len,
+                                              buf.begin() + offset,
-                                                              offset, opt_len));
+                                              buf.begin() + offset + opt_len));
             break;
             break;
         default:
         default:
             // cout << "Creating Option" << endl;
             // cout << "Creating Option" << endl;
-            opt = boost::shared_ptr<Option>(new Option(Option::V6,
+            opt = OptionPtr(new Option(Option::V6,
-                                                       opt_type,
+                                       opt_type,
-                                                       buf,
+                                       buf.begin() + offset,
-                                                       offset,
+                                       buf.begin() + offset + opt_len));
-                                                       opt_len));
             break;
             break;
         }
         }
         // add option to options
         // add option to options
@@ -85,9 +80,8 @@ LibDHCP::unpackOptions6(const boost::shared_array<uint8_t> buf,
     return (offset);
     return (offset);
 }
 }
 
 
-void
+uint32_t LibDHCP::unpackOptions4(const OptionBuffer& buf,
-LibDHCP::unpackOptions4(const std::vector<uint8_t>& buf,
+                                 isc::dhcp::Option::OptionCollection& options) {
-                        isc::dhcp::Option::OptionCollection& options) {
     size_t offset = 0;
     size_t offset = 0;
 
 
     // 2 - header of DHCPv4 option
     // 2 - header of DHCPv4 option
@@ -95,11 +89,11 @@ LibDHCP::unpackOptions4(const std::vector<uint8_t>& buf,
         uint8_t opt_type = buf[offset++];
         uint8_t opt_type = buf[offset++];
 
 
         if (opt_type == DHO_END)
         if (opt_type == DHO_END)
-          return; // just return. Don't need to add DHO_END option
+            return (offset); // just return. Don't need to add DHO_END option
 
 
         if (offset + 1 >= buf.size()) {
         if (offset + 1 >= buf.size()) {
-          isc_throw(OutOfRange, "Attempt to parse truncated option "
+            isc_throw(OutOfRange, "Attempt to parse truncated option "
-                    << opt_type);
+                      << opt_type);
         }
         }
 
 
         uint8_t opt_len =  buf[offset++];
         uint8_t opt_len =  buf[offset++];
@@ -109,41 +103,32 @@ LibDHCP::unpackOptions4(const std::vector<uint8_t>& buf,
                       << "-byte long buffer.");
                       << "-byte long buffer.");
         }
         }
 
 
-        boost::shared_ptr<Option> opt;
+        OptionPtr opt;
         switch(opt_type) {
         switch(opt_type) {
         default:
         default:
-            opt = boost::shared_ptr<Option>(new Option(Option::V4, opt_type,
+            opt = OptionPtr(new Option(Option::V4, opt_type,
-                                                       buf.begin()+offset,
+                                       buf.begin()+offset,
-                                                       buf.begin()+offset+opt_len));
+                                       buf.begin()+offset+opt_len));
         }
         }
 
 
         options.insert(pair<int, boost::shared_ptr<Option> >(opt_type, opt));
         options.insert(pair<int, boost::shared_ptr<Option> >(opt_type, opt));
         offset += opt_len;
         offset += opt_len;
     }
     }
+    return (offset);
 }
 }
 
 
-unsigned int
+void LibDHCP::packOptions6(isc::util::OutputBuffer &buf,
-LibDHCP::packOptions6(boost::shared_array<uint8_t> data,
+                           const isc::dhcp::Option::OptionCollection& options) {
-                      unsigned int data_len,
-                      unsigned int offset,
-                      const isc::dhcp::Option::OptionCollection& options) {
     try {
     try {
         for (Option::OptionCollection::const_iterator it = options.begin();
         for (Option::OptionCollection::const_iterator it = options.begin();
-             it != options.end();
+             it != options.end(); ++it) {
-             ++it) {
+            it->second->pack(buf);
-            unsigned short opt_len = (*it).second->len();
-            if (offset + opt_len > data_len) {
-                isc_throw(OutOfRange, "Failed to build option " <<
-                          (*it).first << ": out of buffer");
-            }
-            offset = it->second->pack(data, data_len, offset);
         }
         }
     }
     }
     catch (const Exception&) {
     catch (const Exception&) {
         cout << "Packet build failed (Option build failed)." << endl;
         cout << "Packet build failed (Option build failed)." << endl;
         throw;
         throw;
     }
     }
-    return (offset);
 }
 }
 
 
 void
 void
@@ -156,11 +141,9 @@ LibDHCP::packOptions(isc::util::OutputBuffer& buf,
     }
     }
 }
 }
 
 
-
+void LibDHCP::OptionFactoryRegister(Option::Universe u,
-bool
+                                    uint16_t opt_type,
-LibDHCP::OptionFactoryRegister(Option::Universe u,
+                                    Option::Factory * factory) {
-                               unsigned short opt_type,
-                               Option::Factory * factory) {
     switch (u) {
     switch (u) {
     case Option::V6: {
     case Option::V6: {
         if (v6factories_.find(opt_type)!=v6factories_.end()) {
         if (v6factories_.find(opt_type)!=v6factories_.end()) {
@@ -168,13 +151,23 @@ LibDHCP::OptionFactoryRegister(Option::Universe u,
                      << "for option type "  << opt_type);
                      << "for option type "  << opt_type);
         }
         }
         v6factories_[opt_type]=factory;
         v6factories_[opt_type]=factory;
-        return true;
+        return;
     }
     }
     case Option::V4:
     case Option::V4:
-    default:{
+    {
-        isc_throw(BadValue, "This universe type is not supported yet.");
+        if (opt_type > 254) {
-        return false; // never happens
+            isc_throw(BadValue, "Too big option type for DHCPv4, only 0-254 allowed.");
+        }
+        if (v4factories_.find(opt_type)!=v4factories_.end()) {
+            isc_throw(BadValue, "There is already DHCPv4 factory registered "
+                     << "for option type "  << opt_type);
+        }
+        v4factories_[opt_type]=factory;
+        return;
     }
     }
+    default:
+        isc_throw(BadValue, "Invalid universe type specified.");
     }
     }
 
 
+    return;
 }
 }

+ 30 - 37
src/lib/dhcp/libdhcp++.h

@@ -29,18 +29,10 @@ public:
     ///
     ///
     /// Builds raw (on-wire) data for provided collection of options.
     /// Builds raw (on-wire) data for provided collection of options.
     ///
     ///
-    /// @param buf shared pointer to buffer. Data will be stored there.
+    /// @param buf output buffer (assembled options will be stored here)
-    /// @param buf_len buffer length. Used for buffer overflow protection.
-    /// @param offset Offset from beginning of the buffer, where store options
     /// @param options collection of options to store to
     /// @param options collection of options to store to
-    ///
+    static void packOptions6(isc::util::OutputBuffer& buf,
-    /// @return offset to the first unused byte in buffer (next one after last
+                             const isc::dhcp::Option::OptionCollection& options);
-    ///         used byte)
-    ///
-    static unsigned int
-    packOptions6(boost::shared_array<uint8_t> buf, unsigned int buf_len,
-                 unsigned int offset,
-                 const isc::dhcp::Option::OptionCollection& options);
 
 
 
 
     /// @brief Stores options in a buffer.
     /// @brief Stores options in a buffer.
@@ -52,48 +44,49 @@ public:
     /// may be different reasons (option too large, option malformed,
     /// may be different reasons (option too large, option malformed,
     /// too many options etc.)
     /// too many options etc.)
     ///
     ///
-    /// @param buf
+    /// @param buf output buffer (assembled options will be stored here)
-    /// @param options
+    /// @param options collection of options to store to
-    static void
+    static void packOptions(isc::util::OutputBuffer& buf,
-    packOptions(isc::util::OutputBuffer& buf,
+                            const isc::dhcp::Option::OptionCollection& options);
-                const isc::dhcp::Option::OptionCollection& options);
 
 
-    static void
+    /// @brief Parses provided buffer as DHCPv4 options and creates Option objects.
-    unpackOptions4(const std::vector<uint8_t>& buf,
-                   isc::dhcp::Option::OptionCollection& options);
-    ///
-    /// Parses provided buffer and creates Option objects.
     ///
     ///
-    /// Parses provided buf array and stores created Option objects
+    /// Parses provided buffer and stores created Option objects
     /// in options container.
     /// in options container.
     ///
     ///
     /// @param buf Buffer to be parsed.
     /// @param buf Buffer to be parsed.
-    /// @param offset Specifies offset for the first option.
     /// @param options Reference to option container. Options will be
     /// @param options Reference to option container. Options will be
     ///        put here.
     ///        put here.
+    static uint32_t unpackOptions4(const OptionBuffer& buf,
+                                   isc::dhcp::Option::OptionCollection& options);
+
+    /// @brief Parses provided buffer as DHCPv6 options and creates Option objects.
     ///
     ///
-    /// @return offset to first byte after last parsed option
+    /// Parses provided buffer and stores created Option objects
+    /// in options container.
     ///
     ///
-    static unsigned int
+    /// @param buf Buffer to be parsed.
-    unpackOptions6(const boost::shared_array<uint8_t> buf, unsigned int buf_len,
+    /// @param options Reference to option container. Options will be
-                   unsigned int offset, unsigned int parse_len,
+    ///        put here.
-                   isc::dhcp::Option::OptionCollection& options_);
+    static uint32_t unpackOptions6(const OptionBuffer& buf,
+                                   isc::dhcp::Option::OptionCollection& options);
 
 
-    ///
     /// Registers factory method that produces options of specific option types.
     /// Registers factory method that produces options of specific option types.
     ///
     ///
+    /// @exception BadValue if provided type is already registered, has too large
+    ///            value or invalid universe is specified
+    ///
     /// @param u universe of the option (V4 or V6)
     /// @param u universe of the option (V4 or V6)
     /// @param opt_type option-type
     /// @param opt_type option-type
     /// @param factory function pointer
     /// @param factory function pointer
-    ///
+    static void OptionFactoryRegister(Option::Universe u,
-    /// @return true, if registration was successful, false otherwise
+                                      uint16_t type,
-    ///
+                                      Option::Factory * factory);
-    static bool
-    OptionFactoryRegister(Option::Universe u,
-                          unsigned short type,
-                          Option::Factory * factory);
 protected:
 protected:
-    // pointers to factories that produce DHCPv6 options
+    /// pointers to factories that produce DHCPv6 options
+    static std::map<unsigned short, Option::Factory*> v4factories_;
+
+    /// pointers to factories that produce DHCPv6 options
     static std::map<unsigned short, Option::Factory*> v6factories_;
     static std::map<unsigned short, Option::Factory*> v6factories_;
 };
 };
 
 

+ 29 - 103
src/lib/dhcp/option.cc

@@ -1,4 +1,4 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011-2012 Internet Systems Consortium, Inc. ("ISC")
 //
 //
 // Permission to use, copy, modify, and/or distribute this software for any
 // Permission to use, copy, modify, and/or distribute this software for any
 // purpose with or without fee is hereby granted, provided that the above
 // purpose with or without fee is hereby granted, provided that the above
@@ -17,7 +17,6 @@
 #include <arpa/inet.h>
 #include <arpa/inet.h>
 #include <sstream>
 #include <sstream>
 #include <iomanip>
 #include <iomanip>
-#include <boost/shared_array.hpp>
 #include "exceptions/exceptions.h"
 #include "exceptions/exceptions.h"
 #include "util/io_utilities.h"
 #include "util/io_utilities.h"
 
 
@@ -37,26 +36,14 @@ Option::Option(Universe u, unsigned short type)
     }
     }
 }
 }
 
 
-Option::Option(Universe u, unsigned short type,
+Option::Option(Universe u, unsigned short type, const OptionBuffer& data)
-               const boost::shared_array<uint8_t>& buf,
-               unsigned int offset, unsigned int len)
-    :universe_(u), type_(type),
-     offset_(offset)
-{
-    uint8_t* ptr = &buf[offset];
-    data_ = std::vector<uint8_t>(ptr, ptr + len);
-
-    check();
-}
-
-Option::Option(Universe u, unsigned short type, std::vector<uint8_t>& data)
     :universe_(u), type_(type), data_(data) {
     :universe_(u), type_(type), data_(data) {
     check();
     check();
 }
 }
 
 
-Option::Option(Universe u, uint16_t type, vector<uint8_t>::const_iterator first,
+Option::Option(Universe u, uint16_t type, OptionBufferConstIter first,
-               vector<uint8_t>::const_iterator last)
+               OptionBufferConstIter last)
-    :universe_(u), type_(type), data_(std::vector<uint8_t>(first,last)) {
+    :universe_(u), type_(type), data_(OptionBuffer(first,last)) {
     check();
     check();
 }
 }
 
 
@@ -84,15 +71,16 @@ Option::check() {
     // both types and data size.
     // both types and data size.
 }
 }
 
 
-unsigned int
+void Option::pack(isc::util::OutputBuffer& buf) {
-Option::pack(boost::shared_array<uint8_t>& buf,
+    switch (universe_) {
-             unsigned int buf_len,
+    case V6:
-             unsigned int offset) {
+        return pack6(buf);
-    if (universe_ != V6) {
+    case V4:
+        return pack4(buf);
+    default:
         isc_throw(BadValue, "Failed to pack " << type_ << " option. Do not "
         isc_throw(BadValue, "Failed to pack " << type_ << " option. Do not "
                   << "use this method for options other than DHCPv6.");
                   << "use this method for options other than DHCPv6.");
     }
     }
-    return pack6(buf, buf_len, offset);
 }
 }
 
 
 void
 void
@@ -127,84 +115,25 @@ Option::pack4(isc::util::OutputBuffer& buf) {
     }
     }
 }
 }
 
 
-unsigned int
+void Option::pack6(isc::util::OutputBuffer& buf) {
-Option::pack6(boost::shared_array<uint8_t>& buf,
+    buf.writeUint16(type_);
-             unsigned int buf_len,
+    buf.writeUint16(len() - getHeaderLen());
-             unsigned int offset) {
-    if (offset+len() > buf_len) {
-        isc_throw(OutOfRange, "Failed to pack v6 option=" <<
-                  type_ << ",len=" << len() << ": too small buffer.");
-    }
-
-    uint8_t* ptr = &buf[offset];
-
-    ptr = writeUint16(type_, ptr);
-
-    ptr = writeUint16(len() - getHeaderLen(), ptr);
-
-    if (! data_.empty())
-        memcpy(ptr, &data_[0], data_.size());
-
-    // end of fixed part of this option
-    offset += OPTION6_HDR_LEN + data_.size();
-
-    return LibDHCP::packOptions6(buf, buf_len, offset, options_);
-}
 
 
-unsigned int
+    if (! data_.empty()) {
-Option::unpack(const boost::shared_array<uint8_t>& buf,
+        buf.writeData(&data_[0], data_.size());
-               unsigned int buf_len,
-               unsigned int offset,
-               unsigned int parse_len) {
-    switch (universe_) {
-    case V4:
-        return unpack4(buf, buf_len, offset, parse_len);
-    case V6:
-        return unpack6(buf, buf_len, offset, parse_len);
-    default:
-        isc_throw(BadValue, "Unknown universe defined for Option " << type_);
     }
     }
 
 
-    return 0; // should not happen
+    return LibDHCP::packOptions6(buf, options_);
-}
-
-unsigned int
-Option::unpack4(const boost::shared_array<uint8_t>&,
-                unsigned int ,
-                unsigned int ,
-                unsigned int ) {
-    isc_throw(Unexpected, "IPv4 support not implemented yet.");
-    return 0;
 }
 }
 
 
-unsigned int
+void Option::unpack(OptionBufferConstIter begin,
-Option::unpack6(const boost::shared_array<uint8_t>& buf,
+                    OptionBufferConstIter end) {
-                unsigned int buf_len,
+    data_ = OptionBuffer(begin, end);
-                unsigned int offset,
-                unsigned int parse_len) {
-
-    if (buf_len < offset+parse_len) {
-        isc_throw(OutOfRange, "Failed to unpack DHCPv6 option len="
-                  << parse_len << " offset=" << offset
-                  << " from buffer (length=" << buf_len
-                  << "): too small buffer.");
-    }
-
-    uint8_t* ptr = &buf[offset];
-    data_ = std::vector<uint8_t>(ptr, ptr + parse_len);
-
-    offset_ = offset;
-
-    return (offset+parse_len);
-
-    //return LibDHCP::unpackOptions6(buf, buf_len, offset, parse_len,
-    //                               options_);
 }
 }
 
 
-/// Returns length of the complete option (data length + DHCPv4/DHCPv6
+uint16_t Option::len() {
-/// option header)
+    // Returns length of the complete option (data length + DHCPv4/DHCPv6
-uint16_t
+    // option header)
-Option::len() {
 
 
     // length of the whole option is header and data stored in this option...
     // length of the whole option is header and data stored in this option...
     int length = getHeaderLen() + data_.size();
     int length = getHeaderLen() + data_.size();
@@ -232,18 +161,16 @@ Option::valid() {
     return (true);
     return (true);
 }
 }
 
 
-boost::shared_ptr<isc::dhcp::Option>
+OptionPtr Option::getOption(unsigned short opt_type) {
-Option::getOption(unsigned short opt_type) {
     isc::dhcp::Option::OptionCollection::const_iterator x =
     isc::dhcp::Option::OptionCollection::const_iterator x =
         options_.find(opt_type);
         options_.find(opt_type);
     if ( x != options_.end() ) {
     if ( x != options_.end() ) {
         return (*x).second;
         return (*x).second;
     }
     }
-    return boost::shared_ptr<isc::dhcp::Option>(); // NULL
+    return OptionPtr(); // NULL
 }
 }
 
 
-bool
+bool Option::delOption(unsigned short opt_type) {
-Option::delOption(unsigned short opt_type) {
     isc::dhcp::Option::OptionCollection::iterator x = options_.find(opt_type);
     isc::dhcp::Option::OptionCollection::iterator x = options_.find(opt_type);
     if ( x != options_.end() ) {
     if ( x != options_.end() ) {
         options_.erase(x);
         options_.erase(x);
@@ -289,8 +216,7 @@ Option::getHeaderLen() {
     return 0; // should not happen
     return 0; // should not happen
 }
 }
 
 
-void
+void Option::addOption(OptionPtr opt) {
-Option::addOption(boost::shared_ptr<Option> opt) {
     if (universe_ == V4) {
     if (universe_ == V4) {
         // check for uniqueness (DHCPv4 options must be unique)
         // check for uniqueness (DHCPv4 options must be unique)
         if (getOption(opt->getType())) {
         if (getOption(opt->getType())) {
@@ -298,7 +224,7 @@ Option::addOption(boost::shared_ptr<Option> opt) {
                       << " already present in this message.");
                       << " already present in this message.");
         }
         }
     }
     }
-    options_.insert(pair<int, boost::shared_ptr<Option> >(opt->getType(), opt));
+    options_.insert(pair<int, OptionPtr >(opt->getType(), opt));
 }
 }
 
 
 uint8_t Option::getUint8() {
 uint8_t Option::getUint8() {

+ 40 - 103
src/lib/dhcp/option.h

@@ -1,4 +1,4 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011-2012 Internet Systems Consortium, Inc. ("ISC")
 //
 //
 // Permission to use, copy, modify, and/or distribute this software for any
 // Permission to use, copy, modify, and/or distribute this software for any
 // purpose with or without fee is hereby granted, provided that the above
 // purpose with or without fee is hereby granted, provided that the above
@@ -19,12 +19,28 @@
 #include <map>
 #include <map>
 #include <vector>
 #include <vector>
 #include <boost/shared_ptr.hpp>
 #include <boost/shared_ptr.hpp>
-#include <boost/shared_array.hpp>
 #include <util/buffer.h>
 #include <util/buffer.h>
 
 
 namespace isc {
 namespace isc {
 namespace dhcp {
 namespace dhcp {
 
 
+/// buffer types used in DHCP code
+typedef std::vector<uint8_t> OptionBuffer;
+
+/// iterator for walking over OptionBuffer
+typedef OptionBuffer::iterator OptionBufferIter;
+
+/// const_iterator for walking over OptionBuffer
+typedef OptionBuffer::const_iterator OptionBufferConstIter;
+
+/// pointer to a DHCP buffer
+typedef boost::shared_ptr< OptionBuffer > OptionBufferPtr;
+
+/// shared pointer to Option object
+class Option;
+typedef boost::shared_ptr<Option> OptionPtr;
+
+
 class Option {
 class Option {
 public:
 public:
     /// length of the usual DHCPv4 option header (there are exceptions)
     /// length of the usual DHCPv4 option header (there are exceptions)
@@ -37,7 +53,7 @@ public:
     enum Universe { V4, V6 };
     enum Universe { V4, V6 };
 
 
     /// a collection of DHCPv6 options
     /// a collection of DHCPv6 options
-    typedef std::multimap<unsigned int, boost::shared_ptr<Option> >
+    typedef std::multimap<unsigned int, OptionPtr >
     OptionCollection;
     OptionCollection;
 
 
     /// @brief a factory function prototype
     /// @brief a factory function prototype
@@ -45,38 +61,17 @@ public:
     /// @param u option universe (DHCPv4 or DHCPv6)
     /// @param u option universe (DHCPv4 or DHCPv6)
     /// @param type option type
     /// @param type option type
     /// @param buf pointer to a buffer
     /// @param buf pointer to a buffer
-    /// @param offset offset to first data byte in that buffer
-    /// @param len data length of this option
     ///
     ///
     /// @return a pointer to a created option object
     /// @return a pointer to a created option object
-    typedef boost::shared_ptr<Option> Factory(Option::Universe u,
+    typedef OptionPtr Factory(Option::Universe u,
-                                              unsigned short type,
+                              uint16_t type,
-                                              boost::shared_array<uint8_t>& buf,
+                              const OptionBuffer& buf);
-                                              unsigned int offset,
-                                              unsigned int len);
 
 
     /// @brief ctor, used for options constructed, usually during transmission
     /// @brief ctor, used for options constructed, usually during transmission
     ///
     ///
     /// @param u option universe (DHCPv4 or DHCPv6)
     /// @param u option universe (DHCPv4 or DHCPv6)
     /// @param type option type
     /// @param type option type
-    Option(Universe u, unsigned short type);
+    Option(Universe u, uint16_t type);
-
-    /// @brief ctor, used for received options
-    ///
-    /// boost::shared_array allows sharing a buffer, but it requires that
-    /// different instances share pointer to the whole array, not point
-    /// to different elements in shared array. Therefore we need to share
-    /// pointer to the whole array and remember offset where data for
-    /// this option begins
-    ///
-    /// @param u specifies universe (V4 or V6)
-    /// @param type option type
-    /// @param buf pointer to a buffer
-    /// @param offset offset in a buffer pointing to first byte of data
-    /// @param len length of the option data
-    Option(Universe u, unsigned short type,
-           const boost::shared_array<uint8_t>& buf, unsigned int offset,
-           unsigned int len);
 
 
     /// @brief Constructor, used for received options.
     /// @brief Constructor, used for received options.
     ///
     ///
@@ -88,7 +83,7 @@ public:
     /// @param u specifies universe (V4 or V6)
     /// @param u specifies universe (V4 or V6)
     /// @param type option type (0-255 for V4 and 0-65535 for V6)
     /// @param type option type (0-255 for V4 and 0-65535 for V6)
     /// @param data content of the option
     /// @param data content of the option
-    Option(Universe u, unsigned short type, std::vector<uint8_t>& data);
+    Option(Universe u, uint16_t type, const OptionBuffer& data);
 
 
     /// @brief Constructor, used for received options.
     /// @brief Constructor, used for received options.
     ///
     ///
@@ -110,15 +105,13 @@ public:
     /// @param first iterator to the first element that should be copied
     /// @param first iterator to the first element that should be copied
     /// @param last iterator to the next element after the last one
     /// @param last iterator to the next element after the last one
     ///        to be copied.
     ///        to be copied.
-    Option(Universe u, uint16_t type,
+    Option(Universe u, uint16_t type, OptionBufferConstIter first,
-           std::vector<uint8_t>::const_iterator first,
+           OptionBufferConstIter last);
-           std::vector<uint8_t>::const_iterator last);
 
 
     /// @brief returns option universe (V4 or V6)
     /// @brief returns option universe (V4 or V6)
     ///
     ///
     /// @return universe type
     /// @return universe type
-    Universe
+    Universe  getUniverse() { return universe_; };
-    getUniverse() { return universe_; };
 
 
     /// @brief Writes option in wire-format to a buffer.
     /// @brief Writes option in wire-format to a buffer.
     ///
     ///
@@ -129,14 +122,10 @@ public:
     /// TODO: Migrate DHCPv6 code to pack(OutputBuffer& buf) version
     /// TODO: Migrate DHCPv6 code to pack(OutputBuffer& buf) version
     ///
     ///
     /// @param buf pointer to a buffer
     /// @param buf pointer to a buffer
-    /// @param buf_len length of the buffer
-    /// @param offset offset to place, where option shout be stored
     ///
     ///
     /// @return offset to first unused byte after stored option
     /// @return offset to first unused byte after stored option
     ///
     ///
-    virtual unsigned int
+    virtual void pack(isc::util::OutputBuffer& buf);
-    pack(boost::shared_array<uint8_t>& buf, unsigned int buf_len,
-         unsigned int offset);
 
 
     /// @brief Writes option in a wire-format to a buffer.
     /// @brief Writes option in a wire-format to a buffer.
     ///
     ///
@@ -146,26 +135,17 @@ public:
     /// unify pack4() and pack6() and rename them to just pack().
     /// unify pack4() and pack6() and rename them to just pack().
     ///
     ///
     /// @param buf output buffer (option will be stored there)
     /// @param buf output buffer (option will be stored there)
-    virtual void
+    virtual void pack4(isc::util::OutputBuffer& buf);
-    pack4(isc::util::OutputBuffer& buf);
-
 
 
     /// @brief Parses buffer.
     /// @brief Parses buffer.
     ///
     ///
     /// Parses received buffer, returns offset to the first unused byte after
     /// Parses received buffer, returns offset to the first unused byte after
     /// parsed option.
     /// parsed option.
     ///
     ///
-    /// @param buf pointer to buffer
+    /// @param begin iterator to first byte of option data
-    /// @param buf_len length of buf
+    /// @param end iterator to end of option data (first byte after option end)
-    /// @param offset offset, where start parsing option
+    virtual void unpack(OptionBufferConstIter begin,
-    /// @param parse_len how many bytes should be parsed
+                        OptionBufferConstIter end);
-    ///
-    /// @return offset after last parsed octet
-    virtual unsigned int
-    unpack(const boost::shared_array<uint8_t>& buf,
-           unsigned int buf_len,
-           unsigned int offset,
-           unsigned int parse_len);
 
 
     /// Returns string representation of the option.
     /// Returns string representation of the option.
     ///
     ///
@@ -203,7 +183,7 @@ public:
     ///
     ///
     /// @return pointer to actual data (or reference to an empty vector
     /// @return pointer to actual data (or reference to an empty vector
     ///         if there is no data)
     ///         if there is no data)
-    virtual const std::vector<uint8_t>& getData() { return (data_); }
+    virtual const OptionBuffer& getData() { return (data_); }
 
 
     /// Adds a sub-option.
     /// Adds a sub-option.
     ///
     ///
@@ -217,24 +197,21 @@ public:
     /// many places. Requiring casting is not feasible.
     /// many places. Requiring casting is not feasible.
     ///
     ///
     /// @param opt shared pointer to a suboption that is going to be added.
     /// @param opt shared pointer to a suboption that is going to be added.
-    void
+    void addOption(OptionPtr opt);
-    addOption(boost::shared_ptr<Option> opt);
 
 
     /// Returns shared_ptr to suboption of specific type
     /// Returns shared_ptr to suboption of specific type
     ///
     ///
     /// @param type type of requested suboption
     /// @param type type of requested suboption
     ///
     ///
     /// @return shared_ptr to requested suoption
     /// @return shared_ptr to requested suoption
-    boost::shared_ptr<isc::dhcp::Option>
+    OptionPtr getOption(uint16_t type);
-    getOption(unsigned short type);
 
 
     /// Attempts to delete first suboption of requested type
     /// Attempts to delete first suboption of requested type
     ///
     ///
     /// @param type Type of option to be deleted.
     /// @param type Type of option to be deleted.
     ///
     ///
     /// @return true if option was deleted, false if no such option existed
     /// @return true if option was deleted, false if no such option existed
-    bool
+    bool delOption(uint16_t type);
-    delOption(unsigned short type);
 
 
     /// @brief Returns content of first byte.
     /// @brief Returns content of first byte.
     ///
     ///
@@ -286,40 +263,7 @@ protected:
     /// defined suboptions. Version for building DHCPv4 options.
     /// defined suboptions. Version for building DHCPv4 options.
     ///
     ///
     /// @param buf output buffer (built options will be stored here)
     /// @param buf output buffer (built options will be stored here)
-    /// @param buf_len buffer length (used for buffer overflow checks)
+    virtual void pack6(isc::util::OutputBuffer& buf);
-    /// @param offset offset from start of the buf buffer
-    ///
-    /// @return offset to the next byte after last used byte
-    virtual unsigned int
-    pack6(boost::shared_array<uint8_t>& buf,
-          unsigned int buf_len,
-          unsigned int offset);
-
-    /// Parses provided buffer and creates DHCPv4 options.
-    ///
-    /// @param buf buffer that contains raw buffer to parse (on-wire format)
-    /// @param buf_len buffer length (used for buffer overflow checks)
-    /// @param offset offset from start of the buf buffer
-    ///
-    /// @return offset to the next byte after last parsed byte
-    virtual unsigned int
-    unpack4(const boost::shared_array<uint8_t>& buf,
-            unsigned int buf_len,
-            unsigned int offset,
-            unsigned int parse_len);
-
-    /// Parses provided buffer and creates DHCPv6 options.
-    ///
-    /// @param buf buffer that contains raw buffer to parse (on-wire format)
-    /// @param buf_len buffer length (used for buffer overflow checks)
-    /// @param offset offset from start of the buf buffer
-    ///
-    /// @return offset to the next byte after last parsed byte
-    virtual unsigned int
-    unpack6(const boost::shared_array<uint8_t>& buf,
-            unsigned int buf_len,
-            unsigned int offset,
-            unsigned int parse_len);
 
 
     /// @brief A private method used for option correctness.
     /// @brief A private method used for option correctness.
     ///
     ///
@@ -332,17 +276,10 @@ protected:
     Universe universe_;
     Universe universe_;
 
 
     /// option type (0-255 for DHCPv4, 0-65535 for DHCPv6)
     /// option type (0-255 for DHCPv4, 0-65535 for DHCPv6)
-    unsigned short type_;
+    uint16_t type_;
 
 
     /// contains content of this data
     /// contains content of this data
-    std::vector<uint8_t> data_;
+    OptionBuffer data_;
-
-    /// TODO: Remove this field. vector<uint8_t> should be used
-    /// instead.
-    /// data is a shared_pointer that points out to the
-    /// whole packet. offset_ specifies where data for
-    /// this option begins.
-    unsigned int offset_;
 
 
     /// collection for storing suboptions
     /// collection for storing suboptions
     OptionCollection options_;
     OptionCollection options_;

+ 3 - 4
src/lib/dhcp/option4_addrlst.cc

@@ -1,4 +1,4 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011-2012 Internet Systems Consortium, Inc. ("ISC")
 //
 //
 // Permission to use, copy, modify, and/or distribute this software for any
 // Permission to use, copy, modify, and/or distribute this software for any
 // purpose with or without fee is hereby granted, provided that the above
 // purpose with or without fee is hereby granted, provided that the above
@@ -38,9 +38,8 @@ Option4AddrLst::Option4AddrLst(uint8_t type, const AddressContainer& addrs)
 }
 }
 
 
 
 
-Option4AddrLst::Option4AddrLst(uint8_t type,
+Option4AddrLst::Option4AddrLst(uint8_t type, OptionBufferConstIter first,
-                               vector<uint8_t>::const_iterator first,
+                               OptionBufferConstIter last)
-                               vector<uint8_t>::const_iterator last)
     :Option(V4, type) {
     :Option(V4, type) {
     if ( (distance(first, last) % V4ADDRESS_LEN) ) {
     if ( (distance(first, last) % V4ADDRESS_LEN) ) {
         isc_throw(OutOfRange, "DHCPv4 Option4AddrLst " << type_
         isc_throw(OutOfRange, "DHCPv4 Option4AddrLst " << type_

+ 6 - 9
src/lib/dhcp/option4_addrlst.h

@@ -1,4 +1,4 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011-2012 Internet Systems Consortium, Inc. ("ISC")
 //
 //
 // Permission to use, copy, modify, and/or distribute this software for any
 // Permission to use, copy, modify, and/or distribute this software for any
 // purpose with or without fee is hereby granted, provided that the above
 // purpose with or without fee is hereby granted, provided that the above
@@ -77,8 +77,8 @@ public:
     /// @param first iterator to the first element that should be copied
     /// @param first iterator to the first element that should be copied
     /// @param last iterator to the next element after the last one
     /// @param last iterator to the next element after the last one
     ///        to be copied.
     ///        to be copied.
-    Option4AddrLst(uint8_t type, std::vector<uint8_t>::const_iterator first,
+    Option4AddrLst(uint8_t type, OptionBufferConstIter first,
-           std::vector<uint8_t>::const_iterator last);
+                   OptionBufferConstIter last);
 
 
     /// @brief Writes option in a wire-format to a buffer.
     /// @brief Writes option in a wire-format to a buffer.
     ///
     ///
@@ -88,16 +88,14 @@ public:
     /// unify pack4() and pack6() and rename them to just pack().
     /// unify pack4() and pack6() and rename them to just pack().
     ///
     ///
     /// @param buf output buffer (option will be stored there)
     /// @param buf output buffer (option will be stored there)
-    virtual void
+    virtual void pack4(isc::util::OutputBuffer& buf);
-    pack4(isc::util::OutputBuffer& buf);
 
 
     /// Returns string representation of the option.
     /// Returns string representation of the option.
     ///
     ///
     /// @param indent number of spaces before printing text
     /// @param indent number of spaces before printing text
     ///
     ///
     /// @return string with text representation.
     /// @return string with text representation.
-    virtual std::string
+    virtual std::string toText(int indent = 0);
-    toText(int indent = 0);
 
 
     /// Returns length of the complete option (data length + DHCPv4/DHCPv6
     /// Returns length of the complete option (data length + DHCPv4/DHCPv6
     /// option header)
     /// option header)
@@ -113,8 +111,7 @@ public:
     /// a couple (1-3) addresses, the overhead is not that big.
     /// a couple (1-3) addresses, the overhead is not that big.
     ///
     ///
     /// @return address container with addresses
     /// @return address container with addresses
-    AddressContainer
+    AddressContainer getAddresses() { return addrs_; };
-    getAddresses() { return addrs_; };
 
 
     /// @brief Sets addresses list.
     /// @brief Sets addresses list.
     ///
     ///

+ 16 - 44
src/lib/dhcp/option6_addrlst.cc

@@ -1,4 +1,4 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011-2012 Internet Systems Consortium, Inc. ("ISC")
 //
 //
 // Permission to use, copy, modify, and/or distribute this software for any
 // Permission to use, copy, modify, and/or distribute this software for any
 // purpose with or without fee is hereby granted, provided that the above
 // purpose with or without fee is hereby granted, provided that the above
@@ -40,12 +40,10 @@ Option6AddrLst::Option6AddrLst(unsigned short type,
 }
 }
 
 
 Option6AddrLst::Option6AddrLst(unsigned short type,
 Option6AddrLst::Option6AddrLst(unsigned short type,
-                               boost::shared_array<uint8_t> buf,
+                               OptionBufferConstIter begin,
-                               unsigned int buf_len,
+                               OptionBufferConstIter end)
-                               unsigned int offset,
-                               unsigned int option_len)
     :Option(V6, type) {
     :Option(V6, type) {
-    unpack(buf, buf_len, offset, option_len);
+    unpack(begin, end);
 }
 }
 
 
 void
 void
@@ -63,58 +61,32 @@ Option6AddrLst::setAddresses(const AddressContainer& addrs) {
     addrs_ = addrs;
     addrs_ = addrs;
 }
 }
 
 
-unsigned int
+void Option6AddrLst::pack(isc::util::OutputBuffer& buf) {
-Option6AddrLst::pack(boost::shared_array<uint8_t>& buf,
-                    unsigned int buf_len,
-                    unsigned int offset) {
-    if (len() > buf_len) {
-        isc_throw(OutOfRange, "Failed to pack IA option: len=" << len()
-                  << ", buffer=" << buf_len << ": too small buffer.");
-    }
 
 
-    writeUint16(type_, &buf[offset]);
+    buf.writeUint16(type_);
-    offset += sizeof(uint16_t);
 
 
     // len() returns complete option length.
     // len() returns complete option length.
     // len field contains length without 4-byte option header
     // len field contains length without 4-byte option header
-    writeUint16(len() - OPTION6_HDR_LEN, &buf[offset]);
+    buf.writeUint16(len() - getHeaderLen());
-    offset += sizeof(uint16_t);
 
 
     // this wrapping is *ugly*. I wish there was a a
     // this wrapping is *ugly*. I wish there was a a
     for (AddressContainer::const_iterator addr=addrs_.begin();
     for (AddressContainer::const_iterator addr=addrs_.begin();
-         addr!=addrs_.end();
+         addr!=addrs_.end(); ++addr) {
-         ++addr) {
+        buf.writeData(addr->getAddress().to_v6().to_bytes().data(), V6ADDRESS_LEN);
-        memcpy(&buf[offset],
-               addr->getAddress().to_v6().to_bytes().data(),
-               V6ADDRESS_LEN);
-        offset += V6ADDRESS_LEN;
     }
     }
-
-    return offset;
 }
 }
 
 
-unsigned int
+void Option6AddrLst::unpack(OptionBufferConstIter begin,
-Option6AddrLst::unpack(const boost::shared_array<uint8_t>& buf,
+                        OptionBufferConstIter end) {
-                       unsigned int buf_len,
+    if (distance(begin, end) % 16) {
-                       unsigned int offset,
-                       unsigned int option_len) {
-    if (offset+option_len > buf_len) {
         isc_throw(OutOfRange, "Option " << type_
         isc_throw(OutOfRange, "Option " << type_
-                  << " truncated.");
+                  << " malformed: len=" << distance(begin, end)
-    }
-
-    if (option_len%16) {
-        isc_throw(OutOfRange, "Option " << type_
-                  << " malformed: len=" << option_len
                   << " is not divisible by 16.");
                   << " is not divisible by 16.");
     }
     }
-    while (option_len > 0) {
+    while (begin != end) {
-        addrs_.push_back(IOAddress::from_bytes(AF_INET6, &buf[offset]));
+        addrs_.push_back(IOAddress::from_bytes(AF_INET6, &(*begin)));
-        offset += 16;
+        begin += V6ADDRESS_LEN;
-        option_len -= 16;
     }
     }
-
-    return offset;
 }
 }
 
 
 std::string Option6AddrLst::toText(int indent /* =0 */) {
 std::string Option6AddrLst::toText(int indent /* =0 */) {

+ 11 - 34
src/lib/dhcp/option6_addrlst.h

@@ -1,4 +1,4 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011-2012 Internet Systems Consortium, Inc. ("ISC")
 //
 //
 // Permission to use, copy, modify, and/or distribute this software for any
 // Permission to use, copy, modify, and/or distribute this software for any
 // purpose with or without fee is hereby granted, provided that the above
 // purpose with or without fee is hereby granted, provided that the above
@@ -36,70 +36,48 @@ public:
     ///
     ///
     /// @param type option type
     /// @param type option type
     /// @param addrs vector of addresses to be stored
     /// @param addrs vector of addresses to be stored
-    ///
+    Option6AddrLst(uint16_t type, const AddressContainer& addrs);
-    Option6AddrLst(unsigned short type,
-                   const AddressContainer& addrs);
 
 
     /// @brief Simplified constructor for a single address
     /// @brief Simplified constructor for a single address
     ///
     ///
     /// @param type option type
     /// @param type option type
     /// @param addr a single address to be stored
     /// @param addr a single address to be stored
-    ///
+    Option6AddrLst(uint16_t type, const isc::asiolink::IOAddress& addr);
-    Option6AddrLst(unsigned short type,
-                   const isc::asiolink::IOAddress& addr);
 
 
     /// @brief Constructor used for parsing received option
     /// @brief Constructor used for parsing received option
     ///
     ///
     /// @param type option type
     /// @param type option type
-    /// @param buf pointer to packet buffer
+    /// @param begin iterator to first byte of option data
-    /// @param buf_len length of packet buffer
+    /// @param end iterator to end of option data (first byte after option end)
-    /// @param offset offset to beginning of option data
+    Option6AddrLst(uint16_t type, OptionBufferConstIter begin,
-    /// @param len length of option data
+                   OptionBufferConstIter end);
-    ///
-    Option6AddrLst(unsigned short type, boost::shared_array<uint8_t> buf,
-                   unsigned int buf_len,
-                   unsigned int offset,
-                   unsigned int len);
 
 
     /// @brief Assembles on-wire form of this option
     /// @brief Assembles on-wire form of this option
     ///
     ///
     /// @param buf pointer to packet buffer
     /// @param buf pointer to packet buffer
-    /// @param buf_len length of packet buffer
+    void pack(isc::util::OutputBuffer& buf);
-    /// @param offset offset to place, where option is to be stored
-    ///
-    /// @return offset to the next unused char (just after stored option)
-    ///
-    unsigned int
-    pack(boost::shared_array<uint8_t>& buf, unsigned int buf_len,
-         unsigned int offset);
 
 
     /// @brief Parses received data
     /// @brief Parses received data
     ///
     ///
     /// @param buf pointer to packet buffer
     /// @param buf pointer to packet buffer
-    /// @param buf_len length of packet buffer
     /// @param offset offset to option data
     /// @param offset offset to option data
     /// @param parse_len specified option data length
     /// @param parse_len specified option data length
     ///
     ///
     /// @return offset to the next unparsed char (just after parsed option)
     /// @return offset to the next unparsed char (just after parsed option)
     ///
     ///
-    virtual unsigned int
+    virtual void unpack(OptionBufferConstIter begin,
-    unpack(const boost::shared_array<uint8_t>& buf,
+                        OptionBufferConstIter end);
-           unsigned int buf_len,
-           unsigned int offset,
-           unsigned int parse_len);
 
 
     virtual std::string toText(int indent = 0);
     virtual std::string toText(int indent = 0);
 
 
     /// @brief Sets a single address.
     /// @brief Sets a single address.
     ///
     ///
     /// @param addr a single address to be added
     /// @param addr a single address to be added
-    ///
     void setAddress(const isc::asiolink::IOAddress& addr);
     void setAddress(const isc::asiolink::IOAddress& addr);
 
 
     /// @brief Sets list of addresses.
     /// @brief Sets list of addresses.
     ///
     ///
     /// @param addrs a vector of addresses to be added
     /// @param addrs a vector of addresses to be added
-    ///
     void setAddresses(const AddressContainer& addrs);
     void setAddresses(const AddressContainer& addrs);
 
 
     /// @brief Returns vector with addresses.
     /// @brief Returns vector with addresses.
@@ -110,8 +88,7 @@ public:
     /// a couple (1-3) addresses, the overhead is not that big.
     /// a couple (1-3) addresses, the overhead is not that big.
     ///
     ///
     /// @return address container with addresses
     /// @return address container with addresses
-    AddressContainer
+    AddressContainer getAddresses() { return addrs_; };
-    getAddresses() { return addrs_; };
 
 
     // returns data length (data length + DHCPv4/DHCPv6 option header)
     // returns data length (data length + DHCPv4/DHCPv6 option header)
     virtual uint16_t len();
     virtual uint16_t len();

+ 26 - 55
src/lib/dhcp/option6_ia.cc

@@ -1,4 +1,4 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011-2012 Internet Systems Consortium, Inc. ("ISC")
 //
 //
 // Permission to use, copy, modify, and/or distribute this software for any
 // Permission to use, copy, modify, and/or distribute this software for any
 // purpose with or without fee is hereby granted, provided that the above
 // purpose with or without fee is hereby granted, provided that the above
@@ -15,12 +15,12 @@
 #include <stdint.h>
 #include <stdint.h>
 #include <arpa/inet.h>
 #include <arpa/inet.h>
 #include <sstream>
 #include <sstream>
-#include "exceptions/exceptions.h"
 
 
-#include "dhcp/libdhcp++.h"
+#include <exceptions/exceptions.h>
-#include "dhcp/option6_ia.h"
+#include <dhcp/libdhcp++.h>
-#include "dhcp/dhcp6.h"
+#include <dhcp/option6_ia.h>
-#include "util/io_utilities.h"
+#include <dhcp/dhcp6.h>
+#include <util/io_utilities.h>
 
 
 using namespace std;
 using namespace std;
 using namespace isc;
 using namespace isc;
@@ -32,65 +32,36 @@ Option6IA::Option6IA(unsigned short type, unsigned int iaid)
 }
 }
 
 
 Option6IA::Option6IA(unsigned short type,
 Option6IA::Option6IA(unsigned short type,
-                     const boost::shared_array<uint8_t>& buf,
+                     OptionBufferConstIter begin,
-                     unsigned int buf_len,
+                     OptionBufferConstIter end)
-                     unsigned int offset,
-                     unsigned int option_len)
     :Option(Option::V6, type) {
     :Option(Option::V6, type) {
-    unpack(buf, buf_len, offset, option_len);
+    unpack(begin, end);
 }
 }
 
 
-unsigned int
+void Option6IA::pack(isc::util::OutputBuffer& buf) {
-Option6IA::pack(boost::shared_array<uint8_t>& buf,
+    buf.writeUint16(type_);
-                unsigned int buf_len,
+    buf.writeUint16(len() - OPTION6_HDR_LEN);
-                unsigned int offset) {
+    buf.writeUint32(iaid_);
-    if (offset + len() > buf_len) {
+    buf.writeUint32(t1_);
-        isc_throw(OutOfRange, "Failed to pack IA option: len=" << len()
+    buf.writeUint32(t2_);
-                  << ", buffer=" << buf_len << ": too small buffer.");
-    }
-
-    if (len() < 16 ) {
-        isc_throw(OutOfRange, "Attempt to build malformed IA option: len="
-                  << len() << " is too small (at least 16 is required).");
-    }
-
-    uint8_t* ptr = &buf[offset];
-
-    ptr = writeUint16(type_, ptr);
-    ptr = writeUint16(len() - OPTION6_HDR_LEN, ptr);
-    offset += OPTION6_HDR_LEN;
 
 
-    ptr = writeUint32(iaid_, ptr);
+    LibDHCP::packOptions6(buf, options_);
-    ptr = writeUint32(t1_, ptr);
-    ptr = writeUint32(t2_, ptr);
-    offset += OPTION6_IA_LEN;
-
-    offset = LibDHCP::packOptions6(buf, buf_len, offset, options_);
-    return offset;
 }
 }
 
 
-unsigned int
+void Option6IA::unpack(OptionBufferConstIter begin,
-Option6IA::unpack(const boost::shared_array<uint8_t>& buf,
+                       OptionBufferConstIter end) {
-                  unsigned int buf_len,
+    if (distance(begin, end) < 12) {
-                  unsigned int offset,
-                  unsigned int parse_len) {
-    if ( parse_len < OPTION6_IA_LEN || offset + OPTION6_IA_LEN > buf_len) {
         isc_throw(OutOfRange, "Option " << type_ << " truncated");
         isc_throw(OutOfRange, "Option " << type_ << " truncated");
     }
     }
+    iaid_ = readUint32( &(*begin) );
+    begin += sizeof(uint32_t);
+    t1_ = readUint32( &(*begin) );
+    begin += sizeof(uint32_t);
 
 
-    iaid_ = readUint32(&buf[offset]);
+    t2_ = readUint32( &(*begin) );
-    offset += sizeof(uint32_t);
+    begin += sizeof(uint32_t);
-
-    t1_ = readUint32(&buf[offset]);
-    offset += sizeof(uint32_t);
-
-    t2_ = readUint32(&buf[offset]);
-    offset += sizeof(uint32_t);
-
-    offset = LibDHCP::unpackOptions6(buf, buf_len, offset,
-                                     parse_len - OPTION6_IA_LEN, options_);
 
 
-    return (offset);
+    LibDHCP::unpackOptions6(OptionBuffer(begin, end), options_);
 }
 }
 
 
 std::string Option6IA::toText(int indent /* = 0*/) {
 std::string Option6IA::toText(int indent /* = 0*/) {

+ 21 - 43
src/lib/dhcp/option6_ia.h

@@ -1,4 +1,4 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011-2012 Internet Systems Consortium, Inc. ("ISC")
 //
 //
 // Permission to use, copy, modify, and/or distribute this software for any
 // Permission to use, copy, modify, and/or distribute this software for any
 // purpose with or without fee is hereby granted, provided that the above
 // purpose with or without fee is hereby granted, provided that the above
@@ -27,54 +27,34 @@ public:
     /// Length of IA_NA and IA_PD content
     /// Length of IA_NA and IA_PD content
     const static size_t OPTION6_IA_LEN = 12;
     const static size_t OPTION6_IA_LEN = 12;
 
 
-    /// @brief ctor, used for options constructed, usually during transmission
+    /// @brief Ctor, used for constructed options, usually during transmission.
     ///
     ///
     /// @param type option type (usually 4 for IA_NA, 25 for IA_PD)
     /// @param type option type (usually 4 for IA_NA, 25 for IA_PD)
     /// @param iaid identity association identifier (id of IA)
     /// @param iaid identity association identifier (id of IA)
-    Option6IA(uint16_t type, unsigned int iaid);
+    Option6IA(uint16_t type, uint32_t iaid);
 
 
-    /// @brief ctor, used for received options
+    /// @brief Ctor, used for received options.
-    ///
-    /// boost::shared_array allows sharing a buffer, but it requires that
-    /// different instances share pointer to the whole array, not point
-    /// to different elements in shared array. Therefore we need to share
-    /// pointer to the whole array and remember offset where data for
-    /// this option begins
     ///
     ///
     /// @param type option type (usually 4 for IA_NA, 25 for IA_PD)
     /// @param type option type (usually 4 for IA_NA, 25 for IA_PD)
-    /// @param buf buffer to be parsed
+    /// @param begin iterator to first byte of option data
-    /// @param buf_len buffer length
+    /// @param end iterator to end of option data (first byte after option end)
-    /// @param offset offset in buffer
+    Option6IA(uint16_t type, OptionBuffer::const_iterator begin,
-    /// @param len number of bytes to parse
+              OptionBuffer::const_iterator end);
-    Option6IA(uint16_t type, const boost::shared_array<uint8_t>& buf,
-              unsigned int buf_len, unsigned int offset, unsigned int len);
 
 
     /// Writes option in wire-format to buf, returns pointer to first unused
     /// Writes option in wire-format to buf, returns pointer to first unused
     /// byte after stored option.
     /// byte after stored option.
     ///
     ///
     /// @param buf buffer (option will be stored here)
     /// @param buf buffer (option will be stored here)
-    /// @param buf_len (buffer length)
+    void pack(isc::util::OutputBuffer& buf);
-    /// @param offset offset place where option should be stored
-    ///
-    /// @return offset to the first unused byte after stored option
-    unsigned int
-    pack(boost::shared_array<uint8_t>& buf, unsigned int buf_len,
-         unsigned int offset);
 
 
     /// @brief Parses received buffer
     /// @brief Parses received buffer
     ///
     ///
     /// Parses received buffer and returns offset to the first unused byte after
     /// Parses received buffer and returns offset to the first unused byte after
     /// parsed option.
     /// parsed option.
     ///
     ///
-    /// @param buf pointer to buffer
+    /// @param begin iterator to first byte of option data
-    /// @param buf_len length of buf
+    /// @param end iterator to end of option data (first byte after option end)
-    /// @param offset offset, where start parsing option
+    virtual void unpack(OptionBufferConstIter begin, OptionBufferConstIter end);
-    /// @param parse_len how many bytes should be parsed
-    ///
-    /// @return offset after last parsed octet
-    virtual unsigned int
-    unpack(const boost::shared_array<uint8_t>& buf, unsigned int buf_len,
-           unsigned int offset, unsigned int parse_len);
 
 
     /// Provides human readable text representation
     /// Provides human readable text representation
     ///
     ///
@@ -87,48 +67,46 @@ public:
     /// Sets T1 timer.
     /// Sets T1 timer.
     ///
     ///
     /// @param t1 t1 value to be set
     /// @param t1 t1 value to be set
-    void setT1(unsigned int t1) { t1_=t1; }
+    void setT1(uint32_t t1) { t1_=t1; }
-
 
 
     /// Sets T2 timer.
     /// Sets T2 timer.
     ///
     ///
     /// @param t2 t2 value to be set
     /// @param t2 t2 value to be set
-    void setT2(unsigned int t2) { t2_=t2; }
+    void setT2(uint32_t t2) { t2_=t2; }
 
 
     /// Returns IA identifier.
     /// Returns IA identifier.
     ///
     ///
     /// @return IAID value.
     /// @return IAID value.
     ///
     ///
-    unsigned int getIAID() const { return iaid_; }
+    uint32_t getIAID() const { return iaid_; }
 
 
     /// Returns T1 timer.
     /// Returns T1 timer.
     ///
     ///
     /// @return T1 value.
     /// @return T1 value.
-    unsigned int getT1() const { return t1_; }
+    uint32_t getT1() const { return t1_; }
 
 
     /// Returns T2 timer.
     /// Returns T2 timer.
     ///
     ///
     /// @return T2 value.
     /// @return T2 value.
-    unsigned int getT2() const { return t2_; }
+    uint32_t getT2() const { return t2_; }
 
 
     /// @brief returns complete length of option
     /// @brief returns complete length of option
     ///
     ///
     /// Returns length of this option, including option header and suboptions
     /// Returns length of this option, including option header and suboptions
     ///
     ///
     /// @return length of this option
     /// @return length of this option
-    virtual uint16_t
+    virtual uint16_t len();
-    len();
 
 
 protected:
 protected:
 
 
     /// keeps IA identifier
     /// keeps IA identifier
-    unsigned int iaid_;
+    uint32_t iaid_;
 
 
     /// keeps T1 timer value
     /// keeps T1 timer value
-    unsigned int t1_;
+    uint32_t t1_;
 
 
     /// keeps T2 timer value
     /// keeps T2 timer value
-    unsigned int t2_;
+    uint32_t t2_;
 };
 };
 
 
 } // isc::dhcp namespace
 } // isc::dhcp namespace

+ 23 - 43
src/lib/dhcp/option6_iaaddr.cc

@@ -1,4 +1,4 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011-2012 Internet Systems Consortium, Inc. ("ISC")
 //
 //
 // Permission to use, copy, modify, and/or distribute this software for any
 // Permission to use, copy, modify, and/or distribute this software for any
 // purpose with or without fee is hereby granted, provided that the above
 // purpose with or without fee is hereby granted, provided that the above
@@ -36,67 +36,47 @@ Option6IAAddr::Option6IAAddr(unsigned short type,
      valid_(valid) {
      valid_(valid) {
 }
 }
 
 
-Option6IAAddr::Option6IAAddr(unsigned short type,
+Option6IAAddr::Option6IAAddr(uint32_t type, OptionBuffer::const_iterator begin,
-                             boost::shared_array<uint8_t> buf,
+                             OptionBuffer::const_iterator end)
-                             unsigned int buf_len, unsigned int offset,
-                             unsigned int option_len)
     :Option(V6, type), addr_("::") {
     :Option(V6, type), addr_("::") {
-    unpack(buf, buf_len, offset, option_len);
+    unpack(begin, end);
 }
 }
 
 
-unsigned int
+void Option6IAAddr::pack(isc::util::OutputBuffer& buf) {
-Option6IAAddr::pack(boost::shared_array<uint8_t>& buf,
-                    unsigned int buf_len,
-                    unsigned int offset) {
-    if (len() > buf_len) {
-        isc_throw(OutOfRange, "Failed to pack IA option: len=" << len()
-                  << ", buffer=" << buf_len << ": too small buffer.");
-    }
-
-    uint8_t* ptr = &buf[offset];
 
 
-    ptr = writeUint16(type_, ptr);
+    buf.writeUint16(type_);
 
 
     // len() returns complete option length. len field contains
     // len() returns complete option length. len field contains
     // length without 4-byte option header
     // length without 4-byte option header
-    ptr = writeUint16(len() - OPTION6_HDR_LEN, ptr);
+    buf.writeUint16(len() - getHeaderLen());
-    offset += OPTION6_HDR_LEN;
 
 
-    memcpy(ptr, addr_.getAddress().to_v6().to_bytes().data(), 16);
-    ptr += V6ADDRESS_LEN;
 
 
-    ptr = writeUint32(preferred_, ptr);
+    buf.writeData(addr_.getAddress().to_v6().to_bytes().data(),
+                  isc::asiolink::V6ADDRESS_LEN);
 
 
-    ptr = writeUint32(valid_, ptr);
+    buf.writeUint32(preferred_);
-    offset += OPTION6_IAADDR_LEN;
+    buf.writeUint32(valid_);
 
 
-    // parse suboption (there shouldn't be any)
+    // parse suboption (there shouldn't be any for IAADDR)
-    offset = LibDHCP::packOptions6(buf, buf_len, offset, options_);
+    LibDHCP::packOptions6(buf, options_);
-    return offset;
 }
 }
 
 
-unsigned int
+void Option6IAAddr::unpack(OptionBuffer::const_iterator begin,
-Option6IAAddr::unpack(const boost::shared_array<uint8_t>& buf,
+                      OptionBuffer::const_iterator end) {
-                  unsigned int buf_len,
+    if ( distance(begin, end) < OPTION6_IAADDR_LEN) {
-                  unsigned int offset,
-                  unsigned int parse_len) {
-    if ( parse_len < OPTION6_IAADDR_LEN || offset + OPTION6_IAADDR_LEN > buf_len) {
         isc_throw(OutOfRange, "Option " << type_ << " truncated");
         isc_throw(OutOfRange, "Option " << type_ << " truncated");
     }
     }
 
 
     // 16 bytes: IPv6 address
     // 16 bytes: IPv6 address
-    addr_ = IOAddress::from_bytes(AF_INET6, &buf[offset]);
+    addr_ = IOAddress::from_bytes(AF_INET6, &(*begin));
-    offset += V6ADDRESS_LEN;
+    begin += V6ADDRESS_LEN;
-
-    preferred_ = readUint32(&buf[offset]);
-    offset += sizeof(uint32_t);
 
 
-    valid_ = readUint32(&buf[offset]);
+    preferred_ = readUint32( &(*begin) );
-    offset += sizeof(uint32_t);
+    begin += sizeof(uint32_t);
-    offset = LibDHCP::unpackOptions6(buf, buf_len, offset,
-                                     parse_len - 24, options_);
 
 
-    return offset;
+    valid_ = readUint32( &(*begin) );
+    begin += sizeof(uint32_t);
+    LibDHCP::unpackOptions6(OptionBuffer(begin, end), options_);
 }
 }
 
 
 std::string Option6IAAddr::toText(int indent /* =0 */) {
 std::string Option6IAAddr::toText(int indent /* =0 */) {

+ 14 - 32
src/lib/dhcp/option6_iaaddr.h

@@ -1,4 +1,4 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011-2012 Internet Systems Consortium, Inc. ("ISC")
 //
 //
 // Permission to use, copy, modify, and/or distribute this software for any
 // Permission to use, copy, modify, and/or distribute this software for any
 // purpose with or without fee is hereby granted, provided that the above
 // purpose with or without fee is hereby granted, provided that the above
@@ -27,28 +27,22 @@ public:
     /// length of the fixed part of the IAADDR option
     /// length of the fixed part of the IAADDR option
     static const size_t OPTION6_IAADDR_LEN = 24;
     static const size_t OPTION6_IAADDR_LEN = 24;
 
 
-    /// @brief ctor, used for options constructed (during transmission)
+    /// @brief Ctor, used for options constructed (during transmission).
     ///
     ///
     /// @param type option type
     /// @param type option type
     /// @param addr reference to an address
     /// @param addr reference to an address
     /// @param preferred address preferred lifetime (in seconds)
     /// @param preferred address preferred lifetime (in seconds)
     /// @param valid address valid lifetime (in seconds)
     /// @param valid address valid lifetime (in seconds)
-    Option6IAAddr(unsigned short type, const isc::asiolink::IOAddress& addr,
+    Option6IAAddr(uint16_t type, const isc::asiolink::IOAddress& addr,
-                  unsigned int preferred, unsigned int valid);
+                  uint32_t preferred, uint32_t valid);
 
 
-    /// ctor, used for received options
+    /// @brief ctor, used for received options.
-    /// boost::shared_array allows sharing a buffer, but it requires that
-    /// different instances share pointer to the whole array, not point
-    /// to different elements in shared array. Therefore we need to share
-    /// pointer to the whole array and remember offset where data for
-    /// this option begins
     ///
     ///
     /// @param type option type
     /// @param type option type
-    /// @param buf pointer to a buffer
+    /// @param begin iterator to first byte of option data
-    /// @param offset offset to first data byte in that buffer
+    /// @param end iterator to end of option data (first byte after option end)
-    /// @param len data length of this option
+    Option6IAAddr(uint32_t type, OptionBuffer::const_iterator begin,
-    Option6IAAddr(unsigned short type, boost::shared_array<uint8_t> buf,
+                  OptionBuffer::const_iterator end);
-                  unsigned int buf_len, unsigned int offset, unsigned int len);
 
 
     /// @brief Writes option in wire-format.
     /// @brief Writes option in wire-format.
     ///
     ///
@@ -56,13 +50,7 @@ public:
     /// byte after stored option.
     /// byte after stored option.
     ///
     ///
     /// @param buf pointer to a buffer
     /// @param buf pointer to a buffer
-    /// @param buf_len length of the buffer
+    void pack(isc::util::OutputBuffer& buf);
-    /// @param offset offset to place, where option shout be stored
-    ///
-    /// @return offset to first unused byte after stored option
-    unsigned int
-    pack(boost::shared_array<uint8_t>& buf, unsigned int buf_len,
-         unsigned int offset);
 
 
     /// @brief Parses buffer.
     /// @brief Parses buffer.
     ///
     ///
@@ -70,16 +58,10 @@ public:
     /// parsed option.
     /// parsed option.
     ///
     ///
     /// @param buf pointer to buffer
     /// @param buf pointer to buffer
-    /// @param buf_len length of buf
+    /// @param begin iterator to first byte of option data
-    /// @param offset offset, where start parsing option
+    /// @param end iterator to end of option data (first byte after option end)
-    /// @param parse_len how many bytes should be parsed
+    virtual void unpack(OptionBufferConstIter begin,
-    ///
+                        OptionBufferConstIter end);
-    /// @return offset after last parsed octet
-    virtual unsigned int
-    unpack(const boost::shared_array<uint8_t>& buf,
-           unsigned int buf_len,
-           unsigned int offset,
-           unsigned int parse_len);
 
 
     /// Returns string representation of the option.
     /// Returns string representation of the option.
     ///
     ///

+ 35 - 44
src/lib/dhcp/pkt4.h

@@ -1,4 +1,4 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011-2012 Internet Systems Consortium, Inc. ("ISC")
 //
 //
 // Permission to use, copy, modify, and/or distribute this software for any
 // Permission to use, copy, modify, and/or distribute this software for any
 // purpose with or without fee is hereby granted, provided that the above
 // purpose with or without fee is hereby granted, provided that the above
@@ -18,7 +18,6 @@
 #include <iostream>
 #include <iostream>
 #include <vector>
 #include <vector>
 #include <boost/shared_ptr.hpp>
 #include <boost/shared_ptr.hpp>
-#include <boost/shared_array.hpp>
 #include "asiolink/io_address.h"
 #include "asiolink/io_address.h"
 #include "util/buffer.h"
 #include "util/buffer.h"
 #include "dhcp/option.h"
 #include "dhcp/option.h"
@@ -103,8 +102,7 @@ public:
     /// This function is useful mainly for debugging.
     /// This function is useful mainly for debugging.
     ///
     ///
     /// @return string with text representation
     /// @return string with text representation
-    std::string
+    std::string toText();
-    toText();
 
 
     /// @brief Returns the size of the required buffer to build the packet.
     /// @brief Returns the size of the required buffer to build the packet.
     ///
     ///
@@ -112,118 +110,110 @@ public:
     /// the current set of packet options.
     /// the current set of packet options.
     ///
     ///
     /// @return number of bytes required to build this packet
     /// @return number of bytes required to build this packet
-    size_t
+    size_t len();
-    len();
 
 
-    /// Sets hops field
+    /// @brief Sets hops field.
     ///
     ///
     /// @param hops value to be set
     /// @param hops value to be set
-    void
+    void setHops(uint8_t hops) { hops_ = hops; };
-    setHops(uint8_t hops) { hops_ = hops; };
 
 
-    /// Returns hops field
+    /// @brief Returns hops field.
     ///
     ///
     /// @return hops field
     /// @return hops field
-    uint8_t
+    uint8_t getHops() const { return (hops_); };
-    getHops() const { return (hops_); };
 
 
     // Note: There's no need to manipulate OP field directly,
     // Note: There's no need to manipulate OP field directly,
     // thus no setOp() method. See op_ comment.
     // thus no setOp() method. See op_ comment.
 
 
-    /// Returns op field
+    /// @brief Returns op field.
     ///
     ///
     /// @return op field
     /// @return op field
-    uint8_t
+    uint8_t getOp() const { return (op_); };
-    getOp() const { return (op_); };
 
 
-    /// Sets secs field
+    /// @brief Sets secs field.
     ///
     ///
     /// @param secs value to be set
     /// @param secs value to be set
-    void
+    void setSecs(uint16_t secs) { secs_ = secs; };
-    setSecs(uint16_t secs) { secs_ = secs; };
 
 
-    /// Returns secs field
+    /// @brief Returns secs field.
     ///
     ///
     /// @return secs field
     /// @return secs field
-    uint16_t
+    uint16_t getSecs() const { return (secs_); };
-    getSecs() const { return (secs_); };
 
 
-    /// Sets flags field
+    /// @brief Sets flags field.
     ///
     ///
     /// @param flags value to be set
     /// @param flags value to be set
-    void
+    void setFlags(uint16_t flags) { flags_ = flags; };
-    setFlags(uint16_t flags) { flags_ = flags; };
 
 
-    /// Returns flags field
+    /// @brief Returns flags field.
     ///
     ///
     /// @return flags field
     /// @return flags field
-    uint16_t
+    uint16_t getFlags() const { return (flags_); };
-    getFlags() const { return (flags_); };
 
 
 
 
-    /// Returns ciaddr field
+    /// @brief Returns ciaddr field.
     ///
     ///
     /// @return ciaddr field
     /// @return ciaddr field
     const isc::asiolink::IOAddress&
     const isc::asiolink::IOAddress&
     getCiaddr() const { return (ciaddr_); };
     getCiaddr() const { return (ciaddr_); };
 
 
-    /// Sets ciaddr field
+    /// @brief Sets ciaddr field.
     ///
     ///
     /// @param ciaddr value to be set
     /// @param ciaddr value to be set
     void
     void
     setCiaddr(const isc::asiolink::IOAddress& ciaddr) { ciaddr_ = ciaddr; };
     setCiaddr(const isc::asiolink::IOAddress& ciaddr) { ciaddr_ = ciaddr; };
 
 
 
 
-    /// Returns siaddr field
+    /// @brief Returns siaddr field.
     ///
     ///
     /// @return siaddr field
     /// @return siaddr field
     const isc::asiolink::IOAddress&
     const isc::asiolink::IOAddress&
     getSiaddr() const { return (siaddr_); };
     getSiaddr() const { return (siaddr_); };
 
 
-    /// Sets siaddr field
+    /// @brief Sets siaddr field.
     ///
     ///
     /// @param siaddr value to be set
     /// @param siaddr value to be set
     void
     void
     setSiaddr(const isc::asiolink::IOAddress& siaddr) { siaddr_ = siaddr; };
     setSiaddr(const isc::asiolink::IOAddress& siaddr) { siaddr_ = siaddr; };
 
 
 
 
-    /// Returns yiaddr field
+    /// @brief Returns yiaddr field.
     ///
     ///
     /// @return yiaddr field
     /// @return yiaddr field
     const isc::asiolink::IOAddress&
     const isc::asiolink::IOAddress&
     getYiaddr() const { return (yiaddr_); };
     getYiaddr() const { return (yiaddr_); };
 
 
-    /// Sets yiaddr field
+    /// @brief Sets yiaddr field.
     ///
     ///
     /// @param yiaddr value to be set
     /// @param yiaddr value to be set
     void
     void
     setYiaddr(const isc::asiolink::IOAddress& yiaddr) { yiaddr_ = yiaddr; };
     setYiaddr(const isc::asiolink::IOAddress& yiaddr) { yiaddr_ = yiaddr; };
 
 
 
 
-    /// Returns giaddr field
+    /// @brief Returns giaddr field.
     ///
     ///
     /// @return giaddr field
     /// @return giaddr field
     const isc::asiolink::IOAddress&
     const isc::asiolink::IOAddress&
     getGiaddr() const { return (giaddr_); };
     getGiaddr() const { return (giaddr_); };
 
 
-    /// Sets giaddr field
+    /// @brief Sets giaddr field.
     ///
     ///
     /// @param giaddr value to be set
     /// @param giaddr value to be set
     void
     void
     setGiaddr(const isc::asiolink::IOAddress& giaddr) { giaddr_ = giaddr; };
     setGiaddr(const isc::asiolink::IOAddress& giaddr) { giaddr_ = giaddr; };
 
 
-    /// Returns value of transaction-id field
+    /// @brief Returns value of transaction-id field.
     ///
     ///
     /// @return transaction-id
     /// @return transaction-id
     uint32_t getTransid() const { return (transid_); };
     uint32_t getTransid() const { return (transid_); };
 
 
-    /// Returns message type (e.g. 1 = DHCPDISCOVER)
+    /// @brief Returns message type (e.g. 1 = DHCPDISCOVER).
     ///
     ///
     /// @return message type
     /// @return message type
     uint8_t
     uint8_t
     getType() const { return (msg_type_); }
     getType() const { return (msg_type_); }
 
 
-    /// Sets message type (e.g. 1 = DHCPDISCOVER)
+    /// @brief Sets message type (e.g. 1 = DHCPDISCOVER).
     ///
     ///
     /// @param type message type to be set
     /// @param type message type to be set
     void setType(uint8_t type) { msg_type_=type; };
     void setType(uint8_t type) { msg_type_=type; };
@@ -234,14 +224,13 @@ public:
     /// null-terminated. Do not use strlen() or similar on it.
     /// null-terminated. Do not use strlen() or similar on it.
     ///
     ///
     /// @return sname field
     /// @return sname field
-    const std::vector<uint8_t>
+    const OptionBuffer
     getSname() const { return (std::vector<uint8_t>(sname_, &sname_[MAX_SNAME_LEN])); };
     getSname() const { return (std::vector<uint8_t>(sname_, &sname_[MAX_SNAME_LEN])); };
 
 
-    /// Sets sname field
+    /// @brief Sets sname field.
     ///
     ///
     /// @param sname value to be set
     /// @param sname value to be set
-    void
+    void setSname(const uint8_t* sname, size_t snameLen = MAX_SNAME_LEN);
-    setSname(const uint8_t* sname, size_t snameLen = MAX_SNAME_LEN);
 
 
     /// @brief Returns file field
     /// @brief Returns file field
     ///
     ///
@@ -249,7 +238,7 @@ public:
     /// null-terminated. Do not use strlen() or similar on it.
     /// null-terminated. Do not use strlen() or similar on it.
     ///
     ///
     /// @return pointer to file field
     /// @return pointer to file field
-    const std::vector<uint8_t>
+    const OptionBuffer
     getFile() const { return (std::vector<uint8_t>(file_, &file_[MAX_FILE_LEN])); };
     getFile() const { return (std::vector<uint8_t>(file_, &file_[MAX_FILE_LEN])); };
 
 
     /// Sets file field
     /// Sets file field
@@ -478,7 +467,7 @@ protected:
 
 
     // end of real DHCPv4 fields
     // end of real DHCPv4 fields
 
 
-    /// output buffer (used during message
+    /// output buffer (used during message transmission)
     isc::util::OutputBuffer bufferOut_;
     isc::util::OutputBuffer bufferOut_;
 
 
     // that's the data of input buffer used in RX packet. Note that
     // that's the data of input buffer used in RX packet. Note that
@@ -496,6 +485,8 @@ protected:
     isc::dhcp::Option::OptionCollection options_;
     isc::dhcp::Option::OptionCollection options_;
 }; // Pkt4 class
 }; // Pkt4 class
 
 
+typedef boost::shared_ptr<Pkt4> Pkt4Ptr;
+
 } // isc::dhcp namespace
 } // isc::dhcp namespace
 
 
 } // isc namespace
 } // isc namespace

+ 48 - 74
src/lib/dhcp/pkt6.cc

@@ -1,4 +1,4 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011-2012 Internet Systems Consortium, Inc. ("ISC")
 //
 //
 // Permission to use, copy, modify, and/or distribute this software for any
 // Permission to use, copy, modify, and/or distribute this software for any
 // purpose with or without fee is hereby granted, provided that the above
 // purpose with or without fee is hereby granted, provided that the above
@@ -25,43 +25,36 @@ using namespace isc::dhcp;
 
 
 namespace isc {
 namespace isc {
 
 
-Pkt6::Pkt6(unsigned int dataLen, DHCPv6Proto proto /* = UDP */)
+Pkt6::Pkt6(const uint8_t* buf, uint32_t buf_len, DHCPv6Proto proto /* = UDP */) :
-    :data_len_(dataLen),
+    proto_(proto),
-     local_addr_("::"),
+    msg_type_(-1),
-     remote_addr_("::"),
+    transid_(rand()%0xffffff),
-     iface_(""),
+    iface_(""),
-     ifindex_(-1),
+    ifindex_(-1),
-     local_port_(-1),
+    local_addr_("::"),
-     remote_port_(-1),
+    remote_addr_("::"),
-     proto_(proto),
+    local_port_(-1),
-     msg_type_(-1),
+    remote_port_(-1),
-     transid_(rand()%0xffffff)
+    bufferOut_(0) {
-{
+    data_.resize(buf_len);
-
+    memcpy(&data_[0], buf, buf_len);
-    data_ = boost::shared_array<uint8_t>(new uint8_t[dataLen]);
-    data_len_ = dataLen;
 }
 }
 
 
-Pkt6::Pkt6(uint8_t msg_type,
+Pkt6::Pkt6(uint8_t msg_type, unsigned int transid, DHCPv6Proto proto /*= UDP*/) :
-           unsigned int transid,
+    proto_(proto),
-           DHCPv6Proto proto /*= UDP*/)
+    msg_type_(msg_type),
-    :local_addr_("::"),
+    transid_(transid),
-     remote_addr_("::"),
+    iface_(""),
-     iface_(""),
+    ifindex_(-1),
-     ifindex_(-1),
+    local_addr_("::"),
-     local_port_(-1),
+    remote_addr_("::"),
-     remote_port_(-1),
+    local_port_(-1),
-     proto_(proto),
+    remote_port_(-1),
-     msg_type_(msg_type),
+    bufferOut_(0) {
-     transid_(transid) {
-
-    data_ = boost::shared_array<uint8_t>(new uint8_t[4]);
-    data_len_ = 4;
 }
 }
 
 
-unsigned short
+uint16_t Pkt6::len() {
-Pkt6::len() {
+    uint16_t length = DHCPV6_PKT_HDR_LEN; // DHCPv6 header
-    unsigned int length = DHCPV6_PKT_HDR_LEN; // DHCPv6 header
 
 
     for (Option::OptionCollection::iterator it = options_.begin();
     for (Option::OptionCollection::iterator it = options_.begin();
          it != options_.end();
          it != options_.end();
@@ -95,44 +88,21 @@ Pkt6::packUDP() {
     // It is better to implement a method in IOAddress that extracts
     // It is better to implement a method in IOAddress that extracts
     // vector<uint8_t>
     // vector<uint8_t>
 
 
-    unsigned short length = len();
-    if (data_len_ < length) {
-        cout << "Previous len=" << data_len_ << ", allocating new buffer: len="
-             << length << endl;
-
-        // May throw exception if out of memory. That is rather fatal,
-        // so we don't catch this
-        data_ = boost::shared_array<uint8_t>(new uint8_t[length]);
-        data_len_ = length;
-    }
-
-    data_len_ = length;
     try {
     try {
         // DHCPv6 header: message-type (1 octect) + transaction id (3 octets)
         // DHCPv6 header: message-type (1 octect) + transaction id (3 octets)
-        data_[0] = msg_type_;
+        bufferOut_.writeUint8(msg_type_);
-
         // store 3-octet transaction-id
         // store 3-octet transaction-id
-        data_[1] = (transid_ >> 16) & 0xff;
+        bufferOut_.writeUint8( (transid_ >> 16) & 0xff );
-        data_[2] = (transid_ >> 8) & 0xff;
+        bufferOut_.writeUint8( (transid_ >> 8) & 0xff );
-        data_[3] = (transid_) & 0xff;
+        bufferOut_.writeUint8( (transid_) & 0xff );
 
 
         // the rest are options
         // the rest are options
-        unsigned short offset = LibDHCP::packOptions6(data_, length,
+        LibDHCP::packOptions6(bufferOut_, options_);
-                                                      4/*offset*/,
-                                                      options_);
-
-        // sanity check
-        if (offset != length) {
-            isc_throw(OutOfRange, "Packet build failed: expected size="
-                      << length << ", actual len=" << offset);
-        }
     }
     }
     catch (const Exception& e) {
     catch (const Exception& e) {
         cout << "Packet build failed:" << e.what() << endl;
         cout << "Packet build failed:" << e.what() << endl;
         return (false);
         return (false);
     }
     }
-    // Limited verbosity of this method
-    // cout << "Packet built, len=" << len() << endl;
     return (true);
     return (true);
 }
 }
 
 
@@ -158,8 +128,8 @@ Pkt6::unpack() {
 
 
 bool
 bool
 Pkt6::unpackUDP() {
 Pkt6::unpackUDP() {
-    if (data_len_ < 4) {
+    if (data_.size() < 4) {
-        std::cout << "DHCPv6 packet truncated. Only " << data_len_
+        std::cout << "DHCPv6 packet truncated. Only " << data_.size()
                   << " bytes. Need at least 4." << std::endl;
                   << " bytes. Need at least 4." << std::endl;
         return (false);
         return (false);
     }
     }
@@ -168,16 +138,13 @@ Pkt6::unpackUDP() {
         ((data_[2]) << 8) + (data_[3]);
         ((data_[2]) << 8) + (data_[3]);
     transid_ = transid_ & 0xffffff;
     transid_ = transid_ & 0xffffff;
 
 
-    unsigned int offset = LibDHCP::unpackOptions6(data_,
+    try {
-                                                  data_len_,
+        OptionBuffer opt_buffer(data_.begin() + 4, data_.end());
-                                                  4, //offset
+
-                                                  data_len_ - 4,
+        LibDHCP::unpackOptions6(opt_buffer, options_);
-                                                  options_);
+    } catch (const Exception& e) {
-    if (offset != data_len_) {
+        cout << "Packet parsing failed:" << e.what() << endl;
-        cout << "DHCPv6 packet contains trailing garbage. Parsed "
+        return (false);
-             << offset << " bytes, packet is " << data_len_ << " bytes."
-             << endl;
-        // just a warning. Ignore trailing garbage and continue
     }
     }
     return (true);
     return (true);
 }
 }
@@ -229,4 +196,11 @@ Pkt6::delOption(unsigned short type) {
     return (false); // can't find option to be deleted
     return (false); // can't find option to be deleted
 }
 }
 
 
+void Pkt6::repack() {
+    cout << "Convering RX packet to TX packet: " << data_.size() << " bytes." << endl;
+
+    bufferOut_.writeData(&data_[0], data_.size());
+}
+
+
 };
 };

+ 140 - 53
src/lib/dhcp/pkt6.h

@@ -1,4 +1,4 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011-2012 Internet Systems Consortium, Inc. ("ISC")
 //
 //
 // Permission to use, copy, modify, and/or distribute this software for any
 // Permission to use, copy, modify, and/or distribute this software for any
 // purpose with or without fee is hereby granted, provided that the above
 // purpose with or without fee is hereby granted, provided that the above
@@ -41,17 +41,18 @@ public:
     /// @param msg_type type of message (SOLICIT=1, ADVERTISE=2, ...)
     /// @param msg_type type of message (SOLICIT=1, ADVERTISE=2, ...)
     /// @param transid transaction-id
     /// @param transid transaction-id
     /// @param proto protocol (TCP or UDP)
     /// @param proto protocol (TCP or UDP)
-    Pkt6(unsigned char msg_type,
+    Pkt6(uint8_t msg_type,
-         unsigned int transid,
+         uint32_t transid,
          DHCPv6Proto proto = UDP);
          DHCPv6Proto proto = UDP);
 
 
     /// Constructor, used in message transmission
     /// Constructor, used in message transmission
     ///
     ///
     /// Creates new message. Transaction-id will randomized.
     /// Creates new message. Transaction-id will randomized.
     ///
     ///
-    /// @param len size of buffer to be allocated for this packet.
+    /// @param buf pointer to a buffer of received packet content
+    /// @param len size of buffer of received packet content
     /// @param proto protocol (usually UDP, but TCP will be supported eventually)
     /// @param proto protocol (usually UDP, but TCP will be supported eventually)
-    Pkt6(unsigned int len, DHCPv6Proto proto = UDP);
+    Pkt6(const uint8_t* buf, uint32_t len, DHCPv6Proto proto = UDP);
 
 
     /// @brief Prepares on-wire format.
     /// @brief Prepares on-wire format.
     ///
     ///
@@ -61,8 +62,7 @@ public:
     /// will be set in data_len_.
     /// will be set in data_len_.
     ///
     ///
     /// @return true if packing procedure was successful
     /// @return true if packing procedure was successful
-    bool
+    bool pack();
-    pack();
 
 
     /// @brief Dispatch method that handles binary packet parsing.
     /// @brief Dispatch method that handles binary packet parsing.
     ///
     ///
@@ -70,59 +70,70 @@ public:
     /// unpackTCP).
     /// unpackTCP).
     ///
     ///
     /// @return true if parsing was successful
     /// @return true if parsing was successful
-    bool
+    bool unpack();
-    unpack();
 
 
-    /// Returns protocol of this packet (UDP or TCP)
+    /// @brief Returns reference to output buffer.
+    ///
+    /// Returned buffer will contain reasonable data only for
+    /// output (TX) packet and after pack() was called. This buffer
+    /// is only valid till Pkt4 object is valid.
+    ///
+    /// RX packet or TX packet before pack() will return buffer with
+    /// zero length
+    ///
+    /// @return reference to output buffer
+    const isc::util::OutputBuffer& getBuffer() const { return (bufferOut_); };
+
+
+    /// @brief Returns reference to input buffer.
+    ///
+    /// @return reference to input buffer
+    const OptionBuffer& getData() const { return(data_); }
+
+    /// @brief Returns protocol of this packet (UDP or TCP).
     ///
     ///
     /// @return protocol type
     /// @return protocol type
-    DHCPv6Proto
+    DHCPv6Proto getProto();
-    getProto();
 
 
     /// Sets protocol of this packet.
     /// Sets protocol of this packet.
     ///
     ///
     /// @param proto protocol (UDP or TCP)
     /// @param proto protocol (UDP or TCP)
-    ///
+    void setProto(DHCPv6Proto proto = UDP) { proto_ = proto; }
-    void
-    setProto(DHCPv6Proto proto = UDP) { proto_ = proto; }
 
 
     /// @brief Returns text representation of the packet.
     /// @brief Returns text representation of the packet.
     ///
     ///
     /// This function is useful mainly for debugging.
     /// This function is useful mainly for debugging.
     ///
     ///
     /// @return string with text representation
     /// @return string with text representation
-    std::string
+    std::string toText();
-    toText();
 
 
     /// @brief Returns calculated length of the packet.
     /// @brief Returns calculated length of the packet.
     ///
     ///
-    /// This function returns size of required buffer to buld this packet.
+    /// This function returns size of all options including DHCPv6
-    /// To use that function, options_ field must be set.
+    /// header. To use that function, options_ field must be set.
     ///
     ///
     /// @return number of bytes required to build this packet
     /// @return number of bytes required to build this packet
-    unsigned short
+    uint16_t len();
-    len();
 
 
     /// Returns message type (e.g. 1 = SOLICIT)
     /// Returns message type (e.g. 1 = SOLICIT)
     ///
     ///
     /// @return message type
     /// @return message type
-    unsigned char
+    uint8_t getType() { return (msg_type_); }
-    getType() { return (msg_type_); }
 
 
     /// Sets message type (e.g. 1 = SOLICIT)
     /// Sets message type (e.g. 1 = SOLICIT)
     ///
     ///
     /// @param type message type to be set
     /// @param type message type to be set
-    void setType(unsigned char type) { msg_type_=type; };
+    void setType(uint8_t type) { msg_type_=type; };
 
 
     /// Returns value of transaction-id field
     /// Returns value of transaction-id field
     ///
     ///
     /// @return transaction-id
     /// @return transaction-id
-    unsigned int getTransid() { return (transid_); };
+    uint32_t getTransid() { return (transid_); };
 
 
     /// Adds an option to this packet.
     /// Adds an option to this packet.
     ///
     ///
     /// @param opt option to be added.
     /// @param opt option to be added.
-    void addOption(boost::shared_ptr<isc::dhcp::Option> opt);
+    void addOption(OptionPtr opt);
 
 
     /// @brief Returns the first option of specified type.
     /// @brief Returns the first option of specified type.
     ///
     ///
@@ -133,49 +144,93 @@ public:
     /// @param opt_type option type we are looking for
     /// @param opt_type option type we are looking for
     ///
     ///
     /// @return pointer to found option (or NULL)
     /// @return pointer to found option (or NULL)
-    boost::shared_ptr<isc::dhcp::Option>
+    OptionPtr getOption(uint16_t type);
-    getOption(unsigned short type);
 
 
     /// Attempts to delete first suboption of requested type
     /// Attempts to delete first suboption of requested type
     ///
     ///
     /// @param type Type of option to be deleted.
     /// @param type Type of option to be deleted.
     ///
     ///
     /// @return true if option was deleted, false if no such option existed
     /// @return true if option was deleted, false if no such option existed
-    bool
+    bool delOption(uint16_t type);
-    delOption(unsigned short type);
 
 
-    /// TODO need getter/setter wrappers
+    /// @brief This method copies data from output buffer to input buffer
-    ///      and hide following fields as protected
+    ///
+    /// This is useful only in testing
+    void repack();
 
 
-    /// buffer that holds memory. It is shared_array as options may
+    /// @brief Sets remote address.
-    /// share pointer to this buffer
+    ///
-    boost::shared_array<uint8_t> data_;
+    /// @params remote specifies remote address
+    void setRemoteAddr(const isc::asiolink::IOAddress& remote) {
+        remote_addr_ = remote;
+    }
 
 
-    /// length of the data
+    /// @brief Returns remote address
-    unsigned int data_len_;
+    ///
+    /// @return remote address
+    const isc::asiolink::IOAddress& getRemoteAddr() {
+        return (remote_addr_);
+    }
 
 
-    /// local address (dst if receiving packet, src if sending packet)
+    /// @brief Sets local address.
-    isc::asiolink::IOAddress local_addr_;
+    ///
+    /// @params local specifies local address
+    void setLocalAddr(const isc::asiolink::IOAddress& local) {
+        local_addr_ = local;
+    }
 
 
-    /// remote address (src if receiving packet, dst if sending packet)
+    /// @brief Returns local address.
-    isc::asiolink::IOAddress remote_addr_;
+    ///
+    /// @return local address
+    const isc::asiolink::IOAddress& getLocalAddr() {
+        return (local_addr_);
+    }
 
 
-    /// name of the network interface the packet was received/to be sent over
+    /// @brief Sets local port.
-    std::string iface_;
+    ///
+    /// @params local specifies local port
+    void setLocalPort(uint16_t local) { local_port_ = local; }
 
 
-    /// @brief interface index
+    /// @brief Returns local port.
     ///
     ///
-    /// interface index (each network interface has assigned unique ifindex
+    /// @return local port
-    /// it is functional equvalent of name, but sometimes more useful, e.g.
+    uint16_t getLocalPort() { return (local_port_); }
-    /// when using crazy systems that allow spaces in interface names
-    /// e.g. windows
-    int ifindex_;
 
 
-    /// local TDP or UDP port
+    /// @brief Sets remote port.
-    int local_port_;
+    ///
+    /// @params remote specifies remote port
+    void setRemotePort(uint16_t remote) { remote_port_ = remote; }
 
 
-    /// remote TCP or UDP port
+    /// @brief Returns remote port.
-    int remote_port_;
+    ///
+    /// @return remote port
+    uint16_t getRemotePort() { return (remote_port_); }
+
+    /// @brief Sets interface index.
+    ///
+    /// @param ifindex specifies interface index.
+    void setIndex(uint32_t ifindex) { ifindex_ = ifindex; };
+
+    /// @brief Returns interface index.
+    ///
+    /// @return interface index
+    uint32_t getIndex() const { return (ifindex_); };
+
+    /// @brief Returns interface name.
+    ///
+    /// Returns interface name over which packet was received or is
+    /// going to be transmitted.
+    ///
+    /// @return interface name
+    std::string getIface() const { return iface_; };
+
+    /// @brief Sets interface name.
+    ///
+    /// Sets interface name over which packet was received or is
+    /// going to be transmitted.
+    ///
+    /// @return interface name
+    void setIface(const std::string& iface ) { iface_ = iface; };
 
 
     /// TODO Need to implement getOptions() as well
     /// TODO Need to implement getOptions() as well
 
 
@@ -225,8 +280,40 @@ protected:
 
 
     /// DHCPv6 transaction-id
     /// DHCPv6 transaction-id
     unsigned int transid_;
     unsigned int transid_;
+
+    /// unparsed data (in received packets)
+    OptionBuffer data_;
+
+    /// name of the network interface the packet was received/to be sent over
+    std::string iface_;
+
+    /// @brief interface index
+    ///
+    /// interface index (each network interface has assigned unique ifindex
+    /// it is functional equvalent of name, but sometimes more useful, e.g.
+    /// when using crazy systems that allow spaces in interface names
+    /// e.g. windows
+    int ifindex_;
+
+    /// local address (dst if receiving packet, src if sending packet)
+    isc::asiolink::IOAddress local_addr_;
+
+    /// remote address (src if receiving packet, dst if sending packet)
+    isc::asiolink::IOAddress remote_addr_;
+
+    /// local TDP or UDP port
+    int local_port_;
+
+    /// remote TCP or UDP port
+    int remote_port_;
+
+    /// output buffer (used during message transmission)
+    isc::util::OutputBuffer bufferOut_;
+
 }; // Pkt6 class
 }; // Pkt6 class
 
 
+typedef boost::shared_ptr<Pkt6> Pkt6Ptr;
+
 } // isc::dhcp namespace
 } // isc::dhcp namespace
 
 
 } // isc namespace
 } // isc namespace

+ 21 - 18
src/lib/dhcp/tests/iface_mgr_unittest.cc

@@ -1,4 +1,4 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011-2012 Internet Systems Consortium, Inc. ("ISC")
 //
 //
 // Permission to use, copy, modify, and/or distribute this software for any
 // Permission to use, copy, modify, and/or distribute this software for any
 // purpose with or without fee is hereby granted, provided that the above
 // purpose with or without fee is hereby granted, provided that the above
@@ -263,8 +263,8 @@ TEST_F(IfaceMgrTest, sockets6) {
 
 
     IOAddress loAddr("::1");
     IOAddress loAddr("::1");
 
 
-    Pkt6 pkt6(128);
+    Pkt6 pkt6(DHCPV6_SOLICIT, 123);
-    pkt6.iface_ = LOOPBACK;
+    pkt6.setIface(LOOPBACK);
 
 
     // bind multicast socket to port 10547
     // bind multicast socket to port 10547
     int socket1 = ifacemgr->openSocket(LOOPBACK, loAddr, 10547);
     int socket1 = ifacemgr->openSocket(LOOPBACK, loAddr, 10547);
@@ -335,19 +335,22 @@ TEST_F(IfaceMgrTest, sendReceive6) {
     EXPECT_GT(socket1, 0);
     EXPECT_GT(socket1, 0);
     EXPECT_GT(socket2, 0);
     EXPECT_GT(socket2, 0);
 
 
-    boost::shared_ptr<Pkt6> sendPkt(new Pkt6(128) );
 
 
     // prepare dummy payload
     // prepare dummy payload
+    uint8_t data[128];
     for (int i=0;i<128; i++) {
     for (int i=0;i<128; i++) {
-        sendPkt->data_[i] = i;
+        data[i] = i;
     }
     }
+    Pkt6Ptr sendPkt = Pkt6Ptr(new Pkt6(data, 128));
 
 
-    sendPkt->remote_port_ = 10547;
+    sendPkt->repack();
-    sendPkt->remote_addr_ = IOAddress("::1");
-    sendPkt->ifindex_ = 1;
-    sendPkt->iface_ = LOOPBACK;
 
 
-    boost::shared_ptr<Pkt6> rcvPkt;
+    sendPkt->setRemotePort(10547);
+    sendPkt->setRemoteAddr(IOAddress("::1"));
+    sendPkt->setIndex(1);
+    sendPkt->setIface(LOOPBACK);
+
+    Pkt6Ptr rcvPkt;
 
 
     EXPECT_EQ(true, ifacemgr->send(sendPkt));
     EXPECT_EQ(true, ifacemgr->send(sendPkt));
 
 
@@ -356,17 +359,17 @@ TEST_F(IfaceMgrTest, sendReceive6) {
     ASSERT_TRUE( rcvPkt ); // received our own packet
     ASSERT_TRUE( rcvPkt ); // received our own packet
 
 
     // let's check that we received what was sent
     // let's check that we received what was sent
-    EXPECT_EQ(sendPkt->data_len_, rcvPkt->data_len_);
+    ASSERT_EQ(sendPkt->getData().size(), rcvPkt->getData().size());
-    EXPECT_EQ(0, memcmp(&sendPkt->data_[0], &rcvPkt->data_[0],
+    EXPECT_EQ(0, memcmp(&sendPkt->getData()[0], &rcvPkt->getData()[0],
-                        rcvPkt->data_len_) );
+                        rcvPkt->getData().size()));
 
 
-    EXPECT_EQ(sendPkt->remote_addr_.toText(), rcvPkt->remote_addr_.toText());
+    EXPECT_EQ(sendPkt->getRemoteAddr().toText(), rcvPkt->getRemoteAddr().toText());
 
 
     // since we opened 2 sockets on the same interface and none of them is multicast,
     // since we opened 2 sockets on the same interface and none of them is multicast,
     // none is preferred over the other for sending data, so we really should not
     // none is preferred over the other for sending data, so we really should not
     // assume the one or the other will always be choosen for sending data. Therefore
     // assume the one or the other will always be choosen for sending data. Therefore
     // we should accept both values as source ports.
     // we should accept both values as source ports.
-    EXPECT_TRUE( (rcvPkt->remote_port_ == 10546) || (rcvPkt->remote_port_ == 10547) );
+    EXPECT_TRUE( (rcvPkt->getRemotePort() == 10546) || (rcvPkt->getRemotePort() == 10547) );
 
 
     delete ifacemgr;
     delete ifacemgr;
 }
 }
@@ -556,7 +559,7 @@ TEST_F(IfaceMgrTest, socketInfo) {
     loopback->addSocket(sock1);
     loopback->addSocket(sock1);
     loopback->addSocket(sock2);
     loopback->addSocket(sock2);
 
 
-    Pkt6 pkt6(100);
+    Pkt6 pkt6(DHCPV6_REPLY, 123456);
 
 
     // pkt6 dos not have interface set yet
     // pkt6 dos not have interface set yet
     EXPECT_THROW(
     EXPECT_THROW(
@@ -565,14 +568,14 @@ TEST_F(IfaceMgrTest, socketInfo) {
     );
     );
 
 
     // try to send over non-existing interface
     // try to send over non-existing interface
-    pkt6.iface_ = "nosuchinterface45";
+    pkt6.setIface("nosuchinterface45");
     EXPECT_THROW(
     EXPECT_THROW(
         ifacemgr->getSocket(pkt6),
         ifacemgr->getSocket(pkt6),
         BadValue
         BadValue
     );
     );
 
 
     // this will work
     // this will work
-    pkt6.iface_ = LOOPBACK;
+    pkt6.setIface(LOOPBACK);
     EXPECT_EQ(9, ifacemgr->getSocket(pkt6));
     EXPECT_EQ(9, ifacemgr->getSocket(pkt6));
 
 
     bool deleted = false;
     bool deleted = false;

+ 29 - 32
src/lib/dhcp/tests/libdhcp++_unittest.cc

@@ -1,4 +1,4 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011-2012 Internet Systems Consortium, Inc. ("ISC")
 //
 //
 // Permission to use, copy, modify, and/or distribute this software for any
 // Permission to use, copy, modify, and/or distribute this software for any
 // purpose with or without fee is hereby granted, provided that the above
 // purpose with or without fee is hereby granted, provided that the above
@@ -42,7 +42,7 @@ static const uint8_t packed[] = {
 };
 };
 
 
 TEST(LibDhcpTest, packOptions6) {
 TEST(LibDhcpTest, packOptions6) {
-    boost::shared_array<uint8_t> buf(new uint8_t[512]);
+    OptionBuffer buf(512);
     isc::dhcp::Option::OptionCollection opts; // list of options
     isc::dhcp::Option::OptionCollection opts; // list of options
 
 
     // generate content for options
     // generate content for options
@@ -50,24 +50,25 @@ TEST(LibDhcpTest, packOptions6) {
         buf[i]=i+100;
         buf[i]=i+100;
     }
     }
 
 
-    boost::shared_ptr<Option> opt1(new Option(Option::V6, 12, buf, 0, 5));
+    OptionPtr opt1(new Option(Option::V6, 12, buf.begin() + 0, buf.begin() + 5));
-    boost::shared_ptr<Option> opt2(new Option(Option::V6, 13, buf, 5, 3));
+    OptionPtr opt2(new Option(Option::V6, 13, buf.begin() + 5, buf.begin() + 8));
-    boost::shared_ptr<Option> opt3(new Option(Option::V6, 14, buf, 8, 2));
+    OptionPtr opt3(new Option(Option::V6, 14, buf.begin() + 8, buf.begin() + 10));
-    boost::shared_ptr<Option> opt4(new Option(Option::V6,256, buf,10, 4));
+    OptionPtr opt4(new Option(Option::V6,256, buf.begin() + 10,buf.begin() + 14));
-    boost::shared_ptr<Option> opt5(new Option(Option::V6,257, buf,14, 1));
+    OptionPtr opt5(new Option(Option::V6,257, buf.begin() + 14,buf.begin() + 15));
 
 
-    opts.insert(pair<int, boost::shared_ptr<Option> >(opt1->getType(), opt1));
+    opts.insert(pair<int, OptionPtr >(opt1->getType(), opt1));
-    opts.insert(pair<int, boost::shared_ptr<Option> >(opt1->getType(), opt2));
+    opts.insert(pair<int, OptionPtr >(opt1->getType(), opt2));
-    opts.insert(pair<int, boost::shared_ptr<Option> >(opt1->getType(), opt3));
+    opts.insert(pair<int, OptionPtr >(opt1->getType(), opt3));
-    opts.insert(pair<int, boost::shared_ptr<Option> >(opt1->getType(), opt4));
+    opts.insert(pair<int, OptionPtr >(opt1->getType(), opt4));
-    opts.insert(pair<int, boost::shared_ptr<Option> >(opt1->getType(), opt5));
+    opts.insert(pair<int, OptionPtr >(opt1->getType(), opt5));
+
+    OutputBuffer assembled(512);
 
 
-    unsigned int offset;
     EXPECT_NO_THROW ({
     EXPECT_NO_THROW ({
-         offset = LibDHCP::packOptions6(buf, 512, 100, opts);
+            LibDHCP::packOptions6(assembled, opts);
     });
     });
-    EXPECT_EQ(135, offset); // options should take 35 bytes
+    EXPECT_EQ(35, assembled.getLength()); // options should take 35 bytes
-    EXPECT_EQ(0, memcmp(&buf[100], packed, 35) );
+    EXPECT_EQ(0, memcmp(assembled.getData(), packed, 35) );
 }
 }
 
 
 TEST(LibDhcpTest, unpackOptions6) {
 TEST(LibDhcpTest, unpackOptions6) {
@@ -78,17 +79,13 @@ TEST(LibDhcpTest, unpackOptions6) {
     // specific derived classes.
     // specific derived classes.
     isc::dhcp::Option::OptionCollection options; // list of options
     isc::dhcp::Option::OptionCollection options; // list of options
 
 
-    // we can't use packed directly, as shared_array would try to
+    OptionBuffer buf(512);
-    // free it eventually
-    boost::shared_array<uint8_t> buf(new uint8_t[512]);
     memcpy(&buf[0], packed, 35);
     memcpy(&buf[0], packed, 35);
 
 
-    unsigned int offset;
     EXPECT_NO_THROW ({
     EXPECT_NO_THROW ({
-        offset = LibDHCP::unpackOptions6(buf, 512, 0, 35, options);
+        LibDHCP::unpackOptions6(OptionBuffer(buf.begin(), buf.begin()+35), options);
     });
     });
 
 
-    EXPECT_EQ(35, offset); // parsed first 35 bytes (offset 0..34)
     EXPECT_EQ(options.size(), 5); // there should be 5 options
     EXPECT_EQ(options.size(), 5); // there should be 5 options
 
 
     isc::dhcp::Option::OptionCollection::const_iterator x = options.find(12);
     isc::dhcp::Option::OptionCollection::const_iterator x = options.find(12);
@@ -153,18 +150,18 @@ TEST(LibDhcpTest, packOptions4) {
         payload[i][2] = i*10+2;
         payload[i][2] = i*10+2;
     }
     }
 
 
-    boost::shared_ptr<Option> opt1(new Option(Option::V4, 12, payload[0]));
+    OptionPtr opt1(new Option(Option::V4, 12, payload[0]));
-    boost::shared_ptr<Option> opt2(new Option(Option::V4, 13, payload[1]));
+    OptionPtr opt2(new Option(Option::V4, 13, payload[1]));
-    boost::shared_ptr<Option> opt3(new Option(Option::V4, 14, payload[2]));
+    OptionPtr opt3(new Option(Option::V4, 14, payload[2]));
-    boost::shared_ptr<Option> opt4(new Option(Option::V4,254, payload[3]));
+    OptionPtr opt4(new Option(Option::V4,254, payload[3]));
-    boost::shared_ptr<Option> opt5(new Option(Option::V4,128, payload[4]));
+    OptionPtr opt5(new Option(Option::V4,128, payload[4]));
 
 
     isc::dhcp::Option::OptionCollection opts; // list of options
     isc::dhcp::Option::OptionCollection opts; // list of options
-    opts.insert(pair<int, boost::shared_ptr<Option> >(opt1->getType(), opt1));
+    opts.insert(pair<int, OptionPtr >(opt1->getType(), opt1));
-    opts.insert(pair<int, boost::shared_ptr<Option> >(opt1->getType(), opt2));
+    opts.insert(pair<int, OptionPtr >(opt1->getType(), opt2));
-    opts.insert(pair<int, boost::shared_ptr<Option> >(opt1->getType(), opt3));
+    opts.insert(pair<int, OptionPtr >(opt1->getType(), opt3));
-    opts.insert(pair<int, boost::shared_ptr<Option> >(opt1->getType(), opt4));
+    opts.insert(pair<int, OptionPtr >(opt1->getType(), opt4));
-    opts.insert(pair<int, boost::shared_ptr<Option> >(opt1->getType(), opt5));
+    opts.insert(pair<int, OptionPtr >(opt1->getType(), opt5));
 
 
     vector<uint8_t> expVect(v4Opts, v4Opts + sizeof(v4Opts));
     vector<uint8_t> expVect(v4Opts, v4Opts + sizeof(v4Opts));
 
 

+ 27 - 25
src/lib/dhcp/tests/option6_addrlst_unittest.cc

@@ -1,4 +1,4 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011-2012 Internet Systems Consortium, Inc. ("ISC")
 //
 //
 // Permission to use, copy, modify, and/or distribute this software for any
 // Permission to use, copy, modify, and/or distribute this software for any
 // purpose with or without fee is hereby granted, provided that the above
 // purpose with or without fee is hereby granted, provided that the above
@@ -21,17 +21,24 @@
 #include <dhcp/dhcp6.h>
 #include <dhcp/dhcp6.h>
 #include <dhcp/option.h>
 #include <dhcp/option.h>
 #include <dhcp/option6_addrlst.h>
 #include <dhcp/option6_addrlst.h>
+#include <util/buffer.h>
 
 
 using namespace std;
 using namespace std;
 using namespace isc;
 using namespace isc;
 using namespace isc::dhcp;
 using namespace isc::dhcp;
 using namespace isc::asiolink;
 using namespace isc::asiolink;
+using namespace isc::util;
 
 
 namespace {
 namespace {
 class Option6AddrLstTest : public ::testing::Test {
 class Option6AddrLstTest : public ::testing::Test {
 public:
 public:
-    Option6AddrLstTest() {
+    Option6AddrLstTest(): buf_(255), outBuf_(255) {
+        for (int i = 0; i < 255; i++) {
+            buf_[i] = 255 - i;
+        }
     }
     }
+    OptionBuffer buf_;
+    OutputBuffer outBuf_;
 };
 };
 
 
 TEST_F(Option6AddrLstTest, basic) {
 TEST_F(Option6AddrLstTest, basic) {
@@ -97,16 +104,12 @@ TEST_F(Option6AddrLstTest, basic) {
         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
     };
     };
 
 
-    boost::shared_array<uint8_t> buf(new uint8_t[300]);
+    memcpy(&buf_[0], sampledata, 48);
-    for (int i = 0; i < 300; i++)
-        buf[i] = 0;
-
-    memcpy(&buf[0], sampledata, 48);
 
 
     // just a single address
     // just a single address
     Option6AddrLst* opt1 = 0;
     Option6AddrLst* opt1 = 0;
     EXPECT_NO_THROW(
     EXPECT_NO_THROW(
-        opt1 = new Option6AddrLst(D6O_NAME_SERVERS, buf, 128, 0, 16);
+        opt1 = new Option6AddrLst(D6O_NAME_SERVERS, buf_.begin(), buf_.begin() + 16 );
     );
     );
 
 
     EXPECT_EQ(Option::V6, opt1->getUniverse());
     EXPECT_EQ(Option::V6, opt1->getUniverse());
@@ -118,17 +121,16 @@ TEST_F(Option6AddrLstTest, basic) {
     IOAddress addr = addrs[0];
     IOAddress addr = addrs[0];
     EXPECT_EQ("2001:db8:1::dead:beef", addr.toText());
     EXPECT_EQ("2001:db8:1::dead:beef", addr.toText());
 
 
-    // pack this option again in the same buffer, but in
+    // pack this option
-    // different place
+    opt1->pack(outBuf_);
-    int offset = opt1->pack(buf,300, 100);
 
 
-    EXPECT_EQ(120, offset);
+    EXPECT_EQ(20, outBuf_.getLength());
-    EXPECT_EQ( 0, memcmp(expected1, &buf[100], 20) );
+    EXPECT_EQ( 0, memcmp(expected1, outBuf_.getData(), 20) );
 
 
     // two addresses
     // two addresses
     Option6AddrLst* opt2 = 0;
     Option6AddrLst* opt2 = 0;
     EXPECT_NO_THROW(
     EXPECT_NO_THROW(
-        opt2 = new Option6AddrLst(D6O_SIP_SERVERS_ADDR, buf, 128, 0, 32);
+        opt2 = new Option6AddrLst(D6O_SIP_SERVERS_ADDR, buf_.begin(), buf_.begin() + 32);
     );
     );
     EXPECT_EQ(D6O_SIP_SERVERS_ADDR, opt2->getType());
     EXPECT_EQ(D6O_SIP_SERVERS_ADDR, opt2->getType());
     EXPECT_EQ(36, opt2->len());
     EXPECT_EQ(36, opt2->len());
@@ -137,17 +139,17 @@ TEST_F(Option6AddrLstTest, basic) {
     EXPECT_EQ("2001:db8:1::dead:beef", addrs[0].toText());
     EXPECT_EQ("2001:db8:1::dead:beef", addrs[0].toText());
     EXPECT_EQ("ff02::face:b00c", addrs[1].toText());
     EXPECT_EQ("ff02::face:b00c", addrs[1].toText());
 
 
-    // pack this option again in the same buffer, but in
+    // pack this option
-    // different place
+    outBuf_.clear();
-    offset = opt2->pack(buf,300, 150);
+    opt2->pack(outBuf_);
 
 
-    EXPECT_EQ(150+36, offset);
+    EXPECT_EQ(36, outBuf_.getLength() );
-    EXPECT_EQ( 0, memcmp(expected2, &buf[150], 36));
+    EXPECT_EQ( 0, memcmp(expected2, outBuf_.getData(), 36));
 
 
     // three addresses
     // three addresses
     Option6AddrLst* opt3 = 0;
     Option6AddrLst* opt3 = 0;
     EXPECT_NO_THROW(
     EXPECT_NO_THROW(
-        opt3 = new Option6AddrLst(D6O_NIS_SERVERS, buf, 128, 0, 48);
+        opt3 = new Option6AddrLst(D6O_NIS_SERVERS, buf_.begin(), buf_.begin() + 48);
     );
     );
 
 
     EXPECT_EQ(D6O_NIS_SERVERS, opt3->getType());
     EXPECT_EQ(D6O_NIS_SERVERS, opt3->getType());
@@ -158,12 +160,12 @@ TEST_F(Option6AddrLstTest, basic) {
     EXPECT_EQ("ff02::face:b00c", addrs[1].toText());
     EXPECT_EQ("ff02::face:b00c", addrs[1].toText());
     EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", addrs[2].toText());
     EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", addrs[2].toText());
 
 
-    // pack this option again in the same buffer, but in
+    // pack this option
-    // different place
+    outBuf_.clear();
-    offset = opt3->pack(buf,300, 200);
+    opt3->pack(outBuf_);
 
 
-    EXPECT_EQ(252, offset);
+    EXPECT_EQ(52, outBuf_.getLength());
-    EXPECT_EQ( 0, memcmp(expected3, &buf[200], 52) );
+    EXPECT_EQ( 0, memcmp(expected3, outBuf_.getData(), 52) );
 
 
     EXPECT_NO_THROW(
     EXPECT_NO_THROW(
         delete opt1;
         delete opt1;

+ 52 - 71
src/lib/dhcp/tests/option6_ia_unittest.cc

@@ -1,4 +1,4 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011-2012 Internet Systems Consortium, Inc. ("ISC")
 //
 //
 // Permission to use, copy, modify, and/or distribute this software for any
 // Permission to use, copy, modify, and/or distribute this software for any
 // purpose with or without fee is hereby granted, provided that the above
 // purpose with or without fee is hereby granted, provided that the above
@@ -19,53 +19,51 @@
 #include <arpa/inet.h>
 #include <arpa/inet.h>
 #include <gtest/gtest.h>
 #include <gtest/gtest.h>
 
 
-#include <boost/shared_array.hpp>
+#include <dhcp/dhcp6.h>
-#include <boost/shared_ptr.hpp>
+#include <dhcp/option.h>
-
+#include <dhcp/option6_ia.h>
-#include "dhcp/dhcp6.h"
+#include <dhcp/option6_iaaddr.h>
-#include "dhcp/option.h"
+#include <util/buffer.h>
-#include "dhcp/option6_ia.h"
-#include "dhcp/option6_iaaddr.h"
 
 
 using namespace std;
 using namespace std;
 using namespace isc;
 using namespace isc;
 using namespace isc::dhcp;
 using namespace isc::dhcp;
 using namespace isc::asiolink;
 using namespace isc::asiolink;
+using namespace isc::util;
 
 
 namespace {
 namespace {
 class Option6IATest : public ::testing::Test {
 class Option6IATest : public ::testing::Test {
 public:
 public:
-    Option6IATest() {
+    Option6IATest(): buf_(255), outBuf_(255) {
+        for (int i = 0; i < 255; i++) {
+            buf_[i] = 255 - i;
+        }
     }
     }
+    OptionBuffer buf_;
+    OutputBuffer outBuf_;
 };
 };
 
 
 TEST_F(Option6IATest, basic) {
 TEST_F(Option6IATest, basic) {
+    buf_[0] = 0xa1; // iaid
+    buf_[1] = 0xa2;
+    buf_[2] = 0xa3;
+    buf_[3] = 0xa4;
 
 
-    boost::shared_array<uint8_t> simple_buf(new uint8_t[128]);
+    buf_[4] = 0x81; // T1
-    for (int i = 0; i < 128; i++)
+    buf_[5] = 0x02;
-        simple_buf[i] = 0;
+    buf_[6] = 0x03;
-    simple_buf[0] = 0xa1; // iaid
+    buf_[7] = 0x04;
-    simple_buf[1] = 0xa2;
-    simple_buf[2] = 0xa3;
-    simple_buf[3] = 0xa4;
-
-    simple_buf[4] = 0x81; // T1
-    simple_buf[5] = 0x02;
-    simple_buf[6] = 0x03;
-    simple_buf[7] = 0x04;
 
 
-    simple_buf[8] = 0x84; // T2
+    buf_[8] = 0x84; // T2
-    simple_buf[9] = 0x03;
+    buf_[9] = 0x03;
-    simple_buf[10] = 0x02;
+    buf_[10] = 0x02;
-    simple_buf[11] = 0x01;
+    buf_[11] = 0x01;
 
 
     // create an option
     // create an option
     // unpack() is called from constructor
     // unpack() is called from constructor
     Option6IA* opt = new Option6IA(D6O_IA_NA,
     Option6IA* opt = new Option6IA(D6O_IA_NA,
-                                   simple_buf,
+                                   buf_.begin(),
-                                   128,
+                                   buf_.begin() + 12);
-                                   0,
-                                   12);
 
 
     EXPECT_EQ(Option::V6, opt->getUniverse());
     EXPECT_EQ(Option::V6, opt->getUniverse());
     EXPECT_EQ(D6O_IA_NA, opt->getType());
     EXPECT_EQ(D6O_IA_NA, opt->getType());
@@ -77,36 +75,31 @@ TEST_F(Option6IATest, basic) {
     // different place
     // different place
 
 
     // test for pack()
     // test for pack()
-    int offset = opt->pack(simple_buf, 128, 60);
+    opt->pack(outBuf_);
 
 
-    // 4 bytes header + 4 bytes content
+    // 12 bytes header + 4 bytes content
-    EXPECT_EQ(12, opt->len() - 4);
+    EXPECT_EQ(12, opt->len() - opt->getHeaderLen());
     EXPECT_EQ(D6O_IA_NA, opt->getType());
     EXPECT_EQ(D6O_IA_NA, opt->getType());
 
 
-    EXPECT_EQ(offset, 76); // 60 + lenght(IA_NA) = 76
+    EXPECT_EQ(16, outBuf_.getLength()); // lenght(IA_NA) = 16
 
 
     // check if pack worked properly:
     // check if pack worked properly:
+    InputBuffer out(outBuf_.getData(), outBuf_.getLength());
+
     // if option type is correct
     // if option type is correct
-    EXPECT_EQ(D6O_IA_NA, simple_buf[60]*256 + simple_buf[61]);
+    EXPECT_EQ(D6O_IA_NA, out.readUint16());
 
 
     // if option length is correct
     // if option length is correct
-    EXPECT_EQ(12, simple_buf[62]*256 + simple_buf[63]);
+    EXPECT_EQ(12, out.readUint16());
 
 
     // if iaid is correct
     // if iaid is correct
-    unsigned int iaid = htonl(*(unsigned int*)&simple_buf[64]);
+    EXPECT_EQ(0xa1a2a3a4, out.readUint32() );
-    EXPECT_EQ(0xa1a2a3a4, iaid );
 
 
    // if T1 is correct
    // if T1 is correct
-    EXPECT_EQ(0x81020304, (simple_buf[68] << 24) +
+    EXPECT_EQ(0x81020304, out.readUint32() );
-                          (simple_buf[69] << 16) +
-                          (simple_buf[70] << 8) +
-                          (simple_buf[71]) );
 
 
     // if T1 is correct
     // if T1 is correct
-    EXPECT_EQ(0x84030201, (simple_buf[72] << 24) +
+    EXPECT_EQ(0x84030201, out.readUint32() );
-                          (simple_buf[73] << 16) +
-                          (simple_buf[74] << 8) +
-                          (simple_buf[75]) );
 
 
     EXPECT_NO_THROW(
     EXPECT_NO_THROW(
         delete opt;
         delete opt;
@@ -114,10 +107,6 @@ TEST_F(Option6IATest, basic) {
 }
 }
 
 
 TEST_F(Option6IATest, simple) {
 TEST_F(Option6IATest, simple) {
-    boost::shared_array<uint8_t> simple_buf(new uint8_t[128]);
-    for (int i = 0; i < 128; i++)
-        simple_buf[i] = 0;
-
     Option6IA * ia = new Option6IA(D6O_IA_NA, 1234);
     Option6IA * ia = new Option6IA(D6O_IA_NA, 1234);
     ia->setT1(2345);
     ia->setT1(2345);
     ia->setT2(3456);
     ia->setT2(3456);
@@ -133,20 +122,18 @@ TEST_F(Option6IATest, simple) {
     );
     );
 }
 }
 
 
+
 // test if option can build suboptions
 // test if option can build suboptions
 TEST_F(Option6IATest, suboptions_pack) {
 TEST_F(Option6IATest, suboptions_pack) {
-    boost::shared_array<uint8_t> buf(new uint8_t[128]);
+    buf_[0] = 0xff;
-    for (int i=0; i<128; i++)
+    buf_[1] = 0xfe;
-        buf[i] = 0;
+    buf_[2] = 0xfc;
-    buf[0] = 0xff;
-    buf[1] = 0xfe;
-    buf[2] = 0xfc;
 
 
     Option6IA * ia = new Option6IA(D6O_IA_NA, 0x13579ace);
     Option6IA * ia = new Option6IA(D6O_IA_NA, 0x13579ace);
     ia->setT1(0x2345);
     ia->setT1(0x2345);
     ia->setT2(0x3456);
     ia->setT2(0x3456);
 
 
-    boost::shared_ptr<Option> sub1(new Option(Option::V6,
+    OptionPtr sub1(new Option(Option::V6,
                                               0xcafe));
                                               0xcafe));
 
 
     boost::shared_ptr<Option6IAAddr> addr1(
     boost::shared_ptr<Option6IAAddr> addr1(
@@ -180,20 +167,20 @@ TEST_F(Option6IATest, suboptions_pack) {
         0, 0 // len
         0, 0 // len
     };
     };
 
 
-    int offset = ia->pack(buf, 128, 10);
+    ia->pack(outBuf_);
-    ASSERT_EQ(offset, 10 + 48);
+    ASSERT_EQ(48, outBuf_.getLength());
 
 
-    EXPECT_EQ(0, memcmp(&buf[10], expected, 48));
+    EXPECT_EQ(0, memcmp(outBuf_.getData(), expected, 48));
 
 
     EXPECT_NO_THROW(
     EXPECT_NO_THROW(
         delete ia;
         delete ia;
     );
     );
 }
 }
 
 
+
 // test if option can parse suboptions
 // test if option can parse suboptions
 TEST_F(Option6IATest, suboptions_unpack) {
 TEST_F(Option6IATest, suboptions_unpack) {
-
+    // 48 bytes
-
     uint8_t expected[] = {
     uint8_t expected[] = {
         D6O_IA_NA/256, D6O_IA_NA%256, // type
         D6O_IA_NA/256, D6O_IA_NA%256, // type
         0, 28, // length
         0, 28, // length
@@ -214,17 +201,11 @@ TEST_F(Option6IATest, suboptions_unpack) {
         0, 0 // len
         0, 0 // len
     };
     };
 
 
-    boost::shared_array<uint8_t> buf(new uint8_t[128]);
+    memcpy(&buf_[0], expected, sizeof(expected));
-    for (int i = 0; i < 128; i++)
-        buf[i] = 0;
-    memcpy(&buf[0], expected, 48);
 
 
     Option6IA* ia = 0;
     Option6IA* ia = 0;
     EXPECT_NO_THROW({
     EXPECT_NO_THROW({
-        ia = new Option6IA(D6O_IA_NA, buf, 128, 4, 44);
+            ia = new Option6IA(D6O_IA_NA, buf_.begin() + 4, buf_.begin() + sizeof(expected));
-
-        // let's limit verbosity of this test
-        // cout << "Parsed option:" << endl << ia->toText() << endl;
     });
     });
     ASSERT_TRUE(ia);
     ASSERT_TRUE(ia);
 
 
@@ -233,8 +214,8 @@ TEST_F(Option6IATest, suboptions_unpack) {
     EXPECT_EQ(0x2345, ia->getT1());
     EXPECT_EQ(0x2345, ia->getT1());
     EXPECT_EQ(0x3456, ia->getT2());
     EXPECT_EQ(0x3456, ia->getT2());
 
 
-    boost::shared_ptr<Option> subopt = ia->getOption(D6O_IAADDR);
+    OptionPtr subopt = ia->getOption(D6O_IAADDR);
-    ASSERT_NE(boost::shared_ptr<Option>(), subopt); // non-NULL
+    ASSERT_NE(OptionPtr(), subopt); // non-NULL
 
 
     // checks for address option
     // checks for address option
     Option6IAAddr * addr = dynamic_cast<Option6IAAddr*>(subopt.get());
     Option6IAAddr * addr = dynamic_cast<Option6IAAddr*>(subopt.get());

+ 45 - 42
src/lib/dhcp/tests/option6_iaaddr_unittest.cc

@@ -1,4 +1,4 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011-2012 Internet Systems Consortium, Inc. ("ISC")
 //
 //
 // Permission to use, copy, modify, and/or distribute this software for any
 // Permission to use, copy, modify, and/or distribute this software for any
 // purpose with or without fee is hereby granted, provided that the above
 // purpose with or without fee is hereby granted, provided that the above
@@ -19,61 +19,62 @@
 #include <arpa/inet.h>
 #include <arpa/inet.h>
 #include <gtest/gtest.h>
 #include <gtest/gtest.h>
 
 
-#include "dhcp/dhcp6.h"
+#include <dhcp/dhcp6.h>
-#include "dhcp/option.h"
+#include <dhcp/option.h>
-#include "dhcp/option6_iaaddr.h"
+#include <dhcp/option6_iaaddr.h>
+#include <util/buffer.h>
 
 
 using namespace std;
 using namespace std;
 using namespace isc;
 using namespace isc;
 using namespace isc::dhcp;
 using namespace isc::dhcp;
+using namespace isc::util;
 
 
 namespace {
 namespace {
 class Option6IAAddrTest : public ::testing::Test {
 class Option6IAAddrTest : public ::testing::Test {
 public:
 public:
-    Option6IAAddrTest() {
+    Option6IAAddrTest() : buf_(255), outBuf_(255) {
+        for (int i = 0; i < 255; i++) {
+            buf_[i] = 255 - i;
+        }
     }
     }
+    OptionBuffer buf_;
+    OutputBuffer outBuf_;
 };
 };
 
 
-/// TODO reenable this once ticket #1313 is implemented.
 TEST_F(Option6IAAddrTest, basic) {
 TEST_F(Option6IAAddrTest, basic) {
-
+    for (int i=0; i<255; i++) {
-    boost::shared_array<uint8_t> simple_buf(new uint8_t[128]);
+        buf_[i]=0;
-    for (int i = 0; i < 128; i++)
+    }
-        simple_buf[i] = 0;
+    buf_[0] = 0x20;
-
+    buf_[1] = 0x01;
-    simple_buf[0] = 0x20;
+    buf_[2] = 0x0d;
-    simple_buf[1] = 0x01;
+    buf_[3] = 0xb8;
-    simple_buf[2] = 0x0d;
+    buf_[4] = 0x00;
-    simple_buf[3] = 0xb8;
+    buf_[5] = 0x01;
-    simple_buf[4] = 0x00;
+    buf_[12] = 0xde;
-    simple_buf[5] = 0x01;
+    buf_[13] = 0xad;
-    simple_buf[12] = 0xde;
+    buf_[14] = 0xbe;
-    simple_buf[13] = 0xad;
+    buf_[15] = 0xef; // 2001:db8:1::dead:beef
-    simple_buf[14] = 0xbe;
+
-    simple_buf[15] = 0xef; // 2001:db8:1::dead:beef
+    buf_[16] = 0x00;
-
+    buf_[17] = 0x00;
-    simple_buf[16] = 0x00;
+    buf_[18] = 0x03;
-    simple_buf[17] = 0x00;
+    buf_[19] = 0xe8; // 1000
-    simple_buf[18] = 0x03;
+
-    simple_buf[19] = 0xe8; // 1000
+    buf_[20] = 0xb2;
-
+    buf_[21] = 0xd0;
-    simple_buf[20] = 0xb2;
+    buf_[22] = 0x5e;
-    simple_buf[21] = 0xd0;
+    buf_[23] = 0x00; // 3,000,000,000
-    simple_buf[22] = 0x5e;
-    simple_buf[23] = 0x00; // 3,000,000,000
 
 
     // create an option (unpack content)
     // create an option (unpack content)
     Option6IAAddr* opt = new Option6IAAddr(D6O_IAADDR,
     Option6IAAddr* opt = new Option6IAAddr(D6O_IAADDR,
-                                           simple_buf,
+                                           buf_.begin(),
-                                           128,
+                                           buf_.begin() + 24);
-                                           0,
-                                           24);
 
 
-    // pack this option again in the same buffer, but in
+    // pack this option
-    // different place
+    opt->pack(outBuf_);
-    int offset = opt->pack(simple_buf, 128, 50);
 
 
-    EXPECT_EQ(78, offset);
+    EXPECT_EQ(28, outBuf_.getLength());
 
 
     EXPECT_EQ(Option::V6, opt->getUniverse());
     EXPECT_EQ(Option::V6, opt->getUniverse());
 
 
@@ -88,14 +89,16 @@ TEST_F(Option6IAAddrTest, basic) {
               opt->len());
               opt->len());
 
 
     // check if pack worked properly:
     // check if pack worked properly:
+    const uint8_t* out = (const uint8_t*)outBuf_.getData();
+
     // if option type is correct
     // if option type is correct
-    EXPECT_EQ(D6O_IAADDR, simple_buf[50]*256 + simple_buf[51]);
+    EXPECT_EQ(D6O_IAADDR, out[0]*256 + out[1]);
 
 
     // if option length is correct
     // if option length is correct
-    EXPECT_EQ(24, simple_buf[52]*256 + simple_buf[53]);
+    EXPECT_EQ(24, out[2]*256 + out[3]);
 
 
     // if option content is correct
     // if option content is correct
-    EXPECT_EQ(0, memcmp(&simple_buf[0], &simple_buf[54],24));
+    EXPECT_EQ(0, memcmp(out + 4, &buf_[0], 24));
 
 
     EXPECT_NO_THROW(
     EXPECT_NO_THROW(
         delete opt;
         delete opt;

+ 90 - 111
src/lib/dhcp/tests/option_unittest.cc

@@ -1,4 +1,4 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011-2012 Internet Systems Consortium, Inc. ("ISC")
 //
 //
 // Permission to use, copy, modify, and/or distribute this software for any
 // Permission to use, copy, modify, and/or distribute this software for any
 // purpose with or without fee is hereby granted, provided that the above
 // purpose with or without fee is hereby granted, provided that the above
@@ -33,14 +33,13 @@ using namespace isc::util;
 namespace {
 namespace {
 class OptionTest : public ::testing::Test {
 class OptionTest : public ::testing::Test {
 public:
 public:
-    OptionTest(): outBuffer_(255) {
+    OptionTest(): buf_(255), outBuf_(255) {
-        buf_ = boost::shared_array<uint8_t>(new uint8_t[255]);
         for (int i = 0; i < 255; i++) {
         for (int i = 0; i < 255; i++) {
             buf_[i] = 255 - i;
             buf_[i] = 255 - i;
         }
         }
     }
     }
-    boost::shared_array<uint8_t> buf_;
+    OptionBuffer buf_;
-    OutputBuffer outBuffer_;
+    OutputBuffer outBuf_;
 };
 };
 
 
 // v4 is not really implemented yet. A simple test will do for now
 // v4 is not really implemented yet. A simple test will do for now
@@ -84,9 +83,7 @@ TEST_F(OptionTest, v4_data1) {
     // create DHCPv4 option of type 123
     // create DHCPv4 option of type 123
     // that contains 4 bytes of data
     // that contains 4 bytes of data
     ASSERT_NO_THROW(
     ASSERT_NO_THROW(
-        opt= new Option(Option::V4,
+        opt= new Option(Option::V4, 123, data);
-                        123, // type
-                        data);
     );
     );
 
 
     // check that content is reported properly
     // check that content is reported properly
@@ -143,10 +140,7 @@ TEST_F(OptionTest, v4_data2) {
     // Create DHCPv4 option of type 123 that contains
     // Create DHCPv4 option of type 123 that contains
     // 4 bytes (sizeof(dummyPayload).
     // 4 bytes (sizeof(dummyPayload).
     ASSERT_NO_THROW(
     ASSERT_NO_THROW(
-        opt= new Option(Option::V4,
+        opt= new Option(Option::V4, 123, data.begin() + 1, data.end() - 1);
-                        123, // type
-                        data.begin() + 1,
-                        data.end() - 1);
     );
     );
 
 
     // check that content is reported properly
     // check that content is reported properly
@@ -210,30 +204,29 @@ TEST_F(OptionTest, v6_basic) {
 // tests contructor used in pkt reception
 // tests contructor used in pkt reception
 // option contains actual data
 // option contains actual data
 TEST_F(OptionTest, v6_data1) {
 TEST_F(OptionTest, v6_data1) {
-    boost::shared_array<uint8_t> buf(new uint8_t[32]);
     for (int i = 0; i < 32; i++)
     for (int i = 0; i < 32; i++)
-        buf[i] = 100+i;
+        buf_[i] = 100+i;
-    Option* opt = new Option(Option::V6, 333, //type
+    Option* opt = new Option(Option::V6, 333,   //type
-                             buf,
+                             buf_.begin() + 3,  // begin offset
-                             3, // offset
+                             buf_.begin() + 10); // end offset (7 bytes of data)
-                             7); // 7 bytes of data
     EXPECT_EQ(333, opt->getType());
     EXPECT_EQ(333, opt->getType());
 
 
     ASSERT_EQ(11, opt->len());
     ASSERT_EQ(11, opt->len());
     ASSERT_EQ(7, opt->getData().size());
     ASSERT_EQ(7, opt->getData().size());
-    EXPECT_EQ(0, memcmp(&buf[3], &opt->getData()[0], 7) );
+    EXPECT_EQ(0, memcmp(&buf_[3], &opt->getData()[0], 7) );
 
 
-    int offset = opt->pack(buf, 32, 20);
+    opt->pack(outBuf_);
-    EXPECT_EQ(31, offset);
+    EXPECT_EQ(11, outBuf_.getLength());
 
 
-    EXPECT_EQ(buf[20], 333/256); // type
+    const uint8_t* out = (const uint8_t*)outBuf_.getData();
-    EXPECT_EQ(buf[21], 333%256);
+    EXPECT_EQ(out[0], 333/256); // type
+    EXPECT_EQ(out[1], 333%256);
 
 
-    EXPECT_EQ(buf[22], 0); // len
+    EXPECT_EQ(out[2], 0); // len
-    EXPECT_EQ(buf[23], 7);
+    EXPECT_EQ(out[3], 7);
 
 
     // payload
     // payload
-    EXPECT_EQ(0, memcmp(&buf[3], &buf[24], 7) );
+    EXPECT_EQ(0, memcmp(&buf_[3], out+4, 7) );
 
 
     EXPECT_NO_THROW(
     EXPECT_NO_THROW(
         delete opt;
         delete opt;
@@ -244,40 +237,37 @@ TEST_F(OptionTest, v6_data1) {
 // with different input parameters
 // with different input parameters
 TEST_F(OptionTest, v6_data2) {
 TEST_F(OptionTest, v6_data2) {
 
 
-    boost::shared_array<uint8_t> simple_buf(new uint8_t[128]);
+    buf_[0] = 0xa1;
-    for (int i = 0; i < 128; i++)
+    buf_[1] = 0xa2;
-        simple_buf[i] = 0;
+    buf_[2] = 0xa3;
-    simple_buf[0] = 0xa1;
+    buf_[3] = 0xa4;
-    simple_buf[1] = 0xa2;
-    simple_buf[2] = 0xa3;
-    simple_buf[3] = 0xa4;
 
 
     // create an option (unpack content)
     // create an option (unpack content)
     Option* opt = new Option(Option::V6,
     Option* opt = new Option(Option::V6,
                              D6O_CLIENTID,
                              D6O_CLIENTID,
-                             simple_buf,
+                             buf_.begin(),
-                             0,
+                             buf_.begin() + 4);
-                             4);
 
 
-    // pack this option again in the same buffer, but in
+    // pack this option
-    // different place
+    opt->pack(outBuf_);
-    int offset18 = opt->pack(simple_buf, 128, 10);
 
 
     // 4 bytes header + 4 bytes content
     // 4 bytes header + 4 bytes content
     EXPECT_EQ(8, opt->len());
     EXPECT_EQ(8, opt->len());
     EXPECT_EQ(D6O_CLIENTID, opt->getType());
     EXPECT_EQ(D6O_CLIENTID, opt->getType());
 
 
-    EXPECT_EQ(offset18, 18);
+    EXPECT_EQ(8, outBuf_.getLength());
 
 
     // check if pack worked properly:
     // check if pack worked properly:
     // if option type is correct
     // if option type is correct
-    EXPECT_EQ(D6O_CLIENTID, simple_buf[10]*256 + simple_buf[11]);
+    const uint8_t* out = (const uint8_t*)outBuf_.getData();
+
+    EXPECT_EQ(D6O_CLIENTID, out[0]*256 + out[1]);
 
 
     // if option length is correct
     // if option length is correct
-    EXPECT_EQ(4, simple_buf[12]*256 + simple_buf[13]);
+    EXPECT_EQ(4, out[2]*256 + out[3]);
 
 
     // if option content is correct
     // if option content is correct
-    EXPECT_EQ(0, memcmp(&simple_buf[0], &simple_buf[14],4));
+    EXPECT_EQ(0, memcmp(&buf_[0], out + 4, 4));
 
 
     EXPECT_NO_THROW(
     EXPECT_NO_THROW(
         delete opt;
         delete opt;
@@ -291,18 +281,15 @@ TEST_F(OptionTest, v6_data2) {
 //  +----opt3
 //  +----opt3
 //
 //
 TEST_F(OptionTest, v6_suboptions1) {
 TEST_F(OptionTest, v6_suboptions1) {
-    boost::shared_array<uint8_t> buf(new uint8_t[128]);
     for (int i=0; i<128; i++)
     for (int i=0; i<128; i++)
-        buf[i] = 100+i;
+        buf_[i] = 100+i;
     Option* opt1 = new Option(Option::V6, 65535, //type
     Option* opt1 = new Option(Option::V6, 65535, //type
-                              buf,
+                              buf_.begin(), // 3 bytes of data
-                              0, // offset
+                              buf_.begin() + 3);
-                              3); // 3 bytes of data
+    OptionPtr opt2(new Option(Option::V6, 13));
-    boost::shared_ptr<Option> opt2(new Option(Option::V6, 13));
+    OptionPtr opt3(new Option(Option::V6, 7,
-    boost::shared_ptr<Option> opt3(new Option(Option::V6, 7,
+                              buf_.begin() + 3,
-                                              buf,
+                              buf_.begin() + 8)); // 5 bytes of data
-                                              3, // offset
-                                              5)); // 5 bytes of data
     opt1->addOption(opt2);
     opt1->addOption(opt2);
     opt1->addOption(opt3);
     opt1->addOption(opt3);
     // opt2 len = 4 (just header)
     // opt2 len = 4 (just header)
@@ -319,11 +306,11 @@ TEST_F(OptionTest, v6_suboptions1) {
         0, 13, 0, 0 // no data at all
         0, 13, 0, 0 // no data at all
     };
     };
 
 
-    int offset = opt1->pack(buf, 128, 20);
+    opt1->pack(outBuf_);
-    EXPECT_EQ(40, offset);
+    EXPECT_EQ(20, outBuf_.getLength());
 
 
     // payload
     // payload
-    EXPECT_EQ(0, memcmp(&buf[20], expected, 20) );
+    EXPECT_EQ(0, memcmp(outBuf_.getData(), expected, 20) );
 
 
     EXPECT_NO_THROW(
     EXPECT_NO_THROW(
         delete opt1;
         delete opt1;
@@ -337,18 +324,15 @@ TEST_F(OptionTest, v6_suboptions1) {
 //        +----opt3
 //        +----opt3
 //
 //
 TEST_F(OptionTest, v6_suboptions2) {
 TEST_F(OptionTest, v6_suboptions2) {
-    boost::shared_array<uint8_t> buf(new uint8_t[128]);
     for (int i=0; i<128; i++)
     for (int i=0; i<128; i++)
-        buf[i] = 100+i;
+        buf_[i] = 100+i;
     Option* opt1 = new Option(Option::V6, 65535, //type
     Option* opt1 = new Option(Option::V6, 65535, //type
-                              buf,
+                              buf_.begin(),
-                              0, // offset
+                              buf_.begin() + 3);
-                              3); // 3 bytes of data
+    OptionPtr opt2(new Option(Option::V6, 13));
-    boost::shared_ptr<Option> opt2(new Option(Option::V6, 13));
+    OptionPtr opt3(new Option(Option::V6, 7,
-    boost::shared_ptr<Option> opt3(new Option(Option::V6, 7,
+                                              buf_.begin() + 3,
-                                              buf,
+                                              buf_.begin() + 8));
-                                              3, // offset
-                                              5)); // 5 bytes of data
     opt1->addOption(opt2);
     opt1->addOption(opt2);
     opt2->addOption(opt3);
     opt2->addOption(opt3);
     // opt3 len = 9 4(header)+5(data)
     // opt3 len = 9 4(header)+5(data)
@@ -361,11 +345,11 @@ TEST_F(OptionTest, v6_suboptions2) {
         0, 7, 0, 5, 103, 104, 105, 106, 107,
         0, 7, 0, 5, 103, 104, 105, 106, 107,
     };
     };
 
 
-    int offset = opt1->pack(buf, 128, 20);
+    opt1->pack(outBuf_);
-    EXPECT_EQ(40, offset);
+    EXPECT_EQ(20, outBuf_.getLength());
 
 
     // payload
     // payload
-    EXPECT_EQ(0, memcmp(&buf[20], expected, 20) );
+    EXPECT_EQ(0, memcmp(outBuf_.getData(), expected, 20) );
 
 
     EXPECT_NO_THROW(
     EXPECT_NO_THROW(
         delete opt1;
         delete opt1;
@@ -373,13 +357,12 @@ TEST_F(OptionTest, v6_suboptions2) {
 }
 }
 
 
 TEST_F(OptionTest, v6_addgetdel) {
 TEST_F(OptionTest, v6_addgetdel) {
-    boost::shared_array<uint8_t> buf(new uint8_t[128]);
     for (int i=0; i<128; i++)
     for (int i=0; i<128; i++)
-        buf[i] = 100+i;
+        buf_[i] = 100+i;
     Option* parent = new Option(Option::V6, 65535); //type
     Option* parent = new Option(Option::V6, 65535); //type
-    boost::shared_ptr<Option> opt1(new Option(Option::V6, 1));
+    OptionPtr opt1(new Option(Option::V6, 1));
-    boost::shared_ptr<Option> opt2(new Option(Option::V6, 2));
+    OptionPtr opt2(new Option(Option::V6, 2));
-    boost::shared_ptr<Option> opt3(new Option(Option::V6, 2));
+    OptionPtr opt3(new Option(Option::V6, 2));
 
 
     parent->addOption(opt1);
     parent->addOption(opt1);
     parent->addOption(opt2);
     parent->addOption(opt2);
@@ -389,7 +372,7 @@ TEST_F(OptionTest, v6_addgetdel) {
     EXPECT_EQ(opt2, parent->getOption(2));
     EXPECT_EQ(opt2, parent->getOption(2));
 
 
     // expect NULL
     // expect NULL
-    EXPECT_EQ(boost::shared_ptr<Option>(), parent->getOption(4));
+    EXPECT_EQ(OptionPtr(), parent->getOption(4));
 
 
     // now there are 2 options of type 2
     // now there are 2 options of type 2
     parent->addOption(opt3);
     parent->addOption(opt3);
@@ -398,13 +381,13 @@ TEST_F(OptionTest, v6_addgetdel) {
     EXPECT_EQ(true, parent->delOption(2));
     EXPECT_EQ(true, parent->delOption(2));
 
 
     // there still should be the other option 2
     // there still should be the other option 2
-    EXPECT_NE(boost::shared_ptr<Option>(), parent->getOption(2));
+    EXPECT_NE(OptionPtr(), parent->getOption(2));
 
 
     // let's delete the other option 2
     // let's delete the other option 2
     EXPECT_EQ(true, parent->delOption(2));
     EXPECT_EQ(true, parent->delOption(2));
 
 
     // no more options with type=2
     // no more options with type=2
-    EXPECT_EQ(boost::shared_ptr<Option>(), parent->getOption(2));
+    EXPECT_EQ(OptionPtr(), parent->getOption(2));
 
 
     // let's try to delete - should fail
     // let's try to delete - should fail
     EXPECT_TRUE(false ==  parent->delOption(2));
     EXPECT_TRUE(false ==  parent->delOption(2));
@@ -412,36 +395,31 @@ TEST_F(OptionTest, v6_addgetdel) {
     delete parent;
     delete parent;
 }
 }
 
 
-}
-
 TEST_F(OptionTest, v6_toText) {
 TEST_F(OptionTest, v6_toText) {
-    boost::shared_array<uint8_t> buf(new uint8_t[3]);
+    buf_[0] = 0;
-    buf[0] = 0;
+    buf_[1] = 0xf;
-    buf[1] = 0xf;
+    buf_[2] = 0xff;
-    buf[2] = 0xff;
 
 
-    boost::shared_ptr<Option> opt(new Option(Option::V6, 258,
+    OptionPtr opt(new Option(Option::V6, 258,  buf_.begin(), buf_.begin() + 3 ));
-                                             buf, 0, 3));
 
 
     EXPECT_EQ("type=258, len=3: 00:0f:ff", opt->toText());
     EXPECT_EQ("type=258, len=3: 00:0f:ff", opt->toText());
 }
 }
 
 
+
 TEST_F(OptionTest, getUintX) {
 TEST_F(OptionTest, getUintX) {
 
 
-    // TODO: Update this test to use buf_ instead of buf
+    buf_[0] = 0x5;
-    boost::shared_array<uint8_t> buf(new uint8_t[5]);
+    buf_[1] = 0x4;
-    buf[0] = 0x5;
+    buf_[2] = 0x3;
-    buf[1] = 0x4;
+    buf_[3] = 0x2;
-    buf[2] = 0x3;
+    buf_[4] = 0x1;
-    buf[3] = 0x2;
-    buf[4] = 0x1;
 
 
     // five options with varying lengths
     // five options with varying lengths
-    boost::shared_ptr<Option> opt1(new Option(Option::V6, 258, buf, 0, 1));
+    OptionPtr opt1(new Option(Option::V6, 258, buf_.begin(), buf_.begin() + 1));
-    boost::shared_ptr<Option> opt2(new Option(Option::V6, 258, buf, 0, 2));
+    OptionPtr opt2(new Option(Option::V6, 258, buf_.begin(), buf_.begin() + 2));
-    boost::shared_ptr<Option> opt3(new Option(Option::V6, 258, buf, 0, 3));
+    OptionPtr opt3(new Option(Option::V6, 258, buf_.begin(), buf_.begin() + 3));
-    boost::shared_ptr<Option> opt4(new Option(Option::V6, 258, buf, 0, 4));
+    OptionPtr opt4(new Option(Option::V6, 258, buf_.begin(), buf_.begin() + 4));
-    boost::shared_ptr<Option> opt5(new Option(Option::V6, 258, buf, 0, 5));
+    OptionPtr opt5(new Option(Option::V6, 258, buf_.begin(), buf_.begin() + 5));
 
 
     EXPECT_EQ(5, opt1->getUint8());
     EXPECT_EQ(5, opt1->getUint8());
     EXPECT_THROW(opt1->getUint16(), OutOfRange);
     EXPECT_THROW(opt1->getUint16(), OutOfRange);
@@ -467,36 +445,37 @@ TEST_F(OptionTest, getUintX) {
 }
 }
 
 
 TEST_F(OptionTest, setUintX) {
 TEST_F(OptionTest, setUintX) {
-    boost::shared_ptr<Option> opt1(new Option(Option::V4, 125));
+    OptionPtr opt1(new Option(Option::V4, 125));
-    boost::shared_ptr<Option> opt2(new Option(Option::V4, 125));
+    OptionPtr opt2(new Option(Option::V4, 125));
-    boost::shared_ptr<Option> opt4(new Option(Option::V4, 125));
+    OptionPtr opt4(new Option(Option::V4, 125));
 
 
     // verify setUint8
     // verify setUint8
     opt1->setUint8(255);
     opt1->setUint8(255);
     EXPECT_EQ(255, opt1->getUint8());
     EXPECT_EQ(255, opt1->getUint8());
-    opt1->pack4(outBuffer_);
+    opt1->pack4(outBuf_);
     EXPECT_EQ(3, opt1->len());
     EXPECT_EQ(3, opt1->len());
-    EXPECT_EQ(3, outBuffer_.getLength());
+    EXPECT_EQ(3, outBuf_.getLength());
     uint8_t exp1[] = {125, 1, 255};
     uint8_t exp1[] = {125, 1, 255};
-    EXPECT_TRUE(0 == memcmp(exp1, outBuffer_.getData(), 3));
+    EXPECT_TRUE(0 == memcmp(exp1, outBuf_.getData(), 3));
 
 
     // verify getUint16
     // verify getUint16
-    outBuffer_.clear();
+    outBuf_.clear();
     opt2->setUint16(12345);
     opt2->setUint16(12345);
-    opt2->pack4(outBuffer_);
+    opt2->pack4(outBuf_);
     EXPECT_EQ(12345, opt2->getUint16());
     EXPECT_EQ(12345, opt2->getUint16());
     EXPECT_EQ(4, opt2->len());
     EXPECT_EQ(4, opt2->len());
-    EXPECT_EQ(4, outBuffer_.getLength());
+    EXPECT_EQ(4, outBuf_.getLength());
     uint8_t exp2[] = {125, 2, 12345/256, 12345%256};
     uint8_t exp2[] = {125, 2, 12345/256, 12345%256};
-    EXPECT_TRUE(0 == memcmp(exp2, outBuffer_.getData(), 4));
+    EXPECT_TRUE(0 == memcmp(exp2, outBuf_.getData(), 4));
 
 
     // verity getUint32
     // verity getUint32
-    outBuffer_.clear();
+    outBuf_.clear();
     opt4->setUint32(0x12345678);
     opt4->setUint32(0x12345678);
-    opt4->pack4(outBuffer_);
+    opt4->pack4(outBuf_);
     EXPECT_EQ(0x12345678, opt4->getUint32());
     EXPECT_EQ(0x12345678, opt4->getUint32());
     EXPECT_EQ(6, opt4->len());
     EXPECT_EQ(6, opt4->len());
-    EXPECT_EQ(6, outBuffer_.getLength());
+    EXPECT_EQ(6, outBuf_.getLength());
     uint8_t exp4[] = {125, 4, 0x12, 0x34, 0x56, 0x78};
     uint8_t exp4[] = {125, 4, 0x12, 0x34, 0x56, 0x78};
-    EXPECT_TRUE(0 == memcmp(exp4, outBuffer_.getData(), 6));
+    EXPECT_TRUE(0 == memcmp(exp4, outBuf_.getData(), 6));
+}
 }
 }

+ 58 - 64
src/lib/dhcp/tests/pkt6_unittest.cc

@@ -1,4 +1,4 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011-2012 Internet Systems Consortium, Inc. ("ISC")
 //
 //
 // Permission to use, copy, modify, and/or distribute this software for any
 // Permission to use, copy, modify, and/or distribute this software for any
 // purpose with or without fee is hereby granted, provided that the above
 // purpose with or without fee is hereby granted, provided that the above
@@ -37,9 +37,11 @@ public:
 };
 };
 
 
 TEST_F(Pkt6Test, constructor) {
 TEST_F(Pkt6Test, constructor) {
-    Pkt6 * pkt1 = new Pkt6(17);
+    uint8_t data[] = { 0, 1, 2, 3, 4, 5 };
+    Pkt6 * pkt1 = new Pkt6(data, sizeof(data) );
 
 
-    EXPECT_EQ(pkt1->data_len_, 17);
+    EXPECT_EQ(6, pkt1->getData().size());
+    EXPECT_EQ(0, memcmp( &pkt1->getData()[0], data, sizeof(data)) );
 
 
     delete pkt1;
     delete pkt1;
 }
 }
@@ -49,42 +51,46 @@ TEST_F(Pkt6Test, constructor) {
 // this code is autogenerated (see src/bin/dhcp6/tests/iface_mgr_unittest.c)
 // this code is autogenerated (see src/bin/dhcp6/tests/iface_mgr_unittest.c)
 Pkt6 *capture1() {
 Pkt6 *capture1() {
     Pkt6* pkt;
     Pkt6* pkt;
-    pkt = new Pkt6(98);
+    uint8_t data[98];
-    pkt->remote_port_ = 546;
+    data[0]=1;
-    pkt->remote_addr_ = IOAddress("fe80::21e:8cff:fe9b:7349");
+    data[1]=01;     data[2]=02;     data[3]=03;     data[4]=0;
-    pkt->local_port_ = 0;
+    data[5]=1;     data[6]=0;     data[7]=14;     data[8]=0;
-    pkt->local_addr_ = IOAddress("ff02::1:2");
+    data[9]=1;     data[10]=0;     data[11]=1;     data[12]=21;
-    pkt->ifindex_ = 2;
+    data[13]=158;     data[14]=60;     data[15]=22;     data[16]=0;
-    pkt->iface_ = "eth0";
+    data[17]=30;     data[18]=140;     data[19]=155;     data[20]=115;
-    pkt->data_[0]=1;
+    data[21]=73;     data[22]=0;     data[23]=3;     data[24]=0;
-    pkt->data_[1]=01;     pkt->data_[2]=02;     pkt->data_[3]=03;     pkt->data_[4]=0;
+    data[25]=40;     data[26]=0;     data[27]=0;     data[28]=0;
-    pkt->data_[5]=1;     pkt->data_[6]=0;     pkt->data_[7]=14;     pkt->data_[8]=0;
+    data[29]=1;     data[30]=255;     data[31]=255;     data[32]=255;
-    pkt->data_[9]=1;     pkt->data_[10]=0;     pkt->data_[11]=1;     pkt->data_[12]=21;
+    data[33]=255;     data[34]=255;     data[35]=255;     data[36]=255;
-    pkt->data_[13]=158;     pkt->data_[14]=60;     pkt->data_[15]=22;     pkt->data_[16]=0;
+    data[37]=255;     data[38]=0;     data[39]=5;     data[40]=0;
-    pkt->data_[17]=30;     pkt->data_[18]=140;     pkt->data_[19]=155;     pkt->data_[20]=115;
+    data[41]=24;     data[42]=32;     data[43]=1;     data[44]=13;
-    pkt->data_[21]=73;     pkt->data_[22]=0;     pkt->data_[23]=3;     pkt->data_[24]=0;
+    data[45]=184;     data[46]=0;     data[47]=1;     data[48]=0;
-    pkt->data_[25]=40;     pkt->data_[26]=0;     pkt->data_[27]=0;     pkt->data_[28]=0;
+    data[49]=0;     data[50]=0;     data[51]=0;     data[52]=0;
-    pkt->data_[29]=1;     pkt->data_[30]=255;     pkt->data_[31]=255;     pkt->data_[32]=255;
+    data[53]=0;     data[54]=0;     data[55]=0;     data[56]=18;
-    pkt->data_[33]=255;     pkt->data_[34]=255;     pkt->data_[35]=255;     pkt->data_[36]=255;
+    data[57]=52;     data[58]=255;     data[59]=255;     data[60]=255;
-    pkt->data_[37]=255;     pkt->data_[38]=0;     pkt->data_[39]=5;     pkt->data_[40]=0;
+    data[61]=255;     data[62]=255;     data[63]=255;     data[64]=255;
-    pkt->data_[41]=24;     pkt->data_[42]=32;     pkt->data_[43]=1;     pkt->data_[44]=13;
+    data[65]=255;     data[66]=0;     data[67]=23;     data[68]=0;
-    pkt->data_[45]=184;     pkt->data_[46]=0;     pkt->data_[47]=1;     pkt->data_[48]=0;
+    data[69]=16;     data[70]=32;     data[71]=1;     data[72]=13;
-    pkt->data_[49]=0;     pkt->data_[50]=0;     pkt->data_[51]=0;     pkt->data_[52]=0;
+    data[73]=184;     data[74]=0;     data[75]=1;     data[76]=0;
-    pkt->data_[53]=0;     pkt->data_[54]=0;     pkt->data_[55]=0;     pkt->data_[56]=18;
+    data[77]=0;     data[78]=0;     data[79]=0;     data[80]=0;
-    pkt->data_[57]=52;     pkt->data_[58]=255;     pkt->data_[59]=255;     pkt->data_[60]=255;
+    data[81]=0;     data[82]=0;     data[83]=0;     data[84]=221;
-    pkt->data_[61]=255;     pkt->data_[62]=255;     pkt->data_[63]=255;     pkt->data_[64]=255;
+    data[85]=221;     data[86]=0;     data[87]=8;     data[88]=0;
-    pkt->data_[65]=255;     pkt->data_[66]=0;     pkt->data_[67]=23;     pkt->data_[68]=0;
+    data[89]=2;     data[90]=0;     data[91]=100;     data[92]=0;
-    pkt->data_[69]=16;     pkt->data_[70]=32;     pkt->data_[71]=1;     pkt->data_[72]=13;
+    data[93]=6;     data[94]=0;     data[95]=2;     data[96]=0;
-    pkt->data_[73]=184;     pkt->data_[74]=0;     pkt->data_[75]=1;     pkt->data_[76]=0;
+    data[97]=23;
-    pkt->data_[77]=0;     pkt->data_[78]=0;     pkt->data_[79]=0;     pkt->data_[80]=0;
+
-    pkt->data_[81]=0;     pkt->data_[82]=0;     pkt->data_[83]=0;     pkt->data_[84]=221;
+    pkt = new Pkt6(data, sizeof(data));
-    pkt->data_[85]=221;     pkt->data_[86]=0;     pkt->data_[87]=8;     pkt->data_[88]=0;
+    pkt->setRemotePort(546);
-    pkt->data_[89]=2;     pkt->data_[90]=0;     pkt->data_[91]=100;     pkt->data_[92]=0;
+    pkt->setRemoteAddr(IOAddress("fe80::21e:8cff:fe9b:7349"));
-    pkt->data_[93]=6;     pkt->data_[94]=0;     pkt->data_[95]=2;     pkt->data_[96]=0;
+    pkt->setLocalPort(0);
-    pkt->data_[97]=23;
+    pkt->setLocalAddr(IOAddress("ff02::1:2"));
+    pkt->setIndex(2);
+    pkt->setIface("eth0");
+
     return (pkt);
     return (pkt);
 }
 }
 
 
+
 TEST_F(Pkt6Test, unpack_solicit1) {
 TEST_F(Pkt6Test, unpack_solicit1) {
     Pkt6 * sol = capture1();
     Pkt6 * sol = capture1();
 
 
@@ -108,17 +114,12 @@ TEST_F(Pkt6Test, unpack_solicit1) {
     EXPECT_FALSE(sol->getOption(D6O_IA_TA));
     EXPECT_FALSE(sol->getOption(D6O_IA_TA));
     EXPECT_FALSE(sol->getOption(D6O_IAADDR));
     EXPECT_FALSE(sol->getOption(D6O_IAADDR));
 
 
-    // let's limit verbosity of this test
-    // std::cout << sol->toText();
-
     delete sol;
     delete sol;
 }
 }
 
 
 TEST_F(Pkt6Test, packUnpack) {
 TEST_F(Pkt6Test, packUnpack) {
 
 
-    Pkt6 * parent = new Pkt6(100);
+    Pkt6* parent = new Pkt6(DHCPV6_SOLICIT, 0x020304);
-
-    parent->setType(DHCPV6_SOLICIT);
 
 
     boost::shared_ptr<Option> opt1(new Option(Option::V6, 1));
     boost::shared_ptr<Option> opt1(new Option(Option::V6, 1));
     boost::shared_ptr<Option> opt2(new Option(Option::V6, 2));
     boost::shared_ptr<Option> opt2(new Option(Option::V6, 2));
@@ -130,43 +131,37 @@ TEST_F(Pkt6Test, packUnpack) {
     parent->addOption(opt3);
     parent->addOption(opt3);
 
 
     EXPECT_EQ(DHCPV6_SOLICIT, parent->getType());
     EXPECT_EQ(DHCPV6_SOLICIT, parent->getType());
-    int transid = parent->getTransid();
-    // transaction-id was randomized, let's remember it
 
 
     // calculated length should be 16
     // calculated length should be 16
-    EXPECT_EQ( Pkt6::DHCPV6_PKT_HDR_LEN + 3*Option::OPTION6_HDR_LEN, 
+    EXPECT_EQ( Pkt6::DHCPV6_PKT_HDR_LEN + 3*Option::OPTION6_HDR_LEN,
                parent->len() );
                parent->len() );
 
 
     EXPECT_TRUE( parent->pack() );
     EXPECT_TRUE( parent->pack() );
 
 
-    //
+    EXPECT_EQ( Pkt6::DHCPV6_PKT_HDR_LEN + 3*Option::OPTION6_HDR_LEN,
-    EXPECT_EQ( Pkt6::DHCPV6_PKT_HDR_LEN + 3*Option::OPTION6_HDR_LEN, 
                parent->len() );
                parent->len() );
 
 
-    // let's delete options from options_ collection
+    // create second packet,based on assembled data from the first one
-    // they still be defined in packed 
+    Pkt6* clone = new Pkt6((const uint8_t*)parent->getBuffer().getData(), parent->getBuffer().getLength());
-    parent->options_.clear();
-
-    // that that removed options are indeed are gone
-    EXPECT_EQ( 4, parent->len() );
 
 
     // now recreate options list
     // now recreate options list
-    EXPECT_TRUE( parent->unpack() );
+    EXPECT_TRUE( clone->unpack() );
 
 
     // transid, message-type should be the same as before
     // transid, message-type should be the same as before
-    EXPECT_EQ(transid, parent->getTransid());
+    EXPECT_EQ(parent->getTransid(), parent->getTransid());
-    EXPECT_EQ(DHCPV6_SOLICIT, parent->getType());
+    EXPECT_EQ(DHCPV6_SOLICIT, clone->getType());
-    
+
-    EXPECT_TRUE( parent->getOption(1));
+    EXPECT_TRUE( clone->getOption(1));
-    EXPECT_TRUE( parent->getOption(2));
+    EXPECT_TRUE( clone->getOption(2));
-    EXPECT_TRUE( parent->getOption(100));
+    EXPECT_TRUE( clone->getOption(100));
-    EXPECT_FALSE( parent->getOption(4));
+    EXPECT_FALSE( clone->getOption(4));
-    
+
     delete parent;
     delete parent;
+    delete clone;
 }
 }
 
 
 TEST_F(Pkt6Test, addGetDelOptions) {
 TEST_F(Pkt6Test, addGetDelOptions) {
-    Pkt6 * parent = new Pkt6(100);
+    Pkt6 * parent = new Pkt6(DHCPV6_SOLICIT, random() );
 
 
     boost::shared_ptr<Option> opt1(new Option(Option::V6, 1));
     boost::shared_ptr<Option> opt1(new Option(Option::V6, 1));
     boost::shared_ptr<Option> opt2(new Option(Option::V6, 2));
     boost::shared_ptr<Option> opt2(new Option(Option::V6, 2));
@@ -203,5 +198,4 @@ TEST_F(Pkt6Test, addGetDelOptions) {
     delete parent;
     delete parent;
 }
 }
 
 
-
 }
 }

+ 11 - 0
src/lib/util/buffer.h

@@ -101,6 +101,17 @@ public:
     /// \param len The length of the data in bytes.
     /// \param len The length of the data in bytes.
     InputBuffer(const void* data, size_t len) :
     InputBuffer(const void* data, size_t len) :
         position_(0), data_(static_cast<const uint8_t*>(data)), len_(len) {}
         position_(0), data_(static_cast<const uint8_t*>(data)), len_(len) {}
+
+    /// @brief Constructor from vector<uint8_t>
+    ///
+    /// It is caller's responsibility to ensure that the data is valid as long
+    /// as the buffer exists.
+    ///
+    /// @param begin iterator to beginning of the vector
+    /// @param end iterator to end of the vector
+    InputBuffer(std::vector<uint8_t>::const_iterator begin,
+                std::vector<uint8_t>::const_iterator end) :
+        data_(&(*begin)), len_(distance(begin, end)) {}
     //@}
     //@}
 
 
     ///
     ///