LocalSocketImpl.java revision c80af6d84d8fb729f17028ac533fac07bb7c4c5d
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 25import android.system.ErrnoException; 26import android.system.Os; 27import android.system.OsConstants; 28import android.system.StructLinger; 29import android.system.StructTimeval; 30 31/** 32 * Socket implementation used for android.net.LocalSocket and 33 * android.net.LocalServerSocket. Supports only AF_LOCAL sockets. 34 */ 35class LocalSocketImpl 36{ 37 private SocketInputStream fis; 38 private SocketOutputStream fos; 39 private Object readMonitor = new Object(); 40 private Object writeMonitor = new Object(); 41 42 /** null if closed or not yet created */ 43 private FileDescriptor fd; 44 /** whether fd is created internally */ 45 private boolean mFdCreatedInternally; 46 47 // These fields are accessed by native code; 48 /** file descriptor array received during a previous read */ 49 FileDescriptor[] inboundFileDescriptors; 50 /** file descriptor array that should be written during next write */ 51 FileDescriptor[] outboundFileDescriptors; 52 53 /** 54 * An input stream for local sockets. Needed because we may 55 * need to read ancillary data. 56 */ 57 class SocketInputStream extends InputStream { 58 /** {@inheritDoc} */ 59 @Override 60 public int available() throws IOException { 61 FileDescriptor myFd = fd; 62 if (myFd == null) throw new IOException("socket closed"); 63 64 return available_native(myFd); 65 } 66 67 /** {@inheritDoc} */ 68 @Override 69 public void close() throws IOException { 70 LocalSocketImpl.this.close(); 71 } 72 73 /** {@inheritDoc} */ 74 @Override 75 public int read() throws IOException { 76 int ret; 77 synchronized (readMonitor) { 78 FileDescriptor myFd = fd; 79 if (myFd == null) throw new IOException("socket closed"); 80 81 ret = read_native(myFd); 82 return ret; 83 } 84 } 85 86 /** {@inheritDoc} */ 87 @Override 88 public int read(byte[] b) throws IOException { 89 return read(b, 0, b.length); 90 } 91 92 /** {@inheritDoc} */ 93 @Override 94 public int read(byte[] b, int off, int len) throws IOException { 95 synchronized (readMonitor) { 96 FileDescriptor myFd = fd; 97 if (myFd == null) throw new IOException("socket closed"); 98 99 if (off < 0 || len < 0 || (off + len) > b.length ) { 100 throw new ArrayIndexOutOfBoundsException(); 101 } 102 103 int ret = readba_native(b, off, len, myFd); 104 105 return ret; 106 } 107 } 108 } 109 110 /** 111 * An output stream for local sockets. Needed because we may 112 * need to read ancillary data. 113 */ 114 class SocketOutputStream extends OutputStream { 115 /** {@inheritDoc} */ 116 @Override 117 public void close() throws IOException { 118 LocalSocketImpl.this.close(); 119 } 120 121 /** {@inheritDoc} */ 122 @Override 123 public void write (byte[] b) throws IOException { 124 write(b, 0, b.length); 125 } 126 127 /** {@inheritDoc} */ 128 @Override 129 public void write (byte[] b, int off, int len) throws IOException { 130 synchronized (writeMonitor) { 131 FileDescriptor myFd = fd; 132 if (myFd == null) throw new IOException("socket closed"); 133 134 if (off < 0 || len < 0 || (off + len) > b.length ) { 135 throw new ArrayIndexOutOfBoundsException(); 136 } 137 writeba_native(b, off, len, myFd); 138 } 139 } 140 141 /** {@inheritDoc} */ 142 @Override 143 public void write (int b) throws IOException { 144 synchronized (writeMonitor) { 145 FileDescriptor myFd = fd; 146 if (myFd == null) throw new IOException("socket closed"); 147 write_native(b, myFd); 148 } 149 } 150 151 /** 152 * Wait until the data in sending queue is emptied. A polling version 153 * for flush implementation. 154 * @throws IOException 155 * if an i/o error occurs. 156 */ 157 @Override 158 public void flush() throws IOException { 159 FileDescriptor myFd = fd; 160 if (myFd == null) throw new IOException("socket closed"); 161 while(pending_native(myFd) > 0) { 162 try { 163 Thread.sleep(10); 164 } catch (InterruptedException ie) { 165 return; 166 } 167 } 168 } 169 } 170 171 private native int pending_native(FileDescriptor fd) throws IOException; 172 private native int available_native(FileDescriptor fd) throws IOException; 173 private native int read_native(FileDescriptor fd) throws IOException; 174 private native int readba_native(byte[] b, int off, int len, 175 FileDescriptor fd) throws IOException; 176 private native void writeba_native(byte[] b, int off, int len, 177 FileDescriptor fd) throws IOException; 178 private native void write_native(int b, FileDescriptor fd) 179 throws IOException; 180 private native void connectLocal(FileDescriptor fd, String name, 181 int namespace) throws IOException; 182 private native void bindLocal(FileDescriptor fd, String name, int namespace) 183 throws IOException; 184 private native void listen_native(FileDescriptor fd, int backlog) 185 throws IOException; 186 private native void shutdown(FileDescriptor fd, boolean shutdownInput); 187 private native Credentials getPeerCredentials_native( 188 FileDescriptor fd) throws IOException; 189 190 /** 191 * Accepts a connection on a server socket. 192 * 193 * @param fd file descriptor of server socket 194 * @param s socket implementation that will become the new socket 195 * @return file descriptor of new socket 196 */ 197 private native FileDescriptor accept 198 (FileDescriptor fd, LocalSocketImpl s) throws IOException; 199 200 /** 201 * Create a new instance. 202 */ 203 /*package*/ LocalSocketImpl() 204 { 205 } 206 207 /** 208 * Create a new instance from a file descriptor representing 209 * a bound socket. The state of the file descriptor is not checked here 210 * but the caller can verify socket state by calling listen(). 211 * 212 * @param fd non-null; bound file descriptor 213 */ 214 /*package*/ LocalSocketImpl(FileDescriptor fd) throws IOException 215 { 216 this.fd = fd; 217 } 218 219 public String toString() { 220 return super.toString() + " fd:" + fd; 221 } 222 223 /** 224 * Creates a socket in the underlying OS. 225 * 226 * @param sockType either {@link LocalSocket#SOCKET_DGRAM}, {@link LocalSocket#SOCKET_STREAM} 227 * or {@link LocalSocket#SOCKET_SEQPACKET} 228 * @throws IOException 229 */ 230 public void create(int sockType) throws IOException { 231 // no error if socket already created 232 // need this for LocalServerSocket.accept() 233 if (fd == null) { 234 int osType; 235 switch (sockType) { 236 case LocalSocket.SOCKET_DGRAM: 237 osType = OsConstants.SOCK_DGRAM; 238 break; 239 case LocalSocket.SOCKET_STREAM: 240 osType = OsConstants.SOCK_STREAM; 241 break; 242 case LocalSocket.SOCKET_SEQPACKET: 243 osType = OsConstants.SOCK_SEQPACKET; 244 break; 245 default: 246 throw new IllegalStateException("unknown sockType"); 247 } 248 try { 249 fd = Os.socket(OsConstants.AF_UNIX, osType, 0); 250 mFdCreatedInternally = true; 251 } catch (ErrnoException e) { 252 e.rethrowAsIOException(); 253 } 254 } 255 } 256 257 /** 258 * Closes the socket. 259 * 260 * @throws IOException 261 */ 262 public void close() throws IOException { 263 synchronized (LocalSocketImpl.this) { 264 if ((fd == null) || (mFdCreatedInternally == false)) { 265 fd = null; 266 return; 267 } 268 try { 269 Os.close(fd); 270 } catch (ErrnoException e) { 271 e.rethrowAsIOException(); 272 } 273 fd = null; 274 } 275 } 276 277 /** note timeout presently ignored */ 278 protected void connect(LocalSocketAddress address, int timeout) 279 throws IOException 280 { 281 if (fd == null) { 282 throw new IOException("socket not created"); 283 } 284 285 connectLocal(fd, address.getName(), address.getNamespace().getId()); 286 } 287 288 /** 289 * Binds this socket to an endpoint name. May only be called on an instance 290 * that has not yet been bound. 291 * 292 * @param endpoint endpoint address 293 * @throws IOException 294 */ 295 public void bind(LocalSocketAddress endpoint) throws IOException 296 { 297 if (fd == null) { 298 throw new IOException("socket not created"); 299 } 300 301 bindLocal(fd, endpoint.getName(), endpoint.getNamespace().getId()); 302 } 303 304 protected void listen(int backlog) throws IOException 305 { 306 if (fd == null) { 307 throw new IOException("socket not created"); 308 } 309 310 listen_native(fd, backlog); 311 } 312 313 /** 314 * Accepts a new connection to the socket. Blocks until a new 315 * connection arrives. 316 * 317 * @param s a socket that will be used to represent the new connection. 318 * @throws IOException 319 */ 320 protected void accept(LocalSocketImpl s) throws IOException 321 { 322 if (fd == null) { 323 throw new IOException("socket not created"); 324 } 325 326 s.fd = accept(fd, s); 327 s.mFdCreatedInternally = true; 328 } 329 330 /** 331 * Retrieves the input stream for this instance. 332 * 333 * @return input stream 334 * @throws IOException if socket has been closed or cannot be created. 335 */ 336 protected InputStream getInputStream() throws IOException 337 { 338 if (fd == null) { 339 throw new IOException("socket not created"); 340 } 341 342 synchronized (this) { 343 if (fis == null) { 344 fis = new SocketInputStream(); 345 } 346 347 return fis; 348 } 349 } 350 351 /** 352 * Retrieves the output stream for this instance. 353 * 354 * @return output stream 355 * @throws IOException if socket has been closed or cannot be created. 356 */ 357 protected OutputStream getOutputStream() throws IOException 358 { 359 if (fd == null) { 360 throw new IOException("socket not created"); 361 } 362 363 synchronized (this) { 364 if (fos == null) { 365 fos = new SocketOutputStream(); 366 } 367 368 return fos; 369 } 370 } 371 372 /** 373 * Returns the number of bytes available for reading without blocking. 374 * 375 * @return >= 0 count bytes available 376 * @throws IOException 377 */ 378 protected int available() throws IOException 379 { 380 return getInputStream().available(); 381 } 382 383 /** 384 * Shuts down the input side of the socket. 385 * 386 * @throws IOException 387 */ 388 protected void shutdownInput() throws IOException 389 { 390 if (fd == null) { 391 throw new IOException("socket not created"); 392 } 393 394 shutdown(fd, true); 395 } 396 397 /** 398 * Shuts down the output side of the socket. 399 * 400 * @throws IOException 401 */ 402 protected void shutdownOutput() throws IOException 403 { 404 if (fd == null) { 405 throw new IOException("socket not created"); 406 } 407 408 shutdown(fd, false); 409 } 410 411 protected FileDescriptor getFileDescriptor() 412 { 413 return fd; 414 } 415 416 protected boolean supportsUrgentData() 417 { 418 return false; 419 } 420 421 protected void sendUrgentData(int data) throws IOException 422 { 423 throw new RuntimeException ("not impled"); 424 } 425 426 public Object getOption(int optID) throws IOException 427 { 428 if (fd == null) { 429 throw new IOException("socket not created"); 430 } 431 432 try { 433 Object toReturn; 434 switch (optID) { 435 case SocketOptions.SO_TIMEOUT: 436 StructTimeval timeval = Os.getsockoptTimeval(fd, OsConstants.SOL_SOCKET, 437 OsConstants.SO_SNDTIMEO); 438 toReturn = (int) timeval.toMillis(); 439 break; 440 case SocketOptions.SO_RCVBUF: 441 case SocketOptions.SO_SNDBUF: 442 case SocketOptions.SO_REUSEADDR: 443 int osOpt = javaSoToOsOpt(optID); 444 toReturn = Os.getsockoptInt(fd, OsConstants.SOL_SOCKET, osOpt); 445 break; 446 case SocketOptions.SO_LINGER: 447 StructLinger linger= 448 Os.getsockoptLinger(fd, OsConstants.SOL_SOCKET, OsConstants.SO_LINGER); 449 if (!linger.isOn()) { 450 toReturn = -1; 451 } else { 452 toReturn = linger.l_linger; 453 } 454 break; 455 case SocketOptions.TCP_NODELAY: 456 toReturn = Os.getsockoptInt(fd, OsConstants.IPPROTO_TCP, 457 OsConstants.TCP_NODELAY); 458 break; 459 default: 460 throw new IOException("Unknown option: " + optID); 461 } 462 return toReturn; 463 } catch (ErrnoException e) { 464 throw e.rethrowAsIOException(); 465 } 466 } 467 468 public void setOption(int optID, Object value) 469 throws IOException { 470 471 if (fd == null) { 472 throw new IOException("socket not created"); 473 } 474 475 /* 476 * Boolean.FALSE is used to disable some options, so it 477 * is important to distinguish between FALSE and unset. 478 * We define it here that -1 is unset, 0 is FALSE, and 1 479 * is TRUE. 480 */ 481 int boolValue = -1; 482 int intValue = 0; 483 if (value instanceof Integer) { 484 intValue = (Integer)value; 485 } else if (value instanceof Boolean) { 486 boolValue = ((Boolean) value)? 1 : 0; 487 } else { 488 throw new IOException("bad value: " + value); 489 } 490 491 try { 492 switch (optID) { 493 case SocketOptions.SO_LINGER: 494 StructLinger linger = new StructLinger(boolValue, intValue); 495 Os.setsockoptLinger(fd, OsConstants.SOL_SOCKET, OsConstants.SO_LINGER, linger); 496 break; 497 case SocketOptions.SO_TIMEOUT: 498 /* 499 * SO_TIMEOUT from the core library gets converted to 500 * SO_SNDTIMEO, but the option is supposed to set both 501 * send and receive timeouts. Note: The incoming timeout 502 * value is in milliseconds. 503 */ 504 StructTimeval timeval = StructTimeval.fromMillis(intValue); 505 Os.setsockoptTimeval(fd, OsConstants.SOL_SOCKET, OsConstants.SO_SNDTIMEO, 506 timeval); 507 break; 508 case SocketOptions.SO_RCVBUF: 509 case SocketOptions.SO_SNDBUF: 510 case SocketOptions.SO_REUSEADDR: 511 int osOpt = javaSoToOsOpt(optID); 512 Os.setsockoptInt(fd, OsConstants.SOL_SOCKET, osOpt, intValue); 513 break; 514 case SocketOptions.TCP_NODELAY: 515 Os.setsockoptInt(fd, OsConstants.IPPROTO_TCP, OsConstants.TCP_NODELAY, 516 intValue); 517 break; 518 default: 519 throw new IOException("Unknown option: " + optID); 520 } 521 } catch (ErrnoException e) { 522 throw e.rethrowAsIOException(); 523 } 524 } 525 526 /** 527 * Enqueues a set of file descriptors to send to the peer. The queue 528 * is one deep. The file descriptors will be sent with the next write 529 * of normal data, and will be delivered in a single ancillary message. 530 * See "man 7 unix" SCM_RIGHTS on a desktop Linux machine. 531 * 532 * @param fds non-null; file descriptors to send. 533 * @throws IOException 534 */ 535 public void setFileDescriptorsForSend(FileDescriptor[] fds) { 536 synchronized(writeMonitor) { 537 outboundFileDescriptors = fds; 538 } 539 } 540 541 /** 542 * Retrieves a set of file descriptors that a peer has sent through 543 * an ancillary message. This method retrieves the most recent set sent, 544 * and then returns null until a new set arrives. 545 * File descriptors may only be passed along with regular data, so this 546 * method can only return a non-null after a read operation. 547 * 548 * @return null or file descriptor array 549 * @throws IOException 550 */ 551 public FileDescriptor[] getAncillaryFileDescriptors() throws IOException { 552 synchronized(readMonitor) { 553 FileDescriptor[] result = inboundFileDescriptors; 554 555 inboundFileDescriptors = null; 556 return result; 557 } 558 } 559 560 /** 561 * Retrieves the credentials of this socket's peer. Only valid on 562 * connected sockets. 563 * 564 * @return non-null; peer credentials 565 * @throws IOException 566 */ 567 public Credentials getPeerCredentials() throws IOException { 568 return getPeerCredentials_native(fd); 569 } 570 571 /** 572 * Retrieves the socket name from the OS. 573 * 574 * @return non-null; socket name 575 * @throws IOException on failure 576 */ 577 public LocalSocketAddress getSockAddress() throws IOException { 578 // This method has never been implemented. 579 return null; 580 } 581 582 @Override 583 protected void finalize() throws IOException { 584 close(); 585 } 586 587 private static int javaSoToOsOpt(int optID) { 588 switch (optID) { 589 case SocketOptions.SO_SNDBUF: 590 return OsConstants.SO_SNDBUF; 591 case SocketOptions.SO_RCVBUF: 592 return OsConstants.SO_RCVBUF; 593 case SocketOptions.SO_REUSEADDR: 594 return OsConstants.SO_REUSEADDR; 595 default: 596 throw new UnsupportedOperationException("Unknown option: " + optID); 597 } 598 } 599} 600