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