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