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