blob: 14ed15f5d236503cc458110db21d26066c25077c [file] [log] [blame]
Ratan Gupta07c462a2016-12-14 00:40:30 +05301#include "slp.hpp"
2
3#include <arpa/inet.h>
Ratan Guptaead7a3c2017-01-05 15:45:09 +05304#include <dirent.h>
Ratan Gupta07c462a2016-12-14 00:40:30 +05305#include <ifaddrs.h>
6#include <net/if.h>
7#include <string.h>
8
9#include <algorithm>
10
Ratan Guptaead7a3c2017-01-05 15:45:09 +053011#include "config.h"
Ratan Gupta07c462a2016-12-14 00:40:30 +053012#include "endian.hpp"
13#include "slp_meta.hpp"
14
15namespace slp
16{
17namespace handler
18{
19
20namespace internal
21{
22
23buffer prepareHeader(const Message& req)
24{
25 uint8_t length = slp::header::MIN_LEN + /* 14 bytes for header */
26 req.header.langtag.length() + /* Actual length of lang tag */
27 slp::response::SIZE_ERROR; /* 2 bytes for error code */
28
29 buffer buff(length, 0);
30
31 buff[slp::header::OFFSET_VERSION] = req.header.version;
32
33 //will increment the function id from 1 as reply
34 buff[slp::header::OFFSET_FUNCTION] = req.header.functionID + 1;
35
36 std::copy_n(&length, slp::header::SIZE_LENGTH,
37 buff.data() +
38 slp::header::OFFSET_LENGTH);
39
40 auto flags = endian::to_network(req.header.flags);
41
42 std::copy_n((uint8_t*)&flags, slp::header::SIZE_FLAGS,
43 buff.data() +
44 slp::header::OFFSET_FLAGS);
45
46 std::copy_n(req.header.extOffset.data(), slp::header::SIZE_EXT,
47 buff.data() +
48 slp::header::OFFSET_EXT);
49
50 auto xid = endian::to_network(req.header.xid);
51
52 std::copy_n((uint8_t*)&xid, slp::header::SIZE_XID,
53 buff.data() +
54 slp::header::OFFSET_XID);
55
56 uint16_t langtagLen = req.header.langtag.length();
57 langtagLen = endian::to_network(langtagLen);
58 std::copy_n((uint8_t*)&langtagLen, slp::header::SIZE_LANG,
59 buff.data() +
60 slp::header::OFFSET_LANG_LEN);
61
62 std::copy_n((uint8_t*)req.header.langtag.c_str(), req.header.langtag.length(),
63 buff.data() +
64 slp::header::OFFSET_LANG);
65 return buff;
66
67}
68
69std::tuple<int, buffer> processSrvTypeRequest(
70 const Message& req)
71{
72
73 /*
74 0 1 2 3
75 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
76 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
77 | Service Location header (function = SrvTypeRply = 10) |
78 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
79 | Error Code | length of <srvType-list> |
80 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
81 | <srvtype--list> \
82 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
83 */
84
85 buffer buff;
86
87 //read the slp service info from conf and create the service type string
88 slp::handler::internal::ServiceList svcList =
Ratan Guptaead7a3c2017-01-05 15:45:09 +053089 slp::handler::internal::readSLPServiceInfo();
Ratan Gupta07c462a2016-12-14 00:40:30 +053090 if (svcList.size() <= 0)
91 {
92 buff.resize(0);
Ratan Gupta0d3e9e32017-02-10 22:27:12 +053093 std::cerr << "SLP unable to read the service info\n";
Ratan Gupta07c462a2016-12-14 00:40:30 +053094 return std::make_tuple((int)slp::Error::INTERNAL_ERROR, buff);
95 }
96
97 std::string service;
98 bool firstIteration = true;
99 for_each(svcList.cbegin(), svcList.cend(),
100 [&service, &firstIteration](const auto& svc)
101 {
102 if (firstIteration == true)
103 {
104 service = svc.first;
105 firstIteration = false;
106 }
107 else
108 {
109 service += ",";
110 service += svc.first;
111 }
112 });
113
114 buff = prepareHeader(req);
115
116 /* Need to modify the length and the function type field of the header
117 * as it is dependent on the handler of the service */
118
119 std::cout << "service=" << service.c_str() << "\n";
120
121 uint8_t length = buff.size() + /* 14 bytes header + length of langtag */
122 slp::response::SIZE_ERROR + /* 2 byte err code */
123 slp::response::SIZE_SERVICE + /* 2 byte srvtype len */
124 service.length();
125
126
127 buff.resize(length);
128
129 std::copy_n(&length, slp::header::SIZE_LENGTH,
130 buff.data() +
131 slp::header::OFFSET_LENGTH);
132
133 /* error code is already set to 0 moving to service type len */
134
135 uint16_t serviceTypeLen = service.length();
136 serviceTypeLen = endian::to_network(serviceTypeLen);
137
138 std::copy_n((uint8_t*)&serviceTypeLen, slp::response::SIZE_SERVICE,
139 buff.data() +
140 slp::response::OFFSET_SERVICE_LEN);
141
142 /* service type data */
143 std::copy_n((uint8_t*)service.c_str(), service.length(),
144 (buff.data() +
145 slp::response::OFFSET_SERVICE));
146
147 return std::make_tuple(slp::SUCCESS, buff);
148}
149
150std::tuple<int, buffer> processSrvRequest(
151 const Message& req)
152{
153
154 /*
155 Service Reply
156 0 1 2 3
157 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
158 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
159 | Service Location header (function = SrvRply = 2) |
160 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
161 | Error Code | URL Entry count |
162 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
163 | <URL Entry 1> ... <URL Entry N> \
164 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
165
166 URL Entry
167 0 1 2 3
168 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
169 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
170 | Reserved | Lifetime | URL Length |
171 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
172 |URL len, contd.| URL (variable length) \
173 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
174 |# of URL auths | Auth. blocks (if any) \
175 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
176 */
177
178 buffer buff;
179 //Get all the services which are registered
180 slp::handler::internal::ServiceList svcList =
Ratan Guptaead7a3c2017-01-05 15:45:09 +0530181 slp::handler::internal::readSLPServiceInfo();
Ratan Gupta07c462a2016-12-14 00:40:30 +0530182 if (svcList.size() <= 0)
183 {
184 buff.resize(0);
Ratan Gupta0d3e9e32017-02-10 22:27:12 +0530185 std::cerr << "SLP unable to read the service info\n";
Ratan Gupta07c462a2016-12-14 00:40:30 +0530186 return std::make_tuple((int)slp::Error::INTERNAL_ERROR, buff);
187 }
188
189 //return error if serice type doesn't match
190 auto& svcName = req.body.srvrqst.srvType;
191 auto svcIt = svcList.find(svcName);
192 if (svcIt == svcList.end())
193 {
194 buff.resize(0);
Ratan Gupta0d3e9e32017-02-10 22:27:12 +0530195 std::cerr << "SLP unable to find the service=" << svcName << "\n";
Ratan Gupta07c462a2016-12-14 00:40:30 +0530196 return std::make_tuple((int)slp::Error::INTERNAL_ERROR, buff);
197 }
198 //Get all the interface address
199 auto ifaddrList = slp::handler::internal::getIntfAddrs();
200 if (ifaddrList.size() <= 0)
201 {
202 buff.resize(0);
Ratan Gupta0d3e9e32017-02-10 22:27:12 +0530203 std::cerr << "SLP unable to read the interface address\n";
Ratan Gupta07c462a2016-12-14 00:40:30 +0530204 return std::make_tuple((int)slp::Error::INTERNAL_ERROR, buff);
205 }
206
207 buff = prepareHeader(req);
208 //Calculate the length and resize the buffer
209 uint8_t length = buff.size() + /* 14 bytes header + length of langtag */
210 slp::response::SIZE_ERROR + /* 2 bytes error code */
211 slp::response::SIZE_URL_COUNT; /* 2 bytes srvtype len */
212
213 buff.resize(length);
214
215 //Populate the url count
216 uint16_t urlCount = ifaddrList.size();
217 urlCount = endian::to_network(urlCount);
218
219 std::copy_n((uint8_t*)&urlCount, slp::response::SIZE_URL_COUNT,
220 buff.data() +
221 slp::response::OFFSET_URL_ENTRY);
222
223 //Find the service
224 const slp::ConfigData& svc = svcIt->second;
225 //Populate the URL Entrys
226 auto pos = slp::response::OFFSET_URL_ENTRY + slp::response::SIZE_URL_COUNT;
227 for (const auto& addr : ifaddrList)
228 {
229 std::string url = svc.name + ':' + svc.type +
230 "//" + addr + ',' + svc.port;
231
232
233 buff.resize(buff.size() +
234 slp::response::SIZE_URL_ENTRY +
235 url.length());
236
237 uint8_t reserved = 0;
238 uint16_t auth = 0;
239 uint16_t lifetime = endian::to_network<uint16_t>(slp::LIFETIME);
240 uint16_t urlLength = url.length();
241
242 std::copy_n((uint8_t*)&reserved, slp::response::SIZE_RESERVED,
243 buff.data() + pos);
244
245 pos += slp::response::SIZE_RESERVED;
246
247
248 std::copy_n((uint8_t*)&lifetime, slp::response::SIZE_LIFETIME,
249 buff.data() + pos);
250
251 pos += slp::response::SIZE_LIFETIME;
252
253 urlLength = endian::to_network(urlLength);
254 std::copy_n((uint8_t*)&urlLength, slp::response::SIZE_URLLENGTH,
255 buff.data() + pos);
256 pos += slp::response::SIZE_URLLENGTH;
257
258 std::copy_n((uint8_t*)url.c_str(), url.length(),
259 buff.data() + pos);
260 pos += url.length();
261
262 std::copy_n((uint8_t*)&auth, slp::response::SIZE_AUTH,
263 buff.data() + pos);
264 pos += slp::response::SIZE_AUTH;
265 }
266 uint8_t packetLength = buff.size();
267 std::copy_n((uint8_t*)&packetLength, slp::header::SIZE_VERSION,
268 buff.data() +
269 slp::header::OFFSET_LENGTH);
270
271 return std::make_tuple((int)slp::SUCCESS, buff);
272}
273
274std::list<std::string> getIntfAddrs()
275{
276 std::list<std::string> addrList;
277
278 struct ifaddrs* ifaddr;
279 // attempt to fill struct with ifaddrs
280 if (getifaddrs(&ifaddr) == -1)
281 {
282 return addrList;
283 }
284
285 slp::deleted_unique_ptr<ifaddrs> ifaddrPtr(ifaddr, [](ifaddrs * addr)
286 {
287 freeifaddrs(addr);
288 });
289
290 ifaddr = nullptr;
291
292 for (ifaddrs* ifa = ifaddrPtr.get(); ifa != nullptr; ifa = ifa->ifa_next)
293 {
294 // walk interfaces
295 if (ifa->ifa_addr == nullptr)
296 {
297 continue;
298 }
299
300 // get only INET interfaces not ipv6
301 if (ifa->ifa_addr->sa_family == AF_INET)
302 {
303 // if loopback, or not running ignore
304 if ((ifa->ifa_flags & IFF_LOOPBACK) ||
305 !(ifa->ifa_flags & IFF_RUNNING))
306 {
307 continue;
308 }
309
310 char tmp[INET_ADDRSTRLEN] = { 0 };
311
312 inet_ntop(AF_INET,
313 &(((struct sockaddr_in*)(ifa->ifa_addr))->sin_addr),
314 tmp,
315 sizeof(tmp));
316 addrList.emplace_back(tmp);
317 }
318 }
319
320 return addrList;
321}
322
Ratan Guptaead7a3c2017-01-05 15:45:09 +0530323slp::handler::internal::ServiceList readSLPServiceInfo()
Ratan Gupta07c462a2016-12-14 00:40:30 +0530324{
325 using namespace std::string_literals;
Ratan Gupta07c462a2016-12-14 00:40:30 +0530326 slp::handler::internal::ServiceList svcLst;
Ratan Gupta07c462a2016-12-14 00:40:30 +0530327 slp::ConfigData service;
Ratan Guptaead7a3c2017-01-05 15:45:09 +0530328 struct dirent* dent = nullptr;
Ratan Gupta07c462a2016-12-14 00:40:30 +0530329
Ratan Guptaead7a3c2017-01-05 15:45:09 +0530330 // Open the services dir and get the service info
331 // from service files.
332 // Service File format would be "ServiceName serviceType Port"
333 DIR* dir = opendir(SERVICE_DIR);
334 // wrap the pointer into smart pointer.
335 slp::deleted_unique_ptr<DIR> dirPtr(dir, [](DIR * dir)
336 {
337 if (!dir)
338 {
339 closedir(dir);
340 }
341 });
342 dir = nullptr;
343
344 if (dirPtr.get())
345 {
346 while ((dent = readdir(dirPtr.get())) != NULL)
347 {
348 if (dent->d_type == DT_REG) //regular file
349 {
350 auto absFileName = std::string(SERVICE_DIR) + dent->d_name;
351 std::ifstream readFile(absFileName);
352 readFile >> service;
353 service.name = "service:"s + service.name;
354 svcLst.emplace(service.name, service);
355 }
356 }
357
358 }
Ratan Gupta07c462a2016-12-14 00:40:30 +0530359 return svcLst;
360}
361}//namespace internal
362
363std::tuple<int, buffer> processRequest(
364 const Message& msg)
365{
366 int rc = slp::SUCCESS;
367 buffer resp(0);
368 switch (msg.header.functionID)
369 {
Ratan Gupta0d3e9e32017-02-10 22:27:12 +0530370 std::cout << "SLP Processing Request="
371 << msg.header.functionID <<"\n";
372
Ratan Gupta07c462a2016-12-14 00:40:30 +0530373 case (uint8_t)slp::FunctionType::SRVTYPERQST:
374 std::tie(rc, resp) = slp::handler::internal::processSrvTypeRequest(msg);
375 break;
376 case (uint8_t)slp::FunctionType::SRVRQST:
377 std::tie(rc, resp) = slp::handler::internal::processSrvRequest(msg);
378 break;
379 default:
380 rc = (uint8_t)slp::Error::MSG_NOT_SUPPORTED;
381 }
382 return std::make_tuple(rc, resp);
383}
384
385buffer processError(const Message& req,
386 uint8_t err)
387{
388 buffer buff;
389 buff = slp::handler::internal::prepareHeader(req);
390
391 std::copy_n(&err, slp::response::SIZE_ERROR,
392 buff.data() +
393 slp::response::OFFSET_ERROR);
394 return buff;
395
396}
397}//namespace handler
398}//namespace slp