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
 	Corrected SOA serial check in xfrout.  It now compares the SOA
 	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
 // purpose with or without fee is hereby granted, provided that the above
@@ -59,8 +59,8 @@ Dhcpv4Srv::~Dhcpv4Srv() {
 bool
 Dhcpv4Srv::run() {
     while (!shutdown_) {
-        boost::shared_ptr<Pkt4> query; // client's message
-        boost::shared_ptr<Pkt4> rsp;   // server's response
+        Pkt4Ptr query; // client's message
+        Pkt4Ptr rsp;   // server's response
 
         query = IfaceMgr::instance().receive4();
 
@@ -141,14 +141,13 @@ Dhcpv4Srv::setServerID() {
 #if 0
     // uncomment this once ticket 1350 is merged.
     IOAddress srvId("127.0.0.1");
-    serverid_ = boost::shared_ptr<Option>(
+    serverid_ = OptionPtr(
       new Option4AddrLst(Option::V4, DHO_DHCP_SERVER_IDENTIFIER, srvId));
 #endif
 }
 
 
-void Dhcpv4Srv::copyDefaultFields(const boost::shared_ptr<Pkt4>& question,
-                                  boost::shared_ptr<Pkt4>& answer) {
+void Dhcpv4Srv::copyDefaultFields(const Pkt4Ptr& question, Pkt4Ptr& answer) {
     answer->setIface(question->getIface());
     answer->setIndex(question->getIndex());
     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) {
-    boost::shared_ptr<Option> opt;
+void Dhcpv4Srv::appendDefaultOptions(Pkt4Ptr& msg, uint8_t msg_type) {
+    OptionPtr opt;
 
     // add Message Type Option (type 53)
     std::vector<uint8_t> tmp;
     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);
 
     // DHCP Server Identifier (type 54)
-    opt = boost::shared_ptr<Option>
+    opt = OptionPtr
         (new Option4AddrLst(DHO_DHCP_SERVER_IDENTIFIER, IOAddress(HARDCODED_SERVER_ID)));
     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) {
-    boost::shared_ptr<Option> opt;
+void Dhcpv4Srv::appendRequestedOptions(Pkt4Ptr& msg) {
+    OptionPtr opt;
 
     // Domain name (type 15)
     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);
     // TODO: Add Option_String class
 
     // DNS servers (type 6)
-    opt = boost::shared_ptr<Option>
-        (new Option4AddrLst(DHO_DOMAIN_NAME_SERVERS, IOAddress(HARDCODED_DNS_SERVER)));
+    opt = OptionPtr(new Option4AddrLst(DHO_DOMAIN_NAME_SERVERS, IOAddress(HARDCODED_DNS_SERVER)));
     msg->addOption(opt);
 }
 
-void Dhcpv4Srv::tryAssignLease(boost::shared_ptr<Pkt4>& msg) {
-    boost::shared_ptr<Option> opt;
+void Dhcpv4Srv::tryAssignLease(Pkt4Ptr& msg) {
+    OptionPtr opt;
 
     // TODO: Implement actual lease assignment here
     msg->setYiaddr(IOAddress(HARDCODED_LEASE));
 
     // 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);
     msg->addOption(opt);
     // TODO: create Option_IntArray that holds list of integers, similar to Option4_AddrLst
 
     // Subnet mask (type 1)
-    opt = boost::shared_ptr<Option>
-        (new Option4AddrLst(DHO_SUBNET_MASK, IOAddress(HARDCODED_NETMASK)));
+    opt = OptionPtr(new Option4AddrLst(DHO_SUBNET_MASK, IOAddress(HARDCODED_NETMASK)));
     msg->addOption(opt);
 
     // Router (type 3)
-    opt = boost::shared_ptr<Option>
-        (new Option4AddrLst(DHO_ROUTERS, IOAddress(HARDCODED_GATEWAY)));
+    opt = OptionPtr(new Option4AddrLst(DHO_ROUTERS, IOAddress(HARDCODED_GATEWAY)));
     msg->addOption(opt);
 }
 
-boost::shared_ptr<Pkt4>
-Dhcpv4Srv::processDiscover(boost::shared_ptr<Pkt4>& discover) {
-    boost::shared_ptr<Pkt4> offer = boost::shared_ptr<Pkt4>
+Pkt4Ptr Dhcpv4Srv::processDiscover(Pkt4Ptr& discover) {
+    Pkt4Ptr offer = Pkt4Ptr
         (new Pkt4(DHCPOFFER, discover->getTransid()));
 
     copyDefaultFields(discover, offer);
@@ -244,9 +239,8 @@ Dhcpv4Srv::processDiscover(boost::shared_ptr<Pkt4>& discover) {
     return (offer);
 }
 
-boost::shared_ptr<Pkt4>
-Dhcpv4Srv::processRequest(boost::shared_ptr<Pkt4>& request) {
-    boost::shared_ptr<Pkt4> ack = boost::shared_ptr<Pkt4>
+Pkt4Ptr Dhcpv4Srv::processRequest(Pkt4Ptr& request) {
+    Pkt4Ptr ack = Pkt4Ptr
         (new Pkt4(DHCPACK, request->getTransid()));
 
     copyDefaultFields(request, ack);
@@ -258,17 +252,17 @@ Dhcpv4Srv::processRequest(boost::shared_ptr<Pkt4>& request) {
     return (ack);
 }
 
-void Dhcpv4Srv::processRelease(boost::shared_ptr<Pkt4>& release) {
+void Dhcpv4Srv::processRelease(Pkt4Ptr& release) {
     /// TODO: Implement this.
     cout << "Received RELEASE on " << release->getIface() << " interface." << endl;
 }
 
-void Dhcpv4Srv::processDecline(boost::shared_ptr<Pkt4>& decline) {
+void Dhcpv4Srv::processDecline(Pkt4Ptr& decline) {
     /// TODO: Implement this.
     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
     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
 // purpose with or without fee is hereby granted, provided that the above
@@ -15,7 +15,6 @@
 #ifndef DHCPV4_SRV_H
 #define DHCPV4_SRV_H
 
-#include <boost/shared_ptr.hpp>
 #include <boost/noncopyable.hpp>
 #include <dhcp/dhcp4.h>
 #include <dhcp/pkt4.h>
@@ -71,8 +70,7 @@ protected:
     /// @param solicit DISCOVER message received from client
     ///
     /// @return OFFER message or NULL
-    boost::shared_ptr<Pkt4>
-    processDiscover(boost::shared_ptr<Pkt4>& discover);
+    Pkt4Ptr processDiscover(Pkt4Ptr& discover);
 
     /// @brief Processes incoming REQUEST and returns REPLY response.
     ///
@@ -86,7 +84,7 @@ protected:
     /// @param request a message received from client
     ///
     /// @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.
     ///
@@ -94,17 +92,17 @@ protected:
     /// this function does not return anything.
     ///
     /// @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.
     ///
     /// @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.
     ///
     /// @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
     ///
@@ -113,9 +111,7 @@ protected:
     ///
     /// @param question any message sent by client
     /// @param answer any message server is going to send as response
-    void copyDefaultFields(const boost::shared_ptr<Pkt4>& question,
-                           boost::shared_ptr<Pkt4>& answer);
-
+    void copyDefaultFields(const Pkt4Ptr& question, Pkt4Ptr& answer);
 
     /// @brief Appends options requested by client.
     ///
@@ -123,8 +119,7 @@ protected:
     /// (sent in PRL) or are enforced by server.
     ///
     /// @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
     ///
@@ -136,20 +131,18 @@ protected:
     /// used fixed, hardcoded lease.
     ///
     /// @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
     ///
     /// @param msg message object (options will be added to it)
     /// @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
     ///
     /// @return server-id option
-    boost::shared_ptr<isc::dhcp::Option>
-    getServerID() { return serverid_; }
+    OptionPtr getServerID() { return serverid_; }
 
     /// @brief Sets server-identifier.
     ///
@@ -163,7 +156,7 @@ protected:
     void setServerID();
 
     /// 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
     /// 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
 // purpose with or without fee is hereby granted, provided that the above
@@ -70,8 +70,8 @@ Dhcpv6Srv::~Dhcpv6Srv() {
 bool
 Dhcpv6Srv::run() {
     while (!shutdown) {
-        boost::shared_ptr<Pkt6> query; // client's message
-        boost::shared_ptr<Pkt6> rsp;   // server's response
+        Pkt6Ptr query; // client's message
+        Pkt6Ptr rsp;   // server's response
 
         query = IfaceMgr::instance().receive6();
 
@@ -110,16 +110,16 @@ Dhcpv6Srv::run() {
                      << query->getType() << endl;
             }
 
-            cout << "Received " << query->data_len_ << " bytes packet type="
+            cout << "Received " << query->getBuffer().getLength() << " bytes packet type="
                  << query->getType() << endl;
             cout << query->toText();
             if (rsp) {
-                rsp->remote_addr_ = query->remote_addr_;
-                rsp->local_addr_ = query->local_addr_;
-                rsp->remote_port_ = DHCP6_CLIENT_PORT;
-                rsp->local_port_ = DHCP6_SERVER_PORT;
-                rsp->ifindex_ = query->ifindex_;
-                rsp->iface_ = query->iface_;
+                rsp->setRemoteAddr(query->getRemoteAddr());
+                rsp->setLocalAddr(query->getLocalAddr());
+                rsp->setRemotePort(DHCP6_CLIENT_PORT);
+                rsp->setLocalPort(DHCP6_SERVER_PORT);
+                rsp->setIndex(query->getIndex());
+                rsp->setIface(query->getIface());
                 cout << "Replying with:" << rsp->getType() << endl;
                 cout << rsp->toText();
                 cout << "----" << endl;
@@ -143,7 +143,7 @@ Dhcpv6Srv::setServerID() {
     /// TODO implement this for real once interface detection is done.
     /// Use hardcoded server-id for now
 
-    boost::shared_array<uint8_t> srvid(new uint8_t[14]);
+    OptionBuffer srvid(14);
     srvid[0] = 0;
     srvid[1] = 1; // DUID type 1 = DUID-LLT (see section 9.2 of RFC3315)
     srvid[2] = 0;
@@ -154,12 +154,11 @@ Dhcpv6Srv::setServerID() {
     }
     serverid_ = boost::shared_ptr<Option>(new Option(Option::V6,
                                                      D6O_SERVERID,
-                                                     srvid,
-                                                     0, 14));
+                                                     srvid.begin(),
+                                                     srvid.end()));
 }
 
-void Dhcpv6Srv::copyDefaultOptions(const boost::shared_ptr<Pkt6>& question,
-                                   boost::shared_ptr<Pkt6>& answer) {
+void Dhcpv6Srv::copyDefaultOptions(const Pkt6Ptr& question, Pkt6Ptr& answer) {
     // add client-id
     boost::shared_ptr<Option> clientid = question->getOption(D6O_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)
 }
 
-void Dhcpv6Srv::appendDefaultOptions(const boost::shared_ptr<Pkt6>& /*question*/,
-                                   boost::shared_ptr<Pkt6>& answer) {
+void Dhcpv6Srv::appendDefaultOptions(const Pkt6Ptr& /*question*/, Pkt6Ptr& answer) {
     // TODO: question is currently unused, but we need it at least to know
     // 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*/,
-                                       boost::shared_ptr<Pkt6>& answer) {
+void Dhcpv6Srv::appendRequestedOptions(const Pkt6Ptr& /*question*/, Pkt6Ptr& answer) {
     // 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.
 
@@ -190,8 +187,7 @@ void Dhcpv6Srv::appendRequestedOptions(const boost::shared_ptr<Pkt6>& /*question
     answer->addOption(dnsservers);
 }
 
-void Dhcpv6Srv::assignLeases(const boost::shared_ptr<Pkt6>& question,
-                             boost::shared_ptr<Pkt6>& answer) {
+void Dhcpv6Srv::assignLeases(const Pkt6Ptr& question, Pkt6Ptr& answer) {
     /// TODO Rewrite this once LeaseManager is implemented.
 
     // 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>
-Dhcpv6Srv::processSolicit(const boost::shared_ptr<Pkt6>& solicit) {
+Pkt6Ptr Dhcpv6Srv::processSolicit(const Pkt6Ptr& solicit) {
 
-    boost::shared_ptr<Pkt6> advertise(new Pkt6(DHCPV6_ADVERTISE,
-                                               solicit->getTransid()));
+    Pkt6Ptr advertise(new Pkt6(DHCPV6_ADVERTISE, solicit->getTransid()));
 
     copyDefaultOptions(solicit, advertise);
     appendDefaultOptions(solicit, advertise);
@@ -232,11 +226,9 @@ Dhcpv6Srv::processSolicit(const boost::shared_ptr<Pkt6>& solicit) {
     return (advertise);
 }
 
-boost::shared_ptr<Pkt6>
-Dhcpv6Srv::processRequest(const boost::shared_ptr<Pkt6>& request) {
+Pkt6Ptr Dhcpv6Srv::processRequest(const Pkt6Ptr& request) {
 
-    boost::shared_ptr<Pkt6> reply(new Pkt6(DHCPV6_REPLY,
-                                           request->getTransid()));
+    Pkt6Ptr reply(new Pkt6(DHCPV6_REPLY, request->getTransid()));
 
     copyDefaultOptions(request, reply);
     appendDefaultOptions(request, reply);
@@ -247,50 +239,34 @@ Dhcpv6Srv::processRequest(const boost::shared_ptr<Pkt6>& request) {
     return (reply);
 }
 
-boost::shared_ptr<Pkt6>
-Dhcpv6Srv::processRenew(const boost::shared_ptr<Pkt6>& renew) {
-    boost::shared_ptr<Pkt6> reply(new Pkt6(DHCPV6_REPLY,
-                                           renew->getTransid(),
-                                           Pkt6::UDP));
+Pkt6Ptr Dhcpv6Srv::processRenew(const Pkt6Ptr& renew) {
+    Pkt6Ptr reply(new Pkt6(DHCPV6_REPLY, renew->getTransid()));
     return reply;
 }
 
-boost::shared_ptr<Pkt6>
-Dhcpv6Srv::processRebind(const boost::shared_ptr<Pkt6>& rebind) {
-    boost::shared_ptr<Pkt6> reply(new Pkt6(DHCPV6_REPLY,
+Pkt6Ptr Dhcpv6Srv::processRebind(const Pkt6Ptr& rebind) {
+    Pkt6Ptr reply(new Pkt6(DHCPV6_REPLY,
                                            rebind->getTransid(),
                                            Pkt6::UDP));
     return reply;
 }
 
-boost::shared_ptr<Pkt6>
-Dhcpv6Srv::processConfirm(const boost::shared_ptr<Pkt6>& confirm) {
-    boost::shared_ptr<Pkt6> reply(new Pkt6(DHCPV6_REPLY,
-                                           confirm->getTransid(),
-                                           Pkt6::UDP));
+Pkt6Ptr Dhcpv6Srv::processConfirm(const Pkt6Ptr& confirm) {
+    Pkt6Ptr reply(new Pkt6(DHCPV6_REPLY, confirm->getTransid()));
     return reply;
 }
 
-boost::shared_ptr<Pkt6>
-Dhcpv6Srv::processRelease(const boost::shared_ptr<Pkt6>& release) {
-    boost::shared_ptr<Pkt6> reply(new Pkt6(DHCPV6_REPLY,
-                                           release->getTransid(),
-                                           Pkt6::UDP));
+Pkt6Ptr Dhcpv6Srv::processRelease(const Pkt6Ptr& release) {
+    Pkt6Ptr reply(new Pkt6(DHCPV6_REPLY, release->getTransid()));
     return reply;
 }
 
-boost::shared_ptr<Pkt6>
-Dhcpv6Srv::processDecline(const boost::shared_ptr<Pkt6>& decline) {
-    boost::shared_ptr<Pkt6> reply(new Pkt6(DHCPV6_REPLY,
-                                           decline->getTransid(),
-                                           Pkt6::UDP));
+Pkt6Ptr Dhcpv6Srv::processDecline(const Pkt6Ptr& decline) {
+    Pkt6Ptr reply(new Pkt6(DHCPV6_REPLY, decline->getTransid()));
     return reply;
 }
 
-boost::shared_ptr<Pkt6>
-Dhcpv6Srv::processInfRequest(const boost::shared_ptr<Pkt6>& infRequest) {
-    boost::shared_ptr<Pkt6> reply(new Pkt6(DHCPV6_REPLY,
-                                           infRequest->getTransid(),
-                                           Pkt6::UDP));
+Pkt6Ptr Dhcpv6Srv::processInfRequest(const Pkt6Ptr& infRequest) {
+    Pkt6Ptr reply(new Pkt6(DHCPV6_REPLY, infRequest->getTransid()));
     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
 // purpose with or without fee is hereby granted, provided that the above
@@ -15,7 +15,6 @@
 #ifndef DHCPV6_SRV_H
 #define DHCPV6_SRV_H
 
-#include <boost/shared_ptr.hpp>
 #include <boost/noncopyable.hpp>
 #include <dhcp/dhcp6.h>
 #include <dhcp/pkt6.h>
@@ -52,8 +51,7 @@ public:
     /// @brief Returns server-intentifier option
     ///
     /// @return server-id option
-    boost::shared_ptr<isc::dhcp::Option>
-    getServerID() { return serverid_; }
+    OptionPtr getServerID() { return serverid_; }
 
     /// @brief Main server processing loop.
     ///
@@ -80,8 +78,7 @@ protected:
     /// @param solicit SOLICIT message received from client
     ///
     /// @return ADVERTISE, REPLY message or NULL
-    boost::shared_ptr<Pkt6>
-    processSolicit(const boost::shared_ptr<Pkt6>& solicit);
+    Pkt6Ptr processSolicit(const Pkt6Ptr& solicit);
 
     /// @brief Processes incoming REQUEST and returns REPLY response.
     ///
@@ -94,44 +91,37 @@ protected:
     /// @param request a message received from client
     ///
     /// @return REPLY message or NULL
-    boost::shared_ptr<Pkt6>
-    processRequest(const boost::shared_ptr<Pkt6>& request);
+    Pkt6Ptr processRequest(const Pkt6Ptr& request);
 
     /// @brief Stub function that will handle incoming RENEW messages.
     ///
     /// @param renew message received from client
-    boost::shared_ptr<Pkt6>
-    processRenew(const boost::shared_ptr<Pkt6>& renew);
+    Pkt6Ptr processRenew(const Pkt6Ptr& renew);
 
     /// @brief Stub function that will handle incoming REBIND messages.
     ///
     /// @param rebind message received from client
-    boost::shared_ptr<Pkt6>
-    processRebind(const boost::shared_ptr<Pkt6>& rebind);
+    Pkt6Ptr processRebind(const Pkt6Ptr& rebind);
 
     /// @brief Stub function that will handle incoming CONFIRM messages.
     ///
     /// @param confirm message received from client
-    boost::shared_ptr<Pkt6>
-    processConfirm(const boost::shared_ptr<Pkt6>& confirm);
+    Pkt6Ptr processConfirm(const Pkt6Ptr& confirm);
 
     /// @brief Stub function that will handle incoming RELEASE messages.
     ///
     /// @param release message received from client
-    boost::shared_ptr<Pkt6>
-    processRelease(const boost::shared_ptr<Pkt6>& release);
+    Pkt6Ptr processRelease(const Pkt6Ptr& release);
 
     /// @brief Stub function that will handle incoming DECLINE messages.
     ///
     /// @param decline message received from client
-    boost::shared_ptr<Pkt6>
-    processDecline(const boost::shared_ptr<Pkt6>& decline);
+    Pkt6Ptr processDecline(const Pkt6Ptr& decline);
 
     /// @brief Stub function that will handle incoming INF-REQUEST messages.
     ///
     /// @param infRequest message received from client
-    boost::shared_ptr<Pkt6>
-    processInfRequest(const boost::shared_ptr<Pkt6>& infRequest);
+    Pkt6Ptr processInfRequest(const Pkt6Ptr& infRequest);
 
     /// @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 answer server's message (options will be copied here)
-    void copyDefaultOptions(const boost::shared_ptr<Pkt6>& question,
-                            boost::shared_ptr<Pkt6>& answer);
+    void copyDefaultOptions(const Pkt6Ptr& question, Pkt6Ptr& answer);
 
     /// @brief Appends default options to server's answer.
     ///
@@ -152,8 +141,7 @@ protected:
     ///
     /// @param question client's message
     /// @param answer server's message (options will be added here)
-    void appendDefaultOptions(const boost::shared_ptr<Pkt6>& question,
-                              boost::shared_ptr<Pkt6>& answer);
+    void appendDefaultOptions(const Pkt6Ptr& question, Pkt6Ptr& answer);
 
     /// @brief Appends requested options to server's answer.
     ///
@@ -163,8 +151,7 @@ protected:
     ///
     /// @param question client's message
     /// @param answer server's message (options will be added here)
-    void appendRequestedOptions(const boost::shared_ptr<Pkt6>& question,
-                                boost::shared_ptr<Pkt6>& answer);
+    void appendRequestedOptions(const Pkt6Ptr& question, Pkt6Ptr& answer);
 
     /// @brief Assigns leases.
     ///
@@ -174,8 +161,7 @@ protected:
     ///
     /// @param question client's message (with requested IA_NA)
     /// @param answer server's message (IA_NA options will be added here)
-    void assignLeases(const boost::shared_ptr<Pkt6>& question,
-                      boost::shared_ptr<Pkt6>& answer);
+    void assignLeases(const Pkt6Ptr& question, Pkt6Ptr& answer);
 
     /// @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(); );
 
     // 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++)
         clntDuid[i] = 100 + i;
 
-    boost::shared_ptr<Pkt6> sol =
-        boost::shared_ptr<Pkt6>(new Pkt6(DHCPV6_SOLICIT,
-                                         1234, Pkt6::UDP));
+    Pkt6Ptr sol = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 1234, Pkt6::UDP));
 
     boost::shared_ptr<Option6IA> ia =
         boost::shared_ptr<Option6IA>(new Option6IA(D6O_IA_NA, 234));
@@ -113,9 +111,9 @@ TEST_F(Dhcpv6SrvTest, Solicit_basic) {
     // - server-id
     // - IA that includes IAADDR
 
-    boost::shared_ptr<Option> clientid =
-        boost::shared_ptr<Option>(new Option(Option::V6, D6O_CLIENTID,
-                                             clntDuid, 0, 16));
+    OptionPtr clientid = OptionPtr(new Option(Option::V6, D6O_CLIENTID,
+                                              clntDuid.begin(),
+                                              clntDuid.begin()+16));
     sol->addOption(clientid);
 
     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( 1234, reply->getTransid() );
 
-    boost::shared_ptr<Option> tmp = reply->getOption(D6O_IA_NA);
+    OptionPtr tmp = reply->getOption(D6O_IA_NA);
     ASSERT_TRUE( tmp );
 
     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.");
     }
 
-    /* Set the REUSEADDR option so that we don't fail to start if
-       we're being restarted. */
+    // Set the REUSEADDR option so that we don't fail to start if
+    // we're being restarted.
     int flag = 1;
     if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
                    (char *)&flag, sizeof(flag)) < 0) {
@@ -452,14 +452,14 @@ int IfaceMgr::openSocket6(Iface& iface, const IOAddress& addr, int port) {
                   << "/port=" << port);
     }
 #ifdef IPV6_RECVPKTINFO
-    /* RFC3542 - a new way */
+    // RFC3542 - a new way
     if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO,
                    &flag, sizeof(flag)) != 0) {
         close(sock);
         isc_throw(Unexpected, "setsockopt: IPV6_RECVPKTINFO failed.");
     }
 #else
-    /* RFC2292 - an old way */
+    // RFC2292 - an old way
     if (setsockopt(sock, IPPROTO_IPV6, IPV6_PKTINFO,
                    &flag, sizeof(flag)) != 0) {
         close(sock);
@@ -523,10 +523,10 @@ IfaceMgr::send(boost::shared_ptr<Pkt6>& pkt) {
     struct in6_pktinfo *pktinfo;
     struct cmsghdr *cmsg;
 
-    Iface* iface = getIface(pkt->iface_);
+    Iface* iface = getIface(pkt->getIface());
     if (!iface) {
         isc_throw(BadValue, "Unable to send Pkt6. Invalid interface ("
-                  << pkt->iface_ << ") specified.");
+                  << pkt->getIface() << ") specified.");
     }
 
     memset(&control_buf_[0], 0, control_buf_len_);
@@ -538,11 +538,11 @@ IfaceMgr::send(boost::shared_ptr<Pkt6>& pkt) {
     sockaddr_in6 to;
     memset(&to, 0, sizeof(to));
     to.sin6_family = AF_INET6;
-    to.sin6_port = htons(pkt->remote_port_);
+    to.sin6_port = htons(pkt->getRemotePort());
     memcpy(&to.sin6_addr,
-           pkt->remote_addr_.getAddress().to_v6().to_bytes().data(),
+           pkt->getRemoteAddr().getAddress().to_v6().to_bytes().data(),
            16);
-    to.sin6_scope_id = pkt->ifindex_;
+    to.sin6_scope_id = pkt->getIndex();
 
     m.msg_name = &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
     // "scatter-gather" stuff... we only have a single chunk
     // of data to send, so we declare a single vector entry.)
-    v.iov_base = (char *) &pkt->data_[0];
-    v.iov_len = pkt->data_len_;
+    v.iov_base = (char *) pkt->getBuffer().getData();
+    v.iov_len = pkt->getBuffer().getLength();
     m.msg_iov = &v;
     m.msg_iovlen = 1;
 
@@ -569,17 +569,17 @@ IfaceMgr::send(boost::shared_ptr<Pkt6>& pkt) {
     cmsg->cmsg_len = CMSG_LEN(sizeof(*pktinfo));
     pktinfo = (struct in6_pktinfo *)CMSG_DATA(cmsg);
     memset(pktinfo, 0, sizeof(*pktinfo));
-    pktinfo->ipi6_ifindex = pkt->ifindex_;
+    pktinfo->ipi6_ifindex = pkt->getIndex();
     m.msg_controllen = cmsg->cmsg_len;
 
     result = sendmsg(getSocket(*pkt), &m, 0);
     if (result < 0) {
         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: "
-         << " dst=[" << pkt->remote_addr_.toText() << "]:" << pkt->remote_port_
-         << ", src=" << pkt->local_addr_.toText() << "]:" << pkt->remote_port_
+         << " dst=[" << pkt->getRemoteAddr().toText() << "]:" << pkt->getRemotePort()
+         << ", src=" << pkt->getLocalAddr().toText() << "]:" << pkt->getLocalPort()
          << endl;
 
     return (result);
@@ -813,8 +813,7 @@ IfaceMgr::receive4() {
     return (pkt);
 }
 
-boost::shared_ptr<Pkt6>
-IfaceMgr::receive6() {
+Pkt6Ptr IfaceMgr::receive6() {
     struct msghdr m;
     struct iovec v;
     int result;
@@ -822,57 +821,43 @@ IfaceMgr::receive6() {
     struct in6_pktinfo* pktinfo;
     struct sockaddr_in6 from;
     struct in6_addr to_addr;
-    boost::shared_ptr<Pkt6> pkt;
-    char addr_str[INET6_ADDRSTRLEN];
-
-    try {
-        // RFC3315 states that server responses may be
-        // fragmented if they are over MTU. There is no
-        // text whether client's packets may be larger
-        // than 1500. Nevertheless to be on the safe side
-        // we use larger buffer. This buffer limit is checked
-        // during reception (see iov_len below), so we are
-        // 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
-    }
+    int ifindex;
+    Pkt6Ptr pkt;
+
+    // RFC3315 states that server responses may be
+    // fragmented if they are over MTU. There is no
+    // text whether client's packets may be larger
+    // than 1500. For now, we can assume that
+    // we don't support packets larger than 1500.
+    const uint32_t RCVBUFSIZE = 1500;
+    static uint8_t buf[RCVBUFSIZE];
 
     memset(&control_buf_[0], 0, control_buf_len_);
 
     memset(&from, 0, sizeof(from));
     memset(&to_addr, 0, sizeof(to_addr));
 
-    /*
-     * Initialize our message header structure.
-     */
+    // Initialize our message header structure.
     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_namelen = sizeof(from);
 
-    /*
-     * Set the data buffer we're receiving. (Using this wacky
-     * "scatter-gather" stuff... but we that doesn't really make
-     * sense for us, so we use a single vector entry.)
-     */
-    v.iov_base = (void*)&pkt->data_[0];
-    v.iov_len = pkt->data_len_;
+    // Set the data buffer we're receiving. (Using this wacky
+    // "scatter-gather" stuff... but we that doesn't really make
+    // sense for us, so we use a single vector entry.)
+    v.iov_base = (void*)buf;
+    v.iov_len = RCVBUFSIZE;
     m.msg_iov = &v;
     m.msg_iovlen = 1;
 
-    /*
-     * Getting the interface is a bit more involved.
-     *
-     * We set up some space for a "control message". We have
-     * previously asked the kernel to give us packet
-     * information (when we initialized the interface), so we
-     * should get the destination address from that.
-     */
+    // Getting the interface is a bit more involved.
+    //
+    // We set up some space for a "control message". We have
+    // previously asked the kernel to give us packet
+    // information (when we initialized the interface), so we
+    // should get the destination address from that.
     m.msg_control = &control_buf_[0];
     m.msg_controllen = control_buf_len_;
 
@@ -917,14 +902,12 @@ IfaceMgr::receive6() {
     result = recvmsg(candidate->sockfd_, &m, 0);
 
     if (result >= 0) {
-        /*
-         * If we did read successfully, then we need to loop
-         * through the control messages we received and
-         * find the one with our destination address.
-         *
-         * We also keep a flag to see if we found it. If we
-         * didn't, then we consider this to be an error.
-         */
+        // If we did read successfully, then we need to loop
+        // through the control messages we received and
+        // find the one with our destination address.
+        //
+        // We also keep a flag to see if we found it. If we
+        // didn't, then we consider this to be an error.
         int found_pktinfo = 0;
         cmsg = CMSG_FIRSTHDR(&m);
         while (cmsg != NULL) {
@@ -932,7 +915,7 @@ IfaceMgr::receive6() {
                 (cmsg->cmsg_type == IPV6_PKTINFO)) {
                 pktinfo = (struct in6_pktinfo*)CMSG_DATA(cmsg);
                 to_addr = pktinfo->ipi6_addr;
-                pkt->ifindex_ = pktinfo->ipi6_ifindex;
+                ifindex = pktinfo->ipi6_ifindex;
                 found_pktinfo = 1;
             }
             cmsg = CMSG_NXTHDR(&m, cmsg);
@@ -946,34 +929,35 @@ IfaceMgr::receive6() {
         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!
-    inet_ntop(AF_INET6, &from.sin6_addr, addr_str, INET6_ADDRSTRLEN);
-    pkt->remote_addr_ = IOAddress(string(addr_str));
+    try {
+        pkt = Pkt6Ptr(new Pkt6(buf, result));
+    } 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) {
-        pkt->iface_ = received->getName();
+        pkt->setIface(received->getName());
     } else {
         cout << "Received packet over unknown interface (ifindex="
-             << pkt->ifindex_ << ")." << endl;
+             << pkt->getIndex() << ")." << endl;
         return (boost::shared_ptr<Pkt6>()); // NULL
     }
 
-    pkt->data_len_ = result;
-
     // TODO Move this to LOG_DEBUG
-    cout << "Received " << pkt->data_len_ << " bytes over "
-         << pkt->iface_ << "/" << pkt->ifindex_ << " interface: "
-         << " src=" << pkt->remote_addr_.toText()
-         << ", dst=" << pkt->local_addr_.toText()
+    cout << "Received " << pkt->getBuffer().getLength() << " bytes over "
+         << pkt->getIface() << "/" << pkt->getIndex() << " interface: "
+         << " src=" << pkt->getRemoteAddr().toText()
+         << ", dst=" << pkt->getLocalAddr().toText()
          << endl;
 
     return (pkt);
@@ -981,10 +965,10 @@ IfaceMgr::receive6() {
 
 uint16_t
 IfaceMgr::getSocket(isc::dhcp::Pkt6 const& pkt) {
-    Iface* iface = getIface(pkt.iface_);
+    Iface* iface = getIface(pkt.getIface());
     if (!iface) {
         isc_throw(BadValue, "Tried to find socket for non-existent interface "
-                  << pkt.iface_);
+                  << pkt.getIface());
     }
 
     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
 // purpose with or without fee is hereby granted, provided that the above
@@ -28,19 +28,16 @@ using namespace isc::dhcp;
 using namespace isc::util;
 
 // 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_;
 
-unsigned int
-LibDHCP::unpackOptions6(const boost::shared_array<uint8_t> buf,
-                        unsigned int buf_len,
-                        unsigned int offset, unsigned int parse_len,
-                        isc::dhcp::Option::OptionCollection& options) {
-    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;
+
+uint32_t LibDHCP::unpackOptions6(const OptionBuffer& buf,
+                                 isc::dhcp::Option::OptionCollection& options) {
+    uint32_t offset = 0;
+    unsigned int end = buf.size();
 
     while (offset +4 <= end) {
         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;
             return (offset);
         }
-        boost::shared_ptr<Option> opt;
+        OptionPtr opt;
         switch (opt_type) {
         case D6O_IA_NA:
         case D6O_IA_PD:
             // cout << "Creating Option6IA" << endl;
-            opt = boost::shared_ptr<Option>(new Option6IA(opt_type,
-                                                          buf, buf_len,
-                                                          offset,
-                                                          opt_len));
+            opt = OptionPtr(new Option6IA(opt_type,
+                                          buf.begin() + offset,
+                                          buf.begin() + offset + opt_len));
             break;
         case D6O_IAADDR:
             // cout << "Creating Option6IAAddr" << endl;
-            opt = boost::shared_ptr<Option>(new Option6IAAddr(opt_type,
-                                                              buf, buf_len,
-                                                              offset, opt_len));
+            opt = OptionPtr(new Option6IAAddr(opt_type,
+                                              buf.begin() + offset,
+                                              buf.begin() + offset + opt_len));
             break;
         default:
             // cout << "Creating Option" << endl;
-            opt = boost::shared_ptr<Option>(new Option(Option::V6,
-                                                       opt_type,
-                                                       buf,
-                                                       offset,
-                                                       opt_len));
+            opt = OptionPtr(new Option(Option::V6,
+                                       opt_type,
+                                       buf.begin() + offset,
+                                       buf.begin() + offset + opt_len));
             break;
         }
         // add option to options
@@ -85,9 +80,8 @@ LibDHCP::unpackOptions6(const boost::shared_array<uint8_t> buf,
     return (offset);
 }
 
-void
-LibDHCP::unpackOptions4(const std::vector<uint8_t>& buf,
-                        isc::dhcp::Option::OptionCollection& options) {
+uint32_t LibDHCP::unpackOptions4(const OptionBuffer& buf,
+                                 isc::dhcp::Option::OptionCollection& options) {
     size_t offset = 0;
 
     // 2 - header of DHCPv4 option
@@ -95,11 +89,11 @@ LibDHCP::unpackOptions4(const std::vector<uint8_t>& buf,
         uint8_t opt_type = buf[offset++];
 
         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()) {
-          isc_throw(OutOfRange, "Attempt to parse truncated option "
-                    << opt_type);
+            isc_throw(OutOfRange, "Attempt to parse truncated option "
+                      << opt_type);
         }
 
         uint8_t opt_len =  buf[offset++];
@@ -109,41 +103,32 @@ LibDHCP::unpackOptions4(const std::vector<uint8_t>& buf,
                       << "-byte long buffer.");
         }
 
-        boost::shared_ptr<Option> opt;
+        OptionPtr opt;
         switch(opt_type) {
         default:
-            opt = boost::shared_ptr<Option>(new Option(Option::V4, opt_type,
-                                                       buf.begin()+offset,
-                                                       buf.begin()+offset+opt_len));
+            opt = OptionPtr(new Option(Option::V4, opt_type,
+                                       buf.begin()+offset,
+                                       buf.begin()+offset+opt_len));
         }
 
         options.insert(pair<int, boost::shared_ptr<Option> >(opt_type, opt));
         offset += opt_len;
     }
+    return (offset);
 }
 
-unsigned int
-LibDHCP::packOptions6(boost::shared_array<uint8_t> data,
-                      unsigned int data_len,
-                      unsigned int offset,
-                      const isc::dhcp::Option::OptionCollection& options) {
+void LibDHCP::packOptions6(isc::util::OutputBuffer &buf,
+                           const isc::dhcp::Option::OptionCollection& options) {
     try {
         for (Option::OptionCollection::const_iterator it = options.begin();
-             it != options.end();
-             ++it) {
-            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);
+             it != options.end(); ++it) {
+            it->second->pack(buf);
         }
     }
     catch (const Exception&) {
         cout << "Packet build failed (Option build failed)." << endl;
         throw;
     }
-    return (offset);
 }
 
 void
@@ -156,11 +141,9 @@ LibDHCP::packOptions(isc::util::OutputBuffer& buf,
     }
 }
 
-
-bool
-LibDHCP::OptionFactoryRegister(Option::Universe u,
-                               unsigned short opt_type,
-                               Option::Factory * factory) {
+void LibDHCP::OptionFactoryRegister(Option::Universe u,
+                                    uint16_t opt_type,
+                                    Option::Factory * factory) {
     switch (u) {
     case Option::V6: {
         if (v6factories_.find(opt_type)!=v6factories_.end()) {
@@ -168,13 +151,23 @@ LibDHCP::OptionFactoryRegister(Option::Universe u,
                      << "for option type "  << opt_type);
         }
         v6factories_[opt_type]=factory;
-        return true;
+        return;
     }
     case Option::V4:
-    default:{
-        isc_throw(BadValue, "This universe type is not supported yet.");
-        return false; // never happens
+    {
+        if (opt_type > 254) {
+            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.
     ///
-    /// @param buf shared pointer to buffer. Data will be stored there.
-    /// @param buf_len buffer length. Used for buffer overflow protection.
-    /// @param offset Offset from beginning of the buffer, where store options
+    /// @param buf output buffer (assembled options will be stored here)
     /// @param options collection of options to store to
-    ///
-    /// @return offset to the first unused byte in buffer (next one after last
-    ///         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);
+    static void packOptions6(isc::util::OutputBuffer& buf,
+                             const isc::dhcp::Option::OptionCollection& options);
 
 
     /// @brief Stores options in a buffer.
@@ -52,48 +44,49 @@ public:
     /// may be different reasons (option too large, option malformed,
     /// too many options etc.)
     ///
-    /// @param buf
-    /// @param options
-    static void
-    packOptions(isc::util::OutputBuffer& buf,
-                const isc::dhcp::Option::OptionCollection& options);
+    /// @param buf output buffer (assembled options will be stored here)
+    /// @param options collection of options to store to
+    static void packOptions(isc::util::OutputBuffer& buf,
+                            const isc::dhcp::Option::OptionCollection& options);
 
-    static void
-    unpackOptions4(const std::vector<uint8_t>& buf,
-                   isc::dhcp::Option::OptionCollection& options);
-    ///
-    /// Parses provided buffer and creates Option objects.
+    /// @brief Parses provided buffer as DHCPv4 options and creates Option objects.
     ///
-    /// Parses provided buf array and stores created Option objects
+    /// Parses provided buffer and stores created Option objects
     /// in options container.
     ///
     /// @param buf Buffer to be parsed.
-    /// @param offset Specifies offset for the first option.
     /// @param options Reference to option container. Options will be
     ///        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
-    unpackOptions6(const boost::shared_array<uint8_t> buf, unsigned int buf_len,
-                   unsigned int offset, unsigned int parse_len,
-                   isc::dhcp::Option::OptionCollection& options_);
+    /// @param buf Buffer to be parsed.
+    /// @param options Reference to option container. Options will be
+    ///        put here.
+    static uint32_t unpackOptions6(const OptionBuffer& buf,
+                                   isc::dhcp::Option::OptionCollection& options);
 
-    ///
     /// 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 opt_type option-type
     /// @param factory function pointer
-    ///
-    /// @return true, if registration was successful, false otherwise
-    ///
-    static bool
-    OptionFactoryRegister(Option::Universe u,
-                          unsigned short type,
-                          Option::Factory * factory);
+    static void OptionFactoryRegister(Option::Universe u,
+                                      uint16_t type,
+                                      Option::Factory * factory);
 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_;
 };
 

+ 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
 // purpose with or without fee is hereby granted, provided that the above
@@ -17,7 +17,6 @@
 #include <arpa/inet.h>
 #include <sstream>
 #include <iomanip>
-#include <boost/shared_array.hpp>
 #include "exceptions/exceptions.h"
 #include "util/io_utilities.h"
 
@@ -37,26 +36,14 @@ Option::Option(Universe u, unsigned short type)
     }
 }
 
-Option::Option(Universe u, unsigned short type,
-               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)
+Option::Option(Universe u, unsigned short type, const OptionBuffer& data)
     :universe_(u), type_(type), data_(data) {
     check();
 }
 
-Option::Option(Universe u, uint16_t type, vector<uint8_t>::const_iterator first,
-               vector<uint8_t>::const_iterator last)
-    :universe_(u), type_(type), data_(std::vector<uint8_t>(first,last)) {
+Option::Option(Universe u, uint16_t type, OptionBufferConstIter first,
+               OptionBufferConstIter last)
+    :universe_(u), type_(type), data_(OptionBuffer(first,last)) {
     check();
 }
 
@@ -84,15 +71,16 @@ Option::check() {
     // both types and data size.
 }
 
-unsigned int
-Option::pack(boost::shared_array<uint8_t>& buf,
-             unsigned int buf_len,
-             unsigned int offset) {
-    if (universe_ != V6) {
+void Option::pack(isc::util::OutputBuffer& buf) {
+    switch (universe_) {
+    case V6:
+        return pack6(buf);
+    case V4:
+        return pack4(buf);
+    default:
         isc_throw(BadValue, "Failed to pack " << type_ << " option. Do not "
                   << "use this method for options other than DHCPv6.");
     }
-    return pack6(buf, buf_len, offset);
 }
 
 void
@@ -127,84 +115,25 @@ Option::pack4(isc::util::OutputBuffer& buf) {
     }
 }
 
-unsigned int
-Option::pack6(boost::shared_array<uint8_t>& buf,
-             unsigned int buf_len,
-             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_);
-}
+void Option::pack6(isc::util::OutputBuffer& buf) {
+    buf.writeUint16(type_);
+    buf.writeUint16(len() - getHeaderLen());
 
-unsigned int
-Option::unpack(const boost::shared_array<uint8_t>& buf,
-               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_);
+    if (! data_.empty()) {
+        buf.writeData(&data_[0], data_.size());
     }
 
-    return 0; // should not happen
-}
-
-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;
+    return LibDHCP::packOptions6(buf, options_);
 }
 
-unsigned int
-Option::unpack6(const boost::shared_array<uint8_t>& buf,
-                unsigned int buf_len,
-                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_);
+void Option::unpack(OptionBufferConstIter begin,
+                    OptionBufferConstIter end) {
+    data_ = OptionBuffer(begin, end);
 }
 
-/// Returns length of the complete option (data length + DHCPv4/DHCPv6
-/// option header)
-uint16_t
-Option::len() {
+uint16_t Option::len() {
+    // Returns length of the complete option (data length + DHCPv4/DHCPv6
+    // option header)
 
     // length of the whole option is header and data stored in this option...
     int length = getHeaderLen() + data_.size();
@@ -232,18 +161,16 @@ Option::valid() {
     return (true);
 }
 
-boost::shared_ptr<isc::dhcp::Option>
-Option::getOption(unsigned short opt_type) {
+OptionPtr Option::getOption(unsigned short opt_type) {
     isc::dhcp::Option::OptionCollection::const_iterator x =
         options_.find(opt_type);
     if ( x != options_.end() ) {
         return (*x).second;
     }
-    return boost::shared_ptr<isc::dhcp::Option>(); // NULL
+    return OptionPtr(); // NULL
 }
 
-bool
-Option::delOption(unsigned short opt_type) {
+bool Option::delOption(unsigned short opt_type) {
     isc::dhcp::Option::OptionCollection::iterator x = options_.find(opt_type);
     if ( x != options_.end() ) {
         options_.erase(x);
@@ -289,8 +216,7 @@ Option::getHeaderLen() {
     return 0; // should not happen
 }
 
-void
-Option::addOption(boost::shared_ptr<Option> opt) {
+void Option::addOption(OptionPtr opt) {
     if (universe_ == V4) {
         // check for uniqueness (DHCPv4 options must be unique)
         if (getOption(opt->getType())) {
@@ -298,7 +224,7 @@ Option::addOption(boost::shared_ptr<Option> opt) {
                       << " 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() {

+ 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
 // purpose with or without fee is hereby granted, provided that the above
@@ -19,12 +19,28 @@
 #include <map>
 #include <vector>
 #include <boost/shared_ptr.hpp>
-#include <boost/shared_array.hpp>
 #include <util/buffer.h>
 
 namespace isc {
 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 {
 public:
     /// length of the usual DHCPv4 option header (there are exceptions)
@@ -37,7 +53,7 @@ public:
     enum Universe { V4, V6 };
 
     /// a collection of DHCPv6 options
-    typedef std::multimap<unsigned int, boost::shared_ptr<Option> >
+    typedef std::multimap<unsigned int, OptionPtr >
     OptionCollection;
 
     /// @brief a factory function prototype
@@ -45,38 +61,17 @@ public:
     /// @param u option universe (DHCPv4 or DHCPv6)
     /// @param type option type
     /// @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
-    typedef boost::shared_ptr<Option> Factory(Option::Universe u,
-                                              unsigned short type,
-                                              boost::shared_array<uint8_t>& buf,
-                                              unsigned int offset,
-                                              unsigned int len);
+    typedef OptionPtr Factory(Option::Universe u,
+                              uint16_t type,
+                              const OptionBuffer& buf);
 
     /// @brief ctor, used for options constructed, usually during transmission
     ///
     /// @param u option universe (DHCPv4 or DHCPv6)
     /// @param type option type
-    Option(Universe u, unsigned short 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);
+    Option(Universe u, uint16_t type);
 
     /// @brief Constructor, used for received options.
     ///
@@ -88,7 +83,7 @@ public:
     /// @param u specifies universe (V4 or V6)
     /// @param type option type (0-255 for V4 and 0-65535 for V6)
     /// @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.
     ///
@@ -110,15 +105,13 @@ public:
     /// @param first iterator to the first element that should be copied
     /// @param last iterator to the next element after the last one
     ///        to be copied.
-    Option(Universe u, uint16_t type,
-           std::vector<uint8_t>::const_iterator first,
-           std::vector<uint8_t>::const_iterator last);
+    Option(Universe u, uint16_t type, OptionBufferConstIter first,
+           OptionBufferConstIter last);
 
     /// @brief returns option universe (V4 or V6)
     ///
     /// @return universe type
-    Universe
-    getUniverse() { return universe_; };
+    Universe  getUniverse() { return universe_; };
 
     /// @brief Writes option in wire-format to a buffer.
     ///
@@ -129,14 +122,10 @@ public:
     /// TODO: Migrate DHCPv6 code to pack(OutputBuffer& buf) version
     ///
     /// @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
     ///
-    virtual unsigned int
-    pack(boost::shared_array<uint8_t>& buf, unsigned int buf_len,
-         unsigned int offset);
+    virtual void pack(isc::util::OutputBuffer& buf);
 
     /// @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().
     ///
     /// @param buf output buffer (option will be stored there)
-    virtual void
-    pack4(isc::util::OutputBuffer& buf);
-
+    virtual void pack4(isc::util::OutputBuffer& buf);
 
     /// @brief Parses buffer.
     ///
     /// Parses received buffer, returns offset to the first unused byte after
     /// parsed option.
     ///
-    /// @param buf pointer to buffer
-    /// @param buf_len length of buf
-    /// @param offset offset, where start parsing option
-    /// @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);
+    /// @param begin iterator to first byte of option data
+    /// @param end iterator to end of option data (first byte after option end)
+    virtual void unpack(OptionBufferConstIter begin,
+                        OptionBufferConstIter end);
 
     /// Returns string representation of the option.
     ///
@@ -203,7 +183,7 @@ public:
     ///
     /// @return pointer to actual data (or reference to an empty vector
     ///         if there is no data)
-    virtual const std::vector<uint8_t>& getData() { return (data_); }
+    virtual const OptionBuffer& getData() { return (data_); }
 
     /// Adds a sub-option.
     ///
@@ -217,24 +197,21 @@ public:
     /// many places. Requiring casting is not feasible.
     ///
     /// @param opt shared pointer to a suboption that is going to be added.
-    void
-    addOption(boost::shared_ptr<Option> opt);
+    void addOption(OptionPtr opt);
 
     /// Returns shared_ptr to suboption of specific type
     ///
     /// @param type type of requested suboption
     ///
     /// @return shared_ptr to requested suoption
-    boost::shared_ptr<isc::dhcp::Option>
-    getOption(unsigned short type);
+    OptionPtr getOption(uint16_t type);
 
     /// Attempts to delete first suboption of requested type
     ///
     /// @param type Type of option to be deleted.
     ///
     /// @return true if option was deleted, false if no such option existed
-    bool
-    delOption(unsigned short type);
+    bool delOption(uint16_t type);
 
     /// @brief Returns content of first byte.
     ///
@@ -286,40 +263,7 @@ protected:
     /// defined suboptions. Version for building DHCPv4 options.
     ///
     /// @param buf output buffer (built options will be stored here)
-    /// @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 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);
+    virtual void pack6(isc::util::OutputBuffer& buf);
 
     /// @brief A private method used for option correctness.
     ///
@@ -332,17 +276,10 @@ protected:
     Universe universe_;
 
     /// option type (0-255 for DHCPv4, 0-65535 for DHCPv6)
-    unsigned short type_;
+    uint16_t type_;
 
     /// contains content of this data
-    std::vector<uint8_t> 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_;
+    OptionBuffer data_;
 
     /// collection for storing suboptions
     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
 // 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,
-                               vector<uint8_t>::const_iterator first,
-                               vector<uint8_t>::const_iterator last)
+Option4AddrLst::Option4AddrLst(uint8_t type, OptionBufferConstIter first,
+                               OptionBufferConstIter last)
     :Option(V4, type) {
     if ( (distance(first, last) % V4ADDRESS_LEN) ) {
         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
 // 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 last iterator to the next element after the last one
     ///        to be copied.
-    Option4AddrLst(uint8_t type, std::vector<uint8_t>::const_iterator first,
-           std::vector<uint8_t>::const_iterator last);
+    Option4AddrLst(uint8_t type, OptionBufferConstIter first,
+                   OptionBufferConstIter last);
 
     /// @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().
     ///
     /// @param buf output buffer (option will be stored there)
-    virtual void
-    pack4(isc::util::OutputBuffer& buf);
+    virtual void pack4(isc::util::OutputBuffer& buf);
 
     /// Returns string representation of the option.
     ///
     /// @param indent number of spaces before printing text
     ///
     /// @return string with text representation.
-    virtual std::string
-    toText(int indent = 0);
+    virtual std::string toText(int indent = 0);
 
     /// Returns length of the complete option (data length + DHCPv4/DHCPv6
     /// option header)
@@ -113,8 +111,7 @@ public:
     /// a couple (1-3) addresses, the overhead is not that big.
     ///
     /// @return address container with addresses
-    AddressContainer
-    getAddresses() { return addrs_; };
+    AddressContainer getAddresses() { return addrs_; };
 
     /// @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
 // 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,
-                               boost::shared_array<uint8_t> buf,
-                               unsigned int buf_len,
-                               unsigned int offset,
-                               unsigned int option_len)
+                               OptionBufferConstIter begin,
+                               OptionBufferConstIter end)
     :Option(V6, type) {
-    unpack(buf, buf_len, offset, option_len);
+    unpack(begin, end);
 }
 
 void
@@ -63,58 +61,32 @@ Option6AddrLst::setAddresses(const AddressContainer& addrs) {
     addrs_ = addrs;
 }
 
-unsigned int
-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.");
-    }
+void Option6AddrLst::pack(isc::util::OutputBuffer& buf) {
 
-    writeUint16(type_, &buf[offset]);
-    offset += sizeof(uint16_t);
+    buf.writeUint16(type_);
 
     // len() returns complete option length.
     // len field contains length without 4-byte option header
-    writeUint16(len() - OPTION6_HDR_LEN, &buf[offset]);
-    offset += sizeof(uint16_t);
+    buf.writeUint16(len() - getHeaderLen());
 
     // this wrapping is *ugly*. I wish there was a a
     for (AddressContainer::const_iterator addr=addrs_.begin();
-         addr!=addrs_.end();
-         ++addr) {
-        memcpy(&buf[offset],
-               addr->getAddress().to_v6().to_bytes().data(),
-               V6ADDRESS_LEN);
-        offset += V6ADDRESS_LEN;
+         addr!=addrs_.end(); ++addr) {
+        buf.writeData(addr->getAddress().to_v6().to_bytes().data(), V6ADDRESS_LEN);
     }
-
-    return offset;
 }
 
-unsigned int
-Option6AddrLst::unpack(const boost::shared_array<uint8_t>& buf,
-                       unsigned int buf_len,
-                       unsigned int offset,
-                       unsigned int option_len) {
-    if (offset+option_len > buf_len) {
+void Option6AddrLst::unpack(OptionBufferConstIter begin,
+                        OptionBufferConstIter end) {
+    if (distance(begin, end) % 16) {
         isc_throw(OutOfRange, "Option " << type_
-                  << " truncated.");
-    }
-
-    if (option_len%16) {
-        isc_throw(OutOfRange, "Option " << type_
-                  << " malformed: len=" << option_len
+                  << " malformed: len=" << distance(begin, end)
                   << " is not divisible by 16.");
     }
-    while (option_len > 0) {
-        addrs_.push_back(IOAddress::from_bytes(AF_INET6, &buf[offset]));
-        offset += 16;
-        option_len -= 16;
+    while (begin != end) {
+        addrs_.push_back(IOAddress::from_bytes(AF_INET6, &(*begin)));
+        begin += V6ADDRESS_LEN;
     }
-
-    return offset;
 }
 
 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
 // purpose with or without fee is hereby granted, provided that the above
@@ -36,70 +36,48 @@ public:
     ///
     /// @param type option type
     /// @param addrs vector of addresses to be stored
-    ///
-    Option6AddrLst(unsigned short type,
-                   const AddressContainer& addrs);
+    Option6AddrLst(uint16_t type, const AddressContainer& addrs);
 
     /// @brief Simplified constructor for a single address
     ///
     /// @param type option type
     /// @param addr a single address to be stored
-    ///
-    Option6AddrLst(unsigned short type,
-                   const isc::asiolink::IOAddress& addr);
+    Option6AddrLst(uint16_t type, const isc::asiolink::IOAddress& addr);
 
     /// @brief Constructor used for parsing received option
     ///
     /// @param type option type
-    /// @param buf pointer to packet buffer
-    /// @param buf_len length of packet buffer
-    /// @param offset offset to beginning of option data
-    /// @param len length of option data
-    ///
-    Option6AddrLst(unsigned short type, boost::shared_array<uint8_t> buf,
-                   unsigned int buf_len,
-                   unsigned int offset,
-                   unsigned int len);
+    /// @param begin iterator to first byte of option data
+    /// @param end iterator to end of option data (first byte after option end)
+    Option6AddrLst(uint16_t type, OptionBufferConstIter begin,
+                   OptionBufferConstIter end);
 
     /// @brief Assembles on-wire form of this option
     ///
     /// @param buf pointer to packet buffer
-    /// @param buf_len length of packet buffer
-    /// @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);
+    void pack(isc::util::OutputBuffer& buf);
 
     /// @brief Parses received data
     ///
     /// @param buf pointer to packet buffer
-    /// @param buf_len length of packet buffer
     /// @param offset offset to option data
     /// @param parse_len specified option data length
     ///
     /// @return offset to the next unparsed char (just after parsed option)
     ///
-    virtual unsigned int
-    unpack(const boost::shared_array<uint8_t>& buf,
-           unsigned int buf_len,
-           unsigned int offset,
-           unsigned int parse_len);
+    virtual void unpack(OptionBufferConstIter begin,
+                        OptionBufferConstIter end);
 
     virtual std::string toText(int indent = 0);
 
     /// @brief Sets a single address.
     ///
     /// @param addr a single address to be added
-    ///
     void setAddress(const isc::asiolink::IOAddress& addr);
 
     /// @brief Sets list of addresses.
     ///
     /// @param addrs a vector of addresses to be added
-    ///
     void setAddresses(const AddressContainer& addrs);
 
     /// @brief Returns vector with addresses.
@@ -110,8 +88,7 @@ public:
     /// a couple (1-3) addresses, the overhead is not that big.
     ///
     /// @return address container with addresses
-    AddressContainer
-    getAddresses() { return addrs_; };
+    AddressContainer getAddresses() { return addrs_; };
 
     // returns data length (data length + DHCPv4/DHCPv6 option header)
     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
 // purpose with or without fee is hereby granted, provided that the above
@@ -15,12 +15,12 @@
 #include <stdint.h>
 #include <arpa/inet.h>
 #include <sstream>
-#include "exceptions/exceptions.h"
 
-#include "dhcp/libdhcp++.h"
-#include "dhcp/option6_ia.h"
-#include "dhcp/dhcp6.h"
-#include "util/io_utilities.h"
+#include <exceptions/exceptions.h>
+#include <dhcp/libdhcp++.h>
+#include <dhcp/option6_ia.h>
+#include <dhcp/dhcp6.h>
+#include <util/io_utilities.h>
 
 using namespace std;
 using namespace isc;
@@ -32,65 +32,36 @@ Option6IA::Option6IA(unsigned short type, unsigned int iaid)
 }
 
 Option6IA::Option6IA(unsigned short type,
-                     const boost::shared_array<uint8_t>& buf,
-                     unsigned int buf_len,
-                     unsigned int offset,
-                     unsigned int option_len)
+                     OptionBufferConstIter begin,
+                     OptionBufferConstIter end)
     :Option(Option::V6, type) {
-    unpack(buf, buf_len, offset, option_len);
+    unpack(begin, end);
 }
 
-unsigned int
-Option6IA::pack(boost::shared_array<uint8_t>& buf,
-                unsigned int buf_len,
-                unsigned int offset) {
-    if (offset + len() > buf_len) {
-        isc_throw(OutOfRange, "Failed to pack IA option: len=" << len()
-                  << ", 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;
+void Option6IA::pack(isc::util::OutputBuffer& buf) {
+    buf.writeUint16(type_);
+    buf.writeUint16(len() - OPTION6_HDR_LEN);
+    buf.writeUint32(iaid_);
+    buf.writeUint32(t1_);
+    buf.writeUint32(t2_);
 
-    ptr = writeUint32(iaid_, ptr);
-    ptr = writeUint32(t1_, ptr);
-    ptr = writeUint32(t2_, ptr);
-    offset += OPTION6_IA_LEN;
-
-    offset = LibDHCP::packOptions6(buf, buf_len, offset, options_);
-    return offset;
+    LibDHCP::packOptions6(buf, options_);
 }
 
-unsigned int
-Option6IA::unpack(const boost::shared_array<uint8_t>& buf,
-                  unsigned int buf_len,
-                  unsigned int offset,
-                  unsigned int parse_len) {
-    if ( parse_len < OPTION6_IA_LEN || offset + OPTION6_IA_LEN > buf_len) {
+void Option6IA::unpack(OptionBufferConstIter begin,
+                       OptionBufferConstIter end) {
+    if (distance(begin, end) < 12) {
         isc_throw(OutOfRange, "Option " << type_ << " truncated");
     }
+    iaid_ = readUint32( &(*begin) );
+    begin += sizeof(uint32_t);
+    t1_ = readUint32( &(*begin) );
+    begin += sizeof(uint32_t);
 
-    iaid_ = readUint32(&buf[offset]);
-    offset += 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_);
+    t2_ = readUint32( &(*begin) );
+    begin += sizeof(uint32_t);
 
-    return (offset);
+    LibDHCP::unpackOptions6(OptionBuffer(begin, end), options_);
 }
 
 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
 // 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
     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 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
-    ///
-    /// 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
+    /// @brief Ctor, used for received options.
     ///
     /// @param type option type (usually 4 for IA_NA, 25 for IA_PD)
-    /// @param buf buffer to be parsed
-    /// @param buf_len buffer length
-    /// @param offset offset in buffer
-    /// @param len number of bytes to parse
-    Option6IA(uint16_t type, const boost::shared_array<uint8_t>& buf,
-              unsigned int buf_len, unsigned int offset, unsigned int len);
+    /// @param begin iterator to first byte of option data
+    /// @param end iterator to end of option data (first byte after option end)
+    Option6IA(uint16_t type, OptionBuffer::const_iterator begin,
+              OptionBuffer::const_iterator end);
 
     /// Writes option in wire-format to buf, returns pointer to first unused
     /// byte after stored option.
     ///
     /// @param buf buffer (option will be stored here)
-    /// @param buf_len (buffer length)
-    /// @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);
+    void pack(isc::util::OutputBuffer& buf);
 
     /// @brief Parses received buffer
     ///
     /// Parses received buffer and returns offset to the first unused byte after
     /// parsed option.
     ///
-    /// @param buf pointer to buffer
-    /// @param buf_len length of buf
-    /// @param offset offset, where start parsing option
-    /// @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);
+    /// @param begin iterator to first byte of option data
+    /// @param end iterator to end of option data (first byte after option end)
+    virtual void unpack(OptionBufferConstIter begin, OptionBufferConstIter end);
 
     /// Provides human readable text representation
     ///
@@ -87,48 +67,46 @@ public:
     /// Sets T1 timer.
     ///
     /// @param t1 t1 value to be set
-    void setT1(unsigned int t1) { t1_=t1; }
-
+    void setT1(uint32_t t1) { t1_=t1; }
 
     /// Sets T2 timer.
     ///
     /// @param t2 t2 value to be set
-    void setT2(unsigned int t2) { t2_=t2; }
+    void setT2(uint32_t t2) { t2_=t2; }
 
     /// Returns IA identifier.
     ///
     /// @return IAID value.
     ///
-    unsigned int getIAID() const { return iaid_; }
+    uint32_t getIAID() const { return iaid_; }
 
     /// Returns T1 timer.
     ///
     /// @return T1 value.
-    unsigned int getT1() const { return t1_; }
+    uint32_t getT1() const { return t1_; }
 
     /// Returns T2 timer.
     ///
     /// @return T2 value.
-    unsigned int getT2() const { return t2_; }
+    uint32_t getT2() const { return t2_; }
 
     /// @brief returns complete length of option
     ///
     /// Returns length of this option, including option header and suboptions
     ///
     /// @return length of this option
-    virtual uint16_t
-    len();
+    virtual uint16_t len();
 
 protected:
 
     /// keeps IA identifier
-    unsigned int iaid_;
+    uint32_t iaid_;
 
     /// keeps T1 timer value
-    unsigned int t1_;
+    uint32_t t1_;
 
     /// keeps T2 timer value
-    unsigned int t2_;
+    uint32_t t2_;
 };
 
 } // 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
 // purpose with or without fee is hereby granted, provided that the above
@@ -36,67 +36,47 @@ Option6IAAddr::Option6IAAddr(unsigned short type,
      valid_(valid) {
 }
 
-Option6IAAddr::Option6IAAddr(unsigned short type,
-                             boost::shared_array<uint8_t> buf,
-                             unsigned int buf_len, unsigned int offset,
-                             unsigned int option_len)
+Option6IAAddr::Option6IAAddr(uint32_t type, OptionBuffer::const_iterator begin,
+                             OptionBuffer::const_iterator end)
     :Option(V6, type), addr_("::") {
-    unpack(buf, buf_len, offset, option_len);
+    unpack(begin, end);
 }
 
-unsigned int
-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];
+void Option6IAAddr::pack(isc::util::OutputBuffer& buf) {
 
-    ptr = writeUint16(type_, ptr);
+    buf.writeUint16(type_);
 
     // len() returns complete option length. len field contains
     // length without 4-byte option header
-    ptr = writeUint16(len() - OPTION6_HDR_LEN, ptr);
-    offset += OPTION6_HDR_LEN;
+    buf.writeUint16(len() - getHeaderLen());
 
-    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);
-    offset += OPTION6_IAADDR_LEN;
+    buf.writeUint32(preferred_);
+    buf.writeUint32(valid_);
 
-    // parse suboption (there shouldn't be any)
-    offset = LibDHCP::packOptions6(buf, buf_len, offset, options_);
-    return offset;
+    // parse suboption (there shouldn't be any for IAADDR)
+    LibDHCP::packOptions6(buf, options_);
 }
 
-unsigned int
-Option6IAAddr::unpack(const boost::shared_array<uint8_t>& buf,
-                  unsigned int buf_len,
-                  unsigned int offset,
-                  unsigned int parse_len) {
-    if ( parse_len < OPTION6_IAADDR_LEN || offset + OPTION6_IAADDR_LEN > buf_len) {
+void Option6IAAddr::unpack(OptionBuffer::const_iterator begin,
+                      OptionBuffer::const_iterator end) {
+    if ( distance(begin, end) < OPTION6_IAADDR_LEN) {
         isc_throw(OutOfRange, "Option " << type_ << " truncated");
     }
 
     // 16 bytes: IPv6 address
-    addr_ = IOAddress::from_bytes(AF_INET6, &buf[offset]);
-    offset += V6ADDRESS_LEN;
-
-    preferred_ = readUint32(&buf[offset]);
-    offset += sizeof(uint32_t);
+    addr_ = IOAddress::from_bytes(AF_INET6, &(*begin));
+    begin += V6ADDRESS_LEN;
 
-    valid_ = readUint32(&buf[offset]);
-    offset += sizeof(uint32_t);
-    offset = LibDHCP::unpackOptions6(buf, buf_len, offset,
-                                     parse_len - 24, options_);
+    preferred_ = readUint32( &(*begin) );
+    begin += sizeof(uint32_t);
 
-    return offset;
+    valid_ = readUint32( &(*begin) );
+    begin += sizeof(uint32_t);
+    LibDHCP::unpackOptions6(OptionBuffer(begin, end), options_);
 }
 
 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
 // 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
     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 addr reference to an address
     /// @param preferred address preferred lifetime (in seconds)
     /// @param valid address valid lifetime (in seconds)
-    Option6IAAddr(unsigned short type, const isc::asiolink::IOAddress& addr,
-                  unsigned int preferred, unsigned int valid);
+    Option6IAAddr(uint16_t type, const isc::asiolink::IOAddress& addr,
+                  uint32_t preferred, uint32_t valid);
 
-    /// 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
+    /// @brief ctor, used for received options.
     ///
     /// @param type option type
-    /// @param buf pointer to a buffer
-    /// @param offset offset to first data byte in that buffer
-    /// @param len data length of this option
-    Option6IAAddr(unsigned short type, boost::shared_array<uint8_t> buf,
-                  unsigned int buf_len, unsigned int offset, unsigned int len);
+    /// @param begin iterator to first byte of option data
+    /// @param end iterator to end of option data (first byte after option end)
+    Option6IAAddr(uint32_t type, OptionBuffer::const_iterator begin,
+                  OptionBuffer::const_iterator end);
 
     /// @brief Writes option in wire-format.
     ///
@@ -56,13 +50,7 @@ public:
     /// byte after stored option.
     ///
     /// @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
-    unsigned int
-    pack(boost::shared_array<uint8_t>& buf, unsigned int buf_len,
-         unsigned int offset);
+    void pack(isc::util::OutputBuffer& buf);
 
     /// @brief Parses buffer.
     ///
@@ -70,16 +58,10 @@ public:
     /// parsed option.
     ///
     /// @param buf pointer to buffer
-    /// @param buf_len length of buf
-    /// @param offset offset, where start parsing option
-    /// @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);
+    /// @param begin iterator to first byte of option data
+    /// @param end iterator to end of option data (first byte after option end)
+    virtual void unpack(OptionBufferConstIter begin,
+                        OptionBufferConstIter end);
 
     /// 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
 // purpose with or without fee is hereby granted, provided that the above
@@ -18,7 +18,6 @@
 #include <iostream>
 #include <vector>
 #include <boost/shared_ptr.hpp>
-#include <boost/shared_array.hpp>
 #include "asiolink/io_address.h"
 #include "util/buffer.h"
 #include "dhcp/option.h"
@@ -103,8 +102,7 @@ public:
     /// This function is useful mainly for debugging.
     ///
     /// @return string with text representation
-    std::string
-    toText();
+    std::string toText();
 
     /// @brief Returns the size of the required buffer to build the packet.
     ///
@@ -112,118 +110,110 @@ public:
     /// the current set of packet options.
     ///
     /// @return number of bytes required to build this packet
-    size_t
-    len();
+    size_t len();
 
-    /// Sets hops field
+    /// @brief Sets hops field.
     ///
     /// @param hops value to be set
-    void
-    setHops(uint8_t hops) { hops_ = hops; };
+    void setHops(uint8_t hops) { hops_ = hops; };
 
-    /// Returns hops field
+    /// @brief Returns hops field.
     ///
     /// @return hops field
-    uint8_t
-    getHops() const { return (hops_); };
+    uint8_t getHops() const { return (hops_); };
 
     // Note: There's no need to manipulate OP field directly,
     // thus no setOp() method. See op_ comment.
 
-    /// Returns op field
+    /// @brief Returns op field.
     ///
     /// @return op field
-    uint8_t
-    getOp() const { return (op_); };
+    uint8_t getOp() const { return (op_); };
 
-    /// Sets secs field
+    /// @brief Sets secs field.
     ///
     /// @param secs value to be set
-    void
-    setSecs(uint16_t secs) { secs_ = secs; };
+    void setSecs(uint16_t secs) { secs_ = secs; };
 
-    /// Returns secs field
+    /// @brief Returns secs field.
     ///
     /// @return secs field
-    uint16_t
-    getSecs() const { return (secs_); };
+    uint16_t getSecs() const { return (secs_); };
 
-    /// Sets flags field
+    /// @brief Sets flags field.
     ///
     /// @param flags value to be set
-    void
-    setFlags(uint16_t flags) { flags_ = flags; };
+    void setFlags(uint16_t flags) { flags_ = flags; };
 
-    /// Returns flags field
+    /// @brief Returns flags field.
     ///
     /// @return flags field
-    uint16_t
-    getFlags() const { return (flags_); };
+    uint16_t getFlags() const { return (flags_); };
 
 
-    /// Returns ciaddr field
+    /// @brief Returns ciaddr field.
     ///
     /// @return ciaddr field
     const isc::asiolink::IOAddress&
     getCiaddr() const { return (ciaddr_); };
 
-    /// Sets ciaddr field
+    /// @brief Sets ciaddr field.
     ///
     /// @param ciaddr value to be set
     void
     setCiaddr(const isc::asiolink::IOAddress& ciaddr) { ciaddr_ = ciaddr; };
 
 
-    /// Returns siaddr field
+    /// @brief Returns siaddr field.
     ///
     /// @return siaddr field
     const isc::asiolink::IOAddress&
     getSiaddr() const { return (siaddr_); };
 
-    /// Sets siaddr field
+    /// @brief Sets siaddr field.
     ///
     /// @param siaddr value to be set
     void
     setSiaddr(const isc::asiolink::IOAddress& siaddr) { siaddr_ = siaddr; };
 
 
-    /// Returns yiaddr field
+    /// @brief Returns yiaddr field.
     ///
     /// @return yiaddr field
     const isc::asiolink::IOAddress&
     getYiaddr() const { return (yiaddr_); };
 
-    /// Sets yiaddr field
+    /// @brief Sets yiaddr field.
     ///
     /// @param yiaddr value to be set
     void
     setYiaddr(const isc::asiolink::IOAddress& yiaddr) { yiaddr_ = yiaddr; };
 
 
-    /// Returns giaddr field
+    /// @brief Returns giaddr field.
     ///
     /// @return giaddr field
     const isc::asiolink::IOAddress&
     getGiaddr() const { return (giaddr_); };
 
-    /// Sets giaddr field
+    /// @brief Sets giaddr field.
     ///
     /// @param giaddr value to be set
     void
     setGiaddr(const isc::asiolink::IOAddress& giaddr) { giaddr_ = giaddr; };
 
-    /// Returns value of transaction-id field
+    /// @brief Returns value of transaction-id field.
     ///
     /// @return transaction-id
     uint32_t getTransid() const { return (transid_); };
 
-    /// Returns message type (e.g. 1 = DHCPDISCOVER)
+    /// @brief Returns message type (e.g. 1 = DHCPDISCOVER).
     ///
     /// @return message type
     uint8_t
     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
     void setType(uint8_t type) { msg_type_=type; };
@@ -234,14 +224,13 @@ public:
     /// null-terminated. Do not use strlen() or similar on it.
     ///
     /// @return sname field
-    const std::vector<uint8_t>
+    const OptionBuffer
     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
-    void
-    setSname(const uint8_t* sname, size_t snameLen = MAX_SNAME_LEN);
+    void setSname(const uint8_t* sname, size_t snameLen = MAX_SNAME_LEN);
 
     /// @brief Returns file field
     ///
@@ -249,7 +238,7 @@ public:
     /// null-terminated. Do not use strlen() or similar on it.
     ///
     /// @return pointer to file field
-    const std::vector<uint8_t>
+    const OptionBuffer
     getFile() const { return (std::vector<uint8_t>(file_, &file_[MAX_FILE_LEN])); };
 
     /// Sets file field
@@ -478,7 +467,7 @@ protected:
 
     // end of real DHCPv4 fields
 
-    /// output buffer (used during message
+    /// output buffer (used during message transmission)
     isc::util::OutputBuffer bufferOut_;
 
     // that's the data of input buffer used in RX packet. Note that
@@ -496,6 +485,8 @@ protected:
     isc::dhcp::Option::OptionCollection options_;
 }; // Pkt4 class
 
+typedef boost::shared_ptr<Pkt4> Pkt4Ptr;
+
 } // isc::dhcp 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
 // purpose with or without fee is hereby granted, provided that the above
@@ -25,43 +25,36 @@ using namespace isc::dhcp;
 
 namespace isc {
 
-Pkt6::Pkt6(unsigned int dataLen, DHCPv6Proto proto /* = UDP */)
-    :data_len_(dataLen),
-     local_addr_("::"),
-     remote_addr_("::"),
-     iface_(""),
-     ifindex_(-1),
-     local_port_(-1),
-     remote_port_(-1),
-     proto_(proto),
-     msg_type_(-1),
-     transid_(rand()%0xffffff)
-{
-
-    data_ = boost::shared_array<uint8_t>(new uint8_t[dataLen]);
-    data_len_ = dataLen;
+Pkt6::Pkt6(const uint8_t* buf, uint32_t buf_len, DHCPv6Proto proto /* = UDP */) :
+    proto_(proto),
+    msg_type_(-1),
+    transid_(rand()%0xffffff),
+    iface_(""),
+    ifindex_(-1),
+    local_addr_("::"),
+    remote_addr_("::"),
+    local_port_(-1),
+    remote_port_(-1),
+    bufferOut_(0) {
+    data_.resize(buf_len);
+    memcpy(&data_[0], buf, buf_len);
 }
 
-Pkt6::Pkt6(uint8_t msg_type,
-           unsigned int transid,
-           DHCPv6Proto proto /*= UDP*/)
-    :local_addr_("::"),
-     remote_addr_("::"),
-     iface_(""),
-     ifindex_(-1),
-     local_port_(-1),
-     remote_port_(-1),
-     proto_(proto),
-     msg_type_(msg_type),
-     transid_(transid) {
-
-    data_ = boost::shared_array<uint8_t>(new uint8_t[4]);
-    data_len_ = 4;
+Pkt6::Pkt6(uint8_t msg_type, unsigned int transid, DHCPv6Proto proto /*= UDP*/) :
+    proto_(proto),
+    msg_type_(msg_type),
+    transid_(transid),
+    iface_(""),
+    ifindex_(-1),
+    local_addr_("::"),
+    remote_addr_("::"),
+    local_port_(-1),
+    remote_port_(-1),
+    bufferOut_(0) {
 }
 
-unsigned short
-Pkt6::len() {
-    unsigned int length = DHCPV6_PKT_HDR_LEN; // DHCPv6 header
+uint16_t Pkt6::len() {
+    uint16_t length = DHCPV6_PKT_HDR_LEN; // DHCPv6 header
 
     for (Option::OptionCollection::iterator it = options_.begin();
          it != options_.end();
@@ -95,44 +88,21 @@ Pkt6::packUDP() {
     // It is better to implement a method in IOAddress that extracts
     // 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 {
         // DHCPv6 header: message-type (1 octect) + transaction id (3 octets)
-        data_[0] = msg_type_;
-
+        bufferOut_.writeUint8(msg_type_);
         // store 3-octet transaction-id
-        data_[1] = (transid_ >> 16) & 0xff;
-        data_[2] = (transid_ >> 8) & 0xff;
-        data_[3] = (transid_) & 0xff;
+        bufferOut_.writeUint8( (transid_ >> 16) & 0xff );
+        bufferOut_.writeUint8( (transid_ >> 8) & 0xff );
+        bufferOut_.writeUint8( (transid_) & 0xff );
 
         // the rest are options
-        unsigned short offset = LibDHCP::packOptions6(data_, length,
-                                                      4/*offset*/,
-                                                      options_);
-
-        // sanity check
-        if (offset != length) {
-            isc_throw(OutOfRange, "Packet build failed: expected size="
-                      << length << ", actual len=" << offset);
-        }
+        LibDHCP::packOptions6(bufferOut_, options_);
     }
     catch (const Exception& e) {
         cout << "Packet build failed:" << e.what() << endl;
         return (false);
     }
-    // Limited verbosity of this method
-    // cout << "Packet built, len=" << len() << endl;
     return (true);
 }
 
@@ -158,8 +128,8 @@ Pkt6::unpack() {
 
 bool
 Pkt6::unpackUDP() {
-    if (data_len_ < 4) {
-        std::cout << "DHCPv6 packet truncated. Only " << data_len_
+    if (data_.size() < 4) {
+        std::cout << "DHCPv6 packet truncated. Only " << data_.size()
                   << " bytes. Need at least 4." << std::endl;
         return (false);
     }
@@ -168,16 +138,13 @@ Pkt6::unpackUDP() {
         ((data_[2]) << 8) + (data_[3]);
     transid_ = transid_ & 0xffffff;
 
-    unsigned int offset = LibDHCP::unpackOptions6(data_,
-                                                  data_len_,
-                                                  4, //offset
-                                                  data_len_ - 4,
-                                                  options_);
-    if (offset != data_len_) {
-        cout << "DHCPv6 packet contains trailing garbage. Parsed "
-             << offset << " bytes, packet is " << data_len_ << " bytes."
-             << endl;
-        // just a warning. Ignore trailing garbage and continue
+    try {
+        OptionBuffer opt_buffer(data_.begin() + 4, data_.end());
+
+        LibDHCP::unpackOptions6(opt_buffer, options_);
+    } catch (const Exception& e) {
+        cout << "Packet parsing failed:" << e.what() << endl;
+        return (false);
     }
     return (true);
 }
@@ -229,4 +196,11 @@ Pkt6::delOption(unsigned short type) {
     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
 // 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 transid transaction-id
     /// @param proto protocol (TCP or UDP)
-    Pkt6(unsigned char msg_type,
-         unsigned int transid,
+    Pkt6(uint8_t msg_type,
+         uint32_t transid,
          DHCPv6Proto proto = UDP);
 
     /// Constructor, used in message transmission
     ///
     /// 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)
-    Pkt6(unsigned int len, DHCPv6Proto proto = UDP);
+    Pkt6(const uint8_t* buf, uint32_t len, DHCPv6Proto proto = UDP);
 
     /// @brief Prepares on-wire format.
     ///
@@ -61,8 +62,7 @@ public:
     /// will be set in data_len_.
     ///
     /// @return true if packing procedure was successful
-    bool
-    pack();
+    bool pack();
 
     /// @brief Dispatch method that handles binary packet parsing.
     ///
@@ -70,59 +70,70 @@ public:
     /// unpackTCP).
     ///
     /// @return true if parsing was successful
-    bool
-    unpack();
+    bool 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
-    DHCPv6Proto
-    getProto();
+    DHCPv6Proto getProto();
 
     /// Sets protocol of this packet.
     ///
     /// @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.
     ///
     /// This function is useful mainly for debugging.
     ///
     /// @return string with text representation
-    std::string
-    toText();
+    std::string toText();
 
     /// @brief Returns calculated length of the packet.
     ///
-    /// This function returns size of required buffer to buld this packet.
-    /// To use that function, options_ field must be set.
+    /// This function returns size of all options including DHCPv6
+    /// header. To use that function, options_ field must be set.
     ///
     /// @return number of bytes required to build this packet
-    unsigned short
-    len();
+    uint16_t len();
 
     /// Returns message type (e.g. 1 = SOLICIT)
     ///
     /// @return message type
-    unsigned char
-    getType() { return (msg_type_); }
+    uint8_t getType() { return (msg_type_); }
 
     /// Sets message type (e.g. 1 = SOLICIT)
     ///
     /// @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
     ///
     /// @return transaction-id
-    unsigned int getTransid() { return (transid_); };
+    uint32_t getTransid() { return (transid_); };
 
     /// Adds an option to this packet.
     ///
     /// @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.
     ///
@@ -133,49 +144,93 @@ public:
     /// @param opt_type option type we are looking for
     ///
     /// @return pointer to found option (or NULL)
-    boost::shared_ptr<isc::dhcp::Option>
-    getOption(unsigned short type);
+    OptionPtr getOption(uint16_t type);
 
     /// Attempts to delete first suboption of requested type
     ///
     /// @param type Type of option to be deleted.
     ///
     /// @return true if option was deleted, false if no such option existed
-    bool
-    delOption(unsigned short type);
+    bool delOption(uint16_t type);
 
-    /// TODO need getter/setter wrappers
-    ///      and hide following fields as protected
+    /// @brief This method copies data from output buffer to input buffer
+    ///
+    /// This is useful only in testing
+    void repack();
 
-    /// buffer that holds memory. It is shared_array as options may
-    /// share pointer to this buffer
-    boost::shared_array<uint8_t> data_;
+    /// @brief Sets remote address.
+    ///
+    /// @params remote specifies remote address
+    void setRemoteAddr(const isc::asiolink::IOAddress& remote) {
+        remote_addr_ = remote;
+    }
 
-    /// length of the data
-    unsigned int data_len_;
+    /// @brief Returns remote address
+    ///
+    /// @return remote address
+    const isc::asiolink::IOAddress& getRemoteAddr() {
+        return (remote_addr_);
+    }
 
-    /// local address (dst if receiving packet, src if sending packet)
-    isc::asiolink::IOAddress local_addr_;
+    /// @brief Sets local address.
+    ///
+    /// @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)
-    isc::asiolink::IOAddress remote_addr_;
+    /// @brief Returns local address.
+    ///
+    /// @return local address
+    const isc::asiolink::IOAddress& getLocalAddr() {
+        return (local_addr_);
+    }
 
-    /// name of the network interface the packet was received/to be sent over
-    std::string iface_;
+    /// @brief Sets local port.
+    ///
+    /// @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
-    /// 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_;
+    /// @return local port
+    uint16_t getLocalPort() { return (local_port_); }
 
-    /// local TDP or UDP port
-    int local_port_;
+    /// @brief Sets remote port.
+    ///
+    /// @params remote specifies remote port
+    void setRemotePort(uint16_t remote) { remote_port_ = remote; }
 
-    /// remote TCP or UDP port
-    int remote_port_;
+    /// @brief Returns 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
 
@@ -225,8 +280,40 @@ protected:
 
     /// DHCPv6 transaction-id
     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
 
+typedef boost::shared_ptr<Pkt6> Pkt6Ptr;
+
 } // isc::dhcp 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
 // purpose with or without fee is hereby granted, provided that the above
@@ -263,8 +263,8 @@ TEST_F(IfaceMgrTest, sockets6) {
 
     IOAddress loAddr("::1");
 
-    Pkt6 pkt6(128);
-    pkt6.iface_ = LOOPBACK;
+    Pkt6 pkt6(DHCPV6_SOLICIT, 123);
+    pkt6.setIface(LOOPBACK);
 
     // bind multicast socket to port 10547
     int socket1 = ifacemgr->openSocket(LOOPBACK, loAddr, 10547);
@@ -335,19 +335,22 @@ TEST_F(IfaceMgrTest, sendReceive6) {
     EXPECT_GT(socket1, 0);
     EXPECT_GT(socket2, 0);
 
-    boost::shared_ptr<Pkt6> sendPkt(new Pkt6(128) );
 
     // prepare dummy payload
+    uint8_t data[128];
     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->remote_addr_ = IOAddress("::1");
-    sendPkt->ifindex_ = 1;
-    sendPkt->iface_ = LOOPBACK;
+    sendPkt->repack();
 
-    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));
 
@@ -356,17 +359,17 @@ TEST_F(IfaceMgrTest, sendReceive6) {
     ASSERT_TRUE( rcvPkt ); // received our own packet
 
     // let's check that we received what was sent
-    EXPECT_EQ(sendPkt->data_len_, rcvPkt->data_len_);
-    EXPECT_EQ(0, memcmp(&sendPkt->data_[0], &rcvPkt->data_[0],
-                        rcvPkt->data_len_) );
+    ASSERT_EQ(sendPkt->getData().size(), rcvPkt->getData().size());
+    EXPECT_EQ(0, memcmp(&sendPkt->getData()[0], &rcvPkt->getData()[0],
+                        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,
     // 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
     // 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;
 }
@@ -556,7 +559,7 @@ TEST_F(IfaceMgrTest, socketInfo) {
     loopback->addSocket(sock1);
     loopback->addSocket(sock2);
 
-    Pkt6 pkt6(100);
+    Pkt6 pkt6(DHCPV6_REPLY, 123456);
 
     // pkt6 dos not have interface set yet
     EXPECT_THROW(
@@ -565,14 +568,14 @@ TEST_F(IfaceMgrTest, socketInfo) {
     );
 
     // try to send over non-existing interface
-    pkt6.iface_ = "nosuchinterface45";
+    pkt6.setIface("nosuchinterface45");
     EXPECT_THROW(
         ifacemgr->getSocket(pkt6),
         BadValue
     );
 
     // this will work
-    pkt6.iface_ = LOOPBACK;
+    pkt6.setIface(LOOPBACK);
     EXPECT_EQ(9, ifacemgr->getSocket(pkt6));
 
     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
 // purpose with or without fee is hereby granted, provided that the above
@@ -42,7 +42,7 @@ static const uint8_t packed[] = {
 };
 
 TEST(LibDhcpTest, packOptions6) {
-    boost::shared_array<uint8_t> buf(new uint8_t[512]);
+    OptionBuffer buf(512);
     isc::dhcp::Option::OptionCollection opts; // list of options
 
     // generate content for options
@@ -50,24 +50,25 @@ TEST(LibDhcpTest, packOptions6) {
         buf[i]=i+100;
     }
 
-    boost::shared_ptr<Option> opt1(new Option(Option::V6, 12, buf, 0, 5));
-    boost::shared_ptr<Option> opt2(new Option(Option::V6, 13, buf, 5, 3));
-    boost::shared_ptr<Option> opt3(new Option(Option::V6, 14, buf, 8, 2));
-    boost::shared_ptr<Option> opt4(new Option(Option::V6,256, buf,10, 4));
-    boost::shared_ptr<Option> opt5(new Option(Option::V6,257, buf,14, 1));
+    OptionPtr opt1(new Option(Option::V6, 12, buf.begin() + 0, buf.begin() + 5));
+    OptionPtr opt2(new Option(Option::V6, 13, buf.begin() + 5, buf.begin() + 8));
+    OptionPtr opt3(new Option(Option::V6, 14, buf.begin() + 8, buf.begin() + 10));
+    OptionPtr opt4(new Option(Option::V6,256, buf.begin() + 10,buf.begin() + 14));
+    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, boost::shared_ptr<Option> >(opt1->getType(), opt2));
-    opts.insert(pair<int, boost::shared_ptr<Option> >(opt1->getType(), opt3));
-    opts.insert(pair<int, boost::shared_ptr<Option> >(opt1->getType(), opt4));
-    opts.insert(pair<int, boost::shared_ptr<Option> >(opt1->getType(), opt5));
+    opts.insert(pair<int, OptionPtr >(opt1->getType(), opt1));
+    opts.insert(pair<int, OptionPtr >(opt1->getType(), opt2));
+    opts.insert(pair<int, OptionPtr >(opt1->getType(), opt3));
+    opts.insert(pair<int, OptionPtr >(opt1->getType(), opt4));
+    opts.insert(pair<int, OptionPtr >(opt1->getType(), opt5));
+
+    OutputBuffer assembled(512);
 
-    unsigned int offset;
     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(0, memcmp(&buf[100], packed, 35) );
+    EXPECT_EQ(35, assembled.getLength()); // options should take 35 bytes
+    EXPECT_EQ(0, memcmp(assembled.getData(), packed, 35) );
 }
 
 TEST(LibDhcpTest, unpackOptions6) {
@@ -78,17 +79,13 @@ TEST(LibDhcpTest, unpackOptions6) {
     // specific derived classes.
     isc::dhcp::Option::OptionCollection options; // list of options
 
-    // we can't use packed directly, as shared_array would try to
-    // free it eventually
-    boost::shared_array<uint8_t> buf(new uint8_t[512]);
+    OptionBuffer buf(512);
     memcpy(&buf[0], packed, 35);
 
-    unsigned int offset;
     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
 
     isc::dhcp::Option::OptionCollection::const_iterator x = options.find(12);
@@ -153,18 +150,18 @@ TEST(LibDhcpTest, packOptions4) {
         payload[i][2] = i*10+2;
     }
 
-    boost::shared_ptr<Option> opt1(new Option(Option::V4, 12, payload[0]));
-    boost::shared_ptr<Option> opt2(new Option(Option::V4, 13, payload[1]));
-    boost::shared_ptr<Option> opt3(new Option(Option::V4, 14, payload[2]));
-    boost::shared_ptr<Option> opt4(new Option(Option::V4,254, payload[3]));
-    boost::shared_ptr<Option> opt5(new Option(Option::V4,128, payload[4]));
+    OptionPtr opt1(new Option(Option::V4, 12, payload[0]));
+    OptionPtr opt2(new Option(Option::V4, 13, payload[1]));
+    OptionPtr opt3(new Option(Option::V4, 14, payload[2]));
+    OptionPtr opt4(new Option(Option::V4,254, payload[3]));
+    OptionPtr opt5(new Option(Option::V4,128, payload[4]));
 
     isc::dhcp::Option::OptionCollection opts; // list of options
-    opts.insert(pair<int, boost::shared_ptr<Option> >(opt1->getType(), opt1));
-    opts.insert(pair<int, boost::shared_ptr<Option> >(opt1->getType(), opt2));
-    opts.insert(pair<int, boost::shared_ptr<Option> >(opt1->getType(), opt3));
-    opts.insert(pair<int, boost::shared_ptr<Option> >(opt1->getType(), opt4));
-    opts.insert(pair<int, boost::shared_ptr<Option> >(opt1->getType(), opt5));
+    opts.insert(pair<int, OptionPtr >(opt1->getType(), opt1));
+    opts.insert(pair<int, OptionPtr >(opt1->getType(), opt2));
+    opts.insert(pair<int, OptionPtr >(opt1->getType(), opt3));
+    opts.insert(pair<int, OptionPtr >(opt1->getType(), opt4));
+    opts.insert(pair<int, OptionPtr >(opt1->getType(), opt5));
 
     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
 // purpose with or without fee is hereby granted, provided that the above
@@ -21,17 +21,24 @@
 #include <dhcp/dhcp6.h>
 #include <dhcp/option.h>
 #include <dhcp/option6_addrlst.h>
+#include <util/buffer.h>
 
 using namespace std;
 using namespace isc;
 using namespace isc::dhcp;
 using namespace isc::asiolink;
+using namespace isc::util;
 
 namespace {
 class Option6AddrLstTest : public ::testing::Test {
 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) {
@@ -97,16 +104,12 @@ TEST_F(Option6AddrLstTest, basic) {
         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
     };
 
-    boost::shared_array<uint8_t> buf(new uint8_t[300]);
-    for (int i = 0; i < 300; i++)
-        buf[i] = 0;
-
-    memcpy(&buf[0], sampledata, 48);
+    memcpy(&buf_[0], sampledata, 48);
 
     // just a single address
     Option6AddrLst* opt1 = 0;
     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());
@@ -118,17 +121,16 @@ TEST_F(Option6AddrLstTest, basic) {
     IOAddress addr = addrs[0];
     EXPECT_EQ("2001:db8:1::dead:beef", addr.toText());
 
-    // pack this option again in the same buffer, but in
-    // different place
-    int offset = opt1->pack(buf,300, 100);
+    // pack this option
+    opt1->pack(outBuf_);
 
-    EXPECT_EQ(120, offset);
-    EXPECT_EQ( 0, memcmp(expected1, &buf[100], 20) );
+    EXPECT_EQ(20, outBuf_.getLength());
+    EXPECT_EQ( 0, memcmp(expected1, outBuf_.getData(), 20) );
 
     // two addresses
     Option6AddrLst* opt2 = 0;
     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(36, opt2->len());
@@ -137,17 +139,17 @@ TEST_F(Option6AddrLstTest, basic) {
     EXPECT_EQ("2001:db8:1::dead:beef", addrs[0].toText());
     EXPECT_EQ("ff02::face:b00c", addrs[1].toText());
 
-    // pack this option again in the same buffer, but in
-    // different place
-    offset = opt2->pack(buf,300, 150);
+    // pack this option
+    outBuf_.clear();
+    opt2->pack(outBuf_);
 
-    EXPECT_EQ(150+36, offset);
-    EXPECT_EQ( 0, memcmp(expected2, &buf[150], 36));
+    EXPECT_EQ(36, outBuf_.getLength() );
+    EXPECT_EQ( 0, memcmp(expected2, outBuf_.getData(), 36));
 
     // three addresses
     Option6AddrLst* opt3 = 0;
     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());
@@ -158,12 +160,12 @@ TEST_F(Option6AddrLstTest, basic) {
     EXPECT_EQ("ff02::face:b00c", addrs[1].toText());
     EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", addrs[2].toText());
 
-    // pack this option again in the same buffer, but in
-    // different place
-    offset = opt3->pack(buf,300, 200);
+    // pack this option
+    outBuf_.clear();
+    opt3->pack(outBuf_);
 
-    EXPECT_EQ(252, offset);
-    EXPECT_EQ( 0, memcmp(expected3, &buf[200], 52) );
+    EXPECT_EQ(52, outBuf_.getLength());
+    EXPECT_EQ( 0, memcmp(expected3, outBuf_.getData(), 52) );
 
     EXPECT_NO_THROW(
         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
 // purpose with or without fee is hereby granted, provided that the above
@@ -19,53 +19,51 @@
 #include <arpa/inet.h>
 #include <gtest/gtest.h>
 
-#include <boost/shared_array.hpp>
-#include <boost/shared_ptr.hpp>
-
-#include "dhcp/dhcp6.h"
-#include "dhcp/option.h"
-#include "dhcp/option6_ia.h"
-#include "dhcp/option6_iaaddr.h"
+#include <dhcp/dhcp6.h>
+#include <dhcp/option.h>
+#include <dhcp/option6_ia.h>
+#include <dhcp/option6_iaaddr.h>
+#include <util/buffer.h>
 
 using namespace std;
 using namespace isc;
 using namespace isc::dhcp;
 using namespace isc::asiolink;
+using namespace isc::util;
 
 namespace {
 class Option6IATest : public ::testing::Test {
 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) {
+    buf_[0] = 0xa1; // iaid
+    buf_[1] = 0xa2;
+    buf_[2] = 0xa3;
+    buf_[3] = 0xa4;
 
-    boost::shared_array<uint8_t> simple_buf(new uint8_t[128]);
-    for (int i = 0; i < 128; i++)
-        simple_buf[i] = 0;
-    simple_buf[0] = 0xa1; // iaid
-    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;
+    buf_[4] = 0x81; // T1
+    buf_[5] = 0x02;
+    buf_[6] = 0x03;
+    buf_[7] = 0x04;
 
-    simple_buf[8] = 0x84; // T2
-    simple_buf[9] = 0x03;
-    simple_buf[10] = 0x02;
-    simple_buf[11] = 0x01;
+    buf_[8] = 0x84; // T2
+    buf_[9] = 0x03;
+    buf_[10] = 0x02;
+    buf_[11] = 0x01;
 
     // create an option
     // unpack() is called from constructor
     Option6IA* opt = new Option6IA(D6O_IA_NA,
-                                   simple_buf,
-                                   128,
-                                   0,
-                                   12);
+                                   buf_.begin(),
+                                   buf_.begin() + 12);
 
     EXPECT_EQ(Option::V6, opt->getUniverse());
     EXPECT_EQ(D6O_IA_NA, opt->getType());
@@ -77,36 +75,31 @@ TEST_F(Option6IATest, basic) {
     // different place
 
     // test for pack()
-    int offset = opt->pack(simple_buf, 128, 60);
+    opt->pack(outBuf_);
 
-    // 4 bytes header + 4 bytes content
-    EXPECT_EQ(12, opt->len() - 4);
+    // 12 bytes header + 4 bytes content
+    EXPECT_EQ(12, opt->len() - opt->getHeaderLen());
     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:
+    InputBuffer out(outBuf_.getData(), outBuf_.getLength());
+
     // 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
-    EXPECT_EQ(12, simple_buf[62]*256 + simple_buf[63]);
+    EXPECT_EQ(12, out.readUint16());
 
     // if iaid is correct
-    unsigned int iaid = htonl(*(unsigned int*)&simple_buf[64]);
-    EXPECT_EQ(0xa1a2a3a4, iaid );
+    EXPECT_EQ(0xa1a2a3a4, out.readUint32() );
 
    // if T1 is correct
-    EXPECT_EQ(0x81020304, (simple_buf[68] << 24) +
-                          (simple_buf[69] << 16) +
-                          (simple_buf[70] << 8) +
-                          (simple_buf[71]) );
+    EXPECT_EQ(0x81020304, out.readUint32() );
 
     // if T1 is correct
-    EXPECT_EQ(0x84030201, (simple_buf[72] << 24) +
-                          (simple_buf[73] << 16) +
-                          (simple_buf[74] << 8) +
-                          (simple_buf[75]) );
+    EXPECT_EQ(0x84030201, out.readUint32() );
 
     EXPECT_NO_THROW(
         delete opt;
@@ -114,10 +107,6 @@ TEST_F(Option6IATest, basic) {
 }
 
 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);
     ia->setT1(2345);
     ia->setT2(3456);
@@ -133,20 +122,18 @@ TEST_F(Option6IATest, simple) {
     );
 }
 
+
 // test if option can build suboptions
 TEST_F(Option6IATest, suboptions_pack) {
-    boost::shared_array<uint8_t> buf(new uint8_t[128]);
-    for (int i=0; i<128; i++)
-        buf[i] = 0;
-    buf[0] = 0xff;
-    buf[1] = 0xfe;
-    buf[2] = 0xfc;
+    buf_[0] = 0xff;
+    buf_[1] = 0xfe;
+    buf_[2] = 0xfc;
 
     Option6IA * ia = new Option6IA(D6O_IA_NA, 0x13579ace);
     ia->setT1(0x2345);
     ia->setT2(0x3456);
 
-    boost::shared_ptr<Option> sub1(new Option(Option::V6,
+    OptionPtr sub1(new Option(Option::V6,
                                               0xcafe));
 
     boost::shared_ptr<Option6IAAddr> addr1(
@@ -180,20 +167,20 @@ TEST_F(Option6IATest, suboptions_pack) {
         0, 0 // len
     };
 
-    int offset = ia->pack(buf, 128, 10);
-    ASSERT_EQ(offset, 10 + 48);
+    ia->pack(outBuf_);
+    ASSERT_EQ(48, outBuf_.getLength());
 
-    EXPECT_EQ(0, memcmp(&buf[10], expected, 48));
+    EXPECT_EQ(0, memcmp(outBuf_.getData(), expected, 48));
 
     EXPECT_NO_THROW(
         delete ia;
     );
 }
 
+
 // test if option can parse suboptions
 TEST_F(Option6IATest, suboptions_unpack) {
-
-
+    // 48 bytes
     uint8_t expected[] = {
         D6O_IA_NA/256, D6O_IA_NA%256, // type
         0, 28, // length
@@ -214,17 +201,11 @@ TEST_F(Option6IATest, suboptions_unpack) {
         0, 0 // len
     };
 
-    boost::shared_array<uint8_t> buf(new uint8_t[128]);
-    for (int i = 0; i < 128; i++)
-        buf[i] = 0;
-    memcpy(&buf[0], expected, 48);
+    memcpy(&buf_[0], expected, sizeof(expected));
 
     Option6IA* ia = 0;
     EXPECT_NO_THROW({
-        ia = new Option6IA(D6O_IA_NA, buf, 128, 4, 44);
-
-        // let's limit verbosity of this test
-        // cout << "Parsed option:" << endl << ia->toText() << endl;
+            ia = new Option6IA(D6O_IA_NA, buf_.begin() + 4, buf_.begin() + sizeof(expected));
     });
     ASSERT_TRUE(ia);
 
@@ -233,8 +214,8 @@ TEST_F(Option6IATest, suboptions_unpack) {
     EXPECT_EQ(0x2345, ia->getT1());
     EXPECT_EQ(0x3456, ia->getT2());
 
-    boost::shared_ptr<Option> subopt = ia->getOption(D6O_IAADDR);
-    ASSERT_NE(boost::shared_ptr<Option>(), subopt); // non-NULL
+    OptionPtr subopt = ia->getOption(D6O_IAADDR);
+    ASSERT_NE(OptionPtr(), subopt); // non-NULL
 
     // checks for address option
     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
 // purpose with or without fee is hereby granted, provided that the above
@@ -19,61 +19,62 @@
 #include <arpa/inet.h>
 #include <gtest/gtest.h>
 
-#include "dhcp/dhcp6.h"
-#include "dhcp/option.h"
-#include "dhcp/option6_iaaddr.h"
+#include <dhcp/dhcp6.h>
+#include <dhcp/option.h>
+#include <dhcp/option6_iaaddr.h>
+#include <util/buffer.h>
 
 using namespace std;
 using namespace isc;
 using namespace isc::dhcp;
+using namespace isc::util;
 
 namespace {
 class Option6IAAddrTest : public ::testing::Test {
 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) {
-
-    boost::shared_array<uint8_t> simple_buf(new uint8_t[128]);
-    for (int i = 0; i < 128; i++)
-        simple_buf[i] = 0;
-
-    simple_buf[0] = 0x20;
-    simple_buf[1] = 0x01;
-    simple_buf[2] = 0x0d;
-    simple_buf[3] = 0xb8;
-    simple_buf[4] = 0x00;
-    simple_buf[5] = 0x01;
-    simple_buf[12] = 0xde;
-    simple_buf[13] = 0xad;
-    simple_buf[14] = 0xbe;
-    simple_buf[15] = 0xef; // 2001:db8:1::dead:beef
-
-    simple_buf[16] = 0x00;
-    simple_buf[17] = 0x00;
-    simple_buf[18] = 0x03;
-    simple_buf[19] = 0xe8; // 1000
-
-    simple_buf[20] = 0xb2;
-    simple_buf[21] = 0xd0;
-    simple_buf[22] = 0x5e;
-    simple_buf[23] = 0x00; // 3,000,000,000
+    for (int i=0; i<255; i++) {
+        buf_[i]=0;
+    }
+    buf_[0] = 0x20;
+    buf_[1] = 0x01;
+    buf_[2] = 0x0d;
+    buf_[3] = 0xb8;
+    buf_[4] = 0x00;
+    buf_[5] = 0x01;
+    buf_[12] = 0xde;
+    buf_[13] = 0xad;
+    buf_[14] = 0xbe;
+    buf_[15] = 0xef; // 2001:db8:1::dead:beef
+
+    buf_[16] = 0x00;
+    buf_[17] = 0x00;
+    buf_[18] = 0x03;
+    buf_[19] = 0xe8; // 1000
+
+    buf_[20] = 0xb2;
+    buf_[21] = 0xd0;
+    buf_[22] = 0x5e;
+    buf_[23] = 0x00; // 3,000,000,000
 
     // create an option (unpack content)
     Option6IAAddr* opt = new Option6IAAddr(D6O_IAADDR,
-                                           simple_buf,
-                                           128,
-                                           0,
-                                           24);
+                                           buf_.begin(),
+                                           buf_.begin() + 24);
 
-    // pack this option again in the same buffer, but in
-    // different place
-    int offset = opt->pack(simple_buf, 128, 50);
+    // pack this option
+    opt->pack(outBuf_);
 
-    EXPECT_EQ(78, offset);
+    EXPECT_EQ(28, outBuf_.getLength());
 
     EXPECT_EQ(Option::V6, opt->getUniverse());
 
@@ -88,14 +89,16 @@ TEST_F(Option6IAAddrTest, basic) {
               opt->len());
 
     // check if pack worked properly:
+    const uint8_t* out = (const uint8_t*)outBuf_.getData();
+
     // 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
-    EXPECT_EQ(24, simple_buf[52]*256 + simple_buf[53]);
+    EXPECT_EQ(24, out[2]*256 + out[3]);
 
     // 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(
         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
 // purpose with or without fee is hereby granted, provided that the above
@@ -33,14 +33,13 @@ using namespace isc::util;
 namespace {
 class OptionTest : public ::testing::Test {
 public:
-    OptionTest(): outBuffer_(255) {
-        buf_ = boost::shared_array<uint8_t>(new uint8_t[255]);
+    OptionTest(): buf_(255), outBuf_(255) {
         for (int i = 0; i < 255; i++) {
             buf_[i] = 255 - i;
         }
     }
-    boost::shared_array<uint8_t> buf_;
-    OutputBuffer outBuffer_;
+    OptionBuffer buf_;
+    OutputBuffer outBuf_;
 };
 
 // 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
     // that contains 4 bytes of data
     ASSERT_NO_THROW(
-        opt= new Option(Option::V4,
-                        123, // type
-                        data);
+        opt= new Option(Option::V4, 123, data);
     );
 
     // check that content is reported properly
@@ -143,10 +140,7 @@ TEST_F(OptionTest, v4_data2) {
     // Create DHCPv4 option of type 123 that contains
     // 4 bytes (sizeof(dummyPayload).
     ASSERT_NO_THROW(
-        opt= new Option(Option::V4,
-                        123, // type
-                        data.begin() + 1,
-                        data.end() - 1);
+        opt= new Option(Option::V4, 123, data.begin() + 1, data.end() - 1);
     );
 
     // check that content is reported properly
@@ -210,30 +204,29 @@ TEST_F(OptionTest, v6_basic) {
 // tests contructor used in pkt reception
 // option contains actual data
 TEST_F(OptionTest, v6_data1) {
-    boost::shared_array<uint8_t> buf(new uint8_t[32]);
     for (int i = 0; i < 32; i++)
-        buf[i] = 100+i;
-    Option* opt = new Option(Option::V6, 333, //type
-                             buf,
-                             3, // offset
-                             7); // 7 bytes of data
+        buf_[i] = 100+i;
+    Option* opt = new Option(Option::V6, 333,   //type
+                             buf_.begin() + 3,  // begin offset
+                             buf_.begin() + 10); // end offset (7 bytes of data)
     EXPECT_EQ(333, opt->getType());
 
     ASSERT_EQ(11, opt->len());
     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);
-    EXPECT_EQ(31, offset);
+    opt->pack(outBuf_);
+    EXPECT_EQ(11, outBuf_.getLength());
 
-    EXPECT_EQ(buf[20], 333/256); // type
-    EXPECT_EQ(buf[21], 333%256);
+    const uint8_t* out = (const uint8_t*)outBuf_.getData();
+    EXPECT_EQ(out[0], 333/256); // type
+    EXPECT_EQ(out[1], 333%256);
 
-    EXPECT_EQ(buf[22], 0); // len
-    EXPECT_EQ(buf[23], 7);
+    EXPECT_EQ(out[2], 0); // len
+    EXPECT_EQ(out[3], 7);
 
     // payload
-    EXPECT_EQ(0, memcmp(&buf[3], &buf[24], 7) );
+    EXPECT_EQ(0, memcmp(&buf_[3], out+4, 7) );
 
     EXPECT_NO_THROW(
         delete opt;
@@ -244,40 +237,37 @@ TEST_F(OptionTest, v6_data1) {
 // with different input parameters
 TEST_F(OptionTest, v6_data2) {
 
-    boost::shared_array<uint8_t> simple_buf(new uint8_t[128]);
-    for (int i = 0; i < 128; i++)
-        simple_buf[i] = 0;
-    simple_buf[0] = 0xa1;
-    simple_buf[1] = 0xa2;
-    simple_buf[2] = 0xa3;
-    simple_buf[3] = 0xa4;
+    buf_[0] = 0xa1;
+    buf_[1] = 0xa2;
+    buf_[2] = 0xa3;
+    buf_[3] = 0xa4;
 
     // create an option (unpack content)
     Option* opt = new Option(Option::V6,
                              D6O_CLIENTID,
-                             simple_buf,
-                             0,
-                             4);
+                             buf_.begin(),
+                             buf_.begin() + 4);
 
-    // pack this option again in the same buffer, but in
-    // different place
-    int offset18 = opt->pack(simple_buf, 128, 10);
+    // pack this option
+    opt->pack(outBuf_);
 
     // 4 bytes header + 4 bytes content
     EXPECT_EQ(8, opt->len());
     EXPECT_EQ(D6O_CLIENTID, opt->getType());
 
-    EXPECT_EQ(offset18, 18);
+    EXPECT_EQ(8, outBuf_.getLength());
 
     // check if pack worked properly:
     // 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
-    EXPECT_EQ(4, simple_buf[12]*256 + simple_buf[13]);
+    EXPECT_EQ(4, out[2]*256 + out[3]);
 
     // 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(
         delete opt;
@@ -291,18 +281,15 @@ TEST_F(OptionTest, v6_data2) {
 //  +----opt3
 //
 TEST_F(OptionTest, v6_suboptions1) {
-    boost::shared_array<uint8_t> buf(new uint8_t[128]);
     for (int i=0; i<128; i++)
-        buf[i] = 100+i;
+        buf_[i] = 100+i;
     Option* opt1 = new Option(Option::V6, 65535, //type
-                              buf,
-                              0, // offset
-                              3); // 3 bytes of data
-    boost::shared_ptr<Option> opt2(new Option(Option::V6, 13));
-    boost::shared_ptr<Option> opt3(new Option(Option::V6, 7,
-                                              buf,
-                                              3, // offset
-                                              5)); // 5 bytes of data
+                              buf_.begin(), // 3 bytes of data
+                              buf_.begin() + 3);
+    OptionPtr opt2(new Option(Option::V6, 13));
+    OptionPtr opt3(new Option(Option::V6, 7,
+                              buf_.begin() + 3,
+                              buf_.begin() + 8)); // 5 bytes of data
     opt1->addOption(opt2);
     opt1->addOption(opt3);
     // opt2 len = 4 (just header)
@@ -319,11 +306,11 @@ TEST_F(OptionTest, v6_suboptions1) {
         0, 13, 0, 0 // no data at all
     };
 
-    int offset = opt1->pack(buf, 128, 20);
-    EXPECT_EQ(40, offset);
+    opt1->pack(outBuf_);
+    EXPECT_EQ(20, outBuf_.getLength());
 
     // payload
-    EXPECT_EQ(0, memcmp(&buf[20], expected, 20) );
+    EXPECT_EQ(0, memcmp(outBuf_.getData(), expected, 20) );
 
     EXPECT_NO_THROW(
         delete opt1;
@@ -337,18 +324,15 @@ TEST_F(OptionTest, v6_suboptions1) {
 //        +----opt3
 //
 TEST_F(OptionTest, v6_suboptions2) {
-    boost::shared_array<uint8_t> buf(new uint8_t[128]);
     for (int i=0; i<128; i++)
-        buf[i] = 100+i;
+        buf_[i] = 100+i;
     Option* opt1 = new Option(Option::V6, 65535, //type
-                              buf,
-                              0, // offset
-                              3); // 3 bytes of data
-    boost::shared_ptr<Option> opt2(new Option(Option::V6, 13));
-    boost::shared_ptr<Option> opt3(new Option(Option::V6, 7,
-                                              buf,
-                                              3, // offset
-                                              5)); // 5 bytes of data
+                              buf_.begin(),
+                              buf_.begin() + 3);
+    OptionPtr opt2(new Option(Option::V6, 13));
+    OptionPtr opt3(new Option(Option::V6, 7,
+                                              buf_.begin() + 3,
+                                              buf_.begin() + 8));
     opt1->addOption(opt2);
     opt2->addOption(opt3);
     // 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,
     };
 
-    int offset = opt1->pack(buf, 128, 20);
-    EXPECT_EQ(40, offset);
+    opt1->pack(outBuf_);
+    EXPECT_EQ(20, outBuf_.getLength());
 
     // payload
-    EXPECT_EQ(0, memcmp(&buf[20], expected, 20) );
+    EXPECT_EQ(0, memcmp(outBuf_.getData(), expected, 20) );
 
     EXPECT_NO_THROW(
         delete opt1;
@@ -373,13 +357,12 @@ TEST_F(OptionTest, v6_suboptions2) {
 }
 
 TEST_F(OptionTest, v6_addgetdel) {
-    boost::shared_array<uint8_t> buf(new uint8_t[128]);
     for (int i=0; i<128; i++)
-        buf[i] = 100+i;
+        buf_[i] = 100+i;
     Option* parent = new Option(Option::V6, 65535); //type
-    boost::shared_ptr<Option> opt1(new Option(Option::V6, 1));
-    boost::shared_ptr<Option> opt2(new Option(Option::V6, 2));
-    boost::shared_ptr<Option> opt3(new Option(Option::V6, 2));
+    OptionPtr opt1(new Option(Option::V6, 1));
+    OptionPtr opt2(new Option(Option::V6, 2));
+    OptionPtr opt3(new Option(Option::V6, 2));
 
     parent->addOption(opt1);
     parent->addOption(opt2);
@@ -389,7 +372,7 @@ TEST_F(OptionTest, v6_addgetdel) {
     EXPECT_EQ(opt2, parent->getOption(2));
 
     // 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
     parent->addOption(opt3);
@@ -398,13 +381,13 @@ TEST_F(OptionTest, v6_addgetdel) {
     EXPECT_EQ(true, parent->delOption(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
     EXPECT_EQ(true, parent->delOption(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
     EXPECT_TRUE(false ==  parent->delOption(2));
@@ -412,36 +395,31 @@ TEST_F(OptionTest, v6_addgetdel) {
     delete parent;
 }
 
-}
-
 TEST_F(OptionTest, v6_toText) {
-    boost::shared_array<uint8_t> buf(new uint8_t[3]);
-    buf[0] = 0;
-    buf[1] = 0xf;
-    buf[2] = 0xff;
+    buf_[0] = 0;
+    buf_[1] = 0xf;
+    buf_[2] = 0xff;
 
-    boost::shared_ptr<Option> opt(new Option(Option::V6, 258,
-                                             buf, 0, 3));
+    OptionPtr opt(new Option(Option::V6, 258,  buf_.begin(), buf_.begin() + 3 ));
 
     EXPECT_EQ("type=258, len=3: 00:0f:ff", opt->toText());
 }
 
+
 TEST_F(OptionTest, getUintX) {
 
-    // TODO: Update this test to use buf_ instead of buf
-    boost::shared_array<uint8_t> buf(new uint8_t[5]);
-    buf[0] = 0x5;
-    buf[1] = 0x4;
-    buf[2] = 0x3;
-    buf[3] = 0x2;
-    buf[4] = 0x1;
+    buf_[0] = 0x5;
+    buf_[1] = 0x4;
+    buf_[2] = 0x3;
+    buf_[3] = 0x2;
+    buf_[4] = 0x1;
 
     // five options with varying lengths
-    boost::shared_ptr<Option> opt1(new Option(Option::V6, 258, buf, 0, 1));
-    boost::shared_ptr<Option> opt2(new Option(Option::V6, 258, buf, 0, 2));
-    boost::shared_ptr<Option> opt3(new Option(Option::V6, 258, buf, 0, 3));
-    boost::shared_ptr<Option> opt4(new Option(Option::V6, 258, buf, 0, 4));
-    boost::shared_ptr<Option> opt5(new Option(Option::V6, 258, buf, 0, 5));
+    OptionPtr opt1(new Option(Option::V6, 258, buf_.begin(), buf_.begin() + 1));
+    OptionPtr opt2(new Option(Option::V6, 258, buf_.begin(), buf_.begin() + 2));
+    OptionPtr opt3(new Option(Option::V6, 258, buf_.begin(), buf_.begin() + 3));
+    OptionPtr opt4(new Option(Option::V6, 258, buf_.begin(), buf_.begin() + 4));
+    OptionPtr opt5(new Option(Option::V6, 258, buf_.begin(), buf_.begin() + 5));
 
     EXPECT_EQ(5, opt1->getUint8());
     EXPECT_THROW(opt1->getUint16(), OutOfRange);
@@ -467,36 +445,37 @@ TEST_F(OptionTest, getUintX) {
 }
 
 TEST_F(OptionTest, setUintX) {
-    boost::shared_ptr<Option> opt1(new Option(Option::V4, 125));
-    boost::shared_ptr<Option> opt2(new Option(Option::V4, 125));
-    boost::shared_ptr<Option> opt4(new Option(Option::V4, 125));
+    OptionPtr opt1(new Option(Option::V4, 125));
+    OptionPtr opt2(new Option(Option::V4, 125));
+    OptionPtr opt4(new Option(Option::V4, 125));
 
     // verify setUint8
     opt1->setUint8(255);
     EXPECT_EQ(255, opt1->getUint8());
-    opt1->pack4(outBuffer_);
+    opt1->pack4(outBuf_);
     EXPECT_EQ(3, opt1->len());
-    EXPECT_EQ(3, outBuffer_.getLength());
+    EXPECT_EQ(3, outBuf_.getLength());
     uint8_t exp1[] = {125, 1, 255};
-    EXPECT_TRUE(0 == memcmp(exp1, outBuffer_.getData(), 3));
+    EXPECT_TRUE(0 == memcmp(exp1, outBuf_.getData(), 3));
 
     // verify getUint16
-    outBuffer_.clear();
+    outBuf_.clear();
     opt2->setUint16(12345);
-    opt2->pack4(outBuffer_);
+    opt2->pack4(outBuf_);
     EXPECT_EQ(12345, opt2->getUint16());
     EXPECT_EQ(4, opt2->len());
-    EXPECT_EQ(4, outBuffer_.getLength());
+    EXPECT_EQ(4, outBuf_.getLength());
     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
-    outBuffer_.clear();
+    outBuf_.clear();
     opt4->setUint32(0x12345678);
-    opt4->pack4(outBuffer_);
+    opt4->pack4(outBuf_);
     EXPECT_EQ(0x12345678, opt4->getUint32());
     EXPECT_EQ(6, opt4->len());
-    EXPECT_EQ(6, outBuffer_.getLength());
+    EXPECT_EQ(6, outBuf_.getLength());
     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
 // purpose with or without fee is hereby granted, provided that the above
@@ -37,9 +37,11 @@ public:
 };
 
 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;
 }
@@ -49,42 +51,46 @@ TEST_F(Pkt6Test, constructor) {
 // this code is autogenerated (see src/bin/dhcp6/tests/iface_mgr_unittest.c)
 Pkt6 *capture1() {
     Pkt6* pkt;
-    pkt = new Pkt6(98);
-    pkt->remote_port_ = 546;
-    pkt->remote_addr_ = IOAddress("fe80::21e:8cff:fe9b:7349");
-    pkt->local_port_ = 0;
-    pkt->local_addr_ = IOAddress("ff02::1:2");
-    pkt->ifindex_ = 2;
-    pkt->iface_ = "eth0";
-    pkt->data_[0]=1;
-    pkt->data_[1]=01;     pkt->data_[2]=02;     pkt->data_[3]=03;     pkt->data_[4]=0;
-    pkt->data_[5]=1;     pkt->data_[6]=0;     pkt->data_[7]=14;     pkt->data_[8]=0;
-    pkt->data_[9]=1;     pkt->data_[10]=0;     pkt->data_[11]=1;     pkt->data_[12]=21;
-    pkt->data_[13]=158;     pkt->data_[14]=60;     pkt->data_[15]=22;     pkt->data_[16]=0;
-    pkt->data_[17]=30;     pkt->data_[18]=140;     pkt->data_[19]=155;     pkt->data_[20]=115;
-    pkt->data_[21]=73;     pkt->data_[22]=0;     pkt->data_[23]=3;     pkt->data_[24]=0;
-    pkt->data_[25]=40;     pkt->data_[26]=0;     pkt->data_[27]=0;     pkt->data_[28]=0;
-    pkt->data_[29]=1;     pkt->data_[30]=255;     pkt->data_[31]=255;     pkt->data_[32]=255;
-    pkt->data_[33]=255;     pkt->data_[34]=255;     pkt->data_[35]=255;     pkt->data_[36]=255;
-    pkt->data_[37]=255;     pkt->data_[38]=0;     pkt->data_[39]=5;     pkt->data_[40]=0;
-    pkt->data_[41]=24;     pkt->data_[42]=32;     pkt->data_[43]=1;     pkt->data_[44]=13;
-    pkt->data_[45]=184;     pkt->data_[46]=0;     pkt->data_[47]=1;     pkt->data_[48]=0;
-    pkt->data_[49]=0;     pkt->data_[50]=0;     pkt->data_[51]=0;     pkt->data_[52]=0;
-    pkt->data_[53]=0;     pkt->data_[54]=0;     pkt->data_[55]=0;     pkt->data_[56]=18;
-    pkt->data_[57]=52;     pkt->data_[58]=255;     pkt->data_[59]=255;     pkt->data_[60]=255;
-    pkt->data_[61]=255;     pkt->data_[62]=255;     pkt->data_[63]=255;     pkt->data_[64]=255;
-    pkt->data_[65]=255;     pkt->data_[66]=0;     pkt->data_[67]=23;     pkt->data_[68]=0;
-    pkt->data_[69]=16;     pkt->data_[70]=32;     pkt->data_[71]=1;     pkt->data_[72]=13;
-    pkt->data_[73]=184;     pkt->data_[74]=0;     pkt->data_[75]=1;     pkt->data_[76]=0;
-    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->data_[85]=221;     pkt->data_[86]=0;     pkt->data_[87]=8;     pkt->data_[88]=0;
-    pkt->data_[89]=2;     pkt->data_[90]=0;     pkt->data_[91]=100;     pkt->data_[92]=0;
-    pkt->data_[93]=6;     pkt->data_[94]=0;     pkt->data_[95]=2;     pkt->data_[96]=0;
-    pkt->data_[97]=23;
+    uint8_t data[98];
+    data[0]=1;
+    data[1]=01;     data[2]=02;     data[3]=03;     data[4]=0;
+    data[5]=1;     data[6]=0;     data[7]=14;     data[8]=0;
+    data[9]=1;     data[10]=0;     data[11]=1;     data[12]=21;
+    data[13]=158;     data[14]=60;     data[15]=22;     data[16]=0;
+    data[17]=30;     data[18]=140;     data[19]=155;     data[20]=115;
+    data[21]=73;     data[22]=0;     data[23]=3;     data[24]=0;
+    data[25]=40;     data[26]=0;     data[27]=0;     data[28]=0;
+    data[29]=1;     data[30]=255;     data[31]=255;     data[32]=255;
+    data[33]=255;     data[34]=255;     data[35]=255;     data[36]=255;
+    data[37]=255;     data[38]=0;     data[39]=5;     data[40]=0;
+    data[41]=24;     data[42]=32;     data[43]=1;     data[44]=13;
+    data[45]=184;     data[46]=0;     data[47]=1;     data[48]=0;
+    data[49]=0;     data[50]=0;     data[51]=0;     data[52]=0;
+    data[53]=0;     data[54]=0;     data[55]=0;     data[56]=18;
+    data[57]=52;     data[58]=255;     data[59]=255;     data[60]=255;
+    data[61]=255;     data[62]=255;     data[63]=255;     data[64]=255;
+    data[65]=255;     data[66]=0;     data[67]=23;     data[68]=0;
+    data[69]=16;     data[70]=32;     data[71]=1;     data[72]=13;
+    data[73]=184;     data[74]=0;     data[75]=1;     data[76]=0;
+    data[77]=0;     data[78]=0;     data[79]=0;     data[80]=0;
+    data[81]=0;     data[82]=0;     data[83]=0;     data[84]=221;
+    data[85]=221;     data[86]=0;     data[87]=8;     data[88]=0;
+    data[89]=2;     data[90]=0;     data[91]=100;     data[92]=0;
+    data[93]=6;     data[94]=0;     data[95]=2;     data[96]=0;
+    data[97]=23;
+
+    pkt = new Pkt6(data, sizeof(data));
+    pkt->setRemotePort(546);
+    pkt->setRemoteAddr(IOAddress("fe80::21e:8cff:fe9b:7349"));
+    pkt->setLocalPort(0);
+    pkt->setLocalAddr(IOAddress("ff02::1:2"));
+    pkt->setIndex(2);
+    pkt->setIface("eth0");
+
     return (pkt);
 }
 
+
 TEST_F(Pkt6Test, unpack_solicit1) {
     Pkt6 * sol = capture1();
 
@@ -108,17 +114,12 @@ TEST_F(Pkt6Test, unpack_solicit1) {
     EXPECT_FALSE(sol->getOption(D6O_IA_TA));
     EXPECT_FALSE(sol->getOption(D6O_IAADDR));
 
-    // let's limit verbosity of this test
-    // std::cout << sol->toText();
-
     delete sol;
 }
 
 TEST_F(Pkt6Test, packUnpack) {
 
-    Pkt6 * parent = new Pkt6(100);
-
-    parent->setType(DHCPV6_SOLICIT);
+    Pkt6* parent = new Pkt6(DHCPV6_SOLICIT, 0x020304);
 
     boost::shared_ptr<Option> opt1(new Option(Option::V6, 1));
     boost::shared_ptr<Option> opt2(new Option(Option::V6, 2));
@@ -130,43 +131,37 @@ TEST_F(Pkt6Test, packUnpack) {
     parent->addOption(opt3);
 
     EXPECT_EQ(DHCPV6_SOLICIT, parent->getType());
-    int transid = parent->getTransid();
-    // transaction-id was randomized, let's remember it
 
     // 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() );
 
     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() );
 
-    // let's delete options from options_ collection
-    // they still be defined in packed 
-    parent->options_.clear();
-
-    // that that removed options are indeed are gone
-    EXPECT_EQ( 4, parent->len() );
+    // create second packet,based on assembled data from the first one
+    Pkt6* clone = new Pkt6((const uint8_t*)parent->getBuffer().getData(), parent->getBuffer().getLength());
 
     // now recreate options list
-    EXPECT_TRUE( parent->unpack() );
+    EXPECT_TRUE( clone->unpack() );
 
     // transid, message-type should be the same as before
-    EXPECT_EQ(transid, parent->getTransid());
-    EXPECT_EQ(DHCPV6_SOLICIT, parent->getType());
-    
-    EXPECT_TRUE( parent->getOption(1));
-    EXPECT_TRUE( parent->getOption(2));
-    EXPECT_TRUE( parent->getOption(100));
-    EXPECT_FALSE( parent->getOption(4));
-    
+    EXPECT_EQ(parent->getTransid(), parent->getTransid());
+    EXPECT_EQ(DHCPV6_SOLICIT, clone->getType());
+
+    EXPECT_TRUE( clone->getOption(1));
+    EXPECT_TRUE( clone->getOption(2));
+    EXPECT_TRUE( clone->getOption(100));
+    EXPECT_FALSE( clone->getOption(4));
+
     delete parent;
+    delete clone;
 }
 
 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> opt2(new Option(Option::V6, 2));
@@ -203,5 +198,4 @@ TEST_F(Pkt6Test, addGetDelOptions) {
     delete parent;
 }
 
-
 }

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

@@ -101,6 +101,17 @@ public:
     /// \param len The length of the data in bytes.
     InputBuffer(const void* data, size_t 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)) {}
     //@}
 
     ///