blob: a99cd540f132b6802a0e21e5815d53999405fa6e [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{
Ratan Gupta07c462a2016-12-14 00:40:30 +053066 /*
67 0 1 2 3
68 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
69 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
70 | Service Location header (function = SrvTypeRply = 10) |
71 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
72 | Error Code | length of <srvType-list> |
73 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
74 | <srvtype--list> \
75 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
76 */
77
78 buffer buff;
79
Patrick Venture537ff142018-11-01 16:37:09 -070080 // read the slp service info from conf and create the service type string
Ratan Gupta07c462a2016-12-14 00:40:30 +053081 slp::handler::internal::ServiceList svcList =
Ratan Guptaead7a3c2017-01-05 15:45:09 +053082 slp::handler::internal::readSLPServiceInfo();
Ratan Gupta07c462a2016-12-14 00:40:30 +053083 if (svcList.size() <= 0)
84 {
85 buff.resize(0);
Ratan Gupta0d3e9e32017-02-10 22:27:12 +053086 std::cerr << "SLP unable to read the service info\n";
Ratan Gupta07c462a2016-12-14 00:40:30 +053087 return std::make_tuple((int)slp::Error::INTERNAL_ERROR, buff);
88 }
89
90 std::string service;
91 bool firstIteration = true;
92 for_each(svcList.cbegin(), svcList.cend(),
Patrick Venture537ff142018-11-01 16:37:09 -070093 [&service, &firstIteration](const auto& svc) {
Patrick Williamsaa902c62023-04-04 19:59:51 -050094 if (firstIteration == true)
95 {
96 service = svc.first;
97 firstIteration = false;
98 }
99 else
100 {
101 service += ",";
102 service += svc.first;
103 }
104 });
Ratan Gupta07c462a2016-12-14 00:40:30 +0530105
106 buff = prepareHeader(req);
107
108 /* Need to modify the length and the function type field of the header
109 * as it is dependent on the handler of the service */
110
111 std::cout << "service=" << service.c_str() << "\n";
112
Patrick Venture537ff142018-11-01 16:37:09 -0700113 uint8_t length = buff.size() + /* 14 bytes header + length of langtag */
114 slp::response::SIZE_ERROR + /* 2 byte err code */
115 slp::response::SIZE_SERVICE + /* 2 byte srvtype len */
116 service.length();
Ratan Gupta07c462a2016-12-14 00:40:30 +0530117
118 buff.resize(length);
119
120 std::copy_n(&length, slp::header::SIZE_LENGTH,
Patrick Venture537ff142018-11-01 16:37:09 -0700121 buff.data() + slp::header::OFFSET_LENGTH);
Ratan Gupta07c462a2016-12-14 00:40:30 +0530122
123 /* error code is already set to 0 moving to service type len */
124
125 uint16_t serviceTypeLen = service.length();
126 serviceTypeLen = endian::to_network(serviceTypeLen);
127
128 std::copy_n((uint8_t*)&serviceTypeLen, slp::response::SIZE_SERVICE,
Patrick Venture537ff142018-11-01 16:37:09 -0700129 buff.data() + slp::response::OFFSET_SERVICE_LEN);
Ratan Gupta07c462a2016-12-14 00:40:30 +0530130
131 /* service type data */
132 std::copy_n((uint8_t*)service.c_str(), service.length(),
Patrick Venture537ff142018-11-01 16:37:09 -0700133 (buff.data() + slp::response::OFFSET_SERVICE));
Ratan Gupta07c462a2016-12-14 00:40:30 +0530134
135 return std::make_tuple(slp::SUCCESS, buff);
136}
137
Patrick Venture537ff142018-11-01 16:37:09 -0700138std::tuple<int, buffer> processSrvRequest(const Message& req)
Ratan Gupta07c462a2016-12-14 00:40:30 +0530139{
Ratan Gupta07c462a2016-12-14 00:40:30 +0530140 /*
141 Service Reply
142 0 1 2 3
143 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
144 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
145 | Service Location header (function = SrvRply = 2) |
146 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
147 | Error Code | URL Entry count |
148 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
149 | <URL Entry 1> ... <URL Entry N> \
150 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
151
152 URL Entry
153 0 1 2 3
154 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
155 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
156 | Reserved | Lifetime | URL Length |
157 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
158 |URL len, contd.| URL (variable length) \
159 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
160 |# of URL auths | Auth. blocks (if any) \
161 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
162 */
163
164 buffer buff;
Patrick Venture537ff142018-11-01 16:37:09 -0700165 // Get all the services which are registered
Ratan Gupta07c462a2016-12-14 00:40:30 +0530166 slp::handler::internal::ServiceList svcList =
Ratan Guptaead7a3c2017-01-05 15:45:09 +0530167 slp::handler::internal::readSLPServiceInfo();
Ratan Gupta07c462a2016-12-14 00:40:30 +0530168 if (svcList.size() <= 0)
169 {
170 buff.resize(0);
Ratan Gupta0d3e9e32017-02-10 22:27:12 +0530171 std::cerr << "SLP unable to read the service info\n";
Ratan Gupta07c462a2016-12-14 00:40:30 +0530172 return std::make_tuple((int)slp::Error::INTERNAL_ERROR, buff);
173 }
174
Patrick Venture537ff142018-11-01 16:37:09 -0700175 // return error if serice type doesn't match
Ratan Gupta07c462a2016-12-14 00:40:30 +0530176 auto& svcName = req.body.srvrqst.srvType;
177 auto svcIt = svcList.find(svcName);
178 if (svcIt == svcList.end())
179 {
180 buff.resize(0);
Ratan Gupta0d3e9e32017-02-10 22:27:12 +0530181 std::cerr << "SLP unable to find the service=" << svcName << "\n";
Ratan Gupta07c462a2016-12-14 00:40:30 +0530182 return std::make_tuple((int)slp::Error::INTERNAL_ERROR, buff);
183 }
Patrick Venture537ff142018-11-01 16:37:09 -0700184 // Get all the interface address
Ratan Gupta07c462a2016-12-14 00:40:30 +0530185 auto ifaddrList = slp::handler::internal::getIntfAddrs();
186 if (ifaddrList.size() <= 0)
187 {
188 buff.resize(0);
Ratan Gupta0d3e9e32017-02-10 22:27:12 +0530189 std::cerr << "SLP unable to read the interface address\n";
Ratan Gupta07c462a2016-12-14 00:40:30 +0530190 return std::make_tuple((int)slp::Error::INTERNAL_ERROR, buff);
191 }
192
193 buff = prepareHeader(req);
Patrick Venture537ff142018-11-01 16:37:09 -0700194 // Calculate the length and resize the buffer
195 uint8_t length = buff.size() + /* 14 bytes header + length of langtag */
196 slp::response::SIZE_ERROR + /* 2 bytes error code */
197 slp::response::SIZE_URL_COUNT; /* 2 bytes srvtype len */
Ratan Gupta07c462a2016-12-14 00:40:30 +0530198
199 buff.resize(length);
200
Patrick Venture537ff142018-11-01 16:37:09 -0700201 // Populate the url count
Ratan Gupta07c462a2016-12-14 00:40:30 +0530202 uint16_t urlCount = ifaddrList.size();
203 urlCount = endian::to_network(urlCount);
204
205 std::copy_n((uint8_t*)&urlCount, slp::response::SIZE_URL_COUNT,
Patrick Venture537ff142018-11-01 16:37:09 -0700206 buff.data() + slp::response::OFFSET_URL_ENTRY);
Ratan Gupta07c462a2016-12-14 00:40:30 +0530207
Patrick Venture537ff142018-11-01 16:37:09 -0700208 // Find the service
Ratan Gupta07c462a2016-12-14 00:40:30 +0530209 const slp::ConfigData& svc = svcIt->second;
Patrick Venture537ff142018-11-01 16:37:09 -0700210 // Populate the URL Entries
Ratan Gupta07c462a2016-12-14 00:40:30 +0530211 auto pos = slp::response::OFFSET_URL_ENTRY + slp::response::SIZE_URL_COUNT;
212 for (const auto& addr : ifaddrList)
213 {
Patrick Williamsaa902c62023-04-04 19:59:51 -0500214 std::string url = svc.name + ':' + svc.type + "//" + addr + ',' +
215 svc.port;
Ratan Gupta07c462a2016-12-14 00:40:30 +0530216
Patrick Venture537ff142018-11-01 16:37:09 -0700217 buff.resize(buff.size() + slp::response::SIZE_URL_ENTRY + url.length());
Ratan Gupta07c462a2016-12-14 00:40:30 +0530218
219 uint8_t reserved = 0;
220 uint16_t auth = 0;
221 uint16_t lifetime = endian::to_network<uint16_t>(slp::LIFETIME);
222 uint16_t urlLength = url.length();
223
224 std::copy_n((uint8_t*)&reserved, slp::response::SIZE_RESERVED,
225 buff.data() + pos);
226
227 pos += slp::response::SIZE_RESERVED;
228
Ratan Gupta07c462a2016-12-14 00:40:30 +0530229 std::copy_n((uint8_t*)&lifetime, slp::response::SIZE_LIFETIME,
230 buff.data() + pos);
231
232 pos += slp::response::SIZE_LIFETIME;
233
234 urlLength = endian::to_network(urlLength);
235 std::copy_n((uint8_t*)&urlLength, slp::response::SIZE_URLLENGTH,
236 buff.data() + pos);
237 pos += slp::response::SIZE_URLLENGTH;
238
Patrick Venture537ff142018-11-01 16:37:09 -0700239 std::copy_n((uint8_t*)url.c_str(), url.length(), buff.data() + pos);
Ratan Gupta07c462a2016-12-14 00:40:30 +0530240 pos += url.length();
241
242 std::copy_n((uint8_t*)&auth, slp::response::SIZE_AUTH,
243 buff.data() + pos);
244 pos += slp::response::SIZE_AUTH;
245 }
246 uint8_t packetLength = buff.size();
247 std::copy_n((uint8_t*)&packetLength, slp::header::SIZE_VERSION,
Patrick Venture537ff142018-11-01 16:37:09 -0700248 buff.data() + slp::header::OFFSET_LENGTH);
Ratan Gupta07c462a2016-12-14 00:40:30 +0530249
250 return std::make_tuple((int)slp::SUCCESS, buff);
251}
252
253std::list<std::string> getIntfAddrs()
254{
255 std::list<std::string> addrList;
256
257 struct ifaddrs* ifaddr;
258 // attempt to fill struct with ifaddrs
259 if (getifaddrs(&ifaddr) == -1)
260 {
261 return addrList;
262 }
263
Patrick Venture537ff142018-11-01 16:37:09 -0700264 slp::deleted_unique_ptr<ifaddrs> ifaddrPtr(
265 ifaddr, [](ifaddrs* addr) { freeifaddrs(addr); });
Ratan Gupta07c462a2016-12-14 00:40:30 +0530266
267 ifaddr = nullptr;
268
269 for (ifaddrs* ifa = ifaddrPtr.get(); ifa != nullptr; ifa = ifa->ifa_next)
270 {
271 // walk interfaces
272 if (ifa->ifa_addr == nullptr)
273 {
274 continue;
275 }
276
277 // get only INET interfaces not ipv6
278 if (ifa->ifa_addr->sa_family == AF_INET)
279 {
280 // if loopback, or not running ignore
281 if ((ifa->ifa_flags & IFF_LOOPBACK) ||
282 !(ifa->ifa_flags & IFF_RUNNING))
283 {
284 continue;
285 }
286
Patrick Venture537ff142018-11-01 16:37:09 -0700287 char tmp[INET_ADDRSTRLEN] = {0};
Ratan Gupta07c462a2016-12-14 00:40:30 +0530288
289 inet_ntop(AF_INET,
Patrick Venture537ff142018-11-01 16:37:09 -0700290 &(((struct sockaddr_in*)(ifa->ifa_addr))->sin_addr), tmp,
Ratan Gupta07c462a2016-12-14 00:40:30 +0530291 sizeof(tmp));
292 addrList.emplace_back(tmp);
293 }
294 }
295
296 return addrList;
297}
298
Patrick Venture537ff142018-11-01 16:37:09 -0700299slp::handler::internal::ServiceList readSLPServiceInfo()
Ratan Gupta07c462a2016-12-14 00:40:30 +0530300{
301 using namespace std::string_literals;
Ratan Gupta07c462a2016-12-14 00:40:30 +0530302 slp::handler::internal::ServiceList svcLst;
Ratan Gupta07c462a2016-12-14 00:40:30 +0530303 slp::ConfigData service;
Ratan Guptaead7a3c2017-01-05 15:45:09 +0530304 struct dirent* dent = nullptr;
Ratan Gupta07c462a2016-12-14 00:40:30 +0530305
Ratan Guptaead7a3c2017-01-05 15:45:09 +0530306 // Open the services dir and get the service info
307 // from service files.
308 // Service File format would be "ServiceName serviceType Port"
309 DIR* dir = opendir(SERVICE_DIR);
310 // wrap the pointer into smart pointer.
Patrick Venture537ff142018-11-01 16:37:09 -0700311 slp::deleted_unique_ptr<DIR> dirPtr(dir, [](DIR* dir) {
Ratan Guptaead7a3c2017-01-05 15:45:09 +0530312 if (!dir)
313 {
314 closedir(dir);
315 }
316 });
317 dir = nullptr;
318
319 if (dirPtr.get())
320 {
321 while ((dent = readdir(dirPtr.get())) != NULL)
322 {
Patrick Venture537ff142018-11-01 16:37:09 -0700323 if (dent->d_type == DT_REG) // regular file
Ratan Guptaead7a3c2017-01-05 15:45:09 +0530324 {
325 auto absFileName = std::string(SERVICE_DIR) + dent->d_name;
326 std::ifstream readFile(absFileName);
327 readFile >> service;
328 service.name = "service:"s + service.name;
329 svcLst.emplace(service.name, service);
330 }
331 }
Ratan Guptaead7a3c2017-01-05 15:45:09 +0530332 }
Ratan Gupta07c462a2016-12-14 00:40:30 +0530333 return svcLst;
334}
Patrick Venture537ff142018-11-01 16:37:09 -0700335} // namespace internal
Ratan Gupta07c462a2016-12-14 00:40:30 +0530336
Patrick Venture537ff142018-11-01 16:37:09 -0700337std::tuple<int, buffer> processRequest(const Message& msg)
Ratan Gupta07c462a2016-12-14 00:40:30 +0530338{
339 int rc = slp::SUCCESS;
340 buffer resp(0);
Patrick Venture537ff142018-11-01 16:37:09 -0700341 std::cout << "SLP Processing Request=" << msg.header.functionID << "\n";
Brad Bishopb5e632a2018-02-23 15:22:12 -0500342
Ratan Gupta07c462a2016-12-14 00:40:30 +0530343 switch (msg.header.functionID)
344 {
Ratan Gupta07c462a2016-12-14 00:40:30 +0530345 case (uint8_t)slp::FunctionType::SRVTYPERQST:
Patrick Williamsaa902c62023-04-04 19:59:51 -0500346 std::tie(rc,
347 resp) = slp::handler::internal::processSrvTypeRequest(msg);
Ratan Gupta07c462a2016-12-14 00:40:30 +0530348 break;
349 case (uint8_t)slp::FunctionType::SRVRQST:
350 std::tie(rc, resp) = slp::handler::internal::processSrvRequest(msg);
351 break;
352 default:
353 rc = (uint8_t)slp::Error::MSG_NOT_SUPPORTED;
354 }
355 return std::make_tuple(rc, resp);
356}
357
Patrick Venture537ff142018-11-01 16:37:09 -0700358buffer processError(const Message& req, uint8_t err)
Ratan Gupta07c462a2016-12-14 00:40:30 +0530359{
360 buffer buff;
361 buff = slp::handler::internal::prepareHeader(req);
362
363 std::copy_n(&err, slp::response::SIZE_ERROR,
Patrick Venture537ff142018-11-01 16:37:09 -0700364 buff.data() + slp::response::OFFSET_ERROR);
Ratan Gupta07c462a2016-12-14 00:40:30 +0530365 return buff;
Ratan Gupta07c462a2016-12-14 00:40:30 +0530366}
Patrick Venture537ff142018-11-01 16:37:09 -0700367} // namespace handler
368} // namespace slp