Fix for x86_64 build fail
[platform/upstream/connectedhomeip.git] / examples / minimal-mdns / server.cpp
1 /*
2  *
3  *    Copyright (c) 2020 Project CHIP Authors
4  *
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
8  *
9  *        http://www.apache.org/licenses/LICENSE-2.0
10  *
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.
16  */
17
18 #include <cstdio>
19 #include <memory>
20
21 #include <arpa/inet.h>
22
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>
38
39 #include "AllInterfaceListener.h"
40 #include "PacketReporter.h"
41
42 using namespace chip;
43
44 namespace {
45
46 struct Options
47 {
48     bool enableIpV4           = false;
49     uint16_t listenPort       = 5353;
50     const char * instanceName = "chip-mdns-demo";
51 } gOptions;
52
53 using namespace chip::ArgParser;
54
55 constexpr uint16_t kOptionEnableIpV4   = '4';
56 constexpr uint16_t kOptionListenPort   = 'p';
57 constexpr uint16_t kOptionInstanceName = 'i';
58
59 bool HandleOptions(const char * aProgram, OptionSet * aOptions, int aIdentifier, const char * aName, const char * aValue)
60 {
61     switch (aIdentifier)
62     {
63     case kOptionEnableIpV4:
64         gOptions.enableIpV4 = true;
65         return true;
66
67     case kOptionInstanceName:
68         gOptions.instanceName = aValue;
69         return true;
70
71     case kOptionListenPort:
72         if (!ParseInt(aValue, gOptions.listenPort))
73         {
74             PrintArgError("%s: invalid value for port: %s\n", aProgram, aValue);
75             return false;
76         }
77         return true;
78
79     default:
80         PrintArgError("%s: INTERNAL ERROR: Unhandled option: %s\n", aProgram, aName);
81         return false;
82     }
83 }
84
85 OptionDef cmdLineOptionsDef[] = {
86     { "listen-port", kArgumentRequired, kOptionListenPort },
87     { "enable-ip-v4", kNoArgument, kOptionEnableIpV4 },
88     { "instance-name", kArgumentRequired, kOptionInstanceName },
89     nullptr,
90 };
91
92 OptionSet cmdLineOptions = { HandleOptions, cmdLineOptionsDef, "PROGRAM OPTIONS",
93                              "  -p <number>\n"
94                              "  --listen-port <number>\n"
95                              "        The port number to listen on\n"
96                              "  -4\n"
97                              "  --enable-ip-v4\n"
98                              "        enable listening on IPv4\n"
99                              "  -i <name>\n"
100                              "  --instance-name <name>\n"
101                              "        instance name to advertise.\n"
102                              "\n" };
103
104 HelpOptions helpOptions("minimal-mdns-server", "Usage: minimal-mdns-server [options]", "1.0");
105
106 OptionSet * allOptions[] = { &cmdLineOptions, &helpOptions, nullptr };
107
108 class ReplyDelegate : public mdns::Minimal::ServerDelegate, public mdns::Minimal::ParserDelegate
109 {
110 public:
111     ReplyDelegate(mdns::Minimal::ResponseSender * responder) : mResponder(responder) {}
112
113     void OnQuery(const mdns::Minimal::BytesRange & data, const chip::Inet::IPPacketInfo * info) override
114     {
115         char addr[INET6_ADDRSTRLEN];
116         info->SrcAddress.ToString(addr, sizeof(addr));
117
118         printf("QUERY from: %-15s on port %d, via interface %d\n", addr, info->SrcPort, info->Interface);
119         Report("QUERY: ", data);
120
121         mCurrentSource = info;
122         if (!mdns::Minimal::ParsePacket(data, this))
123         {
124             printf("Parsing failure may result in reply failure!\n");
125         }
126         mCurrentSource = nullptr;
127     }
128
129     void OnResponse(const mdns::Minimal::BytesRange & data, const chip::Inet::IPPacketInfo * info) override
130     {
131         char addr[INET6_ADDRSTRLEN];
132         info->SrcAddress.ToString(addr, sizeof(addr));
133
134         printf("RESPONSE from: %-15s on port %d, via interface %d\n", addr, info->SrcPort, info->Interface);
135     }
136
137     // ParserDelegate
138     void OnHeader(mdns::Minimal::ConstHeaderRef & header) override { mMessageId = header.GetMessageId(); }
139     void OnResource(mdns::Minimal::ResourceType type, const mdns::Minimal::ResourceData & data) override {}
140
141     void OnQuery(const mdns::Minimal::QueryData & data) override
142     {
143         if (mResponder->Respond(mMessageId, data, mCurrentSource) != CHIP_NO_ERROR)
144         {
145             printf("FAILED to respond!\n");
146         }
147     }
148
149 private:
150     void Report(const char * prefix, const mdns::Minimal::BytesRange & data)
151     {
152         MdnsExample::PacketReporter reporter(prefix, data);
153         if (!mdns::Minimal::ParsePacket(data, &reporter))
154         {
155             printf("INVALID PACKET!!!!!!\n");
156         }
157     }
158
159     mdns::Minimal::ResponseSender * mResponder;
160     const chip::Inet::IPPacketInfo * mCurrentSource = nullptr;
161     uint32_t mMessageId                             = 0;
162 };
163
164 } // namespace
165
166 int main(int argc, char ** args)
167 {
168     if (Platform::MemoryInit() != CHIP_NO_ERROR)
169     {
170         printf("FAILED to initialize memory");
171         return 1;
172     }
173
174     if (DeviceLayer::PlatformMgr().InitChipStack() != CHIP_NO_ERROR)
175     {
176         printf("FAILED to initialize chip stack");
177         return 1;
178     }
179
180     if (!chip::ArgParser::ParseArgs(args[0], argc, args, allOptions))
181     {
182         return 1;
183     }
184
185     printf("Running on port %d using %s...\n", gOptions.listenPort, gOptions.enableIpV4 ? "IPv4 AND IPv6" : "IPv6 ONLY");
186
187     mdns::Minimal::Server<10 /* endpoints */> mdnsServer;
188     mdns::Minimal::QueryResponder<16 /* maxRecords */> queryResponder;
189
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" };
194
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" };
199
200     mdns::Minimal::QNamePart serverName[] = { gOptions.instanceName, "local" };
201
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);
212
213     // report TXT records for our service.
214     const char * txtEntries[] = {
215         "D0840=yes",
216         "VP=123+456",
217         "PH=3",
218         "OTH=Some text here...",
219     };
220     mdns::Minimal::TxtResponder tcpTxtResponder(mdns::Minimal::TxtResourceRecord(tcpServerServiceName, txtEntries));
221     mdns::Minimal::TxtResponder udpTxtResponder(mdns::Minimal::TxtResourceRecord(udpServerServiceName, txtEntries));
222
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);
233
234     if (gOptions.enableIpV4)
235     {
236         queryResponder.AddResponder(&ipv4Responder);
237     }
238
239     mdns::Minimal::ResponseSender responseSender(&mdnsServer, &queryResponder);
240
241     ReplyDelegate delegate(&responseSender);
242     mdnsServer.SetDelegate(&delegate);
243
244     {
245         MdnsExample::AllInterfaces allInterfaces(gOptions.enableIpV4);
246
247         if (mdnsServer.Listen(&chip::DeviceLayer::InetLayer, &allInterfaces, gOptions.listenPort) != CHIP_NO_ERROR)
248         {
249             printf("Server failed to listen on all interfaces\n");
250             return 1;
251         }
252     }
253
254     DeviceLayer::PlatformMgr().RunEventLoop();
255
256     printf("Done...\n");
257     return 0;
258 }