1 /*
2  * Copyright (C) 2021 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #include "wifi_p2p_dns_sd_service_info.h"
16 
17 #include <sstream>
18 #include <algorithm>
19 #include <iomanip>
20 
21 namespace OHOS {
22 namespace Wifi {
FindPacket(std::string & dnsName)23 inline std::string FindPacket(std::string &dnsName)
24 {
25     if (dnsName == "_tcp.local.") {
26         return "c00c";
27     }
28     if (dnsName == "local.") {
29         return "c011";
30     }
31     if (dnsName == "_udp.local.") {
32         return "c01c";
33     }
34     return "";
35 }
36 
37 
WifiP2pDnsSdServiceInfo(const std::vector<std::string> & queryList)38 WifiP2pDnsSdServiceInfo::WifiP2pDnsSdServiceInfo(const std::vector<std::string> &queryList)
39     : WifiP2pServiceInfo(queryList)
40 {}
41 
WifiP2pDnsSdServiceInfo()42 WifiP2pDnsSdServiceInfo::WifiP2pDnsSdServiceInfo()
43 {}
44 
Create(const std::string & instanceName,const std::string & serviceType,const std::map<std::string,std::string> & txtMap,const std::string & svrName)45 WifiP2pDnsSdServiceInfo WifiP2pDnsSdServiceInfo::Create(const std::string &instanceName, const std::string &serviceType,
46     const std::map<std::string, std::string> &txtMap, const std::string &svrName)
47 {
48     WifiP2PDnsTxtRecord txtRecord;
49     for (auto it = txtMap.begin(); it != txtMap.end(); ++it) {
50         txtRecord.SetRecord(it->first, it->second);
51     }
52     std::vector<std::string> queries;
53     queries.push_back(BuildPtrServiceQuery(instanceName, serviceType, svrName));
54     queries.push_back(BuildTxtServiceQuery(instanceName, serviceType, txtRecord, svrName));
55 
56     WifiP2pDnsSdServiceInfo dnsSdServInfo(queries);
57     dnsSdServInfo.SetServiceName(svrName);
58     dnsSdServInfo.SetServicerProtocolType(P2pServicerProtocolType::SERVICE_TYPE_BONJOUR);
59     return dnsSdServInfo;
60 }
BuildPtrServiceQuery(const std::string & instanceName,const std::string & serviceType,const std::string & svrName)61 std::string WifiP2pDnsSdServiceInfo::BuildPtrServiceQuery(
62     const std::string &instanceName, const std::string &serviceType, const std::string &svrName)
63 {
64     std::stringstream ret;
65     std::vector<unsigned char> buf;
66 
67     ret << "bonjour ";
68     ret << BuildRequest(serviceType + ".local.", DNS_PTR_TYPE, VERSION_1);
69     ret << " ";
70 
71     std::stringstream stream(instanceName);
72     buf.clear();
73     buf.push_back(static_cast<unsigned char>(stream.str().length()));
74     ret << Bin2HexStr(buf);
75 
76     ret << Bin2HexStr(stream.str());
77     ret << "c027";
78 
79     ret << Bin2HexStr(std::string(";"));
80     buf.clear();
81     buf.push_back(static_cast<unsigned char>(svrName.length()));
82     ret << Bin2HexStr(buf);
83     ret << Bin2HexStr(svrName);
84     return ret.str();
85 }
86 
BuildTxtServiceQuery(const std::string & instanceName,const std::string & serviceType,const WifiP2PDnsTxtRecord & txtRecord,const std::string & svrName)87 std::string WifiP2pDnsSdServiceInfo::BuildTxtServiceQuery(const std::string &instanceName,
88     const std::string &serviceType, const WifiP2PDnsTxtRecord &txtRecord, const std::string &svrName)
89 {
90     std::string ret("");
91     ret += std::string("bonjour ");
92     std::string dnsName = instanceName + std::string(".") + serviceType + std::string(".local.");
93     ret += BuildRequest(dnsName, DNS_TXT_TYPE, VERSION_1);
94     ret += std::string(" ");
95     std::vector<unsigned char> rawData = txtRecord.GetData();
96     if (rawData.empty()) {
97         ret += std::string("00");
98     } else {
99         ret += Bin2HexStr(rawData);
100     }
101 
102     if (!svrName.empty()) {
103         if (!rawData.empty()) {
104             ret += std::string("00");
105         }
106         ret.append(Bin2HexStr(std::string(";")));
107         std::vector<unsigned char> buf;
108         buf.push_back(static_cast<unsigned char>(svrName.length()));
109         ret.append(Bin2HexStr(buf));
110         ret.append(Bin2HexStr(svrName));
111     }
112 
113     return ret;
114 }
115 
BuildRequest(const std::string & dnsName,int dnsType,int version)116 std::string WifiP2pDnsSdServiceInfo::BuildRequest(const std::string &dnsName, int dnsType, int version)
117 {
118     std::stringstream ret;
119     std::string name = dnsName;
120     const int stepFour = 4;
121     const int stepTwo = 2;
122     if (dnsType == WifiP2pDnsSdServiceInfo::DNS_TXT_TYPE) {
123         transform(name.begin(), name.end(), name.begin(), ::tolower);
124     }
125     ret << TurnDnsNameToStream(name);
126     ret << std::hex << std::setw(stepFour) << std::setfill('0') << dnsType;
127     ret << std::hex << std::setw(stepTwo) << std::setfill('0') << version;
128     return ret.str();
129 }
130 
TurnDnsNameToStream(const std::string & dnsName)131 std::string WifiP2pDnsSdServiceInfo::TurnDnsNameToStream(const std::string &dnsName)
132 {
133     std::stringstream ret;
134     std::string name = dnsName;
135     const int stepTwo = 2;
136 
137     while (true) {
138         std::string data = FindPacket(name);
139         if (!data.empty()) {
140             ret << data;
141             break;
142         }
143         auto i = name.find_first_of('.');
144         if (i == std::string::npos) {
145             if (name.length() > 0) {
146                 ret << std::hex << std::setw(stepTwo) << std::setfill('0') << name.length();
147                 ret << Bin2HexStr(name);
148             }
149             ret << "00"; /* for *\0 */
150             break;
151         }
152         if (i != 0) { /* for .* create dnsreq with (null, "*") will make the dnsname like ".tcp" */
153             std::string splitName = name.substr(0, i);
154             ret << std::hex << std::setw(stepTwo) << std::setfill('0') << splitName.length();
155             ret << Bin2HexStr(splitName);
156         }
157         name = name.substr(i + 1);
158     }
159     return ret.str();
160 }
161 }  // namespace Wifi
162 }  // namespace OHOS