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.IOException; 20import java.io.OutputStream; 21import java.io.InputStream; 22import java.io.FileDescriptor; 23import java.net.SocketOptions; 24 25/** 26 * Socket implementation used for android.net.LocalSocket and 27 * android.net.LocalServerSocket. Supports only AF_LOCAL sockets. 28 */ 29class LocalSocketImpl 30{ 31 private SocketInputStream fis; 32 private SocketOutputStream fos; 33 private Object readMonitor = new Object(); 34 private Object writeMonitor = new Object(); 35 36 /** null if closed or not yet created */ 37 private FileDescriptor fd; 38 39 // These fields are accessed by native code; 40 /** file descriptor array received during a previous read */ 41 FileDescriptor[] inboundFileDescriptors; 42 /** file descriptor array that should be written during next write */ 43 FileDescriptor[] outboundFileDescriptors; 44 45 /** 46 * An input stream for local sockets. Needed because we may 47 * need to read ancillary data. 48 */ 49 class SocketInputStream extends InputStream { 50 /** {@inheritDoc} */ 51 @Override 52 public int available() throws IOException { 53 return available_native(fd); 54 } 55 56 /** {@inheritDoc} */ 57 @Override 58 public void close() throws IOException { 59 LocalSocketImpl.this.close(); 60 } 61 62 /** {@inheritDoc} */ 63 @Override 64 public int read() throws IOException { 65 int ret; 66 synchronized (readMonitor) { 67 FileDescriptor myFd = fd; 68 if (myFd == null) throw new IOException("socket closed"); 69 70 ret = read_native(myFd); 71 return ret; 72 } 73 } 74 75 /** {@inheritDoc} */ 76 @Override 77 public int read(byte[] b) throws IOException { 78 return read(b, 0, b.length); 79 } 80 81 /** {@inheritDoc} */ 82 @Override 83 public int read(byte[] b, int off, int len) throws IOException { 84 synchronized (readMonitor) { 85 FileDescriptor myFd = fd; 86 if (myFd == null) throw new IOException("socket closed"); 87 88 if (off < 0 || len < 0 || (off + len) > b.length ) { 89 throw new ArrayIndexOutOfBoundsException(); 90 } 91 92 int ret = readba_native(b, off, len, myFd); 93 94 return ret; 95 } 96 } 97 } 98 99 /** 100 * An output stream for local sockets. Needed because we may 101 * need to read ancillary data. 102 */ 103 class SocketOutputStream extends OutputStream { 104 /** {@inheritDoc} */ 105 @Override 106 public void close() throws IOException { 107 LocalSocketImpl.this.close(); 108 } 109 110 /** {@inheritDoc} */ 111 @Override 112 public void write (byte[] b) throws IOException { 113 write(b, 0, b.length); 114 } 115 116 /** {@inheritDoc} */ 117 @Override 118 public void write (byte[] b, int off, int len) throws IOException { 119 synchronized (writeMonitor) { 120 FileDescriptor myFd = fd; 121 if (myFd == null) throw new IOException("socket closed"); 122 123 if (off < 0 || len < 0 || (off + len) > b.length ) { 124 throw new ArrayIndexOutOfBoundsException(); 125 } 126 writeba_native(b, off, len, myFd); 127 } 128 } 129 130 /** {@inheritDoc} */ 131 @Override 132 public void write (int b) throws IOException { 133 synchronized (writeMonitor) { 134 FileDescriptor myFd = fd; 135 if (myFd == null) throw new IOException("socket closed"); 136 write_native(b, myFd); 137 } 138 } 139 } 140 141 private native int available_native(FileDescriptor fd) throws IOException; 142 private native void close_native(FileDescriptor fd) throws IOException; 143 private native int read_native(FileDescriptor fd) throws IOException; 144 private native int readba_native(byte[] b, int off, int len, 145 FileDescriptor fd) throws IOException; 146 private native void writeba_native(byte[] b, int off, int len, 147 FileDescriptor fd) throws IOException; 148 private native void write_native(int b, FileDescriptor fd) 149 throws IOException; 150 private native void connectLocal(FileDescriptor fd, String name, 151 int namespace) throws IOException; 152 private native void bindLocal(FileDescriptor fd, String name, int namespace) 153 throws IOException; 154 private native FileDescriptor create_native(boolean stream) 155 throws IOException; 156 private native void listen_native(FileDescriptor fd, int backlog) 157 throws IOException; 158 private native void shutdown(FileDescriptor fd, boolean shutdownInput); 159 private native Credentials getPeerCredentials_native( 160 FileDescriptor fd) throws IOException; 161 private native int getOption_native(FileDescriptor fd, int optID) 162 throws IOException; 163 private native void setOption_native(FileDescriptor fd, int optID, 164 int b, int value) throws IOException; 165 166// private native LocalSocketAddress getSockName_native 167// (FileDescriptor fd) throws IOException; 168 169 /** 170 * Accepts a connection on a server socket. 171 * 172 * @param fd file descriptor of server socket 173 * @param s socket implementation that will become the new socket 174 * @return file descriptor of new socket 175 */ 176 private native FileDescriptor accept 177 (FileDescriptor fd, LocalSocketImpl s) throws IOException; 178 179 /** 180 * Create a new instance. 181 */ 182 /*package*/ LocalSocketImpl() 183 { 184 } 185 186 /** 187 * Create a new instance from a file descriptor representing 188 * a bound socket. The state of the file descriptor is not checked here 189 * but the caller can verify socket state by calling listen(). 190 * 191 * @param fd non-null; bound file descriptor 192 */ 193 /*package*/ LocalSocketImpl(FileDescriptor fd) throws IOException 194 { 195 this.fd = fd; 196 } 197 198 public String toString() { 199 return super.toString() + " fd:" + fd; 200 } 201 202 /** 203 * Creates a socket in the underlying OS. 204 * 205 * @param stream true if this should be a stream socket, false for 206 * datagram. 207 * @throws IOException 208 */ 209 public void create (boolean stream) throws IOException { 210 // no error if socket already created 211 // need this for LocalServerSocket.accept() 212 if (fd == null) { 213 fd = create_native(stream); 214 } 215 } 216 217 /** 218 * Closes the socket. 219 * 220 * @throws IOException 221 */ 222 public void close() throws IOException { 223 synchronized (LocalSocketImpl.this) { 224 if (fd == null) return; 225 close_native(fd); 226 fd = null; 227 } 228 } 229 230 /** note timeout presently ignored */ 231 protected void connect(LocalSocketAddress address, int timeout) 232 throws IOException 233 { 234 if (fd == null) { 235 throw new IOException("socket not created"); 236 } 237 238 connectLocal(fd, address.getName(), address.getNamespace().getId()); 239 } 240 241 /** 242 * Binds this socket to an endpoint name. May only be called on an instance 243 * that has not yet been bound. 244 * 245 * @param endpoint endpoint address 246 * @throws IOException 247 */ 248 public void bind(LocalSocketAddress endpoint) throws IOException 249 { 250 if (fd == null) { 251 throw new IOException("socket not created"); 252 } 253 254 bindLocal(fd, endpoint.getName(), endpoint.getNamespace().getId()); 255 } 256 257 protected void listen(int backlog) throws IOException 258 { 259 if (fd == null) { 260 throw new IOException("socket not created"); 261 } 262 263 listen_native(fd, backlog); 264 } 265 266 /** 267 * Accepts a new connection to the socket. Blocks until a new 268 * connection arrives. 269 * 270 * @param s a socket that will be used to represent the new connection. 271 * @throws IOException 272 */ 273 protected void accept(LocalSocketImpl s) throws IOException 274 { 275 if (fd == null) { 276 throw new IOException("socket not created"); 277 } 278 279 s.fd = accept(fd, s); 280 } 281 282 /** 283 * Retrieves the input stream for this instance. 284 * 285 * @return input stream 286 * @throws IOException if socket has been closed or cannot be created. 287 */ 288 protected InputStream getInputStream() throws IOException 289 { 290 if (fd == null) { 291 throw new IOException("socket not created"); 292 } 293 294 synchronized (this) { 295 if (fis == null) { 296 fis = new SocketInputStream(); 297 } 298 299 return fis; 300 } 301 } 302 303 /** 304 * Retrieves the output stream for this instance. 305 * 306 * @return output stream 307 * @throws IOException if socket has been closed or cannot be created. 308 */ 309 protected OutputStream getOutputStream() throws IOException 310 { 311 if (fd == null) { 312 throw new IOException("socket not created"); 313 } 314 315 synchronized (this) { 316 if (fos == null) { 317 fos = new SocketOutputStream(); 318 } 319 320 return fos; 321 } 322 } 323 324 /** 325 * Returns the number of bytes available for reading without blocking. 326 * 327 * @return >= 0 count bytes available 328 * @throws IOException 329 */ 330 protected int available() throws IOException 331 { 332 return getInputStream().available(); 333 } 334 335 /** 336 * Shuts down the input side of the socket. 337 * 338 * @throws IOException 339 */ 340 protected void shutdownInput() throws IOException 341 { 342 if (fd == null) { 343 throw new IOException("socket not created"); 344 } 345 346 shutdown(fd, true); 347 } 348 349 /** 350 * Shuts down the output side of the socket. 351 * 352 * @throws IOException 353 */ 354 protected void shutdownOutput() throws IOException 355 { 356 if (fd == null) { 357 throw new IOException("socket not created"); 358 } 359 360 shutdown(fd, false); 361 } 362 363 protected FileDescriptor getFileDescriptor() 364 { 365 return fd; 366 } 367 368 protected boolean supportsUrgentData() 369 { 370 return false; 371 } 372 373 protected void sendUrgentData(int data) throws IOException 374 { 375 throw new RuntimeException ("not impled"); 376 } 377 378 public Object getOption(int optID) throws IOException 379 { 380 if (fd == null) { 381 throw new IOException("socket not created"); 382 } 383 384 if (optID == SocketOptions.SO_TIMEOUT) { 385 return 0; 386 } 387 388 int value = getOption_native(fd, optID); 389 switch (optID) 390 { 391 case SocketOptions.SO_RCVBUF: 392 case SocketOptions.SO_SNDBUF: 393 return value; 394 case SocketOptions.SO_REUSEADDR: 395 default: 396 return value; 397 } 398 } 399 400 public void setOption(int optID, Object value) 401 throws IOException { 402 /* 403 * Boolean.FALSE is used to disable some options, so it 404 * is important to distinguish between FALSE and unset. 405 * We define it here that -1 is unset, 0 is FALSE, and 1 406 * is TRUE. 407 */ 408 int boolValue = -1; 409 int intValue = 0; 410 411 if (fd == null) { 412 throw new IOException("socket not created"); 413 } 414 415 if (value instanceof Integer) { 416 intValue = (Integer)value; 417 } else if (value instanceof Boolean) { 418 boolValue = ((Boolean) value)? 1 : 0; 419 } else { 420 throw new IOException("bad value: " + value); 421 } 422 423 setOption_native(fd, optID, boolValue, intValue); 424 } 425 426 /** 427 * Enqueues a set of file descriptors to send to the peer. The queue 428 * is one deep. The file descriptors will be sent with the next write 429 * of normal data, and will be delivered in a single ancillary message. 430 * See "man 7 unix" SCM_RIGHTS on a desktop Linux machine. 431 * 432 * @param fds non-null; file descriptors to send. 433 * @throws IOException 434 */ 435 public void setFileDescriptorsForSend(FileDescriptor[] fds) { 436 synchronized(writeMonitor) { 437 outboundFileDescriptors = fds; 438 } 439 } 440 441 /** 442 * Retrieves a set of file descriptors that a peer has sent through 443 * an ancillary message. This method retrieves the most recent set sent, 444 * and then returns null until a new set arrives. 445 * File descriptors may only be passed along with regular data, so this 446 * method can only return a non-null after a read operation. 447 * 448 * @return null or file descriptor array 449 * @throws IOException 450 */ 451 public FileDescriptor[] getAncillaryFileDescriptors() throws IOException { 452 synchronized(readMonitor) { 453 FileDescriptor[] result = inboundFileDescriptors; 454 455 inboundFileDescriptors = null; 456 return result; 457 } 458 } 459 460 /** 461 * Retrieves the credentials of this socket's peer. Only valid on 462 * connected sockets. 463 * 464 * @return non-null; peer credentials 465 * @throws IOException 466 */ 467 public Credentials getPeerCredentials() throws IOException 468 { 469 return getPeerCredentials_native(fd); 470 } 471 472 /** 473 * Retrieves the socket name from the OS. 474 * 475 * @return non-null; socket name 476 * @throws IOException on failure 477 */ 478 public LocalSocketAddress getSockAddress() throws IOException 479 { 480 return null; 481 //TODO implement this 482 //return getSockName_native(fd); 483 } 484 485 @Override 486 protected void finalize() throws IOException { 487 close(); 488 } 489} 490 491