xref: /aosp_15_r20/external/ot-br-posix/tests/mdns/main.cpp (revision 4a64e381480ef79f0532b2421e44e6ee336b8e0d)
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