1 /*
2 * Copyright (c) 2017, The OpenThread Authors.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. Neither the name of the copyright holder nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #define OTBR_LOG_TAG "TEST"
30
31 #include <assert.h>
32 #include <errno.h>
33 #include <limits.h>
34 #include <stdio.h>
35 #include <string.h>
36 #include <time.h>
37
38 #include <netinet/in.h>
39 #include <signal.h>
40
41 #include <functional>
42 #include <vector>
43
44 #include "common/code_utils.hpp"
45 #include "common/logging.hpp"
46 #include "common/mainloop.hpp"
47 #include "common/mainloop_manager.hpp"
48 #include "mdns/mdns.hpp"
49
50 using namespace otbr;
51 using namespace otbr::Mdns;
52
53 static Publisher *sPublisher = nullptr;
54
55 typedef std::function<void(void)> TestRunner;
56
RunMainloop(void)57 int RunMainloop(void)
58 {
59 int rval = 0;
60
61 while (true)
62 {
63 MainloopContext mainloop;
64
65 mainloop.mMaxFd = -1;
66 mainloop.mTimeout = {INT_MAX, INT_MAX};
67 FD_ZERO(&mainloop.mReadFdSet);
68 FD_ZERO(&mainloop.mWriteFdSet);
69 FD_ZERO(&mainloop.mErrorFdSet);
70
71 MainloopManager::GetInstance().Update(mainloop);
72 rval = select(mainloop.mMaxFd + 1, &mainloop.mReadFdSet, &mainloop.mWriteFdSet, &mainloop.mErrorFdSet,
73 (mainloop.mTimeout.tv_sec == INT_MAX ? nullptr : &mainloop.mTimeout));
74
75 if (rval < 0)
76 {
77 perror("select");
78 break;
79 }
80
81 MainloopManager::GetInstance().Process(mainloop);
82 }
83
84 return rval;
85 }
86
ErrorChecker(std::string aMessage)87 std::function<void(otbrError aError)> ErrorChecker(std::string aMessage)
88 {
89 return [aMessage](otbrError aError) {
90 if (aError == OTBR_ERROR_NONE)
91 {
92 otbrLogInfo("Got success callback: %s", aMessage.c_str());
93 }
94 else
95 {
96 otbrLogEmerg("Got error %d callback: %s", aError, aMessage.c_str());
97 exit(-1);
98 }
99 };
100 }
101
PublishSingleServiceWithCustomHost(void)102 void PublishSingleServiceWithCustomHost(void)
103 {
104 uint8_t xpanid[kSizeExtPanId] = {0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48};
105 uint8_t extAddr[kSizeExtAddr] = {0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48};
106 uint8_t hostAddr[OTBR_IP6_ADDRESS_SIZE] = {0};
107 const char hostName[] = "custom-host";
108 std::vector<uint8_t> keyData = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06};
109 Publisher::TxtData txtData;
110 Publisher::TxtList txtList{
111 {"nn", "cool"},
112 {"xp", xpanid, sizeof(xpanid)},
113 {"tv", "1.1.1"},
114 {"xa", extAddr, sizeof(extAddr)},
115 };
116
117 otbrLogInfo("PublishSingleServiceWithCustomHost");
118
119 hostAddr[0] = 0x20;
120 hostAddr[1] = 0x02;
121 hostAddr[15] = 0x01;
122
123 Publisher::EncodeTxtData(txtList, txtData);
124
125 sPublisher->PublishKey(hostName, keyData, ErrorChecker("publish key for host"));
126 sPublisher->PublishHost(hostName, {Ip6Address(hostAddr)}, ErrorChecker("publish the host"));
127 sPublisher->PublishService(hostName, "SingleService", "_meshcop._udp", Publisher::SubTypeList{}, 12345, txtData,
128 ErrorChecker("publish the service"));
129 sPublisher->PublishKey("SingleService._meshcop._udp", keyData, ErrorChecker("publish key for service"));
130 }
131
PublishSingleServiceWithKeyAfterwards(void)132 void PublishSingleServiceWithKeyAfterwards(void)
133 {
134 uint8_t hostAddr[OTBR_IP6_ADDRESS_SIZE] = {0};
135 const char hostName[] = "custom-host";
136 Publisher::TxtData txtData;
137
138 otbrLogInfo("PublishSingleServiceWithKeyAfterwards");
139
140 hostAddr[0] = 0x20;
141 hostAddr[1] = 0x02;
142 hostAddr[15] = 0x01;
143
144 txtData.push_back(0);
145
146 sPublisher->PublishHost(hostName, {Ip6Address(hostAddr)}, ErrorChecker("publish the host"));
147
148 sPublisher->PublishService(
149 hostName, "SingleService", "_meshcop._udp", Publisher::SubTypeList{}, 12345, txtData, [](otbrError aError) {
150 std::vector<uint8_t> keyData = {0x55, 0xaa, 0xbb, 0xcc, 0x77, 0x33};
151
152 SuccessOrDie(aError, "publish the service");
153
154 sPublisher->PublishKey("SingleService._meshcop._udp", keyData, ErrorChecker("publish key for service"));
155 });
156 }
157
PublishMultipleServicesWithCustomHost(void)158 void PublishMultipleServicesWithCustomHost(void)
159 {
160 uint8_t xpanid[kSizeExtPanId] = {0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48};
161 uint8_t extAddr[kSizeExtAddr] = {0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48};
162 uint8_t hostAddr[OTBR_IP6_ADDRESS_SIZE] = {0};
163 const char hostName1[] = "custom-host-1";
164 const char hostName2[] = "custom-host-2";
165 std::vector<uint8_t> keyData1 = {0x10, 0x20, 0x03, 0x15};
166 std::vector<uint8_t> keyData2 = {0xCA, 0xFE, 0xBE, 0xEF};
167 Publisher::TxtData txtData;
168 Publisher::TxtList txtList{
169 {"nn", "cool"},
170 {"xp", xpanid, sizeof(xpanid)},
171 {"tv", "1.1.1"},
172 {"xa", extAddr, sizeof(extAddr)},
173 };
174
175 otbrLogInfo("PublishMultipleServicesWithCustomHost");
176
177 hostAddr[0] = 0x20;
178 hostAddr[1] = 0x02;
179 hostAddr[15] = 0x01;
180
181 Publisher::EncodeTxtData(txtList, txtData);
182
183 // For host1 and its services we register keys first, then host/services
184
185 sPublisher->PublishKey(hostName1, keyData1, ErrorChecker("publish key for host1"));
186 sPublisher->PublishKey("MultipleService11._meshcop._udp", keyData1, ErrorChecker("publish key for service11"));
187 sPublisher->PublishKey("MultipleService12._meshcop._udp", keyData1, ErrorChecker("publish key for service12"));
188
189 sPublisher->PublishHost(hostName1, {Ip6Address(hostAddr)}, ErrorChecker("publish the host1"));
190 sPublisher->PublishService(hostName1, "MultipleService11", "_meshcop._udp", Publisher::SubTypeList{}, 12345,
191 txtData, ErrorChecker("publish service11"));
192 sPublisher->PublishService(hostName1, "MultipleService12", "_meshcop._udp", Publisher::SubTypeList{}, 12345,
193 txtData, ErrorChecker("publish service12"));
194
195 // For host2 and its services we register host and services first, then keys.
196
197 sPublisher->PublishHost(hostName2, {Ip6Address(hostAddr)}, ErrorChecker("publish host2"));
198 sPublisher->PublishService(hostName2, "MultipleService21", "_meshcop._udp", Publisher::SubTypeList{}, 12345,
199 txtData, ErrorChecker("publish service21"));
200 sPublisher->PublishService(hostName2, "MultipleService22", "_meshcop._udp", Publisher::SubTypeList{}, 12345,
201 txtData, ErrorChecker("publish service22"));
202
203 sPublisher->PublishKey(hostName2, keyData2, ErrorChecker("publish key for host2"));
204 sPublisher->PublishKey("MultipleService21._meshcop._udp", keyData2, ErrorChecker("publish key for service21"));
205 sPublisher->PublishKey("MultipleService22._meshcop._udp", keyData2, ErrorChecker("publish key for service22"));
206 }
207
PublishSingleService(void)208 void PublishSingleService(void)
209 {
210 uint8_t xpanid[kSizeExtPanId] = {0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48};
211 uint8_t extAddr[kSizeExtAddr] = {0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48};
212 Publisher::TxtData txtData;
213 Publisher::TxtList txtList{
214 {"nn", "cool"},
215 {"xp", xpanid, sizeof(xpanid)},
216 {"tv", "1.1.1"},
217 {"xa", extAddr, sizeof(extAddr)},
218 };
219
220 otbrLogInfo("PublishSingleService");
221
222 Publisher::EncodeTxtData(txtList, txtData);
223
224 sPublisher->PublishService("", "SingleService", "_meshcop._udp", Publisher::SubTypeList{}, 12345, txtData,
225 ErrorChecker("publish service"));
226 }
227
PublishSingleServiceWithEmptyName(void)228 void PublishSingleServiceWithEmptyName(void)
229 {
230 uint8_t xpanid[kSizeExtPanId] = {0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48};
231 uint8_t extAddr[kSizeExtAddr] = {0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48};
232 Publisher::TxtData txtData;
233 Publisher::TxtList txtList{
234 {"nn", "cool"},
235 {"xp", xpanid, sizeof(xpanid)},
236 {"tv", "1.1.1"},
237 {"xa", extAddr, sizeof(extAddr)},
238 };
239
240 otbrLogInfo("PublishSingleServiceWithEmptyName");
241
242 Publisher::EncodeTxtData(txtList, txtData);
243
244 sPublisher->PublishService("", "", "_meshcop._udp", Publisher::SubTypeList{}, 12345, txtData,
245 ErrorChecker("publish (empty)._meshcop._udp"));
246 }
247
PublishMultipleServices(void)248 void PublishMultipleServices(void)
249 {
250 uint8_t xpanid[kSizeExtPanId] = {0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48};
251 uint8_t extAddr[kSizeExtAddr] = {0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48};
252 Publisher::TxtData txtData;
253 Publisher::TxtList txtList1{
254 {"nn", "cool1"},
255 {"xp", xpanid, sizeof(xpanid)},
256 {"tv", "1.1.1"},
257 {"xa", extAddr, sizeof(extAddr)},
258 };
259 Publisher::TxtList txtList2{
260 {"nn", "cool2"},
261 {"xp", xpanid, sizeof(xpanid)},
262 {"tv", "1.1.1"},
263 {"xa", extAddr, sizeof(extAddr)},
264 };
265
266 otbrLogInfo("PublishMultipleServices");
267
268 Publisher::EncodeTxtData(txtList1, txtData);
269
270 sPublisher->PublishService("", "MultipleService1", "_meshcop._udp", Publisher::SubTypeList{}, 12345, txtData,
271 ErrorChecker("publish MultipleService1._meshcop._udp"));
272
273 Publisher::EncodeTxtData(txtList2, txtData);
274
275 sPublisher->PublishService("", "MultipleService2", "_meshcop._udp", Publisher::SubTypeList{}, 12345, txtData,
276 ErrorChecker("publish MultipleService2._meshcop._udp"));
277 }
278
PublishUpdateServices(void)279 void PublishUpdateServices(void)
280 {
281 uint8_t xpanidOld[kSizeExtPanId] = {0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48};
282 uint8_t xpanidNew[kSizeExtPanId] = {0x48, 0x47, 0x46, 0x45, 0x44, 0x43, 0x42, 0x41};
283 uint8_t extAddr[kSizeExtAddr] = {0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48};
284 Publisher::TxtData txtData;
285 Publisher::TxtList txtList1{
286 {"nn", "cool"},
287 {"xp", xpanidOld, sizeof(xpanidOld)},
288 {"tv", "1.1.1"},
289 {"xa", extAddr, sizeof(extAddr)},
290 };
291 Publisher::TxtList txtList2{
292 {"nn", "coolcool"},
293 {"xp", xpanidNew, sizeof(xpanidNew)},
294 {"tv", "1.1.1"},
295 {"xa", extAddr, sizeof(extAddr)},
296 };
297
298 otbrLogInfo("PublishUpdateServices");
299
300 Publisher::EncodeTxtData(txtList1, txtData);
301
302 sPublisher->PublishService("", "UpdateService", "_meshcop._udp", Publisher::SubTypeList{}, 12345, txtData,
303 [](otbrError aError) { otbrLogResult(aError, "UpdateService._meshcop._udp"); });
304
305 Publisher::EncodeTxtData(txtList2, txtData);
306
307 sPublisher->PublishService("", "UpdateService", "_meshcop._udp", Publisher::SubTypeList{}, 12345, txtData,
308 ErrorChecker("publish UpdateService._meshcop._udp"));
309 }
310
PublishServiceSubTypes(void)311 void PublishServiceSubTypes(void)
312 {
313 Publisher::TxtData txtData;
314 Publisher::SubTypeList subTypeList{"_subtype1", "_SUBTYPE2"};
315
316 otbrLogInfo("PublishServiceSubTypes");
317
318 txtData.push_back(0);
319
320 subTypeList.back() = "_SUBTYPE3";
321
322 sPublisher->PublishService("", "ServiceWithSubTypes", "_meshcop._udp", subTypeList, 12345, txtData,
323 ErrorChecker("publish ServiceWithSubTypes._meshcop._udp"));
324 }
325
PublishKey(void)326 void PublishKey(void)
327 {
328 std::vector<uint8_t> keyData = {0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0};
329
330 otbrLogInfo("PublishKey");
331
332 sPublisher->PublishKey("SingleService._meshcop._udp", keyData, ErrorChecker("publish key for service"));
333 }
334
PublishKeyWithServiceRemoved(void)335 void PublishKeyWithServiceRemoved(void)
336 {
337 uint8_t hostAddr[OTBR_IP6_ADDRESS_SIZE] = {0};
338 const char hostName[] = "custom-host";
339 Publisher::TxtData txtData;
340
341 otbrLogInfo("PublishKeyWithServiceRemoved");
342
343 hostAddr[0] = 0x20;
344 hostAddr[1] = 0x02;
345 hostAddr[15] = 0x01;
346
347 txtData.push_back(0);
348
349 sPublisher->PublishHost(hostName, {Ip6Address(hostAddr)}, ErrorChecker("publish the host"));
350
351 sPublisher->PublishService(
352 hostName, "SingleService", "_meshcop._udp", Publisher::SubTypeList{}, 12345, txtData, [](otbrError aError) {
353 std::vector<uint8_t> keyData = {0x55, 0xaa, 0xbb, 0xcc, 0x77, 0x33};
354
355 SuccessOrDie(aError, "publish the service");
356
357 sPublisher->PublishKey("SingleService._meshcop._udp", keyData, [](otbrError aError) {
358 SuccessOrDie(aError, "publish key for service");
359
360 sPublisher->UnpublishService("SingleService", "_meshcop._udp", ErrorChecker("unpublish service"));
361 });
362 });
363 }
364
Test(TestRunner aTestRunner)365 otbrError Test(TestRunner aTestRunner)
366 {
367 otbrError error = OTBR_ERROR_NONE;
368
369 sPublisher = Publisher::Create([aTestRunner](Publisher::State aState) {
370 if (aState == Publisher::State::kReady)
371 {
372 aTestRunner();
373 }
374 });
375 SuccessOrExit(error = sPublisher->Start());
376 RunMainloop();
377
378 exit:
379 Publisher::Destroy(sPublisher);
380 return error;
381 }
382
RecoverSignal(int aSignal)383 void RecoverSignal(int aSignal)
384 {
385 if (aSignal == SIGUSR1)
386 {
387 signal(SIGUSR1, SIG_DFL);
388 }
389 else if (aSignal == SIGUSR2)
390 {
391 signal(SIGUSR2, SIG_DFL);
392 }
393 }
394
TestStopService(void)395 otbrError TestStopService(void)
396 {
397 otbrError ret = OTBR_ERROR_NONE;
398
399 otbrLogInfo("TestStopService");
400
401 sPublisher = Publisher::Create([](Publisher::State aState) {
402 if (aState == Publisher::State::kReady)
403 {
404 PublishSingleService();
405 }
406 });
407 SuccessOrExit(ret = sPublisher->Start());
408 signal(SIGUSR1, RecoverSignal);
409 signal(SIGUSR2, RecoverSignal);
410 RunMainloop();
411 sPublisher->Stop();
412 RunMainloop();
413 SuccessOrExit(ret = sPublisher->Start());
414 RunMainloop();
415
416 exit:
417 Publisher::Destroy(sPublisher);
418 return ret;
419 }
420
CheckTxtDataEncoderDecoder(void)421 otbrError CheckTxtDataEncoderDecoder(void)
422 {
423 otbrError error = OTBR_ERROR_NONE;
424 Publisher::TxtList txtList;
425 Publisher::TxtList parsedTxtList;
426 std::vector<uint8_t> txtData;
427
428 // Encode empty `TxtList`
429
430 SuccessOrExit(error = Publisher::EncodeTxtData(txtList, txtData));
431 VerifyOrExit(txtData.size() == 1, error = OTBR_ERROR_PARSE);
432 VerifyOrExit(txtData[0] == 0, error = OTBR_ERROR_PARSE);
433
434 SuccessOrExit(error = Publisher::DecodeTxtData(parsedTxtList, txtData.data(), txtData.size()));
435 VerifyOrExit(parsedTxtList.size() == 0, error = OTBR_ERROR_PARSE);
436
437 // TxtList with one bool attribute
438
439 txtList.clear();
440 txtList.emplace_back("b1");
441
442 SuccessOrExit(error = Publisher::EncodeTxtData(txtList, txtData));
443 SuccessOrExit(error = Publisher::DecodeTxtData(parsedTxtList, txtData.data(), txtData.size()));
444 VerifyOrExit(parsedTxtList == txtList, error = OTBR_ERROR_PARSE);
445
446 // TxtList with one one key/value
447
448 txtList.clear();
449 txtList.emplace_back("k1", "v1");
450
451 SuccessOrExit(error = Publisher::EncodeTxtData(txtList, txtData));
452 SuccessOrExit(error = Publisher::DecodeTxtData(parsedTxtList, txtData.data(), txtData.size()));
453 VerifyOrExit(parsedTxtList == txtList, error = OTBR_ERROR_PARSE);
454
455 // TxtList with multiple entries
456
457 txtList.clear();
458 txtList.emplace_back("k1", "v1");
459 txtList.emplace_back("b1");
460 txtList.emplace_back("b2");
461 txtList.emplace_back("k2", "valu2");
462
463 SuccessOrExit(error = Publisher::EncodeTxtData(txtList, txtData));
464 SuccessOrExit(error = Publisher::DecodeTxtData(parsedTxtList, txtData.data(), txtData.size()));
465 VerifyOrExit(parsedTxtList == txtList, error = OTBR_ERROR_PARSE);
466
467 exit:
468 return error;
469 }
470
main(int argc,char * argv[])471 int main(int argc, char *argv[])
472 {
473 int ret = 0;
474
475 if (CheckTxtDataEncoderDecoder() != OTBR_ERROR_NONE)
476 {
477 return 1;
478 }
479
480 if (argc < 2)
481 {
482 return 1;
483 }
484
485 otbrLogInit("otbr-mdns", OTBR_LOG_DEBUG, true, false);
486 // allow quitting elegantly
487 signal(SIGTERM, RecoverSignal);
488 switch (argv[1][0])
489 {
490 case 's':
491 switch (argv[1][1])
492 {
493 case 'c':
494 ret = Test(PublishSingleServiceWithCustomHost);
495 break;
496 case 'e':
497 ret = Test(PublishSingleServiceWithEmptyName);
498 break;
499 case 'k':
500 ret = Test(PublishSingleServiceWithKeyAfterwards);
501 break;
502 default:
503 ret = Test(PublishSingleService);
504 break;
505 }
506 break;
507
508 case 'm':
509 ret = argv[1][1] == 'c' ? Test(PublishMultipleServicesWithCustomHost) : Test(PublishMultipleServices);
510 break;
511
512 case 'u':
513 ret = Test(PublishUpdateServices);
514 break;
515
516 case 't':
517 ret = Test(PublishServiceSubTypes);
518 break;
519
520 case 'k':
521 ret = TestStopService();
522 break;
523
524 case 'y':
525 ret = Test(PublishKey);
526 break;
527
528 case 'z':
529 ret = Test(PublishKeyWithServiceRemoved);
530 break;
531
532 default:
533 ret = 1;
534 break;
535 }
536
537 return ret;
538 }
539