blob: 1c3db23cadfb79ac23228ea6b2be0e3cbdf22c9a [file] [log] [blame]
Daniel Brightf9e945b2020-06-15 16:10:01 -07001/*
2 * Copyright (C) 2020 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
17package android.net;
18
sewookseo82657d72022-03-07 06:31:57 +000019import static android.system.OsConstants.SOCK_DGRAM;
20import static android.system.OsConstants.SOCK_STREAM;
21
Daniel Brightf9e945b2020-06-15 16:10:01 -070022import android.annotation.NonNull;
Jayachandran Cb5335502021-04-19 18:21:36 -070023import android.annotation.Nullable;
Daniel Brightf9e945b2020-06-15 16:10:01 -070024import android.annotation.SystemApi;
25import android.os.Parcel;
26import android.os.ParcelFileDescriptor;
27import android.os.Parcelable;
28
29import java.io.IOException;
sewookseo82657d72022-03-07 06:31:57 +000030import java.net.DatagramSocket;
Daniel Brightf9e945b2020-06-15 16:10:01 -070031import java.net.InetAddress;
32import java.net.InetSocketAddress;
33import java.net.Socket;
34import java.net.UnknownHostException;
35import java.util.Objects;
36
37/**
38 * Used in conjunction with
39 * {@link ConnectivityManager#registerQosCallback}
Jayachandran Cb5335502021-04-19 18:21:36 -070040 * in order to receive Qos Sessions related to the local address and port of a bound {@link Socket}
41 * and/or remote address and port of a connected {@link Socket}.
Daniel Brightf9e945b2020-06-15 16:10:01 -070042 *
43 * @hide
44 */
45@SystemApi
46public final class QosSocketInfo implements Parcelable {
47
48 @NonNull
49 private final Network mNetwork;
50
51 @NonNull
52 private final ParcelFileDescriptor mParcelFileDescriptor;
53
54 @NonNull
55 private final InetSocketAddress mLocalSocketAddress;
56
Jayachandran Cb5335502021-04-19 18:21:36 -070057 @Nullable
58 private final InetSocketAddress mRemoteSocketAddress;
59
sewookseo82657d72022-03-07 06:31:57 +000060 private final int mSocketType;
61
Daniel Brightf9e945b2020-06-15 16:10:01 -070062 /**
63 * The {@link Network} the socket is on.
64 *
65 * @return the registered {@link Network}
66 */
67 @NonNull
68 public Network getNetwork() {
69 return mNetwork;
70 }
71
72 /**
73 * The parcel file descriptor wrapped around the socket's file descriptor.
74 *
75 * @return the parcel file descriptor of the socket
Remi NGUYEN VANe55a88d2022-04-20 15:59:16 +090076 * @hide
Daniel Brightf9e945b2020-06-15 16:10:01 -070077 */
78 @NonNull
Remi NGUYEN VANe55a88d2022-04-20 15:59:16 +090079 public ParcelFileDescriptor getParcelFileDescriptor() {
Daniel Brightf9e945b2020-06-15 16:10:01 -070080 return mParcelFileDescriptor;
81 }
82
83 /**
84 * The local address of the socket passed into {@link QosSocketInfo(Network, Socket)}.
85 * The value does not reflect any changes that occur to the socket after it is first set
86 * in the constructor.
87 *
88 * @return the local address of the socket
89 */
90 @NonNull
91 public InetSocketAddress getLocalSocketAddress() {
92 return mLocalSocketAddress;
93 }
94
95 /**
Jayachandran Cb5335502021-04-19 18:21:36 -070096 * The remote address of the socket passed into {@link QosSocketInfo(Network, Socket)}.
97 * The value does not reflect any changes that occur to the socket after it is first set
98 * in the constructor.
99 *
100 * @return the remote address of the socket if socket is connected, null otherwise
101 */
102 @Nullable
103 public InetSocketAddress getRemoteSocketAddress() {
104 return mRemoteSocketAddress;
105 }
106
107 /**
sewookseo82657d72022-03-07 06:31:57 +0000108 * The socket type of the socket passed in when this QosSocketInfo object was constructed.
109 *
110 * @return the socket type of the socket.
111 * @hide
112 */
113 public int getSocketType() {
114 return mSocketType;
115 }
116
117 /**
Daniel Brightf9e945b2020-06-15 16:10:01 -0700118 * Creates a {@link QosSocketInfo} given a {@link Network} and bound {@link Socket}. The
119 * {@link Socket} must remain bound in order to receive {@link QosSession}s.
120 *
121 * @param network the network
122 * @param socket the bound {@link Socket}
123 */
124 public QosSocketInfo(@NonNull final Network network, @NonNull final Socket socket)
125 throws IOException {
126 Objects.requireNonNull(socket, "socket cannot be null");
127
128 mNetwork = Objects.requireNonNull(network, "network cannot be null");
Remi NGUYEN VAN0942ad92021-03-09 23:53:55 +0000129 mParcelFileDescriptor = ParcelFileDescriptor.fromSocket(socket);
Daniel Brightf9e945b2020-06-15 16:10:01 -0700130 mLocalSocketAddress =
131 new InetSocketAddress(socket.getLocalAddress(), socket.getLocalPort());
sewookseo82657d72022-03-07 06:31:57 +0000132 mSocketType = SOCK_STREAM;
133
134 if (socket.isConnected()) {
135 mRemoteSocketAddress = (InetSocketAddress) socket.getRemoteSocketAddress();
136 } else {
137 mRemoteSocketAddress = null;
138 }
139 }
140
141 /**
142 * Creates a {@link QosSocketInfo} given a {@link Network} and bound {@link DatagramSocket}. The
143 * {@link DatagramSocket} must remain bound in order to receive {@link QosSession}s.
144 *
145 * @param network the network
146 * @param socket the bound {@link DatagramSocket}
sewookseo82657d72022-03-07 06:31:57 +0000147 */
148 public QosSocketInfo(@NonNull final Network network, @NonNull final DatagramSocket socket)
149 throws IOException {
150 Objects.requireNonNull(socket, "socket cannot be null");
151
152 mNetwork = Objects.requireNonNull(network, "network cannot be null");
153 mParcelFileDescriptor = ParcelFileDescriptor.fromDatagramSocket(socket);
154 mLocalSocketAddress =
155 new InetSocketAddress(socket.getLocalAddress(), socket.getLocalPort());
156 mSocketType = SOCK_DGRAM;
Jayachandran Cb5335502021-04-19 18:21:36 -0700157
158 if (socket.isConnected()) {
159 mRemoteSocketAddress = (InetSocketAddress) socket.getRemoteSocketAddress();
160 } else {
161 mRemoteSocketAddress = null;
162 }
Daniel Brightf9e945b2020-06-15 16:10:01 -0700163 }
164
165 /* Parcelable methods */
166 private QosSocketInfo(final Parcel in) {
167 mNetwork = Objects.requireNonNull(Network.CREATOR.createFromParcel(in));
sewookseoafc22b02022-03-07 11:03:13 +0000168 final boolean withFd = in.readBoolean();
169 if (withFd) {
170 mParcelFileDescriptor = ParcelFileDescriptor.CREATOR.createFromParcel(in);
171 } else {
172 mParcelFileDescriptor = null;
173 }
Daniel Brightf9e945b2020-06-15 16:10:01 -0700174
sewookseoafc22b02022-03-07 11:03:13 +0000175 mLocalSocketAddress = readSocketAddress(in);
176 mRemoteSocketAddress = readSocketAddress(in);
sewookseo82657d72022-03-07 06:31:57 +0000177
178 mSocketType = in.readInt();
Daniel Brightf9e945b2020-06-15 16:10:01 -0700179 }
180
sewookseoafc22b02022-03-07 11:03:13 +0000181 private InetSocketAddress readSocketAddress(final Parcel in) {
182 final byte[] addrBytes = in.createByteArray();
183 if (addrBytes == null) {
184 return null;
185 }
Daniel Brightf9e945b2020-06-15 16:10:01 -0700186 final int port = in.readInt();
187
188 try {
sewookseoafc22b02022-03-07 11:03:13 +0000189 return new InetSocketAddress(InetAddress.getByAddress(addrBytes), port);
Daniel Brightf9e945b2020-06-15 16:10:01 -0700190 } catch (final UnknownHostException e) {
Remi NGUYEN VANd059f212021-03-11 07:43:37 +0000191 /* This can never happen. UnknownHostException will never be thrown
Daniel Brightf9e945b2020-06-15 16:10:01 -0700192 since the address provided is numeric and non-null. */
Remi NGUYEN VANd059f212021-03-11 07:43:37 +0000193 throw new RuntimeException("UnknownHostException on numeric address", e);
Daniel Brightf9e945b2020-06-15 16:10:01 -0700194 }
Daniel Brightf9e945b2020-06-15 16:10:01 -0700195 }
196
197 @Override
198 public int describeContents() {
199 return 0;
200 }
201
202 @Override
203 public void writeToParcel(@NonNull final Parcel dest, final int flags) {
sewookseoafc22b02022-03-07 11:03:13 +0000204 writeToParcelInternal(dest, flags, /*includeFd=*/ true);
205 }
Daniel Brightf9e945b2020-06-15 16:10:01 -0700206
sewookseoafc22b02022-03-07 11:03:13 +0000207 /**
208 * Used when sending QosSocketInfo to telephony, which does not need access to the socket FD.
209 * @hide
210 */
211 public void writeToParcelWithoutFd(@NonNull final Parcel dest, final int flags) {
212 writeToParcelInternal(dest, flags, /*includeFd=*/ false);
213 }
214
215 private void writeToParcelInternal(
216 @NonNull final Parcel dest, final int flags, boolean includeFd) {
217 mNetwork.writeToParcel(dest, 0);
218
219 if (includeFd) {
220 dest.writeBoolean(true);
221 mParcelFileDescriptor.writeToParcel(dest, 0);
222 } else {
223 dest.writeBoolean(false);
224 }
225
226 dest.writeByteArray(mLocalSocketAddress.getAddress().getAddress());
Daniel Brightf9e945b2020-06-15 16:10:01 -0700227 dest.writeInt(mLocalSocketAddress.getPort());
Jayachandran Cb5335502021-04-19 18:21:36 -0700228
229 if (mRemoteSocketAddress == null) {
sewookseoafc22b02022-03-07 11:03:13 +0000230 dest.writeByteArray(null);
Jayachandran Cb5335502021-04-19 18:21:36 -0700231 } else {
sewookseoafc22b02022-03-07 11:03:13 +0000232 dest.writeByteArray(mRemoteSocketAddress.getAddress().getAddress());
Jayachandran Cb5335502021-04-19 18:21:36 -0700233 dest.writeInt(mRemoteSocketAddress.getPort());
234 }
sewookseo82657d72022-03-07 06:31:57 +0000235 dest.writeInt(mSocketType);
Daniel Brightf9e945b2020-06-15 16:10:01 -0700236 }
237
238 @NonNull
239 public static final Parcelable.Creator<QosSocketInfo> CREATOR =
240 new Parcelable.Creator<QosSocketInfo>() {
241 @NonNull
242 @Override
243 public QosSocketInfo createFromParcel(final Parcel in) {
244 return new QosSocketInfo(in);
245 }
246
247 @NonNull
248 @Override
249 public QosSocketInfo[] newArray(final int size) {
250 return new QosSocketInfo[size];
251 }
252 };
253}