blob: a9b6ff008b0829cbb04e60cd7c63197a5054b883 [file] [log] [blame]
Patrick Venture537ff142018-11-01 16:37:09 -07001#include "config.h"
2
3#include "endian.hpp"
Ratan Gupta07c462a2016-12-14 00:40:30 +05304#include "slp.hpp"
Patrick Venture537ff142018-11-01 16:37:09 -07005#include "slp_meta.hpp"
Ratan Gupta07c462a2016-12-14 00:40:30 +05306
7#include <arpa/inet.h>
Ratan Guptaead7a3c2017-01-05 15:45:09 +05308#include <dirent.h>
Ratan Gupta07c462a2016-12-14 00:40:30 +05309#include <ifaddrs.h>
10#include <net/if.h>
11#include <string.h>
12
13#include <algorithm>
14
Ratan Gupta07c462a2016-12-14 00:40:30 +053015namespace slp
16{
17namespace handler
18{
19
20namespace internal
21{
22
23buffer prepareHeader(const Message& req)
24{
Patrick Venture537ff142018-11-01 16:37:09 -070025 uint8_t length =
26 slp::header::MIN_LEN + /* 14 bytes for header */
27 req.header.langtag.length() + /* Actual length of lang tag */
28 slp::response::SIZE_ERROR; /* 2 bytes for error code */
Ratan Gupta07c462a2016-12-14 00:40:30 +053029
30 buffer buff(length, 0);
31
32 buff[slp::header::OFFSET_VERSION] = req.header.version;
33
Patrick Venture537ff142018-11-01 16:37:09 -070034 // will increment the function id from 1 as reply
Ratan Gupta07c462a2016-12-14 00:40:30 +053035 buff[slp::header::OFFSET_FUNCTION] = req.header.functionID + 1;
36
37 std::copy_n(&length, slp::header::SIZE_LENGTH,
Patrick Venture537ff142018-11-01 16:37:09 -070038 buff.data() + slp::header::OFFSET_LENGTH);
Ratan Gupta07c462a2016-12-14 00:40:30 +053039
40 auto flags = endian::to_network(req.header.flags);
41
42 std::copy_n((uint8_t*)&flags, slp::header::SIZE_FLAGS,
Patrick Venture537ff142018-11-01 16:37:09 -070043 buff.data() + slp::header::OFFSET_FLAGS);
Ratan Gupta07c462a2016-12-14 00:40:30 +053044
45 std::copy_n(req.header.extOffset.data(), slp::header::SIZE_EXT,
Patrick Venture537ff142018-11-01 16:37:09 -070046 buff.data() + slp::header::OFFSET_EXT);
Ratan Gupta07c462a2016-12-14 00:40:30 +053047
48 auto xid = endian::to_network(req.header.xid);
49
50 std::copy_n((uint8_t*)&xid, slp::header::SIZE_XID,
Patrick Venture537ff142018-11-01 16:37:09 -070051 buff.data() + slp::header::OFFSET_XID);
Ratan Gupta07c462a2016-12-14 00:40:30 +053052
53 uint16_t langtagLen = req.header.langtag.length();
54 langtagLen = endian::to_network(langtagLen);
55 std::copy_n((uint8_t*)&langtagLen, slp::header::SIZE_LANG,
Patrick Venture537ff142018-11-01 16:37:09 -070056 buff.data() + slp::header::OFFSET_LANG_LEN);
Ratan Gupta07c462a2016-12-14 00:40:30 +053057
Patrick Venture537ff142018-11-01 16:37:09 -070058 std::copy_n((uint8_t*)req.header.langtag.c_str(),
59 req.header.langtag.length(),
60 buff.data() + slp::header::OFFSET_LANG);
Ratan Gupta07c462a2016-12-14 00:40:30 +053061 return buff;
Ratan Gupta07c462a2016-12-14 00:40:30 +053062}
63
Patrick Venture537ff142018-11-01 16:37:09 -070064std::tuple<int, buffer> processSrvTypeRequest(const Message& req)
Ratan Gupta07c462a2016-12-14 00:40:30 +053065{
66
67 /*
68 0 1 2 3
69 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
70 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
71 | Service Location header (function = SrvTypeRply = 10) |
72 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
73 | Error Code | length of <srvType-list> |
74 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
75 | <srvtype--list> \
76 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
77 */
78
79 buffer buff;
80
Patrick Venture537ff142018-11-01 16:37:09 -070081 // read the slp service info from conf and create the service type string
Ratan Gupta07c462a2016-12-14 00:40:30 +053082 slp::handler::internal::ServiceList svcList =
Ratan Guptaead7a3c2017-01-05 15:45:09 +053083 slp::handler::internal::readSLPServiceInfo();
Ratan Gupta07c462a2016-12-14 00:40:30 +053084 if (svcList.size() <= 0)
85 {
86 buff.resize(0);
Ratan Gupta0d3e9e32017-02-10 22:27:12 +053087 std::cerr << "SLP unable to read the service info\n";
Ratan Gupta07c462a2016-12-14 00:40:30 +053088 return std::make_tuple((int)slp::Error::INTERNAL_ERROR, buff);
89 }
90
91 std::string service;
92 bool firstIteration = true;
93 for_each(svcList.cbegin(), svcList.cend(),
Patrick Venture537ff142018-11-01 16:37:09 -070094 [&service, &firstIteration](const auto& svc) {
95 if (firstIteration == true)
96 {
97 service = svc.first;
98 firstIteration = false;
99 }
100 else
101 {
102 service += ",";
103 service += svc.first;
104 }
105 });
Ratan Gupta07c462a2016-12-14 00:40:30 +0530106
107 buff = prepareHeader(req);
108
109 /* Need to modify the length and the function type field of the header
110 * as it is dependent on the handler of the service */
111
112 std::cout << "service=" << service.c_str() << "\n";
113
Patrick Venture537ff142018-11-01 16:37:09 -0700114 uint8_t length = buff.size() + /* 14 bytes header + length of langtag */
115 slp::response::SIZE_ERROR + /* 2 byte err code */
116 slp::response::SIZE_SERVICE + /* 2 byte srvtype len */
117 service.length();
Ratan Gupta07c462a2016-12-14 00:40:30 +0530118
119 buff.resize(length);
120
121 std::copy_n(&length, slp::header::SIZE_LENGTH,
Patrick Venture537ff142018-11-01 16:37:09 -0700122 buff.data() + slp::header::OFFSET_LENGTH);
Ratan Gupta07c462a2016-12-14 00:40:30 +0530123
124 /* error code is already set to 0 moving to service type len */
125
126 uint16_t serviceTypeLen = service.length();
127 serviceTypeLen = endian::to_network(serviceTypeLen);
128
129 std::copy_n((uint8_t*)&serviceTypeLen, slp::response::SIZE_SERVICE,
Patrick Venture537ff142018-11-01 16:37:09 -0700130 buff.data() + slp::response::OFFSET_SERVICE_LEN);
Ratan Gupta07c462a2016-12-14 00:40:30 +0530131
132 /* service type data */
133 std::copy_n((uint8_t*)service.c_str(), service.length(),
Patrick Venture537ff142018-11-01 16:37:09 -0700134 (buff.data() + slp::response::OFFSET_SERVICE));
Ratan Gupta07c462a2016-12-14 00:40:30 +0530135
136 return std::make_tuple(slp::SUCCESS, buff);
137}
138
Patrick Venture537ff142018-11-01 16:37:09 -0700139std::tuple<int, buffer> processSrvRequest(const Message& req)
Ratan Gupta07c462a2016-12-14 00:40:30 +0530140{
141
142 /*
143 Service Reply
144 0 1 2 3
145 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
146 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
147 | Service Location header (function = SrvRply = 2) |
148 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
149 | Error Code | URL Entry count |
150 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
151 | <URL Entry 1> ... <URL Entry N> \
152 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
153
154 URL Entry
155 0 1 2 3
156 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
157 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
158 | Reserved | Lifetime | URL Length |
159 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
160 |URL len, contd.| URL (variable length) \
161 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
162 |# of URL auths | Auth. blocks (if any) \
163 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
164 */
165
166 buffer buff;
Patrick Venture537ff142018-11-01 16:37:09 -0700167 // Get all the services which are registered
Ratan Gupta07c462a2016-12-14 00:40:30 +0530168 slp::handler::internal::ServiceList svcList =
Ratan Guptaead7a3c2017-01-05 15:45:09 +0530169 slp::handler::internal::readSLPServiceInfo();
Ratan Gupta07c462a2016-12-14 00:40:30 +0530170 if (svcList.size() <= 0)
171 {
172 buff.resize(0);
Ratan Gupta0d3e9e32017-02-10 22:27:12 +0530173 std::cerr << "SLP unable to read the service info\n";
Ratan Gupta07c462a2016-12-14 00:40:30 +0530174 return std::make_tuple((int)slp::Error::INTERNAL_ERROR, buff);
175 }
176
Patrick Venture537ff142018-11-01 16:37:09 -0700177 // return error if serice type doesn't match
Ratan Gupta07c462a2016-12-14 00:40:30 +0530178 auto& svcName = req.body.srvrqst.srvType;
179 auto svcIt = svcList.find(svcName);
180 if (svcIt == svcList.end())
181 {
182 buff.resize(0);
Ratan Gupta0d3e9e32017-02-10 22:27:12 +0530183 std::cerr << "SLP unable to find the service=" << svcName << "\n";
Ratan Gupta07c462a2016-12-14 00:40:30 +0530184 return std::make_tuple((int)slp::Error::INTERNAL_ERROR, buff);
185 }
Patrick Venture537ff142018-11-01 16:37:09 -0700186 // Get all the interface address
Ratan Gupta07c462a2016-12-14 00:40:30 +0530187 auto ifaddrList = slp::handler::internal::getIntfAddrs();
188 if (ifaddrList.size() <= 0)
189 {
190 buff.resize(0);
Ratan Gupta0d3e9e32017-02-10 22:27:12 +0530191 std::cerr << "SLP unable to read the interface address\n";
Ratan Gupta07c462a2016-12-14 00:40:30 +0530192 return std::make_tuple((int)slp::Error::INTERNAL_ERROR, buff);
193 }
194
195 buff = prepareHeader(req);
Patrick Venture537ff142018-11-01 16:37:09 -0700196 // Calculate the length and resize the buffer
197 uint8_t length = buff.size() + /* 14 bytes header + length of langtag */
198 slp::response::SIZE_ERROR + /* 2 bytes error code */
199 slp::response::SIZE_URL_COUNT; /* 2 bytes srvtype len */
Ratan Gupta07c462a2016-12-14 00:40:30 +0530200
201 buff.resize(length);
202
Patrick Venture537ff142018-11-01 16:37:09 -0700203 // Populate the url count
Ratan Gupta07c462a2016-12-14 00:40:30 +0530204 uint16_t urlCount = ifaddrList.size();
205 urlCount = endian::to_network(urlCount);
206
207 std::copy_n((uint8_t*)&urlCount, slp::response::SIZE_URL_COUNT,
Patrick Venture537ff142018-11-01 16:37:09 -0700208 buff.data() + slp::response::OFFSET_URL_ENTRY);
Ratan Gupta07c462a2016-12-14 00:40:30 +0530209
Patrick Venture537ff142018-11-01 16:37:09 -0700210 // Find the service
Ratan Gupta07c462a2016-12-14 00:40:30 +0530211 const slp::ConfigData& svc = svcIt->second;
Patrick Venture537ff142018-11-01 16:37:09 -0700212 // Populate the URL Entries
Ratan Gupta07c462a2016-12-14 00:40:30 +0530213 auto pos = slp::response::OFFSET_URL_ENTRY + slp::response::SIZE_URL_COUNT;
214 for (const auto& addr : ifaddrList)
215 {
Patrick Venture537ff142018-11-01 16:37:09 -0700216 std::string url =
217 svc.name + ':' + svc.type + "//" + addr + ',' + svc.port;
Ratan Gupta07c462a2016-12-14 00:40:30 +0530218
Patrick Venture537ff142018-11-01 16:37:09 -0700219 buff.resize(buff.size() + slp::response::SIZE_URL_ENTRY + url.length());
Ratan Gupta07c462a2016-12-14 00:40:30 +0530220
221 uint8_t reserved = 0;
222 uint16_t auth = 0;
223 uint16_t lifetime = endian::to_network<uint16_t>(slp::LIFETIME);
224 uint16_t urlLength = url.length();
225
226 std::copy_n((uint8_t*)&reserved, slp::response::SIZE_RESERVED,
227 buff.data() + pos);
228
229 pos += slp::response::SIZE_RESERVED;
230
Ratan Gupta07c462a2016-12-14 00:40:30 +0530231 std::copy_n((uint8_t*)&lifetime, slp::response::SIZE_LIFETIME,
232 buff.data() + pos);
233
234 pos += slp::response::SIZE_LIFETIME;
235
236 urlLength = endian::to_network(urlLength);
237 std::copy_n((uint8_t*)&urlLength, slp::response::SIZE_URLLENGTH,
238 buff.data() + pos);
239 pos += slp::response::SIZE_URLLENGTH;
240
Patrick Venture537ff142018-11-01 16:37:09 -0700241 std::copy_n((uint8_t*)url.c_str(), url.length(), buff.data() + pos);
Ratan Gupta07c462a2016-12-14 00:40:30 +0530242 pos += url.length();
243
244 std::copy_n((uint8_t*)&auth, slp::response::SIZE_AUTH,
245 buff.data() + pos);
246 pos += slp::response::SIZE_AUTH;
247 }
248 uint8_t packetLength = buff.size();
249 std::copy_n((uint8_t*)&packetLength, slp::header::SIZE_VERSION,
Patrick Venture537ff142018-11-01 16:37:09 -0700250 buff.data() + slp::header::OFFSET_LENGTH);
Ratan Gupta07c462a2016-12-14 00:40:30 +0530251
252 return std::make_tuple((int)slp::SUCCESS, buff);
253}
254
255std::list<std::string> getIntfAddrs()
256{
257 std::list<std::string> addrList;
258
259 struct ifaddrs* ifaddr;
260 // attempt to fill struct with ifaddrs
261 if (getifaddrs(&ifaddr) == -1)
262 {
263 return addrList;
264 }
265
Patrick Venture537ff142018-11-01 16:37:09 -0700266 slp::deleted_unique_ptr<ifaddrs> ifaddrPtr(
267 ifaddr, [](ifaddrs* addr) { freeifaddrs(addr); });
Ratan Gupta07c462a2016-12-14 00:40:30 +0530268
269 ifaddr = nullptr;
270
271 for (ifaddrs* ifa = ifaddrPtr.get(); ifa != nullptr; ifa = ifa->ifa_next)
272 {
273 // walk interfaces
274 if (ifa->ifa_addr == nullptr)
275 {
276 continue;
277 }
278
279 // get only INET interfaces not ipv6
280 if (ifa->ifa_addr->sa_family == AF_INET)
281 {
282 // if loopback, or not running ignore
283 if ((ifa->ifa_flags & IFF_LOOPBACK) ||
284 !(ifa->ifa_flags & IFF_RUNNING))
285 {
286 continue;
287 }
288
Patrick Venture537ff142018-11-01 16:37:09 -0700289 char tmp[INET_ADDRSTRLEN] = {0};
Ratan Gupta07c462a2016-12-14 00:40:30 +0530290
291 inet_ntop(AF_INET,
Patrick Venture537ff142018-11-01 16:37:09 -0700292 &(((struct sockaddr_in*)(ifa->ifa_addr))->sin_addr), tmp,
Ratan Gupta07c462a2016-12-14 00:40:30 +0530293 sizeof(tmp));
294 addrList.emplace_back(tmp);
295 }
296 }
297
298 return addrList;
299}
300
Patrick Venture537ff142018-11-01 16:37:09 -0700301slp::handler::internal::ServiceList readSLPServiceInfo()
Ratan Gupta07c462a2016-12-14 00:40:30 +0530302{
303 using namespace std::string_literals;
Ratan Gupta07c462a2016-12-14 00:40:30 +0530304 slp::handler::internal::ServiceList svcLst;
Ratan Gupta07c462a2016-12-14 00:40:30 +0530305 slp::ConfigData service;
Ratan Guptaead7a3c2017-01-05 15:45:09 +0530306 struct dirent* dent = nullptr;
Ratan Gupta07c462a2016-12-14 00:40:30 +0530307
Ratan Guptaead7a3c2017-01-05 15:45:09 +0530308 // Open the services dir and get the service info
309 // from service files.
310 // Service File format would be "ServiceName serviceType Port"
311 DIR* dir = opendir(SERVICE_DIR);
312 // wrap the pointer into smart pointer.
Patrick Venture537ff142018-11-01 16:37:09 -0700313 slp::deleted_unique_ptr<DIR> dirPtr(dir, [](DIR* dir) {
Ratan Guptaead7a3c2017-01-05 15:45:09 +0530314 if (!dir)
315 {
316 closedir(dir);
317 }
318 });
319 dir = nullptr;
320
321 if (dirPtr.get())
322 {
323 while ((dent = readdir(dirPtr.get())) != NULL)
324 {
Patrick Venture537ff142018-11-01 16:37:09 -0700325 if (dent->d_type == DT_REG) // regular file
Ratan Guptaead7a3c2017-01-05 15:45:09 +0530326 {
327 auto absFileName = std::string(SERVICE_DIR) + dent->d_name;
328 std::ifstream readFile(absFileName);
329 readFile >> service;
330 service.name = "service:"s + service.name;
331 svcLst.emplace(service.name, service);
332 }
333 }
Ratan Guptaead7a3c2017-01-05 15:45:09 +0530334 }
Ratan Gupta07c462a2016-12-14 00:40:30 +0530335 return svcLst;
336}
Patrick Venture537ff142018-11-01 16:37:09 -0700337} // namespace internal
Ratan Gupta07c462a2016-12-14 00:40:30 +0530338
Patrick Venture537ff142018-11-01 16:37:09 -0700339std::tuple<int, buffer> processRequest(const Message& msg)
Ratan Gupta07c462a2016-12-14 00:40:30 +0530340{
341 int rc = slp::SUCCESS;
342 buffer resp(0);
Patrick Venture537ff142018-11-01 16:37:09 -0700343 std::cout << "SLP Processing Request=" << msg.header.functionID << "\n";
Brad Bishopb5e632a2018-02-23 15:22:12 -0500344
Ratan Gupta07c462a2016-12-14 00:40:30 +0530345 switch (msg.header.functionID)
346 {
Ratan Gupta07c462a2016-12-14 00:40:30 +0530347 case (uint8_t)slp::FunctionType::SRVTYPERQST:
Patrick Venture537ff142018-11-01 16:37:09 -0700348 std::tie(rc, resp) =
349 slp::handler::internal::processSrvTypeRequest(msg);
Ratan Gupta07c462a2016-12-14 00:40:30 +0530350 break;
351 case (uint8_t)slp::FunctionType::SRVRQST:
352 std::tie(rc, resp) = slp::handler::internal::processSrvRequest(msg);
353 break;
354 default:
355 rc = (uint8_t)slp::Error::MSG_NOT_SUPPORTED;
356 }
357 return std::make_tuple(rc, resp);
358}
359
Patrick Venture537ff142018-11-01 16:37:09 -0700360buffer processError(const Message& req, uint8_t err)
Ratan Gupta07c462a2016-12-14 00:40:30 +0530361{
362 buffer buff;
363 buff = slp::handler::internal::prepareHeader(req);
364
365 std::copy_n(&err, slp::response::SIZE_ERROR,
Patrick Venture537ff142018-11-01 16:37:09 -0700366 buff.data() + slp::response::OFFSET_ERROR);
Ratan Gupta07c462a2016-12-14 00:40:30 +0530367 return buff;
Ratan Gupta07c462a2016-12-14 00:40:30 +0530368}
Patrick Venture537ff142018-11-01 16:37:09 -0700369} // namespace handler
370} // namespace slp