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