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 android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.annotation.SystemApi; 22 import android.os.Parcel; 23 import android.os.ParcelFileDescriptor; 24 import android.os.Parcelable; 25 26 import java.io.IOException; 27 import java.net.InetAddress; 28 import java.net.InetSocketAddress; 29 import java.net.Socket; 30 import java.net.UnknownHostException; 31 import java.util.Objects; 32 33 /** 34 * Used in conjunction with 35 * {@link ConnectivityManager#registerQosCallback} 36 * in order to receive Qos Sessions related to the local address and port of a bound {@link Socket} 37 * and/or remote address and port of a connected {@link Socket}. 38 * 39 * @hide 40 */ 41 @SystemApi 42 public final class QosSocketInfo implements Parcelable { 43 44 @NonNull 45 private final Network mNetwork; 46 47 @NonNull 48 private final ParcelFileDescriptor mParcelFileDescriptor; 49 50 @NonNull 51 private final InetSocketAddress mLocalSocketAddress; 52 53 @Nullable 54 private final InetSocketAddress mRemoteSocketAddress; 55 56 /** 57 * The {@link Network} the socket is on. 58 * 59 * @return the registered {@link Network} 60 */ 61 @NonNull getNetwork()62 public Network getNetwork() { 63 return mNetwork; 64 } 65 66 /** 67 * The parcel file descriptor wrapped around the socket's file descriptor. 68 * 69 * @return the parcel file descriptor of the socket 70 */ 71 @NonNull getParcelFileDescriptor()72 ParcelFileDescriptor getParcelFileDescriptor() { 73 return mParcelFileDescriptor; 74 } 75 76 /** 77 * The local address of the socket passed into {@link QosSocketInfo(Network, Socket)}. 78 * The value does not reflect any changes that occur to the socket after it is first set 79 * in the constructor. 80 * 81 * @return the local address of the socket 82 */ 83 @NonNull getLocalSocketAddress()84 public InetSocketAddress getLocalSocketAddress() { 85 return mLocalSocketAddress; 86 } 87 88 /** 89 * The remote address of the socket passed into {@link QosSocketInfo(Network, Socket)}. 90 * The value does not reflect any changes that occur to the socket after it is first set 91 * in the constructor. 92 * 93 * @return the remote address of the socket if socket is connected, null otherwise 94 */ 95 @Nullable getRemoteSocketAddress()96 public InetSocketAddress getRemoteSocketAddress() { 97 return mRemoteSocketAddress; 98 } 99 100 /** 101 * Creates a {@link QosSocketInfo} given a {@link Network} and bound {@link Socket}. The 102 * {@link Socket} must remain bound in order to receive {@link QosSession}s. 103 * 104 * @param network the network 105 * @param socket the bound {@link Socket} 106 */ QosSocketInfo(@onNull final Network network, @NonNull final Socket socket)107 public QosSocketInfo(@NonNull final Network network, @NonNull final Socket socket) 108 throws IOException { 109 Objects.requireNonNull(socket, "socket cannot be null"); 110 111 mNetwork = Objects.requireNonNull(network, "network cannot be null"); 112 mParcelFileDescriptor = ParcelFileDescriptor.fromSocket(socket); 113 mLocalSocketAddress = 114 new InetSocketAddress(socket.getLocalAddress(), socket.getLocalPort()); 115 116 if (socket.isConnected()) { 117 mRemoteSocketAddress = (InetSocketAddress) socket.getRemoteSocketAddress(); 118 } else { 119 mRemoteSocketAddress = null; 120 } 121 } 122 123 /* Parcelable methods */ QosSocketInfo(final Parcel in)124 private QosSocketInfo(final Parcel in) { 125 mNetwork = Objects.requireNonNull(Network.CREATOR.createFromParcel(in)); 126 mParcelFileDescriptor = ParcelFileDescriptor.CREATOR.createFromParcel(in); 127 128 final int localAddressLength = in.readInt(); 129 mLocalSocketAddress = readSocketAddress(in, localAddressLength); 130 131 final int remoteAddressLength = in.readInt(); 132 mRemoteSocketAddress = remoteAddressLength == 0 ? null 133 : readSocketAddress(in, remoteAddressLength); 134 } 135 readSocketAddress(final Parcel in, final int addressLength)136 private @NonNull InetSocketAddress readSocketAddress(final Parcel in, final int addressLength) { 137 final byte[] address = new byte[addressLength]; 138 in.readByteArray(address); 139 final int port = in.readInt(); 140 141 try { 142 return new InetSocketAddress(InetAddress.getByAddress(address), port); 143 } catch (final UnknownHostException e) { 144 /* This can never happen. UnknownHostException will never be thrown 145 since the address provided is numeric and non-null. */ 146 throw new RuntimeException("UnknownHostException on numeric address", e); 147 } 148 } 149 150 @Override describeContents()151 public int describeContents() { 152 return 0; 153 } 154 155 @Override writeToParcel(@onNull final Parcel dest, final int flags)156 public void writeToParcel(@NonNull final Parcel dest, final int flags) { 157 mNetwork.writeToParcel(dest, 0); 158 mParcelFileDescriptor.writeToParcel(dest, 0); 159 160 final byte[] localAddress = mLocalSocketAddress.getAddress().getAddress(); 161 dest.writeInt(localAddress.length); 162 dest.writeByteArray(localAddress); 163 dest.writeInt(mLocalSocketAddress.getPort()); 164 165 if (mRemoteSocketAddress == null) { 166 dest.writeInt(0); 167 } else { 168 final byte[] remoteAddress = mRemoteSocketAddress.getAddress().getAddress(); 169 dest.writeInt(remoteAddress.length); 170 dest.writeByteArray(remoteAddress); 171 dest.writeInt(mRemoteSocketAddress.getPort()); 172 } 173 } 174 175 @NonNull 176 public static final Parcelable.Creator<QosSocketInfo> CREATOR = 177 new Parcelable.Creator<QosSocketInfo>() { 178 @NonNull 179 @Override 180 public QosSocketInfo createFromParcel(final Parcel in) { 181 return new QosSocketInfo(in); 182 } 183 184 @NonNull 185 @Override 186 public QosSocketInfo[] newArray(final int size) { 187 return new QosSocketInfo[size]; 188 } 189 }; 190 } 191