• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.connectivity.mdns;
18 
19 import android.annotation.Nullable;
20 
21 import com.android.net.module.util.DnsUtils;
22 
23 import java.io.IOException;
24 import java.util.Arrays;
25 import java.util.Locale;
26 import java.util.Objects;
27 
28 /** An mDNS "SRV" record, which contains service information. */
29 public class MdnsServiceRecord extends MdnsRecord {
30     public static final int PROTO_NONE = 0;
31     public static final int PROTO_TCP = 1;
32     public static final int PROTO_UDP = 2;
33     private static final String PROTO_TOKEN_TCP = "_tcp";
34     private static final String PROTO_TOKEN_UDP = "_udp";
35     private int servicePriority;
36     private int serviceWeight;
37     private int servicePort;
38     private String[] serviceHost;
39 
MdnsServiceRecord(String[] name, MdnsPacketReader reader)40     public MdnsServiceRecord(String[] name, MdnsPacketReader reader) throws IOException {
41         this(name, reader, false);
42     }
43 
MdnsServiceRecord(String[] name, MdnsPacketReader reader, boolean isQuestion)44     public MdnsServiceRecord(String[] name, MdnsPacketReader reader, boolean isQuestion)
45             throws IOException {
46         super(name, TYPE_SRV, reader, isQuestion);
47     }
48 
MdnsServiceRecord(String[] name, boolean isUnicast)49     public MdnsServiceRecord(String[] name, boolean isUnicast) {
50         super(name, TYPE_SRV,
51                 MdnsConstants.QCLASS_INTERNET | (isUnicast ? MdnsConstants.QCLASS_UNICAST : 0),
52                 0L /* receiptTimeMillis */, false /* cacheFlush */, 0L /* ttlMillis */);
53     }
54 
MdnsServiceRecord(String[] name, long receiptTimeMillis, boolean cacheFlush, long ttlMillis, int servicePriority, int serviceWeight, int servicePort, String[] serviceHost)55     public MdnsServiceRecord(String[] name, long receiptTimeMillis, boolean cacheFlush,
56                     long ttlMillis, int servicePriority, int serviceWeight, int servicePort,
57                     String[] serviceHost) {
58         super(name, TYPE_SRV, MdnsConstants.QCLASS_INTERNET, receiptTimeMillis, cacheFlush,
59                 ttlMillis);
60         this.servicePriority = servicePriority;
61         this.serviceWeight = serviceWeight;
62         this.servicePort = servicePort;
63         this.serviceHost = serviceHost;
64     }
65 
66     /** Returns the service's port number. */
getServicePort()67     public int getServicePort() {
68         return servicePort;
69     }
70 
71     /** Returns the service's host name. */
getServiceHost()72     public String[] getServiceHost() {
73         return serviceHost;
74     }
75 
76     /** Returns the service's priority. */
getServicePriority()77     public int getServicePriority() {
78         return servicePriority;
79     }
80 
81     /** Returns the service's weight. */
getServiceWeight()82     public int getServiceWeight() {
83         return serviceWeight;
84     }
85 
86     // Format of name is <instance-name>.<service-name>.<protocol>.<domain>
87 
88     /** Returns the service's instance name, which uniquely identifies the service instance. */
getServiceInstanceName()89     public String getServiceInstanceName() {
90         if (name.length < 1) {
91             return null;
92         }
93         return name[0];
94     }
95 
96     /** Returns the service's name. */
getServiceName()97     public String getServiceName() {
98         if (name.length < 2) {
99             return null;
100         }
101         return name[1];
102     }
103 
104     /** Returns the service's protocol. */
getServiceProtocol()105     public int getServiceProtocol() {
106         if (name.length < 3) {
107             return PROTO_NONE;
108         }
109 
110         String protocol = name[2];
111         if (protocol.equals(PROTO_TOKEN_TCP)) {
112             return PROTO_TCP;
113         }
114         if (protocol.equals(PROTO_TOKEN_UDP)) {
115             return PROTO_UDP;
116         }
117         return PROTO_NONE;
118     }
119 
120     @Override
readData(MdnsPacketReader reader)121     protected void readData(MdnsPacketReader reader) throws IOException {
122         servicePriority = reader.readUInt16();
123         serviceWeight = reader.readUInt16();
124         servicePort = reader.readUInt16();
125         serviceHost = reader.readLabels();
126     }
127 
128     @Override
writeData(MdnsPacketWriter writer)129     protected void writeData(MdnsPacketWriter writer) throws IOException {
130         writer.writeUInt16(servicePriority);
131         writer.writeUInt16(serviceWeight);
132         writer.writeUInt16(servicePort);
133         writer.writeLabels(serviceHost);
134     }
135 
136     @Override
toString()137     public String toString() {
138         return String.format(
139                 Locale.ROOT,
140                 "SRV: %s:%d (prio=%d, weight=%d)",
141                 labelsToString(serviceHost),
142                 servicePort,
143                 servicePriority,
144                 serviceWeight);
145     }
146 
147     @Override
hashCode()148     public int hashCode() {
149         return (super.hashCode() * 31)
150                 + Objects.hash(servicePriority, serviceWeight,
151                 Arrays.hashCode(DnsUtils.toDnsLabelsUpperCase(serviceHost)),
152                 servicePort);
153     }
154 
155     @Override
equals(@ullable Object other)156     public boolean equals(@Nullable Object other) {
157         if (this == other) {
158             return true;
159         }
160         if (!(other instanceof MdnsServiceRecord)) {
161             return false;
162         }
163         MdnsServiceRecord otherRecord = (MdnsServiceRecord) other;
164 
165         return super.equals(other)
166                 && (servicePriority == otherRecord.servicePriority)
167                 && (serviceWeight == otherRecord.serviceWeight)
168                 && DnsUtils.equalsDnsLabelIgnoreDnsCase(serviceHost, otherRecord.serviceHost)
169                 && (servicePort == otherRecord.servicePort);
170     }
171 }
172