1537ff140SPatrick Venture #include "endian.hpp"
207c462acSRatan Gupta #include "slp.hpp"
3537ff140SPatrick Venture #include "slp_meta.hpp"
407c462acSRatan Gupta 
507c462acSRatan Gupta #include <arpa/inet.h>
6ead7a3caSRatan Gupta #include <dirent.h>
707c462acSRatan Gupta #include <ifaddrs.h>
807c462acSRatan Gupta #include <net/if.h>
907c462acSRatan Gupta #include <string.h>
1007c462acSRatan Gupta 
1107c462acSRatan Gupta #include <algorithm>
126f01edceSAndrew Geissler #include <bitset>
1307c462acSRatan Gupta 
1407c462acSRatan Gupta namespace slp
1507c462acSRatan Gupta {
1607c462acSRatan Gupta namespace handler
1707c462acSRatan Gupta {
1807c462acSRatan Gupta 
1907c462acSRatan Gupta namespace internal
2007c462acSRatan Gupta {
2107c462acSRatan Gupta 
22f93142e8SPatrick Williams static constexpr auto SERVICE_DIR = "/etc/slp/services/";
23f93142e8SPatrick Williams 
prepareHeader(const Message & req)2407c462acSRatan Gupta buffer prepareHeader(const Message& req)
2507c462acSRatan Gupta {
26537ff140SPatrick Venture     uint8_t length =
27537ff140SPatrick Venture         slp::header::MIN_LEN +        /* 14 bytes for header     */
2807c462acSRatan Gupta         req.header.langtag.length() + /* Actual length of lang tag */
2907c462acSRatan Gupta         slp::response::SIZE_ERROR;    /*  2 bytes for error code */
3007c462acSRatan Gupta 
3107c462acSRatan Gupta     buffer buff(length, 0);
3207c462acSRatan Gupta 
3307c462acSRatan Gupta     buff[slp::header::OFFSET_VERSION] = req.header.version;
3407c462acSRatan Gupta 
3507c462acSRatan Gupta     // will increment the function id from 1 as reply
3607c462acSRatan Gupta     buff[slp::header::OFFSET_FUNCTION] = req.header.functionID + 1;
3707c462acSRatan Gupta 
3807c462acSRatan Gupta     std::copy_n(&length, slp::header::SIZE_LENGTH,
39537ff140SPatrick Venture                 buff.data() + slp::header::OFFSET_LENGTH);
4007c462acSRatan Gupta 
4107c462acSRatan Gupta     auto flags = endian::to_network(req.header.flags);
4207c462acSRatan Gupta 
4307c462acSRatan Gupta     std::copy_n((uint8_t*)&flags, slp::header::SIZE_FLAGS,
44537ff140SPatrick Venture                 buff.data() + slp::header::OFFSET_FLAGS);
4507c462acSRatan Gupta 
4607c462acSRatan Gupta     std::copy_n(req.header.extOffset.data(), slp::header::SIZE_EXT,
47537ff140SPatrick Venture                 buff.data() + slp::header::OFFSET_EXT);
4807c462acSRatan Gupta 
4907c462acSRatan Gupta     auto xid = endian::to_network(req.header.xid);
5007c462acSRatan Gupta 
5107c462acSRatan Gupta     std::copy_n((uint8_t*)&xid, slp::header::SIZE_XID,
52537ff140SPatrick Venture                 buff.data() + slp::header::OFFSET_XID);
5307c462acSRatan Gupta 
5407c462acSRatan Gupta     uint16_t langtagLen = req.header.langtag.length();
5507c462acSRatan Gupta     langtagLen = endian::to_network(langtagLen);
5607c462acSRatan Gupta     std::copy_n((uint8_t*)&langtagLen, slp::header::SIZE_LANG,
57537ff140SPatrick Venture                 buff.data() + slp::header::OFFSET_LANG_LEN);
5807c462acSRatan Gupta 
59537ff140SPatrick Venture     std::copy_n((uint8_t*)req.header.langtag.c_str(),
60537ff140SPatrick Venture                 req.header.langtag.length(),
61537ff140SPatrick Venture                 buff.data() + slp::header::OFFSET_LANG);
6207c462acSRatan Gupta     return buff;
6307c462acSRatan Gupta }
6407c462acSRatan Gupta 
processSrvTypeRequest(const Message & req)65537ff140SPatrick Venture std::tuple<int, buffer> processSrvTypeRequest(const Message& req)
6607c462acSRatan Gupta {
6707c462acSRatan Gupta     /*
6807c462acSRatan Gupta        0                   1                   2                   3
6907c462acSRatan Gupta        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
7007c462acSRatan Gupta       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
7107c462acSRatan Gupta       |      Service Location header (function = SrvTypeRply = 10)    |
7207c462acSRatan Gupta       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
7307c462acSRatan Gupta       |           Error Code          |    length of <srvType-list>   |
7407c462acSRatan Gupta       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
7507c462acSRatan Gupta       |                       <srvtype--list>                         \
7607c462acSRatan Gupta       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
7707c462acSRatan Gupta     */
7807c462acSRatan Gupta 
7907c462acSRatan Gupta     buffer buff;
8007c462acSRatan Gupta 
8107c462acSRatan Gupta     // read the slp service info from conf and create the service type string
8207c462acSRatan Gupta     slp::handler::internal::ServiceList svcList =
83ead7a3caSRatan Gupta         slp::handler::internal::readSLPServiceInfo();
8407c462acSRatan Gupta     if (svcList.size() <= 0)
8507c462acSRatan Gupta     {
8607c462acSRatan Gupta         buff.resize(0);
870d3e9e33SRatan Gupta         std::cerr << "SLP unable to read the service info\n";
8807c462acSRatan Gupta         return std::make_tuple((int)slp::Error::INTERNAL_ERROR, buff);
8907c462acSRatan Gupta     }
9007c462acSRatan Gupta 
9107c462acSRatan Gupta     std::string service;
9207c462acSRatan Gupta     bool firstIteration = true;
9307c462acSRatan Gupta     for_each(svcList.cbegin(), svcList.cend(),
94537ff140SPatrick Venture              [&service, &firstIteration](const auto& svc) {
9507c462acSRatan Gupta                  if (firstIteration == true)
9607c462acSRatan Gupta                  {
9707c462acSRatan Gupta                      service = svc.first;
9807c462acSRatan Gupta                      firstIteration = false;
9907c462acSRatan Gupta                  }
10007c462acSRatan Gupta                  else
10107c462acSRatan Gupta                  {
10207c462acSRatan Gupta                      service += ",";
10307c462acSRatan Gupta                      service += svc.first;
10407c462acSRatan Gupta                  }
10507c462acSRatan Gupta              });
10607c462acSRatan Gupta 
10707c462acSRatan Gupta     buff = prepareHeader(req);
10807c462acSRatan Gupta 
10907c462acSRatan Gupta     /* Need to modify the length and the function type field of the header
11007c462acSRatan Gupta      * as it is dependent on the handler of the service */
11107c462acSRatan Gupta 
11207c462acSRatan Gupta     std::cout << "service=" << service.c_str() << "\n";
11307c462acSRatan Gupta 
114eebd0815SAndrew Geissler     // See if total response size exceeds our max
115eebd0815SAndrew Geissler     uint32_t totalLength =
116eebd0815SAndrew Geissler         buff.size() +                 /* 14 bytes header + length of langtag */
117eebd0815SAndrew Geissler         slp::response::SIZE_ERROR +   /* 2 byte err code */
118eebd0815SAndrew Geissler         slp::response::SIZE_SERVICE + /* 2 byte srvtype len */
119eebd0815SAndrew Geissler         service.length();
120eebd0815SAndrew Geissler     if (totalLength > slp::MAX_LEN)
121eebd0815SAndrew Geissler     {
122eebd0815SAndrew Geissler         std::cerr << "Message response size exceeds maximum allowed: "
123eebd0815SAndrew Geissler                   << totalLength << " / " << slp::MAX_LEN << std::endl;
124eebd0815SAndrew Geissler         buff.resize(0);
125eebd0815SAndrew Geissler         return std::make_tuple((int)slp::Error::PARSE_ERROR, buff);
126eebd0815SAndrew Geissler     }
127eebd0815SAndrew Geissler 
12807c462acSRatan Gupta     uint8_t length = buff.size() + /* 14 bytes header + length of langtag */
12907c462acSRatan Gupta                      slp::response::SIZE_ERROR +   /* 2 byte err code */
13007c462acSRatan Gupta                      slp::response::SIZE_SERVICE + /* 2 byte srvtype len */
13107c462acSRatan Gupta                      service.length();
13207c462acSRatan Gupta 
13307c462acSRatan Gupta     buff.resize(length);
13407c462acSRatan Gupta 
13507c462acSRatan Gupta     std::copy_n(&length, slp::header::SIZE_LENGTH,
136537ff140SPatrick Venture                 buff.data() + slp::header::OFFSET_LENGTH);
13707c462acSRatan Gupta 
13807c462acSRatan Gupta     /* error code is already set to 0 moving to service type len */
13907c462acSRatan Gupta 
14007c462acSRatan Gupta     uint16_t serviceTypeLen = service.length();
14107c462acSRatan Gupta     serviceTypeLen = endian::to_network(serviceTypeLen);
14207c462acSRatan Gupta 
14307c462acSRatan Gupta     std::copy_n((uint8_t*)&serviceTypeLen, slp::response::SIZE_SERVICE,
144537ff140SPatrick Venture                 buff.data() + slp::response::OFFSET_SERVICE_LEN);
14507c462acSRatan Gupta 
14607c462acSRatan Gupta     /* service type data */
14707c462acSRatan Gupta     std::copy_n((uint8_t*)service.c_str(), service.length(),
148537ff140SPatrick Venture                 (buff.data() + slp::response::OFFSET_SERVICE));
14907c462acSRatan Gupta 
15007c462acSRatan Gupta     return std::make_tuple(slp::SUCCESS, buff);
15107c462acSRatan Gupta }
15207c462acSRatan Gupta 
processSrvRequest(const Message & req)153537ff140SPatrick Venture std::tuple<int, buffer> processSrvRequest(const Message& req)
15407c462acSRatan Gupta {
15507c462acSRatan Gupta     /*
15607c462acSRatan Gupta           Service Reply
15707c462acSRatan Gupta           0                   1                   2                   3
15807c462acSRatan Gupta           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
15907c462acSRatan Gupta          +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
16007c462acSRatan Gupta          |        Service Location header (function = SrvRply = 2)       |
16107c462acSRatan Gupta          +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
16207c462acSRatan Gupta          |        Error Code             |        URL Entry count        |
16307c462acSRatan Gupta          +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
16407c462acSRatan Gupta          |       <URL Entry 1>          ...       <URL Entry N>          \
16507c462acSRatan Gupta          +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
16607c462acSRatan Gupta 
16707c462acSRatan Gupta          URL Entry
16807c462acSRatan Gupta           0                   1                   2                   3
16907c462acSRatan Gupta           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
17007c462acSRatan Gupta          +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
17107c462acSRatan Gupta          |   Reserved    |          Lifetime             |   URL Length  |
17207c462acSRatan Gupta          +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
17307c462acSRatan Gupta          |URL len, contd.|            URL (variable length)              \
17407c462acSRatan Gupta          +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
17507c462acSRatan Gupta          |# of URL auths |            Auth. blocks (if any)              \
17607c462acSRatan Gupta          +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
17707c462acSRatan Gupta     */
17807c462acSRatan Gupta 
17907c462acSRatan Gupta     buffer buff;
18007c462acSRatan Gupta     // Get all the services which are registered
18107c462acSRatan Gupta     slp::handler::internal::ServiceList svcList =
182ead7a3caSRatan Gupta         slp::handler::internal::readSLPServiceInfo();
18307c462acSRatan Gupta     if (svcList.size() <= 0)
18407c462acSRatan Gupta     {
18507c462acSRatan Gupta         buff.resize(0);
1860d3e9e33SRatan Gupta         std::cerr << "SLP unable to read the service info\n";
18707c462acSRatan Gupta         return std::make_tuple((int)slp::Error::INTERNAL_ERROR, buff);
18807c462acSRatan Gupta     }
18907c462acSRatan Gupta 
19007c462acSRatan Gupta     // return error if serice type doesn't match
19107c462acSRatan Gupta     auto& svcName = req.body.srvrqst.srvType;
19207c462acSRatan Gupta     auto svcIt = svcList.find(svcName);
19307c462acSRatan Gupta     if (svcIt == svcList.end())
19407c462acSRatan Gupta     {
19507c462acSRatan Gupta         buff.resize(0);
1960d3e9e33SRatan Gupta         std::cerr << "SLP unable to find the service=" << svcName << "\n";
19707c462acSRatan Gupta         return std::make_tuple((int)slp::Error::INTERNAL_ERROR, buff);
19807c462acSRatan Gupta     }
19907c462acSRatan Gupta     // Get all the interface address
20007c462acSRatan Gupta     auto ifaddrList = slp::handler::internal::getIntfAddrs();
20107c462acSRatan Gupta     if (ifaddrList.size() <= 0)
20207c462acSRatan Gupta     {
20307c462acSRatan Gupta         buff.resize(0);
2040d3e9e33SRatan Gupta         std::cerr << "SLP unable to read the interface address\n";
20507c462acSRatan Gupta         return std::make_tuple((int)slp::Error::INTERNAL_ERROR, buff);
20607c462acSRatan Gupta     }
20707c462acSRatan Gupta 
20807c462acSRatan Gupta     buff = prepareHeader(req);
20907c462acSRatan Gupta     // Calculate the length and resize the buffer
21007c462acSRatan Gupta     uint8_t length = buff.size() + /* 14 bytes header + length of langtag */
21107c462acSRatan Gupta                      slp::response::SIZE_ERROR +    /* 2 bytes error code */
21207c462acSRatan Gupta                      slp::response::SIZE_URL_COUNT; /* 2 bytes srvtype len */
21307c462acSRatan Gupta 
21407c462acSRatan Gupta     buff.resize(length);
21507c462acSRatan Gupta 
21607c462acSRatan Gupta     // Populate the url count
21707c462acSRatan Gupta     uint16_t urlCount = ifaddrList.size();
21807c462acSRatan Gupta     urlCount = endian::to_network(urlCount);
21907c462acSRatan Gupta 
22007c462acSRatan Gupta     std::copy_n((uint8_t*)&urlCount, slp::response::SIZE_URL_COUNT,
221537ff140SPatrick Venture                 buff.data() + slp::response::OFFSET_URL_ENTRY);
22207c462acSRatan Gupta 
22307c462acSRatan Gupta     // Find the service
22407c462acSRatan Gupta     const slp::ConfigData& svc = svcIt->second;
2251f12e380SGunnar Mills     // Populate the URL Entries
22607c462acSRatan Gupta     auto pos = slp::response::OFFSET_URL_ENTRY + slp::response::SIZE_URL_COUNT;
22707c462acSRatan Gupta     for (const auto& addr : ifaddrList)
22807c462acSRatan Gupta     {
229*1a6b1c2bSPatrick Williams         std::string url =
230*1a6b1c2bSPatrick Williams             svc.name + ':' + svc.type + "//" + addr + ',' + svc.port;
23107c462acSRatan Gupta 
232eebd0815SAndrew Geissler         // See if total response size exceeds our max
233*1a6b1c2bSPatrick Williams         uint32_t totalLength =
234*1a6b1c2bSPatrick Williams             buff.size() + slp::response::SIZE_URL_ENTRY + url.length();
235eebd0815SAndrew Geissler         if (totalLength > slp::MAX_LEN)
236eebd0815SAndrew Geissler         {
237eebd0815SAndrew Geissler             std::cerr << "Message response size exceeds maximum allowed: "
238eebd0815SAndrew Geissler                       << totalLength << " / " << slp::MAX_LEN << std::endl;
239eebd0815SAndrew Geissler             buff.resize(0);
240eebd0815SAndrew Geissler             return std::make_tuple((int)slp::Error::PARSE_ERROR, buff);
241eebd0815SAndrew Geissler         }
242eebd0815SAndrew Geissler 
243537ff140SPatrick Venture         buff.resize(buff.size() + slp::response::SIZE_URL_ENTRY + url.length());
24407c462acSRatan Gupta 
24507c462acSRatan Gupta         uint8_t reserved = 0;
24607c462acSRatan Gupta         uint16_t auth = 0;
24707c462acSRatan Gupta         uint16_t lifetime = endian::to_network<uint16_t>(slp::LIFETIME);
24807c462acSRatan Gupta         uint16_t urlLength = url.length();
24907c462acSRatan Gupta 
25007c462acSRatan Gupta         std::copy_n((uint8_t*)&reserved, slp::response::SIZE_RESERVED,
25107c462acSRatan Gupta                     buff.data() + pos);
25207c462acSRatan Gupta 
25307c462acSRatan Gupta         pos += slp::response::SIZE_RESERVED;
25407c462acSRatan Gupta 
25507c462acSRatan Gupta         std::copy_n((uint8_t*)&lifetime, slp::response::SIZE_LIFETIME,
25607c462acSRatan Gupta                     buff.data() + pos);
25707c462acSRatan Gupta 
25807c462acSRatan Gupta         pos += slp::response::SIZE_LIFETIME;
25907c462acSRatan Gupta 
26007c462acSRatan Gupta         urlLength = endian::to_network(urlLength);
26107c462acSRatan Gupta         std::copy_n((uint8_t*)&urlLength, slp::response::SIZE_URLLENGTH,
26207c462acSRatan Gupta                     buff.data() + pos);
26307c462acSRatan Gupta         pos += slp::response::SIZE_URLLENGTH;
26407c462acSRatan Gupta 
265537ff140SPatrick Venture         std::copy_n((uint8_t*)url.c_str(), url.length(), buff.data() + pos);
26607c462acSRatan Gupta         pos += url.length();
26707c462acSRatan Gupta 
26807c462acSRatan Gupta         std::copy_n((uint8_t*)&auth, slp::response::SIZE_AUTH,
26907c462acSRatan Gupta                     buff.data() + pos);
27007c462acSRatan Gupta         pos += slp::response::SIZE_AUTH;
27107c462acSRatan Gupta     }
27207c462acSRatan Gupta     uint8_t packetLength = buff.size();
27307c462acSRatan Gupta     std::copy_n((uint8_t*)&packetLength, slp::header::SIZE_VERSION,
274537ff140SPatrick Venture                 buff.data() + slp::header::OFFSET_LENGTH);
27507c462acSRatan Gupta 
27607c462acSRatan Gupta     return std::make_tuple((int)slp::SUCCESS, buff);
27707c462acSRatan Gupta }
27807c462acSRatan Gupta 
getIntfAddrs()27907c462acSRatan Gupta std::list<std::string> getIntfAddrs()
28007c462acSRatan Gupta {
28107c462acSRatan Gupta     std::list<std::string> addrList;
28207c462acSRatan Gupta 
28307c462acSRatan Gupta     struct ifaddrs* ifaddr;
28407c462acSRatan Gupta     // attempt to fill struct with ifaddrs
28507c462acSRatan Gupta     if (getifaddrs(&ifaddr) == -1)
28607c462acSRatan Gupta     {
28707c462acSRatan Gupta         return addrList;
28807c462acSRatan Gupta     }
28907c462acSRatan Gupta 
290*1a6b1c2bSPatrick Williams     slp::deleted_unique_ptr<ifaddrs> ifaddrPtr(ifaddr, [](ifaddrs* addr) {
291*1a6b1c2bSPatrick Williams         freeifaddrs(addr);
292*1a6b1c2bSPatrick Williams     });
29307c462acSRatan Gupta 
29407c462acSRatan Gupta     ifaddr = nullptr;
29507c462acSRatan Gupta 
29607c462acSRatan Gupta     for (ifaddrs* ifa = ifaddrPtr.get(); ifa != nullptr; ifa = ifa->ifa_next)
29707c462acSRatan Gupta     {
29807c462acSRatan Gupta         // walk interfaces
29907c462acSRatan Gupta         if (ifa->ifa_addr == nullptr)
30007c462acSRatan Gupta         {
30107c462acSRatan Gupta             continue;
30207c462acSRatan Gupta         }
30307c462acSRatan Gupta 
30407c462acSRatan Gupta         // get only INET interfaces not ipv6
30507c462acSRatan Gupta         if (ifa->ifa_addr->sa_family == AF_INET)
30607c462acSRatan Gupta         {
30707c462acSRatan Gupta             // if loopback, or not running ignore
30807c462acSRatan Gupta             if ((ifa->ifa_flags & IFF_LOOPBACK) ||
30907c462acSRatan Gupta                 !(ifa->ifa_flags & IFF_RUNNING))
31007c462acSRatan Gupta             {
31107c462acSRatan Gupta                 continue;
31207c462acSRatan Gupta             }
31307c462acSRatan Gupta 
31407c462acSRatan Gupta             char tmp[INET_ADDRSTRLEN] = {0};
31507c462acSRatan Gupta 
31607c462acSRatan Gupta             inet_ntop(AF_INET,
317537ff140SPatrick Venture                       &(((struct sockaddr_in*)(ifa->ifa_addr))->sin_addr), tmp,
31807c462acSRatan Gupta                       sizeof(tmp));
31907c462acSRatan Gupta             addrList.emplace_back(tmp);
32007c462acSRatan Gupta         }
32107c462acSRatan Gupta     }
32207c462acSRatan Gupta 
32307c462acSRatan Gupta     return addrList;
32407c462acSRatan Gupta }
32507c462acSRatan Gupta 
readSLPServiceInfo()326ead7a3caSRatan Gupta slp::handler::internal::ServiceList readSLPServiceInfo()
32707c462acSRatan Gupta {
32807c462acSRatan Gupta     using namespace std::string_literals;
32907c462acSRatan Gupta     slp::handler::internal::ServiceList svcLst;
33007c462acSRatan Gupta     slp::ConfigData service;
331ead7a3caSRatan Gupta     struct dirent* dent = nullptr;
332ead7a3caSRatan Gupta 
333ead7a3caSRatan Gupta     // Open the services dir and get the service info
334ead7a3caSRatan Gupta     // from service files.
335ead7a3caSRatan Gupta     // Service File format would be "ServiceName serviceType Port"
336ead7a3caSRatan Gupta     DIR* dir = opendir(SERVICE_DIR);
337ead7a3caSRatan Gupta     // wrap the pointer into smart pointer.
338537ff140SPatrick Venture     slp::deleted_unique_ptr<DIR> dirPtr(dir, [](DIR* dir) {
339ead7a3caSRatan Gupta         if (!dir)
340ead7a3caSRatan Gupta         {
341ead7a3caSRatan Gupta             closedir(dir);
342ead7a3caSRatan Gupta         }
343ead7a3caSRatan Gupta     });
344ead7a3caSRatan Gupta     dir = nullptr;
345ead7a3caSRatan Gupta 
346ead7a3caSRatan Gupta     if (dirPtr.get())
347ead7a3caSRatan Gupta     {
348ead7a3caSRatan Gupta         while ((dent = readdir(dirPtr.get())) != NULL)
349ead7a3caSRatan Gupta         {
350ead7a3caSRatan Gupta             if (dent->d_type == DT_REG) // regular file
351ead7a3caSRatan Gupta             {
352ead7a3caSRatan Gupta                 auto absFileName = std::string(SERVICE_DIR) + dent->d_name;
353ead7a3caSRatan Gupta                 std::ifstream readFile(absFileName);
354ead7a3caSRatan Gupta                 readFile >> service;
355ead7a3caSRatan Gupta                 service.name = "service:"s + service.name;
35607c462acSRatan Gupta                 svcLst.emplace(service.name, service);
35707c462acSRatan Gupta             }
358ead7a3caSRatan Gupta         }
359ead7a3caSRatan Gupta     }
36007c462acSRatan Gupta     return svcLst;
36107c462acSRatan Gupta }
36207c462acSRatan Gupta } // namespace internal
36307c462acSRatan Gupta 
processRequest(const Message & msg)364537ff140SPatrick Venture std::tuple<int, buffer> processRequest(const Message& msg)
36507c462acSRatan Gupta {
36607c462acSRatan Gupta     int rc = slp::SUCCESS;
36740efe672SAndrew Geissler     buffer resp;
3686f01edceSAndrew Geissler     std::cout << "SLP Processing Request="
3696f01edceSAndrew Geissler               << std::bitset<8>(msg.header.functionID) << "\n";
3700d3e9e33SRatan Gupta 
371b5e632a1SBrad Bishop     switch (msg.header.functionID)
372b5e632a1SBrad Bishop     {
37307c462acSRatan Gupta         case (uint8_t)slp::FunctionType::SRVTYPERQST:
374*1a6b1c2bSPatrick Williams             std::tie(rc, resp) =
375*1a6b1c2bSPatrick Williams                 slp::handler::internal::processSrvTypeRequest(msg);
37607c462acSRatan Gupta             break;
37707c462acSRatan Gupta         case (uint8_t)slp::FunctionType::SRVRQST:
37807c462acSRatan Gupta             std::tie(rc, resp) = slp::handler::internal::processSrvRequest(msg);
37907c462acSRatan Gupta             break;
38007c462acSRatan Gupta         default:
38107c462acSRatan Gupta             rc = (uint8_t)slp::Error::MSG_NOT_SUPPORTED;
38207c462acSRatan Gupta     }
38307c462acSRatan Gupta     return std::make_tuple(rc, resp);
38407c462acSRatan Gupta }
38507c462acSRatan Gupta 
processError(const Message & req,uint8_t err)386537ff140SPatrick Venture buffer processError(const Message& req, uint8_t err)
38707c462acSRatan Gupta {
3886f01edceSAndrew Geissler     if (req.header.functionID != 0)
3896f01edceSAndrew Geissler     {
3906f01edceSAndrew Geissler         std::cout << "Processing Error for function: "
3916f01edceSAndrew Geissler                   << std::bitset<8>(req.header.functionID) << std::endl;
3926f01edceSAndrew Geissler     }
3936f01edceSAndrew Geissler 
3946f01edceSAndrew Geissler     /*  0                   1                   2                   3
3956f01edceSAndrew Geissler         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
3966f01edceSAndrew Geissler         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3976f01edceSAndrew Geissler         |        Service Location header (function = SrvRply = 2)       |
3986f01edceSAndrew Geissler         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3996f01edceSAndrew Geissler         |        Error Code             |        URL Entry count        |
4006f01edceSAndrew Geissler         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
4016f01edceSAndrew Geissler         |       <URL Entry 1>          ...       <URL Entry N>          \
4026f01edceSAndrew Geissler         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+*/
4036f01edceSAndrew Geissler 
4046f01edceSAndrew Geissler     // There has been some sort of issue processing the request from
4056f01edceSAndrew Geissler     // the client. Can not assume the input request buffer is valid
4066f01edceSAndrew Geissler     // so just create an empty buffer with the non-variable size
4076f01edceSAndrew Geissler     // fields set and the error code
4086f01edceSAndrew Geissler     uint8_t length = slp::header::MIN_LEN +     /* 14 bytes for header     */
4096f01edceSAndrew Geissler                      slp::response::SIZE_ERROR; /*  2 bytes for error code */
4106f01edceSAndrew Geissler 
4116f01edceSAndrew Geissler     buffer buff(length, 0);
41207c462acSRatan Gupta 
413edf88cb2SPatrick Williams     static_assert(sizeof(err) == 1, "Errors should be 1 byte.");
414edf88cb2SPatrick Williams 
4156f01edceSAndrew Geissler     buff[slp::header::OFFSET_VERSION] = req.header.version;
4166f01edceSAndrew Geissler 
4176f01edceSAndrew Geissler     // will increment the function id from 1 as reply
4186f01edceSAndrew Geissler     buff[slp::header::OFFSET_FUNCTION] = req.header.functionID + 1;
4196f01edceSAndrew Geissler 
4206f01edceSAndrew Geissler     std::copy_n(&length, slp::header::SIZE_LENGTH,
4216f01edceSAndrew Geissler                 buff.data() + slp::header::OFFSET_LENGTH);
4226f01edceSAndrew Geissler 
4236f01edceSAndrew Geissler     auto flags = endian::to_network(req.header.flags);
4246f01edceSAndrew Geissler 
4256f01edceSAndrew Geissler     std::copy_n((uint8_t*)&flags, slp::header::SIZE_FLAGS,
4266f01edceSAndrew Geissler                 buff.data() + slp::header::OFFSET_FLAGS);
4276f01edceSAndrew Geissler 
4286f01edceSAndrew Geissler     std::copy_n(req.header.extOffset.data(), slp::header::SIZE_EXT,
4296f01edceSAndrew Geissler                 buff.data() + slp::header::OFFSET_EXT);
4306f01edceSAndrew Geissler 
4316f01edceSAndrew Geissler     auto xid = endian::to_network(req.header.xid);
4326f01edceSAndrew Geissler 
4336f01edceSAndrew Geissler     std::copy_n((uint8_t*)&xid, slp::header::SIZE_XID,
4346f01edceSAndrew Geissler                 buff.data() + slp::header::OFFSET_XID);
4356f01edceSAndrew Geissler 
4366f01edceSAndrew Geissler     // This is an invalid header from user so just fill in 0 for langtag
4376f01edceSAndrew Geissler     uint16_t langtagLen = 0;
4386f01edceSAndrew Geissler     std::copy_n((uint8_t*)&langtagLen, slp::header::SIZE_LANG,
4396f01edceSAndrew Geissler                 buff.data() + slp::header::OFFSET_LANG_LEN);
4406f01edceSAndrew Geissler 
441edf88cb2SPatrick Williams     // Since this is network order, the err should go in the 2nd byte of the
4426f01edceSAndrew Geissler     // error field.
4436f01edceSAndrew Geissler     buff[slp::header::MIN_LEN + 1] = err;
444edf88cb2SPatrick Williams 
44507c462acSRatan Gupta     return buff;
44607c462acSRatan Gupta }
44707c462acSRatan Gupta } // namespace handler
44807c462acSRatan Gupta } // namespace slp
449