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