blob: 8c31a3b22fe21819605030ce3c62aa9dedde06da [file] [log] [blame]
James Kuszmaulcf324122023-01-14 14:07:17 -08001// Copyright (c) FIRST and other WPILib contributors.
2// Open Source Software; you can modify and/or share it under the terms of
3// the WPILib BSD license file in the root directory of this project.
4
5#include "wpinet/MulticastServiceAnnouncer.h"
6
7#include <arpa/inet.h>
8
9#include <wpi/SmallString.h>
10
11#include "dns_sd.h"
12
13using namespace wpi;
14
15struct MulticastServiceAnnouncer::Impl {
16 std::string serviceName;
17 std::string serviceType;
18 int port;
19 DNSServiceRef serviceRef{nullptr};
20 TXTRecordRef txtRecord;
21
22 Impl() { TXTRecordCreate(&txtRecord, 0, nullptr); }
23
24 ~Impl() noexcept { TXTRecordDeallocate(&txtRecord); }
25};
26
27MulticastServiceAnnouncer::MulticastServiceAnnouncer(
28 std::string_view serviceName, std::string_view serviceType, int port) {
29 pImpl = std::make_unique<Impl>();
30 pImpl->serviceName = serviceName;
31 pImpl->serviceType = serviceType;
32 pImpl->port = port;
33}
34
35MulticastServiceAnnouncer::MulticastServiceAnnouncer(
36 std::string_view serviceName, std::string_view serviceType, int port,
37 std::span<const std::pair<std::string, std::string>> txt) {
38 pImpl = std::make_unique<Impl>();
39 pImpl->serviceName = serviceName;
40 pImpl->serviceType = serviceType;
41 pImpl->port = port;
42
43 for (auto&& i : txt) {
44 TXTRecordSetValue(&pImpl->txtRecord, i.first.c_str(), i.second.length(),
45 i.second.c_str());
46 }
47}
48
49MulticastServiceAnnouncer::MulticastServiceAnnouncer(
50 std::string_view serviceName, std::string_view serviceType, int port,
51 std::span<const std::pair<std::string_view, std::string_view>> txt) {
52 pImpl = std::make_unique<Impl>();
53 pImpl->serviceName = serviceName;
54 pImpl->serviceType = serviceType;
55 pImpl->port = port;
56
57 wpi::SmallString<64> key;
58
59 for (auto&& i : txt) {
60 key.clear();
61 key.append(i.first);
62 key.emplace_back('\0');
63
64 TXTRecordSetValue(&pImpl->txtRecord, key.data(), i.second.length(),
65 i.second.data());
66 }
67}
68
69MulticastServiceAnnouncer::~MulticastServiceAnnouncer() noexcept {
70 Stop();
71}
72
73bool MulticastServiceAnnouncer::HasImplementation() const {
74 return true;
75}
76
77void MulticastServiceAnnouncer::Start() {
78 if (pImpl->serviceRef) {
79 return;
80 }
81
82 uint16_t len = TXTRecordGetLength(&pImpl->txtRecord);
83 const void* ptr = TXTRecordGetBytesPtr(&pImpl->txtRecord);
84
85 (void)DNSServiceRegister(&pImpl->serviceRef, 0, 0, pImpl->serviceName.c_str(),
86 pImpl->serviceType.c_str(), "local", nullptr,
87 htons(pImpl->port), len, ptr, nullptr, nullptr);
88}
89
90void MulticastServiceAnnouncer::Stop() {
91 if (!pImpl->serviceRef) {
92 return;
93 }
94 DNSServiceRefDeallocate(pImpl->serviceRef);
95 pImpl->serviceRef = nullptr;
96}