| /* |
| * Copyright (c) 2017, The OpenThread Authors. |
| * All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * 3. Neither the name of the copyright holder nor the |
| * names of its contributors may be used to endorse or promote products |
| * derived from this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
| * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE |
| * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
| * POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #include <assert.h> |
| #include <errno.h> |
| #include <limits.h> |
| #include <stdio.h> |
| #include <string.h> |
| #include <time.h> |
| |
| #include <netinet/in.h> |
| #include <signal.h> |
| |
| #include "common/code_utils.hpp" |
| #include "common/logging.hpp" |
| #include "mdns/mdns.hpp" |
| |
| using namespace otbr; |
| |
| static struct Context |
| { |
| Mdns::Publisher *mPublisher; |
| bool mUpdate; |
| } sContext; |
| |
| int Mainloop(Mdns::Publisher &aPublisher) |
| { |
| int rval = 0; |
| |
| while (true) |
| { |
| fd_set readFdSet; |
| fd_set writeFdSet; |
| fd_set errorFdSet; |
| int maxFd = -1; |
| struct timeval timeout = {INT_MAX, INT_MAX}; |
| |
| FD_ZERO(&readFdSet); |
| FD_ZERO(&writeFdSet); |
| FD_ZERO(&errorFdSet); |
| |
| aPublisher.UpdateFdSet(readFdSet, writeFdSet, errorFdSet, maxFd, timeout); |
| rval = |
| select(maxFd + 1, &readFdSet, &writeFdSet, &errorFdSet, (timeout.tv_sec == INT_MAX ? nullptr : &timeout)); |
| |
| if (rval < 0) |
| { |
| perror("select"); |
| break; |
| } |
| |
| aPublisher.Process(readFdSet, writeFdSet, errorFdSet); |
| } |
| |
| return rval; |
| } |
| |
| void PublishSingleServiceWithCustomHost(void *aContext, Mdns::Publisher::State aState) |
| { |
| uint8_t xpanid[kSizeExtPanId] = {0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48}; |
| uint8_t extAddr[kSizeExtAddr] = {0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48}; |
| uint8_t hostAddr[16] = {0}; |
| const char hostName[] = "custom-host"; |
| |
| hostAddr[0] = 0x20; |
| hostAddr[1] = 0x02; |
| hostAddr[15] = 0x01; |
| |
| VerifyOrDie(aContext == &sContext, "unexpected context"); |
| if (aState == Mdns::Publisher::State::kReady) |
| { |
| otbrError error; |
| Mdns::Publisher::TxtList txtList{ |
| {"nn", "cool"}, {"xp", xpanid, sizeof(xpanid)}, {"tv", "1.1.1"}, {"dd", extAddr, sizeof(extAddr)}}; |
| |
| error = sContext.mPublisher->PublishHost(hostName, hostAddr, sizeof(hostAddr)); |
| SuccessOrDie(error, "cannot publish the host"); |
| |
| error = sContext.mPublisher->PublishService(hostName, 12345, "SingleService", "_meshcop._udp.", txtList); |
| SuccessOrDie(error, "cannot publish the service"); |
| } |
| } |
| |
| void PublishMultipleServicesWithCustomHost(void *aContext, Mdns::Publisher::State aState) |
| { |
| uint8_t xpanid[kSizeExtPanId] = {0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48}; |
| uint8_t extAddr[kSizeExtAddr] = {0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48}; |
| uint8_t hostAddr[16] = {0}; |
| const char hostName1[] = "custom-host-1"; |
| const char hostName2[] = "custom-host-2"; |
| |
| hostAddr[0] = 0x20; |
| hostAddr[1] = 0x02; |
| hostAddr[15] = 0x01; |
| |
| VerifyOrDie(aContext == &sContext, "unexpected context"); |
| if (aState == Mdns::Publisher::State::kReady) |
| { |
| otbrError error; |
| Mdns::Publisher::TxtList txtList{ |
| {"nn", "cool"}, {"xp", xpanid, sizeof(xpanid)}, {"tv", "1.1.1"}, {"dd", extAddr, sizeof(extAddr)}}; |
| |
| error = sContext.mPublisher->PublishHost(hostName1, hostAddr, sizeof(hostAddr)); |
| SuccessOrDie(error, "cannot publish the first host"); |
| |
| error = sContext.mPublisher->PublishService(hostName1, 12345, "MultipleService11", "_meshcop._udp.", txtList); |
| SuccessOrDie(error, "cannot publish the first service"); |
| |
| error = sContext.mPublisher->PublishService(hostName1, 12345, "MultipleService12", "_meshcop._udp.", txtList); |
| SuccessOrDie(error, "cannot publish the second service"); |
| |
| error = sContext.mPublisher->PublishHost(hostName2, hostAddr, sizeof(hostAddr)); |
| SuccessOrDie(error, "cannot publish the second host"); |
| |
| error = sContext.mPublisher->PublishService(hostName2, 12345, "MultipleService21", "_meshcop._udp.", txtList); |
| SuccessOrDie(error, "cannot publish the first service"); |
| |
| error = sContext.mPublisher->PublishService(hostName2, 12345, "MultipleService22", "_meshcop._udp.", txtList); |
| SuccessOrDie(error, "cannot publish the second service"); |
| } |
| } |
| |
| void PublishSingleService(void *aContext, Mdns::Publisher::State aState) |
| { |
| uint8_t xpanid[kSizeExtPanId] = {0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48}; |
| uint8_t extAddr[kSizeExtAddr] = {0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48}; |
| Mdns::Publisher::TxtList txtList{ |
| {"nn", "cool"}, {"xp", xpanid, sizeof(xpanid)}, {"tv", "1.1.1"}, {"dd", extAddr, sizeof(extAddr)}}; |
| |
| assert(aContext == &sContext); |
| if (aState == Mdns::Publisher::State::kReady) |
| { |
| otbrError error = |
| sContext.mPublisher->PublishService(nullptr, 12345, "SingleService", "_meshcop._udp.", txtList); |
| assert(error == OTBR_ERROR_NONE); |
| } |
| } |
| |
| void PublishMultipleServices(void *aContext, Mdns::Publisher::State aState) |
| { |
| uint8_t xpanid[kSizeExtPanId] = {0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48}; |
| uint8_t extAddr[kSizeExtAddr] = {0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48}; |
| |
| assert(aContext == &sContext); |
| if (aState == Mdns::Publisher::State::kReady) |
| { |
| otbrError error; |
| Mdns::Publisher::TxtList txtList{ |
| {"nn", "cool1"}, {"xp", xpanid, sizeof(xpanid)}, {"tv", "1.1.1"}, {"dd", extAddr, sizeof(extAddr)}}; |
| |
| error = sContext.mPublisher->PublishService(nullptr, 12345, "MultipleService1", "_meshcop._udp.", txtList); |
| assert(error == OTBR_ERROR_NONE); |
| } |
| |
| if (aState == Mdns::Publisher::State::kReady) |
| { |
| otbrError error; |
| Mdns::Publisher::TxtList txtList{ |
| {"nn", "cool2"}, {"xp", xpanid, sizeof(xpanid)}, {"tv", "1.1.1"}, {"dd", extAddr, sizeof(extAddr)}}; |
| |
| error = sContext.mPublisher->PublishService(nullptr, 12345, "MultipleService2", "_meshcop._udp.", txtList); |
| assert(error == OTBR_ERROR_NONE); |
| } |
| } |
| |
| void PublishUpdateServices(void *aContext, Mdns::Publisher::State aState) |
| { |
| uint8_t xpanidOld[kSizeExtPanId] = {0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48}; |
| uint8_t xpanidNew[kSizeExtPanId] = {0x48, 0x47, 0x46, 0x45, 0x44, 0x43, 0x42, 0x41}; |
| uint8_t extAddr[kSizeExtAddr] = {0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48}; |
| |
| assert(aContext == &sContext); |
| if (aState == Mdns::Publisher::State::kReady) |
| { |
| otbrError error; |
| |
| if (!sContext.mUpdate) |
| { |
| Mdns::Publisher::TxtList txtList{{"nn", "cool"}, |
| {"xp", xpanidOld, sizeof(xpanidOld)}, |
| {"tv", "1.1.1"}, |
| {"dd", extAddr, sizeof(extAddr)}}; |
| |
| error = sContext.mPublisher->PublishService(nullptr, 12345, "UpdateService", "_meshcop._udp.", txtList); |
| } |
| else |
| { |
| Mdns::Publisher::TxtList txtList{{"nn", "coolcool"}, |
| {"xp", xpanidNew, sizeof(xpanidNew)}, |
| {"tv", "1.1.1"}, |
| {"dd", extAddr, sizeof(extAddr)}}; |
| |
| error = sContext.mPublisher->PublishService(nullptr, 12345, "UpdateService", "_meshcop._udp.", txtList); |
| } |
| assert(error == OTBR_ERROR_NONE); |
| } |
| } |
| |
| otbrError TestSingleServiceWithCustomHost(void) |
| { |
| otbrError error = OTBR_ERROR_NONE; |
| |
| Mdns::Publisher *pub = |
| Mdns::Publisher::Create(AF_UNSPEC, /* aDomain */ nullptr, PublishSingleServiceWithCustomHost, &sContext); |
| sContext.mPublisher = pub; |
| SuccessOrExit(error = pub->Start()); |
| Mainloop(*pub); |
| |
| exit: |
| Mdns::Publisher::Destroy(pub); |
| return error; |
| } |
| |
| otbrError TestMultipleServicesWithCustomHost(void) |
| { |
| otbrError error = OTBR_ERROR_NONE; |
| |
| Mdns::Publisher *pub = |
| Mdns::Publisher::Create(AF_UNSPEC, /* aDomain */ nullptr, PublishMultipleServicesWithCustomHost, &sContext); |
| sContext.mPublisher = pub; |
| SuccessOrExit(error = pub->Start()); |
| Mainloop(*pub); |
| |
| exit: |
| Mdns::Publisher::Destroy(pub); |
| return error; |
| } |
| |
| otbrError TestSingleService(void) |
| { |
| otbrError ret = OTBR_ERROR_NONE; |
| |
| Mdns::Publisher *pub = Mdns::Publisher::Create(AF_UNSPEC, /* aDomain */ nullptr, PublishSingleService, &sContext); |
| sContext.mPublisher = pub; |
| SuccessOrExit(ret = pub->Start()); |
| Mainloop(*pub); |
| |
| exit: |
| Mdns::Publisher::Destroy(pub); |
| return ret; |
| } |
| |
| otbrError TestMultipleServices(void) |
| { |
| otbrError ret = OTBR_ERROR_NONE; |
| |
| Mdns::Publisher *pub = |
| Mdns::Publisher::Create(AF_UNSPEC, /* aDomain */ nullptr, PublishMultipleServices, &sContext); |
| sContext.mPublisher = pub; |
| SuccessOrExit(ret = pub->Start()); |
| Mainloop(*pub); |
| |
| exit: |
| Mdns::Publisher::Destroy(pub); |
| return ret; |
| } |
| |
| otbrError TestUpdateService(void) |
| { |
| otbrError ret = OTBR_ERROR_NONE; |
| |
| Mdns::Publisher *pub = Mdns::Publisher::Create(AF_UNSPEC, /* aDomain */ nullptr, PublishUpdateServices, &sContext); |
| sContext.mPublisher = pub; |
| sContext.mUpdate = false; |
| SuccessOrExit(ret = pub->Start()); |
| sContext.mUpdate = true; |
| PublishUpdateServices(&sContext, Mdns::Publisher::State::kReady); |
| Mainloop(*pub); |
| |
| exit: |
| Mdns::Publisher::Destroy(pub); |
| return ret; |
| } |
| |
| void RecoverSignal(int aSignal) |
| { |
| if (aSignal == SIGUSR1) |
| { |
| signal(SIGUSR1, SIG_DFL); |
| } |
| else if (aSignal == SIGUSR2) |
| { |
| signal(SIGUSR2, SIG_DFL); |
| } |
| } |
| |
| otbrError TestStopService(void) |
| { |
| otbrError ret = OTBR_ERROR_NONE; |
| |
| Mdns::Publisher *pub = Mdns::Publisher::Create(AF_UNSPEC, /* aDomain */ nullptr, PublishSingleService, &sContext); |
| sContext.mPublisher = pub; |
| SuccessOrExit(ret = pub->Start()); |
| signal(SIGUSR1, RecoverSignal); |
| signal(SIGUSR2, RecoverSignal); |
| Mainloop(*pub); |
| sContext.mPublisher->Stop(); |
| Mainloop(*pub); |
| SuccessOrExit(ret = sContext.mPublisher->Start()); |
| Mainloop(*pub); |
| |
| exit: |
| Mdns::Publisher::Destroy(pub); |
| return ret; |
| } |
| |
| int main(int argc, char *argv[]) |
| { |
| int ret = 0; |
| |
| if (argc < 2) |
| { |
| return 1; |
| } |
| |
| otbrLogInit("otbr-mdns", OTBR_LOG_DEBUG, true); |
| // allow quitting elegantly |
| signal(SIGTERM, RecoverSignal); |
| switch (argv[1][0]) |
| { |
| case 's': |
| ret = argv[1][1] == 'c' ? TestSingleServiceWithCustomHost() : TestSingleService(); |
| break; |
| |
| case 'm': |
| ret = argv[1][1] == 'c' ? TestMultipleServicesWithCustomHost() : TestMultipleServices(); |
| break; |
| |
| case 'u': |
| ret = TestUpdateService(); |
| break; |
| |
| case 'k': |
| ret = TestStopService(); |
| break; |
| |
| default: |
| ret = 1; |
| break; |
| } |
| |
| return ret; |
| } |