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