1 /* 2 * Copyright (C) 2007 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.annotation.SystemApi.Client.MODULE_LIBRARIES; 20 21 import android.annotation.NonNull; 22 import android.annotation.SuppressLint; 23 import android.annotation.SystemApi; 24 import android.compat.annotation.UnsupportedAppUsage; 25 import android.system.ErrnoException; 26 import android.system.Os; 27 28 import java.io.Closeable; 29 import java.io.FileDescriptor; 30 import java.io.IOException; 31 import java.io.InputStream; 32 import java.io.OutputStream; 33 import java.net.SocketOptions; 34 35 /** 36 * Creates a (non-server) socket in the UNIX-domain namespace. The interface 37 * here is not entirely unlike that of java.net.Socket. This class and the streams 38 * returned from it may be used from multiple threads. 39 */ 40 public class LocalSocket implements Closeable { 41 42 @UnsupportedAppUsage 43 private final LocalSocketImpl impl; 44 /** false if impl.create() needs to be called */ 45 private volatile boolean implCreated; 46 private LocalSocketAddress localAddress; 47 private boolean isBound; 48 private boolean isConnected; 49 private final int sockType; 50 51 /** unknown socket type (used for constructor with existing file descriptor) */ 52 /* package */ static final int SOCKET_UNKNOWN = 0; 53 /** Datagram socket type */ 54 public static final int SOCKET_DGRAM = 1; 55 /** Stream socket type */ 56 public static final int SOCKET_STREAM = 2; 57 /** Sequential packet socket type */ 58 public static final int SOCKET_SEQPACKET = 3; 59 60 /** 61 * Creates a AF_LOCAL/UNIX domain stream socket. 62 */ LocalSocket()63 public LocalSocket() { 64 this(SOCKET_STREAM); 65 } 66 67 /** 68 * Creates a AF_LOCAL/UNIX domain stream socket with given socket type 69 * 70 * @param sockType either {@link #SOCKET_DGRAM}, {@link #SOCKET_STREAM} 71 * or {@link #SOCKET_SEQPACKET} 72 */ LocalSocket(int sockType)73 public LocalSocket(int sockType) { 74 this(new LocalSocketImpl(), sockType); 75 } 76 LocalSocket(LocalSocketImpl impl, int sockType)77 private LocalSocket(LocalSocketImpl impl, int sockType) { 78 this.impl = impl; 79 this.sockType = sockType; 80 this.isConnected = false; 81 this.isBound = false; 82 } 83 checkConnected()84 private void checkConnected() { 85 try { 86 Os.getpeername(impl.getFileDescriptor()); 87 } catch (ErrnoException e) { 88 throw new IllegalArgumentException("Not a connected socket", e); 89 } 90 isConnected = true; 91 isBound = true; 92 implCreated = true; 93 } 94 95 /** 96 * Creates a LocalSocket instance using the {@link FileDescriptor} for an already-connected 97 * AF_LOCAL/UNIX domain stream socket. The passed-in FileDescriptor is not managed by this class 98 * and must be closed by the caller. Calling {@link #close()} on a socket created by this 99 * method has no effect. 100 * 101 * @param fd the filedescriptor to adopt 102 * 103 * @hide 104 */ 105 @SystemApi(client = MODULE_LIBRARIES) LocalSocket(@onNull @uppressLintR) FileDescriptor fd)106 public LocalSocket(@NonNull @SuppressLint("UseParcelFileDescriptor") FileDescriptor fd) { 107 this(new LocalSocketImpl(fd), SOCKET_UNKNOWN); 108 checkConnected(); 109 } 110 111 /** 112 * for use with LocalServerSocket.accept() 113 */ createLocalSocketForAccept(LocalSocketImpl impl)114 static LocalSocket createLocalSocketForAccept(LocalSocketImpl impl) { 115 LocalSocket socket = new LocalSocket(impl, SOCKET_UNKNOWN); 116 socket.checkConnected(); 117 return socket; 118 } 119 120 /** {@inheritDoc} */ 121 @Override toString()122 public String toString() { 123 return super.toString() + " impl:" + impl; 124 } 125 126 /** 127 * It's difficult to discern from the spec when impl.create() should be 128 * called, but it seems like a reasonable rule is "as soon as possible, 129 * but not in a context where IOException cannot be thrown" 130 * 131 * @throws IOException from SocketImpl.create() 132 */ implCreateIfNeeded()133 private void implCreateIfNeeded() throws IOException { 134 if (!implCreated) { 135 synchronized (this) { 136 if (!implCreated) { 137 try { 138 impl.create(sockType); 139 } finally { 140 implCreated = true; 141 } 142 } 143 } 144 } 145 } 146 147 /** 148 * Connects this socket to an endpoint. May only be called on an instance 149 * that has not yet been connected. 150 * 151 * @param endpoint endpoint address 152 * @throws IOException if socket is in invalid state or the address does 153 * not exist. 154 */ connect(LocalSocketAddress endpoint)155 public void connect(LocalSocketAddress endpoint) throws IOException { 156 synchronized (this) { 157 if (isConnected) { 158 throw new IOException("already connected"); 159 } 160 161 implCreateIfNeeded(); 162 impl.connect(endpoint, 0); 163 isConnected = true; 164 isBound = true; 165 } 166 } 167 168 /** 169 * Binds this socket to an endpoint name. May only be called on an instance 170 * that has not yet been bound. 171 * 172 * @param bindpoint endpoint address 173 * @throws IOException 174 */ bind(LocalSocketAddress bindpoint)175 public void bind(LocalSocketAddress bindpoint) throws IOException { 176 implCreateIfNeeded(); 177 178 synchronized (this) { 179 if (isBound) { 180 throw new IOException("already bound"); 181 } 182 183 localAddress = bindpoint; 184 impl.bind(localAddress); 185 isBound = true; 186 } 187 } 188 189 /** 190 * Retrieves the name that this socket is bound to, if any. 191 * 192 * @return Local address or null if anonymous 193 */ getLocalSocketAddress()194 public LocalSocketAddress getLocalSocketAddress() { 195 return localAddress; 196 } 197 198 /** 199 * Retrieves the input stream for this instance. 200 * 201 * @return input stream 202 * @throws IOException if socket has been closed or cannot be created. 203 */ getInputStream()204 public InputStream getInputStream() throws IOException { 205 implCreateIfNeeded(); 206 return impl.getInputStream(); 207 } 208 209 /** 210 * Retrieves the output stream for this instance. 211 * 212 * @return output stream 213 * @throws IOException if socket has been closed or cannot be created. 214 */ getOutputStream()215 public OutputStream getOutputStream() throws IOException { 216 implCreateIfNeeded(); 217 return impl.getOutputStream(); 218 } 219 220 /** 221 * Closes the socket. 222 * 223 * @throws IOException 224 */ 225 @Override close()226 public void close() throws IOException { 227 implCreateIfNeeded(); 228 impl.close(); 229 } 230 231 /** 232 * Shuts down the input side of the socket. 233 * 234 * @throws IOException 235 */ shutdownInput()236 public void shutdownInput() throws IOException { 237 implCreateIfNeeded(); 238 impl.shutdownInput(); 239 } 240 241 /** 242 * Shuts down the output side of the socket. 243 * 244 * @throws IOException 245 */ shutdownOutput()246 public void shutdownOutput() throws IOException { 247 implCreateIfNeeded(); 248 impl.shutdownOutput(); 249 } 250 setReceiveBufferSize(int size)251 public void setReceiveBufferSize(int size) throws IOException { 252 impl.setOption(SocketOptions.SO_RCVBUF, Integer.valueOf(size)); 253 } 254 getReceiveBufferSize()255 public int getReceiveBufferSize() throws IOException { 256 return ((Integer) impl.getOption(SocketOptions.SO_RCVBUF)).intValue(); 257 } 258 setSoTimeout(int n)259 public void setSoTimeout(int n) throws IOException { 260 impl.setOption(SocketOptions.SO_TIMEOUT, Integer.valueOf(n)); 261 } 262 getSoTimeout()263 public int getSoTimeout() throws IOException { 264 return ((Integer) impl.getOption(SocketOptions.SO_TIMEOUT)).intValue(); 265 } 266 setSendBufferSize(int n)267 public void setSendBufferSize(int n) throws IOException { 268 impl.setOption(SocketOptions.SO_SNDBUF, Integer.valueOf(n)); 269 } 270 getSendBufferSize()271 public int getSendBufferSize() throws IOException { 272 return ((Integer) impl.getOption(SocketOptions.SO_SNDBUF)).intValue(); 273 } 274 275 //???SEC getRemoteSocketAddress()276 public LocalSocketAddress getRemoteSocketAddress() { 277 throw new UnsupportedOperationException(); 278 } 279 280 //???SEC isConnected()281 public synchronized boolean isConnected() { 282 return isConnected; 283 } 284 285 //???SEC isClosed()286 public boolean isClosed() { 287 throw new UnsupportedOperationException(); 288 } 289 290 //???SEC isBound()291 public synchronized boolean isBound() { 292 return isBound; 293 } 294 295 //???SEC isOutputShutdown()296 public boolean isOutputShutdown() { 297 throw new UnsupportedOperationException(); 298 } 299 300 //???SEC isInputShutdown()301 public boolean isInputShutdown() { 302 throw new UnsupportedOperationException(); 303 } 304 305 //???SEC connect(LocalSocketAddress endpoint, int timeout)306 public void connect(LocalSocketAddress endpoint, int timeout) 307 throws IOException { 308 throw new UnsupportedOperationException(); 309 } 310 311 /** 312 * Enqueues a set of file descriptors to send to the peer. The queue 313 * is one deep. The file descriptors will be sent with the next write 314 * of normal data, and will be delivered in a single ancillary message. 315 * See "man 7 unix" SCM_RIGHTS on a desktop Linux machine. 316 * 317 * @param fds non-null; file descriptors to send. 318 */ setFileDescriptorsForSend(FileDescriptor[] fds)319 public void setFileDescriptorsForSend(FileDescriptor[] fds) { 320 impl.setFileDescriptorsForSend(fds); 321 } 322 323 /** 324 * Retrieves a set of file descriptors that a peer has sent through 325 * an ancillary message. This method retrieves the most recent set sent, 326 * and then returns null until a new set arrives. 327 * File descriptors may only be passed along with regular data, so this 328 * method can only return a non-null after a read operation. 329 * 330 * @return null or file descriptor array 331 * @throws IOException 332 */ getAncillaryFileDescriptors()333 public FileDescriptor[] getAncillaryFileDescriptors() throws IOException { 334 return impl.getAncillaryFileDescriptors(); 335 } 336 337 /** 338 * Retrieves the credentials of this socket's peer. Only valid on 339 * connected sockets. 340 * 341 * @return non-null; peer credentials 342 * @throws IOException 343 */ getPeerCredentials()344 public Credentials getPeerCredentials() throws IOException { 345 return impl.getPeerCredentials(); 346 } 347 348 /** 349 * Returns file descriptor or null if not yet open/already closed 350 * 351 * @return fd or null 352 */ getFileDescriptor()353 public FileDescriptor getFileDescriptor() { 354 return impl.getFileDescriptor(); 355 } 356 } 357