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