SLP Parser

Contains SLP Parser and SLP Message Handler for
the following messages:
 -findsrvtypes.
 -findsrvs.

Change-Id: I24234b63a8a1226b5c4bb3f6ac0c9aa799987ffc
Signed-off-by: Ratan Gupta <ratagupt@in.ibm.com>
diff --git a/slp_parser.cpp b/slp_parser.cpp
new file mode 100644
index 0000000..28726b0
--- /dev/null
+++ b/slp_parser.cpp
@@ -0,0 +1,285 @@
+#include "slp.hpp"
+
+#include <string.h>
+
+#include <string>
+#include <algorithm>
+
+#include "endian.hpp"
+#include "slp_meta.hpp"
+
+namespace slp
+{
+
+namespace parser
+{
+
+namespace internal
+{
+
+std::tuple<int, Message> parseHeader(const buffer& buff)
+{
+    /*  0                   1                   2                   3
+        0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+       |    Version    |  Function-ID  |            Length             |
+       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+       | Length, contd.|O|F|R|       reserved          |Next Ext Offset|
+       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+       |  Next Extension Offset, contd.|              XID              |
+       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+       |      Language Tag Length      |         Language Tag          \
+       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */
+
+    Message req {0};
+    int rc = slp::SUCCESS;
+
+    std::copy_n(buff.data(),
+                slp::header::SIZE_VERSION,
+                &req.header.version);
+
+    std::copy_n(buff.data() + slp::header::OFFSET_FUNCTION,
+                slp::header::SIZE_VERSION,
+                &req.header.functionID);
+
+    std::copy_n(buff.data() + slp::header::OFFSET_LENGTH,
+                slp::header::SIZE_LENGTH,
+                req.header.length.data());
+
+    std::copy_n(buff.data() + slp::header::OFFSET_FLAGS,
+                slp::header::SIZE_FLAGS,
+                (uint8_t*)&req.header.flags);
+
+    req.header.flags = endian::from_network(req.header.flags);
+    std::copy_n(buff.data() + slp::header::OFFSET_EXT,
+                slp::header::SIZE_EXT,
+                req.header.extOffset.data());
+
+    std::copy_n(buff.data() + slp::header::OFFSET_XID,
+                slp::header::SIZE_XID,
+                (uint8_t*)&req.header.xid);
+
+    req.header.xid = endian::from_network(req.header.xid);
+
+    uint16_t langtagLen;
+
+    std::copy_n(buff.data() + slp::header::OFFSET_LANG_LEN,
+                slp::header::SIZE_LANG,
+                (uint8_t*)&langtagLen);
+
+
+    langtagLen = endian::from_network(langtagLen);
+
+
+    req.header.langtag.insert(0, (const char*)buff.data() +
+                              slp::header::OFFSET_LANG,
+                              langtagLen);
+
+    /* check for the validity of the function */
+    if (req.header.functionID < static_cast<uint8_t>
+        (slp::FunctionType::SRVRQST)
+        || req.header.functionID > static_cast<uint8_t>(slp::FunctionType::SAADV))
+    {
+        rc = static_cast<int>(slp::Error::PARSE_ERROR);
+    }
+
+    return std::make_tuple(rc, std::move(req));
+}
+
+
+int parseSrvTypeRqst(const buffer& buff, Message& req)
+{
+
+
+    /*  0                   1                   2                   3
+        0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+       |        length of PRList       |        <PRList> String        \
+       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+       |   length of Naming Authority  |   <Naming Authority String>   \
+       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+       |     length of <scope-list>    |      <scope-list> String      \
+       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */
+
+    /* Enforce SLPv2 service type request size limits. */
+    if (buff.size() < slp::request::MIN_SRVTYPE_LEN)
+    {
+        return (int)slp::Error::PARSE_ERROR;
+    }
+
+    /* Parse the PRList. */
+    uint16_t prListLen;
+    std::copy_n(buff.data() + slp::request::OFFSET_PR_LEN,
+                slp::request::SIZE_PRLIST,
+                (uint8_t*)&prListLen);
+
+    prListLen = endian::from_network(prListLen);
+
+    req.body.srvtyperqst.prList.insert(0, (const char*)buff.data() +
+                                       slp::request::OFFSET_PR,
+                                       prListLen);
+
+    uint8_t pos = slp::request::OFFSET_PR + prListLen;
+
+    /* Parse the Naming Authority. */
+    uint16_t namingAuthLen;
+    std::copy_n(buff.data() + pos,
+                slp::request::SIZE_NAMING,
+                (uint8_t*)&namingAuthLen);
+
+    pos += slp::request::SIZE_NAMING;
+
+    namingAuthLen = endian::from_network(namingAuthLen);
+
+    if (namingAuthLen == 0 || namingAuthLen == 0xffff)
+    {
+        req.body.srvtyperqst.namingAuth = "";
+    }
+    else
+    {
+        req.body.srvtyperqst.namingAuth.insert(0, (const char*)buff.data() +
+                                               pos,
+                                               namingAuthLen);
+    }
+
+    pos += namingAuthLen;
+
+    /* Parse the <scope-list>. */
+    uint16_t scopeListLen;
+    std::copy_n(buff.data() + pos,
+                slp::request::SIZE_SCOPE,
+                (uint8_t*)&scopeListLen);
+
+    pos += slp::request::SIZE_SCOPE;
+
+    scopeListLen = endian::from_network(scopeListLen);
+
+    req.body.srvtyperqst.scopeList.insert(0, (const char*)buff.data() + pos,
+                                          scopeListLen);
+
+    return slp::SUCCESS;
+}
+
+int parseSrvRqst(const buffer& buff, Message& req)
+{
+    /*  0                   1                   2                   3
+        0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+       |      length of <PRList>       |        <PRList> String        \
+       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+       |   length of <service-type>    |    <service-type> String      \
+       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+       |    length of <scope-list>     |     <scope-list> String       \
+       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+       |  length of predicate string   |  Service Request <predicate>  \
+       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+       |  length of <SLP SPI> string   |       <SLP SPI> String        \
+       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */
+
+    /* Enforce v2 service request size limits. */
+    if (buff.size() < slp::request::MIN_SRV_LEN)
+    {
+        return (int)slp::Error::PARSE_ERROR;
+    }
+
+    /* 1) Parse the PRList. */
+    uint16_t prListLen;
+    std::copy_n(buff.data() + slp::request::OFFSET_PR_LEN,
+                slp::request::SIZE_PRLIST,
+                (uint8_t*)&prListLen);
+
+    auto pos = slp::request::OFFSET_PR_LEN + slp::request::SIZE_PRLIST;
+
+    prListLen = endian::from_network(prListLen);
+
+    req.body.srvrqst.prList.insert(0, (const char*)buff.data() + pos,
+                                   prListLen);
+
+    pos += prListLen;
+
+
+    /* 2) Parse the <service-type> string. */
+    uint16_t srvTypeLen;
+    std::copy_n(buff.data() + pos,
+                slp::request::SIZE_SERVICE_TYPE,
+                (uint8_t*)&srvTypeLen);
+
+    srvTypeLen = endian::from_network(srvTypeLen);
+
+    pos += slp::request::SIZE_SERVICE_TYPE;
+
+    req.body.srvrqst.srvType.insert(0, (const char*)buff.data() + pos,
+                                    srvTypeLen);
+
+    pos += srvTypeLen;
+
+    /* 3) Parse the <scope-list> string. */
+    uint16_t scopeListLen;
+    std::copy_n(buff.data() + pos,
+                slp::request::SIZE_SCOPE,
+                (uint8_t*)&scopeListLen);
+
+    scopeListLen = endian::from_network(scopeListLen);
+
+    pos += slp::request::SIZE_SCOPE;
+
+    req.body.srvrqst.scopeList.insert(0, (const char*)buff.data() + pos,
+                                      scopeListLen);
+
+    pos += scopeListLen;
+
+    /* 4) Parse the <predicate> string. */
+    uint16_t predicateLen;
+    std::copy_n(buff.data() + pos,
+                slp::request::SIZE_PREDICATE,
+                (uint8_t*)&predicateLen);
+
+    predicateLen = endian::from_network(predicateLen);
+    pos += slp::request::SIZE_PREDICATE;
+
+    req.body.srvrqst.predicate.insert(0, (const char*)buff.data() + pos,
+                                      predicateLen);
+
+    pos += predicateLen;
+
+    /* 5) Parse the <SLP SPI> string. */
+    uint16_t spistrLen;
+    std::copy_n(buff.data() + pos,
+                slp::request::SIZE_SLPI,
+                (uint8_t*)&spistrLen);
+
+    spistrLen = endian::from_network(spistrLen);
+    pos += slp::request::SIZE_SLPI;
+
+    req.body.srvrqst.spistr.insert(0, (const char*)buff.data() + pos,
+                                   spistrLen);
+
+    return slp::SUCCESS;
+}
+}//namespace internal
+
+std::tuple<int, Message> parseBuffer(const buffer& buff)
+{
+    Message req;
+    int rc = slp::SUCCESS;
+    /* parse the header first */
+    std::tie(rc, req) = internal::parseHeader(buff);
+    if (!rc)
+    {
+        /* switch on the function id to parse the body */
+        switch (req.header.functionID)
+        {
+            case (uint8_t)slp::FunctionType::SRVTYPERQST:
+                rc = internal::parseSrvTypeRqst(buff, req);
+                break;
+            case (uint8_t)slp::FunctionType::SRVRQST:
+                rc = internal::parseSrvRqst(buff, req);
+                break;
+            default:
+                rc = (int)slp::Error::MSG_NOT_SUPPORTED;
+        }
+    }
+    return std::make_tuple(rc, std::move(req));
+}
+}//namespace parser
+}//namespace slp