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