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 * Wait until the data in sending queue is emptied. A polling version 142 * for flush implementation. 143 * @throws IOException 144 * if an i/o error occurs. 145 */ 146 @Override 147 public void flush() throws IOException { 148 FileDescriptor myFd = fd; 149 if (myFd == null) throw new IOException("socket closed"); 150 while(pending_native(myFd) > 0) { 151 try { 152 Thread.sleep(10); 153 } catch (InterruptedException ie) { 154 return; 155 } 156 } 157 } 158 } 159 160 private native int pending_native(FileDescriptor fd) throws IOException; 161 private native int available_native(FileDescriptor fd) throws IOException; 162 private native void close_native(FileDescriptor fd) throws IOException; 163 private native int read_native(FileDescriptor fd) throws IOException; 164 private native int readba_native(byte[] b, int off, int len, 165 FileDescriptor fd) throws IOException; 166 private native void writeba_native(byte[] b, int off, int len, 167 FileDescriptor fd) throws IOException; 168 private native void write_native(int b, FileDescriptor fd) 169 throws IOException; 170 private native void connectLocal(FileDescriptor fd, String name, 171 int namespace) throws IOException; 172 private native void bindLocal(FileDescriptor fd, String name, int namespace) 173 throws IOException; 174 private native FileDescriptor create_native(boolean stream) 175 throws IOException; 176 private native void listen_native(FileDescriptor fd, int backlog) 177 throws IOException; 178 private native void shutdown(FileDescriptor fd, boolean shutdownInput); 179 private native Credentials getPeerCredentials_native( 180 FileDescriptor fd) throws IOException; 181 private native int getOption_native(FileDescriptor fd, int optID) 182 throws IOException; 183 private native void setOption_native(FileDescriptor fd, int optID, 184 int b, int value) throws IOException; 185 186// private native LocalSocketAddress getSockName_native 187// (FileDescriptor fd) throws IOException; 188 189 /** 190 * Accepts a connection on a server socket. 191 * 192 * @param fd file descriptor of server socket 193 * @param s socket implementation that will become the new socket 194 * @return file descriptor of new socket 195 */ 196 private native FileDescriptor accept 197 (FileDescriptor fd, LocalSocketImpl s) throws IOException; 198 199 /** 200 * Create a new instance. 201 */ 202 /*package*/ LocalSocketImpl() 203 { 204 } 205 206 /** 207 * Create a new instance from a file descriptor representing 208 * a bound socket. The state of the file descriptor is not checked here 209 * but the caller can verify socket state by calling listen(). 210 * 211 * @param fd non-null; bound file descriptor 212 */ 213 /*package*/ LocalSocketImpl(FileDescriptor fd) throws IOException 214 { 215 this.fd = fd; 216 } 217 218 public String toString() { 219 return super.toString() + " fd:" + fd; 220 } 221 222 /** 223 * Creates a socket in the underlying OS. 224 * 225 * @param stream true if this should be a stream socket, false for 226 * datagram. 227 * @throws IOException 228 */ 229 public void create (boolean stream) throws IOException { 230 // no error if socket already created 231 // need this for LocalServerSocket.accept() 232 if (fd == null) { 233 fd = create_native(stream); 234 } 235 } 236 237 /** 238 * Closes the socket. 239 * 240 * @throws IOException 241 */ 242 public void close() throws IOException { 243 synchronized (LocalSocketImpl.this) { 244 if (fd == null) return; 245 close_native(fd); 246 fd = null; 247 } 248 } 249 250 /** note timeout presently ignored */ 251 protected void connect(LocalSocketAddress address, int timeout) 252 throws IOException 253 { 254 if (fd == null) { 255 throw new IOException("socket not created"); 256 } 257 258 connectLocal(fd, address.getName(), address.getNamespace().getId()); 259 } 260 261 /** 262 * Binds this socket to an endpoint name. May only be called on an instance 263 * that has not yet been bound. 264 * 265 * @param endpoint endpoint address 266 * @throws IOException 267 */ 268 public void bind(LocalSocketAddress endpoint) throws IOException 269 { 270 if (fd == null) { 271 throw new IOException("socket not created"); 272 } 273 274 bindLocal(fd, endpoint.getName(), endpoint.getNamespace().getId()); 275 } 276 277 protected void listen(int backlog) throws IOException 278 { 279 if (fd == null) { 280 throw new IOException("socket not created"); 281 } 282 283 listen_native(fd, backlog); 284 } 285 286 /** 287 * Accepts a new connection to the socket. Blocks until a new 288 * connection arrives. 289 * 290 * @param s a socket that will be used to represent the new connection. 291 * @throws IOException 292 */ 293 protected void accept(LocalSocketImpl s) throws IOException 294 { 295 if (fd == null) { 296 throw new IOException("socket not created"); 297 } 298 299 s.fd = accept(fd, s); 300 } 301 302 /** 303 * Retrieves the input stream for this instance. 304 * 305 * @return input stream 306 * @throws IOException if socket has been closed or cannot be created. 307 */ 308 protected InputStream getInputStream() throws IOException 309 { 310 if (fd == null) { 311 throw new IOException("socket not created"); 312 } 313 314 synchronized (this) { 315 if (fis == null) { 316 fis = new SocketInputStream(); 317 } 318 319 return fis; 320 } 321 } 322 323 /** 324 * Retrieves the output stream for this instance. 325 * 326 * @return output stream 327 * @throws IOException if socket has been closed or cannot be created. 328 */ 329 protected OutputStream getOutputStream() throws IOException 330 { 331 if (fd == null) { 332 throw new IOException("socket not created"); 333 } 334 335 synchronized (this) { 336 if (fos == null) { 337 fos = new SocketOutputStream(); 338 } 339 340 return fos; 341 } 342 } 343 344 /** 345 * Returns the number of bytes available for reading without blocking. 346 * 347 * @return >= 0 count bytes available 348 * @throws IOException 349 */ 350 protected int available() throws IOException 351 { 352 return getInputStream().available(); 353 } 354 355 /** 356 * Shuts down the input side of the socket. 357 * 358 * @throws IOException 359 */ 360 protected void shutdownInput() throws IOException 361 { 362 if (fd == null) { 363 throw new IOException("socket not created"); 364 } 365 366 shutdown(fd, true); 367 } 368 369 /** 370 * Shuts down the output side of the socket. 371 * 372 * @throws IOException 373 */ 374 protected void shutdownOutput() throws IOException 375 { 376 if (fd == null) { 377 throw new IOException("socket not created"); 378 } 379 380 shutdown(fd, false); 381 } 382 383 protected FileDescriptor getFileDescriptor() 384 { 385 return fd; 386 } 387 388 protected boolean supportsUrgentData() 389 { 390 return false; 391 } 392 393 protected void sendUrgentData(int data) throws IOException 394 { 395 throw new RuntimeException ("not impled"); 396 } 397 398 public Object getOption(int optID) throws IOException 399 { 400 if (fd == null) { 401 throw new IOException("socket not created"); 402 } 403 404 if (optID == SocketOptions.SO_TIMEOUT) { 405 return 0; 406 } 407 408 int value = getOption_native(fd, optID); 409 switch (optID) 410 { 411 case SocketOptions.SO_RCVBUF: 412 case SocketOptions.SO_SNDBUF: 413 return value; 414 case SocketOptions.SO_REUSEADDR: 415 default: 416 return value; 417 } 418 } 419 420 public void setOption(int optID, Object value) 421 throws IOException { 422 /* 423 * Boolean.FALSE is used to disable some options, so it 424 * is important to distinguish between FALSE and unset. 425 * We define it here that -1 is unset, 0 is FALSE, and 1 426 * is TRUE. 427 */ 428 int boolValue = -1; 429 int intValue = 0; 430 431 if (fd == null) { 432 throw new IOException("socket not created"); 433 } 434 435 if (value instanceof Integer) { 436 intValue = (Integer)value; 437 } else if (value instanceof Boolean) { 438 boolValue = ((Boolean) value)? 1 : 0; 439 } else { 440 throw new IOException("bad value: " + value); 441 } 442 443 setOption_native(fd, optID, boolValue, intValue); 444 } 445 446 /** 447 * Enqueues a set of file descriptors to send to the peer. The queue 448 * is one deep. The file descriptors will be sent with the next write 449 * of normal data, and will be delivered in a single ancillary message. 450 * See "man 7 unix" SCM_RIGHTS on a desktop Linux machine. 451 * 452 * @param fds non-null; file descriptors to send. 453 * @throws IOException 454 */ 455 public void setFileDescriptorsForSend(FileDescriptor[] fds) { 456 synchronized(writeMonitor) { 457 outboundFileDescriptors = fds; 458 } 459 } 460 461 /** 462 * Retrieves a set of file descriptors that a peer has sent through 463 * an ancillary message. This method retrieves the most recent set sent, 464 * and then returns null until a new set arrives. 465 * File descriptors may only be passed along with regular data, so this 466 * method can only return a non-null after a read operation. 467 * 468 * @return null or file descriptor array 469 * @throws IOException 470 */ 471 public FileDescriptor[] getAncillaryFileDescriptors() throws IOException { 472 synchronized(readMonitor) { 473 FileDescriptor[] result = inboundFileDescriptors; 474 475 inboundFileDescriptors = null; 476 return result; 477 } 478 } 479 480 /** 481 * Retrieves the credentials of this socket's peer. Only valid on 482 * connected sockets. 483 * 484 * @return non-null; peer credentials 485 * @throws IOException 486 */ 487 public Credentials getPeerCredentials() throws IOException 488 { 489 return getPeerCredentials_native(fd); 490 } 491 492 /** 493 * Retrieves the socket name from the OS. 494 * 495 * @return non-null; socket name 496 * @throws IOException on failure 497 */ 498 public LocalSocketAddress getSockAddress() throws IOException 499 { 500 return null; 501 //TODO implement this 502 //return getSockName_native(fd); 503 } 504 505 @Override 506 protected void finalize() throws IOException { 507 close(); 508 } 509} 510 511