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 @uppressLint"UseParcelFileDescriptor") 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. Closing this stream is equivalent to closing 200 * the entire socket and its associated streams using {@link #close()}. 201 * 202 * @return input stream 203 * @throws IOException if socket has been closed or cannot be created. 204 */ getInputStream()205 public InputStream getInputStream() throws IOException { 206 implCreateIfNeeded(); 207 return impl.getInputStream(); 208 } 209 210 /** 211 * Retrieves the output stream for this instance. Closing this stream is equivalent to closing 212 * the entire socket and its associated streams using {@link #close()}. 213 * 214 * @return output stream 215 * @throws IOException if socket has been closed or cannot be created. 216 */ getOutputStream()217 public OutputStream getOutputStream() throws IOException { 218 implCreateIfNeeded(); 219 return impl.getOutputStream(); 220 } 221 222 /** 223 * Closes the socket. 224 * 225 * @throws IOException 226 */ 227 @Override close()228 public void close() throws IOException { 229 implCreateIfNeeded(); 230 impl.close(); 231 } 232 233 /** 234 * Shuts down the input side of the socket. 235 * 236 * @throws IOException 237 */ shutdownInput()238 public void shutdownInput() throws IOException { 239 implCreateIfNeeded(); 240 impl.shutdownInput(); 241 } 242 243 /** 244 * Shuts down the output side of the socket. 245 * 246 * @throws IOException 247 */ shutdownOutput()248 public void shutdownOutput() throws IOException { 249 implCreateIfNeeded(); 250 impl.shutdownOutput(); 251 } 252 setReceiveBufferSize(int size)253 public void setReceiveBufferSize(int size) throws IOException { 254 impl.setOption(SocketOptions.SO_RCVBUF, Integer.valueOf(size)); 255 } 256 getReceiveBufferSize()257 public int getReceiveBufferSize() throws IOException { 258 return ((Integer) impl.getOption(SocketOptions.SO_RCVBUF)).intValue(); 259 } 260 setSoTimeout(int n)261 public void setSoTimeout(int n) throws IOException { 262 impl.setOption(SocketOptions.SO_TIMEOUT, Integer.valueOf(n)); 263 } 264 getSoTimeout()265 public int getSoTimeout() throws IOException { 266 return ((Integer) impl.getOption(SocketOptions.SO_TIMEOUT)).intValue(); 267 } 268 setSendBufferSize(int n)269 public void setSendBufferSize(int n) throws IOException { 270 impl.setOption(SocketOptions.SO_SNDBUF, Integer.valueOf(n)); 271 } 272 getSendBufferSize()273 public int getSendBufferSize() throws IOException { 274 return ((Integer) impl.getOption(SocketOptions.SO_SNDBUF)).intValue(); 275 } 276 277 //???SEC getRemoteSocketAddress()278 public LocalSocketAddress getRemoteSocketAddress() { 279 throw new UnsupportedOperationException(); 280 } 281 282 //???SEC isConnected()283 public synchronized boolean isConnected() { 284 return isConnected; 285 } 286 287 //???SEC isClosed()288 public boolean isClosed() { 289 throw new UnsupportedOperationException(); 290 } 291 292 //???SEC isBound()293 public synchronized boolean isBound() { 294 return isBound; 295 } 296 297 //???SEC isOutputShutdown()298 public boolean isOutputShutdown() { 299 throw new UnsupportedOperationException(); 300 } 301 302 //???SEC isInputShutdown()303 public boolean isInputShutdown() { 304 throw new UnsupportedOperationException(); 305 } 306 307 //???SEC connect(LocalSocketAddress endpoint, int timeout)308 public void connect(LocalSocketAddress endpoint, int timeout) 309 throws IOException { 310 throw new UnsupportedOperationException(); 311 } 312 313 /** 314 * Enqueues a set of file descriptors to send to the peer. The queue 315 * is one deep. The file descriptors will be sent with the next write 316 * of normal data, and will be delivered in a single ancillary message. 317 * See "man 7 unix" SCM_RIGHTS on a desktop Linux machine. 318 * 319 * @param fds non-null; file descriptors to send. 320 */ setFileDescriptorsForSend(FileDescriptor[] fds)321 public void setFileDescriptorsForSend(FileDescriptor[] fds) { 322 impl.setFileDescriptorsForSend(fds); 323 } 324 325 /** 326 * Retrieves a set of file descriptors that a peer has sent through 327 * an ancillary message. This method retrieves the most recent set sent, 328 * and then returns null until a new set arrives. 329 * File descriptors may only be passed along with regular data, so this 330 * method can only return a non-null after a read operation. 331 * 332 * @return null or file descriptor array 333 * @throws IOException 334 */ getAncillaryFileDescriptors()335 public FileDescriptor[] getAncillaryFileDescriptors() throws IOException { 336 return impl.getAncillaryFileDescriptors(); 337 } 338 339 /** 340 * Retrieves the credentials of this socket's peer. Only valid on 341 * connected sockets. 342 * 343 * @return non-null; peer credentials 344 * @throws IOException 345 */ getPeerCredentials()346 public Credentials getPeerCredentials() throws IOException { 347 return impl.getPeerCredentials(); 348 } 349 350 /** 351 * Returns file descriptor or null if not yet open/already closed 352 * 353 * @return fd or null 354 */ getFileDescriptor()355 public FileDescriptor getFileDescriptor() { 356 return impl.getFileDescriptor(); 357 } 358 } 359