3 * Copyright (c) 2020 Project CHIP Authors
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
21 #include <arpa/inet.h>
23 #include <inet/InetInterface.h>
24 #include <inet/UDPEndPoint.h>
25 #include <mdns/minimal/QueryBuilder.h>
26 #include <mdns/minimal/ResponseSender.h>
27 #include <mdns/minimal/Server.h>
28 #include <mdns/minimal/core/QName.h>
29 #include <mdns/minimal/responders/IP.h>
30 #include <mdns/minimal/responders/Ptr.h>
31 #include <mdns/minimal/responders/Srv.h>
32 #include <mdns/minimal/responders/Txt.h>
33 #include <platform/CHIPDeviceLayer.h>
34 #include <support/CHIPArgParser.hpp>
35 #include <support/CHIPMem.h>
36 #include <system/SystemPacketBuffer.h>
37 #include <system/SystemTimer.h>
39 #include "AllInterfaceListener.h"
40 #include "PacketReporter.h"
48 bool enableIpV4 = false;
49 uint16_t listenPort = 5353;
50 const char * instanceName = "chip-mdns-demo";
53 using namespace chip::ArgParser;
55 constexpr uint16_t kOptionEnableIpV4 = '4';
56 constexpr uint16_t kOptionListenPort = 'p';
57 constexpr uint16_t kOptionInstanceName = 'i';
59 bool HandleOptions(const char * aProgram, OptionSet * aOptions, int aIdentifier, const char * aName, const char * aValue)
63 case kOptionEnableIpV4:
64 gOptions.enableIpV4 = true;
67 case kOptionInstanceName:
68 gOptions.instanceName = aValue;
71 case kOptionListenPort:
72 if (!ParseInt(aValue, gOptions.listenPort))
74 PrintArgError("%s: invalid value for port: %s\n", aProgram, aValue);
80 PrintArgError("%s: INTERNAL ERROR: Unhandled option: %s\n", aProgram, aName);
85 OptionDef cmdLineOptionsDef[] = {
86 { "listen-port", kArgumentRequired, kOptionListenPort },
87 { "enable-ip-v4", kNoArgument, kOptionEnableIpV4 },
88 { "instance-name", kArgumentRequired, kOptionInstanceName },
92 OptionSet cmdLineOptions = { HandleOptions, cmdLineOptionsDef, "PROGRAM OPTIONS",
94 " --listen-port <number>\n"
95 " The port number to listen on\n"
98 " enable listening on IPv4\n"
100 " --instance-name <name>\n"
101 " instance name to advertise.\n"
104 HelpOptions helpOptions("minimal-mdns-server", "Usage: minimal-mdns-server [options]", "1.0");
106 OptionSet * allOptions[] = { &cmdLineOptions, &helpOptions, nullptr };
108 class ReplyDelegate : public mdns::Minimal::ServerDelegate, public mdns::Minimal::ParserDelegate
111 ReplyDelegate(mdns::Minimal::ResponseSender * responder) : mResponder(responder) {}
113 void OnQuery(const mdns::Minimal::BytesRange & data, const chip::Inet::IPPacketInfo * info) override
115 char addr[INET6_ADDRSTRLEN];
116 info->SrcAddress.ToString(addr, sizeof(addr));
118 printf("QUERY from: %-15s on port %d, via interface %d\n", addr, info->SrcPort, info->Interface);
119 Report("QUERY: ", data);
121 mCurrentSource = info;
122 if (!mdns::Minimal::ParsePacket(data, this))
124 printf("Parsing failure may result in reply failure!\n");
126 mCurrentSource = nullptr;
129 void OnResponse(const mdns::Minimal::BytesRange & data, const chip::Inet::IPPacketInfo * info) override
131 char addr[INET6_ADDRSTRLEN];
132 info->SrcAddress.ToString(addr, sizeof(addr));
134 printf("RESPONSE from: %-15s on port %d, via interface %d\n", addr, info->SrcPort, info->Interface);
138 void OnHeader(mdns::Minimal::ConstHeaderRef & header) override { mMessageId = header.GetMessageId(); }
139 void OnResource(mdns::Minimal::ResourceType type, const mdns::Minimal::ResourceData & data) override {}
141 void OnQuery(const mdns::Minimal::QueryData & data) override
143 if (mResponder->Respond(mMessageId, data, mCurrentSource) != CHIP_NO_ERROR)
145 printf("FAILED to respond!\n");
150 void Report(const char * prefix, const mdns::Minimal::BytesRange & data)
152 MdnsExample::PacketReporter reporter(prefix, data);
153 if (!mdns::Minimal::ParsePacket(data, &reporter))
155 printf("INVALID PACKET!!!!!!\n");
159 mdns::Minimal::ResponseSender * mResponder;
160 const chip::Inet::IPPacketInfo * mCurrentSource = nullptr;
161 uint32_t mMessageId = 0;
166 int main(int argc, char ** args)
168 if (Platform::MemoryInit() != CHIP_NO_ERROR)
170 printf("FAILED to initialize memory");
174 if (DeviceLayer::PlatformMgr().InitChipStack() != CHIP_NO_ERROR)
176 printf("FAILED to initialize chip stack");
180 if (!chip::ArgParser::ParseArgs(args[0], argc, args, allOptions))
185 printf("Running on port %d using %s...\n", gOptions.listenPort, gOptions.enableIpV4 ? "IPv4 AND IPv6" : "IPv6 ONLY");
187 mdns::Minimal::Server<10 /* endpoints */> mdnsServer;
188 mdns::Minimal::QueryResponder<16 /* maxRecords */> queryResponder;
190 mdns::Minimal::QNamePart tcpServiceName[] = { "_chip", "_tcp", "local" };
191 mdns::Minimal::QNamePart tcpServerServiceName[] = { gOptions.instanceName, "_chip", "_tcp", "local" };
192 mdns::Minimal::QNamePart udpServiceName[] = { "_chip", "_udp", "local" };
193 mdns::Minimal::QNamePart udpServerServiceName[] = { gOptions.instanceName, "_chip", "_udp", "local" };
195 // several UDP versions for discriminators
196 mdns::Minimal::QNamePart udpDiscriminator1[] = { "S052", "_sub", "_chip", "_udp", "local" };
197 mdns::Minimal::QNamePart udpDiscriminator2[] = { "V123", "_sub", "_chip", "_udp", "local" };
198 mdns::Minimal::QNamePart udpDiscriminator3[] = { "L0840", "_sub", "_chip", "_udp", "local" };
200 mdns::Minimal::QNamePart serverName[] = { gOptions.instanceName, "local" };
202 mdns::Minimal::IPv4Responder ipv4Responder(serverName);
203 mdns::Minimal::IPv6Responder ipv6Responder(serverName);
204 mdns::Minimal::SrvResourceRecord srvRecord(tcpServerServiceName, serverName, CHIP_PORT);
205 mdns::Minimal::SrvResponder tcpSrvResponder(mdns::Minimal::SrvResourceRecord(tcpServerServiceName, serverName, CHIP_PORT));
206 mdns::Minimal::SrvResponder udpSrvResponder(mdns::Minimal::SrvResourceRecord(udpServerServiceName, serverName, CHIP_PORT));
207 mdns::Minimal::PtrResponder ptrTcpResponder(tcpServiceName, tcpServerServiceName);
208 mdns::Minimal::PtrResponder ptrUdpResponder(udpServiceName, udpServerServiceName);
209 mdns::Minimal::PtrResponder ptrUdpDiscriminator1Responder(udpDiscriminator1, udpServerServiceName);
210 mdns::Minimal::PtrResponder ptrUdpDiscriminator2Responder(udpDiscriminator2, udpServerServiceName);
211 mdns::Minimal::PtrResponder ptrUdpDiscriminator3Responder(udpDiscriminator3, udpServerServiceName);
213 // report TXT records for our service.
214 const char * txtEntries[] = {
218 "OTH=Some text here...",
220 mdns::Minimal::TxtResponder tcpTxtResponder(mdns::Minimal::TxtResourceRecord(tcpServerServiceName, txtEntries));
221 mdns::Minimal::TxtResponder udpTxtResponder(mdns::Minimal::TxtResourceRecord(udpServerServiceName, txtEntries));
223 queryResponder.AddResponder(&ptrTcpResponder).SetReportInServiceListing(true).SetReportAdditional(tcpServerServiceName);
224 queryResponder.AddResponder(&ptrUdpResponder).SetReportInServiceListing(true).SetReportAdditional(udpServerServiceName);
225 queryResponder.AddResponder(&ptrUdpDiscriminator1Responder).SetReportAdditional(udpServerServiceName);
226 queryResponder.AddResponder(&ptrUdpDiscriminator2Responder).SetReportAdditional(udpServerServiceName);
227 queryResponder.AddResponder(&ptrUdpDiscriminator3Responder).SetReportAdditional(udpServerServiceName);
228 queryResponder.AddResponder(&tcpTxtResponder);
229 queryResponder.AddResponder(&udpTxtResponder);
230 queryResponder.AddResponder(&tcpSrvResponder).SetReportAdditional(serverName);
231 queryResponder.AddResponder(&udpSrvResponder).SetReportAdditional(serverName);
232 queryResponder.AddResponder(&ipv6Responder);
234 if (gOptions.enableIpV4)
236 queryResponder.AddResponder(&ipv4Responder);
239 mdns::Minimal::ResponseSender responseSender(&mdnsServer, &queryResponder);
241 ReplyDelegate delegate(&responseSender);
242 mdnsServer.SetDelegate(&delegate);
245 MdnsExample::AllInterfaces allInterfaces(gOptions.enableIpV4);
247 if (mdnsServer.Listen(&chip::DeviceLayer::InetLayer, &allInterfaces, gOptions.listenPort) != CHIP_NO_ERROR)
249 printf("Server failed to listen on all interfaces\n");
254 DeviceLayer::PlatformMgr().RunEventLoop();