1 /* 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 17 package android.net; 18 19 import static android.system.OsConstants.SOCK_DGRAM; 20 import static android.system.OsConstants.SOCK_STREAM; 21 22 import android.annotation.NonNull; 23 import android.annotation.Nullable; 24 import android.annotation.SystemApi; 25 import android.os.Parcel; 26 import android.os.ParcelFileDescriptor; 27 import android.os.Parcelable; 28 29 import java.io.IOException; 30 import java.net.DatagramSocket; 31 import java.net.InetAddress; 32 import java.net.InetSocketAddress; 33 import java.net.Socket; 34 import java.net.UnknownHostException; 35 import java.util.Objects; 36 37 /** 38 * Used in conjunction with 39 * {@link ConnectivityManager#registerQosCallback} 40 * 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}. 42 * 43 * @hide 44 */ 45 @SystemApi 46 public 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 57 @Nullable 58 private final InetSocketAddress mRemoteSocketAddress; 59 60 private final int mSocketType; 61 62 /** 63 * The {@link Network} the socket is on. 64 * 65 * @return the registered {@link Network} 66 */ 67 @NonNull getNetwork()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 76 * @hide 77 */ 78 @NonNull getParcelFileDescriptor()79 public ParcelFileDescriptor getParcelFileDescriptor() { 80 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 getLocalSocketAddress()91 public InetSocketAddress getLocalSocketAddress() { 92 return mLocalSocketAddress; 93 } 94 95 /** 96 * 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 getRemoteSocketAddress()103 public InetSocketAddress getRemoteSocketAddress() { 104 return mRemoteSocketAddress; 105 } 106 107 /** 108 * 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 */ getSocketType()113 public int getSocketType() { 114 return mSocketType; 115 } 116 117 /** 118 * 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 */ QosSocketInfo(@onNull final Network network, @NonNull final Socket socket)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"); 129 mParcelFileDescriptor = ParcelFileDescriptor.fromSocket(socket); 130 mLocalSocketAddress = 131 new InetSocketAddress(socket.getLocalAddress(), socket.getLocalPort()); 132 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} 147 */ QosSocketInfo(@onNull final Network network, @NonNull final DatagramSocket socket)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; 157 158 if (socket.isConnected()) { 159 mRemoteSocketAddress = (InetSocketAddress) socket.getRemoteSocketAddress(); 160 } else { 161 mRemoteSocketAddress = null; 162 } 163 } 164 165 /* Parcelable methods */ QosSocketInfo(final Parcel in)166 private QosSocketInfo(final Parcel in) { 167 mNetwork = Objects.requireNonNull(Network.CREATOR.createFromParcel(in)); 168 final boolean withFd = in.readBoolean(); 169 if (withFd) { 170 mParcelFileDescriptor = ParcelFileDescriptor.CREATOR.createFromParcel(in); 171 } else { 172 mParcelFileDescriptor = null; 173 } 174 175 mLocalSocketAddress = readSocketAddress(in); 176 mRemoteSocketAddress = readSocketAddress(in); 177 178 mSocketType = in.readInt(); 179 } 180 readSocketAddress(final Parcel in)181 private InetSocketAddress readSocketAddress(final Parcel in) { 182 final byte[] addrBytes = in.createByteArray(); 183 if (addrBytes == null) { 184 return null; 185 } 186 final int port = in.readInt(); 187 188 try { 189 return new InetSocketAddress(InetAddress.getByAddress(addrBytes), port); 190 } catch (final UnknownHostException e) { 191 /* This can never happen. UnknownHostException will never be thrown 192 since the address provided is numeric and non-null. */ 193 throw new RuntimeException("UnknownHostException on numeric address", e); 194 } 195 } 196 197 @Override describeContents()198 public int describeContents() { 199 return 0; 200 } 201 202 @Override writeToParcel(@onNull final Parcel dest, final int flags)203 public void writeToParcel(@NonNull final Parcel dest, final int flags) { 204 writeToParcelInternal(dest, flags, /*includeFd=*/ true); 205 } 206 207 /** 208 * Used when sending QosSocketInfo to telephony, which does not need access to the socket FD. 209 * @hide 210 */ writeToParcelWithoutFd(@onNull final Parcel dest, final int flags)211 public void writeToParcelWithoutFd(@NonNull final Parcel dest, final int flags) { 212 writeToParcelInternal(dest, flags, /*includeFd=*/ false); 213 } 214 writeToParcelInternal( @onNull final Parcel dest, final int flags, boolean includeFd)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()); 227 dest.writeInt(mLocalSocketAddress.getPort()); 228 229 if (mRemoteSocketAddress == null) { 230 dest.writeByteArray(null); 231 } else { 232 dest.writeByteArray(mRemoteSocketAddress.getAddress().getAddress()); 233 dest.writeInt(mRemoteSocketAddress.getPort()); 234 } 235 dest.writeInt(mSocketType); 236 } 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 } 254