blob: 5fd3e3876accc15aecee8a31b84402a3ff903f91 [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);
93 return std::make_tuple((int)slp::Error::INTERNAL_ERROR, buff);
94 }
95
96 std::string service;
97 bool firstIteration = true;
98 for_each(svcList.cbegin(), svcList.cend(),
99 [&service, &firstIteration](const auto& svc)
100 {
101 if (firstIteration == true)
102 {
103 service = svc.first;
104 firstIteration = false;
105 }
106 else
107 {
108 service += ",";
109 service += svc.first;
110 }
111 });
112
113 buff = prepareHeader(req);
114
115 /* Need to modify the length and the function type field of the header
116 * as it is dependent on the handler of the service */
117
118 std::cout << "service=" << service.c_str() << "\n";
119
120 uint8_t length = buff.size() + /* 14 bytes header + length of langtag */
121 slp::response::SIZE_ERROR + /* 2 byte err code */
122 slp::response::SIZE_SERVICE + /* 2 byte srvtype len */
123 service.length();
124
125
126 buff.resize(length);
127
128 std::copy_n(&length, slp::header::SIZE_LENGTH,
129 buff.data() +
130 slp::header::OFFSET_LENGTH);
131
132 /* error code is already set to 0 moving to service type len */
133
134 uint16_t serviceTypeLen = service.length();
135 serviceTypeLen = endian::to_network(serviceTypeLen);
136
137 std::copy_n((uint8_t*)&serviceTypeLen, slp::response::SIZE_SERVICE,
138 buff.data() +
139 slp::response::OFFSET_SERVICE_LEN);
140
141 /* service type data */
142 std::copy_n((uint8_t*)service.c_str(), service.length(),
143 (buff.data() +
144 slp::response::OFFSET_SERVICE));
145
146 return std::make_tuple(slp::SUCCESS, buff);
147}
148
149std::tuple<int, buffer> processSrvRequest(
150 const Message& req)
151{
152
153 /*
154 Service Reply
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 | Service Location header (function = SrvRply = 2) |
159 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
160 | Error Code | URL Entry count |
161 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
162 | <URL Entry 1> ... <URL Entry N> \
163 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
164
165 URL Entry
166 0 1 2 3
167 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
168 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
169 | Reserved | Lifetime | URL Length |
170 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
171 |URL len, contd.| URL (variable length) \
172 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
173 |# of URL auths | Auth. blocks (if any) \
174 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
175 */
176
177 buffer buff;
178 //Get all the services which are registered
179 slp::handler::internal::ServiceList svcList =
Ratan Guptaead7a3c2017-01-05 15:45:09 +0530180 slp::handler::internal::readSLPServiceInfo();
Ratan Gupta07c462a2016-12-14 00:40:30 +0530181 if (svcList.size() <= 0)
182 {
183 buff.resize(0);
184 return std::make_tuple((int)slp::Error::INTERNAL_ERROR, buff);
185 }
186
187 //return error if serice type doesn't match
188 auto& svcName = req.body.srvrqst.srvType;
189 auto svcIt = svcList.find(svcName);
190 if (svcIt == svcList.end())
191 {
192 buff.resize(0);
193 return std::make_tuple((int)slp::Error::INTERNAL_ERROR, buff);
194 }
195 //Get all the interface address
196 auto ifaddrList = slp::handler::internal::getIntfAddrs();
197 if (ifaddrList.size() <= 0)
198 {
199 buff.resize(0);
200 return std::make_tuple((int)slp::Error::INTERNAL_ERROR, buff);
201 }
202
203 buff = prepareHeader(req);
204 //Calculate the length and resize the buffer
205 uint8_t length = buff.size() + /* 14 bytes header + length of langtag */
206 slp::response::SIZE_ERROR + /* 2 bytes error code */
207 slp::response::SIZE_URL_COUNT; /* 2 bytes srvtype len */
208
209 buff.resize(length);
210
211 //Populate the url count
212 uint16_t urlCount = ifaddrList.size();
213 urlCount = endian::to_network(urlCount);
214
215 std::copy_n((uint8_t*)&urlCount, slp::response::SIZE_URL_COUNT,
216 buff.data() +
217 slp::response::OFFSET_URL_ENTRY);
218
219 //Find the service
220 const slp::ConfigData& svc = svcIt->second;
221 //Populate the URL Entrys
222 auto pos = slp::response::OFFSET_URL_ENTRY + slp::response::SIZE_URL_COUNT;
223 for (const auto& addr : ifaddrList)
224 {
225 std::string url = svc.name + ':' + svc.type +
226 "//" + addr + ',' + svc.port;
227
228
229 buff.resize(buff.size() +
230 slp::response::SIZE_URL_ENTRY +
231 url.length());
232
233 uint8_t reserved = 0;
234 uint16_t auth = 0;
235 uint16_t lifetime = endian::to_network<uint16_t>(slp::LIFETIME);
236 uint16_t urlLength = url.length();
237
238 std::copy_n((uint8_t*)&reserved, slp::response::SIZE_RESERVED,
239 buff.data() + pos);
240
241 pos += slp::response::SIZE_RESERVED;
242
243
244 std::copy_n((uint8_t*)&lifetime, slp::response::SIZE_LIFETIME,
245 buff.data() + pos);
246
247 pos += slp::response::SIZE_LIFETIME;
248
249 urlLength = endian::to_network(urlLength);
250 std::copy_n((uint8_t*)&urlLength, slp::response::SIZE_URLLENGTH,
251 buff.data() + pos);
252 pos += slp::response::SIZE_URLLENGTH;
253
254 std::copy_n((uint8_t*)url.c_str(), url.length(),
255 buff.data() + pos);
256 pos += url.length();
257
258 std::copy_n((uint8_t*)&auth, slp::response::SIZE_AUTH,
259 buff.data() + pos);
260 pos += slp::response::SIZE_AUTH;
261 }
262 uint8_t packetLength = buff.size();
263 std::copy_n((uint8_t*)&packetLength, slp::header::SIZE_VERSION,
264 buff.data() +
265 slp::header::OFFSET_LENGTH);
266
267 return std::make_tuple((int)slp::SUCCESS, buff);
268}
269
270std::list<std::string> getIntfAddrs()
271{
272 std::list<std::string> addrList;
273
274 struct ifaddrs* ifaddr;
275 // attempt to fill struct with ifaddrs
276 if (getifaddrs(&ifaddr) == -1)
277 {
278 return addrList;
279 }
280
281 slp::deleted_unique_ptr<ifaddrs> ifaddrPtr(ifaddr, [](ifaddrs * addr)
282 {
283 freeifaddrs(addr);
284 });
285
286 ifaddr = nullptr;
287
288 for (ifaddrs* ifa = ifaddrPtr.get(); ifa != nullptr; ifa = ifa->ifa_next)
289 {
290 // walk interfaces
291 if (ifa->ifa_addr == nullptr)
292 {
293 continue;
294 }
295
296 // get only INET interfaces not ipv6
297 if (ifa->ifa_addr->sa_family == AF_INET)
298 {
299 // if loopback, or not running ignore
300 if ((ifa->ifa_flags & IFF_LOOPBACK) ||
301 !(ifa->ifa_flags & IFF_RUNNING))
302 {
303 continue;
304 }
305
306 char tmp[INET_ADDRSTRLEN] = { 0 };
307
308 inet_ntop(AF_INET,
309 &(((struct sockaddr_in*)(ifa->ifa_addr))->sin_addr),
310 tmp,
311 sizeof(tmp));
312 addrList.emplace_back(tmp);
313 }
314 }
315
316 return addrList;
317}
318
Ratan Guptaead7a3c2017-01-05 15:45:09 +0530319slp::handler::internal::ServiceList readSLPServiceInfo()
Ratan Gupta07c462a2016-12-14 00:40:30 +0530320{
321 using namespace std::string_literals;
Ratan Gupta07c462a2016-12-14 00:40:30 +0530322 slp::handler::internal::ServiceList svcLst;
Ratan Gupta07c462a2016-12-14 00:40:30 +0530323 slp::ConfigData service;
Ratan Guptaead7a3c2017-01-05 15:45:09 +0530324 struct dirent* dent = nullptr;
Ratan Gupta07c462a2016-12-14 00:40:30 +0530325
Ratan Guptaead7a3c2017-01-05 15:45:09 +0530326 // Open the services dir and get the service info
327 // from service files.
328 // Service File format would be "ServiceName serviceType Port"
329 DIR* dir = opendir(SERVICE_DIR);
330 // wrap the pointer into smart pointer.
331 slp::deleted_unique_ptr<DIR> dirPtr(dir, [](DIR * dir)
332 {
333 if (!dir)
334 {
335 closedir(dir);
336 }
337 });
338 dir = nullptr;
339
340 if (dirPtr.get())
341 {
342 while ((dent = readdir(dirPtr.get())) != NULL)
343 {
344 if (dent->d_type == DT_REG) //regular file
345 {
346 auto absFileName = std::string(SERVICE_DIR) + dent->d_name;
347 std::ifstream readFile(absFileName);
348 readFile >> service;
349 service.name = "service:"s + service.name;
350 svcLst.emplace(service.name, service);
351 }
352 }
353
354 }
Ratan Gupta07c462a2016-12-14 00:40:30 +0530355 return svcLst;
356}
357}//namespace internal
358
359std::tuple<int, buffer> processRequest(
360 const Message& msg)
361{
362 int rc = slp::SUCCESS;
363 buffer resp(0);
364 switch (msg.header.functionID)
365 {
366 case (uint8_t)slp::FunctionType::SRVTYPERQST:
367 std::tie(rc, resp) = slp::handler::internal::processSrvTypeRequest(msg);
368 break;
369 case (uint8_t)slp::FunctionType::SRVRQST:
370 std::tie(rc, resp) = slp::handler::internal::processSrvRequest(msg);
371 break;
372 default:
373 rc = (uint8_t)slp::Error::MSG_NOT_SUPPORTED;
374 }
375 return std::make_tuple(rc, resp);
376}
377
378buffer processError(const Message& req,
379 uint8_t err)
380{
381 buffer buff;
382 buff = slp::handler::internal::prepareHeader(req);
383
384 std::copy_n(&err, slp::response::SIZE_ERROR,
385 buff.data() +
386 slp::response::OFFSET_ERROR);
387 return buff;
388
389}
390}//namespace handler
391}//namespace slp