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