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 } 330 331 /** 332 * Retrieves the input stream for this instance. 333 * 334 * @return input stream 335 * @throws IOException if socket has been closed or cannot be created. 336 */ 337 protected InputStream getInputStream() throws IOException 338 { 339 if (fd == null) { 340 throw new IOException("socket not created"); 341 } 342 343 synchronized (this) { 344 if (fis == null) { 345 fis = new SocketInputStream(); 346 } 347 348 return fis; 349 } 350 } 351 352 /** 353 * Retrieves the output stream for this instance. 354 * 355 * @return output stream 356 * @throws IOException if socket has been closed or cannot be created. 357 */ 358 protected OutputStream getOutputStream() throws IOException 359 { 360 if (fd == null) { 361 throw new IOException("socket not created"); 362 } 363 364 synchronized (this) { 365 if (fos == null) { 366 fos = new SocketOutputStream(); 367 } 368 369 return fos; 370 } 371 } 372 373 /** 374 * Returns the number of bytes available for reading without blocking. 375 * 376 * @return >= 0 count bytes available 377 * @throws IOException 378 */ 379 protected int available() throws IOException 380 { 381 return getInputStream().available(); 382 } 383 384 /** 385 * Shuts down the input side of the socket. 386 * 387 * @throws IOException 388 */ 389 protected void shutdownInput() throws IOException 390 { 391 if (fd == null) { 392 throw new IOException("socket not created"); 393 } 394 395 shutdown(fd, true); 396 } 397 398 /** 399 * Shuts down the output side of the socket. 400 * 401 * @throws IOException 402 */ 403 protected void shutdownOutput() throws IOException 404 { 405 if (fd == null) { 406 throw new IOException("socket not created"); 407 } 408 409 shutdown(fd, false); 410 } 411 412 protected FileDescriptor getFileDescriptor() 413 { 414 return fd; 415 } 416 417 protected boolean supportsUrgentData() 418 { 419 return false; 420 } 421 422 protected void sendUrgentData(int data) throws IOException 423 { 424 throw new RuntimeException ("not impled"); 425 } 426 427 public Object getOption(int optID) throws IOException 428 { 429 if (fd == null) { 430 throw new IOException("socket not created"); 431 } 432 433 if (optID == SocketOptions.SO_TIMEOUT) { 434 return 0; 435 } 436 437 int value = getOption_native(fd, optID); 438 switch (optID) 439 { 440 case SocketOptions.SO_RCVBUF: 441 case SocketOptions.SO_SNDBUF: 442 return value; 443 case SocketOptions.SO_REUSEADDR: 444 default: 445 return value; 446 } 447 } 448 449 public void setOption(int optID, Object value) 450 throws IOException { 451 /* 452 * Boolean.FALSE is used to disable some options, so it 453 * is important to distinguish between FALSE and unset. 454 * We define it here that -1 is unset, 0 is FALSE, and 1 455 * is TRUE. 456 */ 457 int boolValue = -1; 458 int intValue = 0; 459 460 if (fd == null) { 461 throw new IOException("socket not created"); 462 } 463 464 if (value instanceof Integer) { 465 intValue = (Integer)value; 466 } else if (value instanceof Boolean) { 467 boolValue = ((Boolean) value)? 1 : 0; 468 } else { 469 throw new IOException("bad value: " + value); 470 } 471 472 setOption_native(fd, optID, boolValue, intValue); 473 } 474 475 /** 476 * Enqueues a set of file descriptors to send to the peer. The queue 477 * is one deep. The file descriptors will be sent with the next write 478 * of normal data, and will be delivered in a single ancillary message. 479 * See "man 7 unix" SCM_RIGHTS on a desktop Linux machine. 480 * 481 * @param fds non-null; file descriptors to send. 482 * @throws IOException 483 */ 484 public void setFileDescriptorsForSend(FileDescriptor[] fds) { 485 synchronized(writeMonitor) { 486 outboundFileDescriptors = fds; 487 } 488 } 489 490 /** 491 * Retrieves a set of file descriptors that a peer has sent through 492 * an ancillary message. This method retrieves the most recent set sent, 493 * and then returns null until a new set arrives. 494 * File descriptors may only be passed along with regular data, so this 495 * method can only return a non-null after a read operation. 496 * 497 * @return null or file descriptor array 498 * @throws IOException 499 */ 500 public FileDescriptor[] getAncillaryFileDescriptors() throws IOException { 501 synchronized(readMonitor) { 502 FileDescriptor[] result = inboundFileDescriptors; 503 504 inboundFileDescriptors = null; 505 return result; 506 } 507 } 508 509 /** 510 * Retrieves the credentials of this socket's peer. Only valid on 511 * connected sockets. 512 * 513 * @return non-null; peer credentials 514 * @throws IOException 515 */ 516 public Credentials getPeerCredentials() throws IOException 517 { 518 return getPeerCredentials_native(fd); 519 } 520 521 /** 522 * Retrieves the socket name from the OS. 523 * 524 * @return non-null; socket name 525 * @throws IOException on failure 526 */ 527 public LocalSocketAddress getSockAddress() throws IOException 528 { 529 return null; 530 //TODO implement this 531 //return getSockName_native(fd); 532 } 533 534 @Override 535 protected void finalize() throws IOException { 536 close(); 537 } 538 } 539 540