1/* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18package java.net; 19 20import android.system.ErrnoException; 21import java.io.Closeable; 22import java.io.FileDescriptor; 23import java.io.IOException; 24import java.nio.channels.DatagramChannel; 25import libcore.io.IoBridge; 26import libcore.io.Libcore; 27import static android.system.OsConstants.*; 28 29/** 30 * This class implements a UDP socket for sending and receiving {@code 31 * DatagramPacket}. A {@code DatagramSocket} object can be used for both 32 * endpoints of a connection for a packet delivery service. 33 * 34 * @see DatagramPacket 35 * @see DatagramSocketImplFactory 36 */ 37public class DatagramSocket implements Closeable { 38 39 DatagramSocketImpl impl; 40 41 InetAddress address; 42 43 int port = -1; 44 45 static DatagramSocketImplFactory factory; 46 47 boolean isBound = false; 48 49 private boolean isConnected = false; 50 51 private SocketException pendingConnectException; 52 53 private boolean isClosed = false; 54 55 private Object lock = new Object(); 56 57 /** 58 * Constructs a UDP datagram socket which is bound to any available port on 59 * the local host using a wildcard address. 60 * 61 * @throws SocketException 62 * if an error occurs while creating or binding the socket. 63 */ 64 public DatagramSocket() throws SocketException { 65 this(0); 66 } 67 68 /** 69 * Constructs a UDP datagram socket which is bound to the specific port 70 * {@code aPort} on the local host using a wildcard address. Valid values for {@code aPort} are 71 * between 0 and 65535 inclusive. 72 * 73 * @param aPort 74 * the port to bind on the local host. 75 * @throws SocketException 76 * if an error occurs while creating or binding the socket. 77 */ 78 public DatagramSocket(int aPort) throws SocketException { 79 checkPort(aPort); 80 createSocket(aPort, Inet6Address.ANY); 81 } 82 83 /** 84 * Constructs a UDP datagram socket which is bound to the specific local address {@code addr} on 85 * port {@code aPort}. Valid values for {@code aPort} are between 0 and 65535 inclusive. If 86 * {@code addr} is {@code null} the socket will be bound to a wildcard address. 87 * 88 * @param aPort 89 * the port to bind on the local host. 90 * @param addr 91 * the address to bind on the local host. 92 * @throws SocketException 93 * if an error occurs while creating or binding the socket. 94 */ 95 public DatagramSocket(int aPort, InetAddress addr) throws SocketException { 96 checkPort(aPort); 97 createSocket(aPort, (addr == null) ? Inet6Address.ANY : addr); 98 } 99 100 private void checkPort(int aPort) { 101 if (aPort < 0 || aPort > 65535) { 102 throw new IllegalArgumentException("Port out of range: " + aPort); 103 } 104 } 105 106 /** 107 * Closes this UDP datagram socket and all possibly associated channels. 108 */ 109 // In the documentation jdk1.1.7a/guide/net/miscNet.html, this method is 110 // noted as not being synchronized. 111 public void close() { 112 isClosed = true; 113 impl.close(); 114 } 115 116 /** 117 * Sets the DatagramSocket and its related DatagramSocketImpl state as if a successful close() 118 * took place, without actually performing an OS close(). 119 * 120 * @hide used in java.nio 121 */ 122 public void onClose() { 123 isClosed = true; 124 impl.onClose(); 125 } 126 127 /** 128 * Disconnects this UDP datagram socket from the remote host. This method 129 * called on an unconnected socket does nothing. 130 */ 131 public void disconnect() { 132 if (isClosed() || !isConnected()) { 133 return; 134 } 135 impl.disconnect(); 136 address = null; 137 port = -1; 138 isConnected = false; 139 } 140 141 /** 142 * Sets the DatagramSocket and its related DatagramSocketImpl state as if a successful 143 * disconnect() took place, without actually performing a disconnect(). 144 * 145 * @hide used in java.nio 146 */ 147 public void onDisconnect() { 148 address = null; 149 port = -1; 150 isConnected = false; 151 impl.onDisconnect(); 152 } 153 154 synchronized void createSocket(int aPort, InetAddress addr) throws SocketException { 155 impl = factory != null ? factory.createDatagramSocketImpl() 156 : new PlainDatagramSocketImpl(); 157 impl.create(); 158 try { 159 impl.bind(aPort, addr); 160 isBound = true; 161 } catch (SocketException e) { 162 close(); 163 throw e; 164 } 165 } 166 167 /** 168 * Gets the {@code InetAddress} instance representing the remote address to 169 * which this UDP datagram socket is connected. 170 * 171 * @return the remote address this socket is connected to or {@code null} if 172 * this socket is not connected. 173 */ 174 public InetAddress getInetAddress() { 175 return address; 176 } 177 178 /** 179 * Returns the local address to which this socket is bound, a wildcard address if this 180 * socket is not yet bound, or {@code null} if this socket is closed. 181 */ 182 public InetAddress getLocalAddress() { 183 try { 184 return IoBridge.getSocketLocalAddress(impl.fd); 185 } catch (SocketException ex) { 186 return null; 187 } 188 } 189 190 /** 191 * Gets the local port which this socket is bound to. 192 * 193 * @return the local port of this socket or {@code -1} if this socket is 194 * closed and {@code 0} if it is unbound. 195 */ 196 public int getLocalPort() { 197 if (isClosed()) { 198 return -1; 199 } 200 if (!isBound()) { 201 return 0; 202 } 203 return impl.getLocalPort(); 204 } 205 206 /** 207 * Gets the remote port which this socket is connected to. 208 * 209 * @return the remote port of this socket. The return value {@code -1} 210 * indicates that this socket is not connected. 211 */ 212 public int getPort() { 213 return port; 214 } 215 216 /** 217 * Indicates whether this socket is multicast or not. 218 * 219 * @return the return value is always {@code false}. 220 */ 221 boolean isMulticastSocket() { 222 return false; 223 } 224 225 /** 226 * Returns this socket's {@link SocketOptions#SO_RCVBUF receive buffer size}. 227 */ 228 public synchronized int getReceiveBufferSize() throws SocketException { 229 checkOpen(); 230 return ((Integer) impl.getOption(SocketOptions.SO_RCVBUF)).intValue(); 231 } 232 233 /** 234 * Returns this socket's {@link SocketOptions#SO_SNDBUF send buffer size}. 235 */ 236 public synchronized int getSendBufferSize() throws SocketException { 237 checkOpen(); 238 return ((Integer) impl.getOption(SocketOptions.SO_SNDBUF)).intValue(); 239 } 240 241 /** 242 * Gets the socket {@link SocketOptions#SO_TIMEOUT receive timeout}. 243 * 244 * @throws SocketException 245 * if an error occurs while getting the option value. 246 */ 247 public synchronized int getSoTimeout() throws SocketException { 248 checkOpen(); 249 return ((Integer) impl.getOption(SocketOptions.SO_TIMEOUT)).intValue(); 250 } 251 252 /** 253 * Receives a packet from this socket and stores it in the argument {@code 254 * pack}. All fields of {@code pack} must be set according to the data 255 * received. If the received data is longer than the packet buffer size it 256 * is truncated. This method blocks until a packet is received or a timeout 257 * has expired. 258 * 259 * @param pack 260 * the {@code DatagramPacket} to store the received data. 261 * @throws IOException 262 * if an error occurs while receiving the packet. 263 */ 264 public synchronized void receive(DatagramPacket pack) throws IOException { 265 checkOpen(); 266 ensureBound(); 267 if (pack == null) { 268 throw new NullPointerException("pack == null"); 269 } 270 if (pendingConnectException != null) { 271 throw new SocketException("Pending connect failure", pendingConnectException); 272 } 273 pack.resetLengthForReceive(); 274 impl.receive(pack); 275 } 276 277 /** 278 * Sends a packet over this socket. 279 * 280 * @param pack 281 * the {@code DatagramPacket} which has to be sent. 282 * @throws IOException 283 * if an error occurs while sending the packet. 284 */ 285 public void send(DatagramPacket pack) throws IOException { 286 checkOpen(); 287 ensureBound(); 288 289 InetAddress packAddr = pack.getAddress(); 290 if (address != null) { // The socket is connected 291 if (packAddr != null) { 292 if (!address.equals(packAddr) || port != pack.getPort()) { 293 throw new IllegalArgumentException("Packet address mismatch with connected address"); 294 } 295 } else { 296 pack.setAddress(address); 297 pack.setPort(port); 298 } 299 } else { 300 // not connected so the target address is not allowed to be null 301 if (packAddr == null) { 302 throw new NullPointerException("Destination address is null"); 303 } 304 } 305 impl.send(pack); 306 } 307 308 /** 309 * Sets the network interface used by this socket. Any packets sent 310 * via this socket are transmitted via the specified interface. Any 311 * packets received by this socket will come from the specified 312 * interface. Broadcast datagrams received on this interface will 313 * be processed by this socket. This corresponds to Linux's SO_BINDTODEVICE. 314 * 315 * @hide used by GoogleTV for DHCP 316 */ 317 public void setNetworkInterface(NetworkInterface netInterface) throws SocketException { 318 if (netInterface == null) { 319 throw new NullPointerException("netInterface == null"); 320 } 321 try { 322 Libcore.os.setsockoptIfreq(impl.fd, SOL_SOCKET, SO_BINDTODEVICE, netInterface.getName()); 323 } catch (ErrnoException errnoException) { 324 throw errnoException.rethrowAsSocketException(); 325 } 326 } 327 328 /** 329 * Sets this socket's {@link SocketOptions#SO_SNDBUF send buffer size}. 330 */ 331 public synchronized void setSendBufferSize(int size) throws SocketException { 332 if (size < 1) { 333 throw new IllegalArgumentException("size < 1"); 334 } 335 checkOpen(); 336 impl.setOption(SocketOptions.SO_SNDBUF, Integer.valueOf(size)); 337 } 338 339 /** 340 * Sets this socket's {@link SocketOptions#SO_SNDBUF receive buffer size}. 341 */ 342 public synchronized void setReceiveBufferSize(int size) throws SocketException { 343 if (size < 1) { 344 throw new IllegalArgumentException("size < 1"); 345 } 346 checkOpen(); 347 impl.setOption(SocketOptions.SO_RCVBUF, Integer.valueOf(size)); 348 } 349 350 /** 351 * Sets the {@link SocketOptions#SO_TIMEOUT read timeout} in milliseconds for this socket. 352 * This receive timeout defines the period the socket will block waiting to 353 * receive data before throwing an {@code InterruptedIOException}. The value 354 * {@code 0} (default) is used to set an infinite timeout. To have effect 355 * this option must be set before the blocking method was called. 356 * 357 * @param timeout the timeout in milliseconds or 0 for no timeout. 358 * @throws SocketException 359 * if an error occurs while setting the option. 360 */ 361 public synchronized void setSoTimeout(int timeout) throws SocketException { 362 if (timeout < 0) { 363 throw new IllegalArgumentException("timeout < 0"); 364 } 365 checkOpen(); 366 impl.setOption(SocketOptions.SO_TIMEOUT, Integer.valueOf(timeout)); 367 } 368 369 /** 370 * Sets the socket implementation factory. This may only be invoked once 371 * over the lifetime of the application. This factory is used to create 372 * a new datagram socket implementation. 373 * 374 * @param fac 375 * the socket factory to use. 376 * @throws IOException 377 * if the factory has already been set. 378 * @see DatagramSocketImplFactory 379 */ 380 public static synchronized void setDatagramSocketImplFactory(DatagramSocketImplFactory fac) 381 throws IOException { 382 if (factory != null) { 383 throw new SocketException("Factory already set"); 384 } 385 factory = fac; 386 } 387 388 /** 389 * Constructs a new {@code DatagramSocket} using the specific datagram 390 * socket implementation {@code socketImpl}. The created {@code 391 * DatagramSocket} will not be bound. 392 * 393 * @param socketImpl 394 * the DatagramSocketImpl to use. 395 */ 396 protected DatagramSocket(DatagramSocketImpl socketImpl) { 397 if (socketImpl == null) { 398 throw new NullPointerException("socketImpl == null"); 399 } 400 impl = socketImpl; 401 } 402 403 /** 404 * Constructs a new {@code DatagramSocket} bound to the host/port specified 405 * by the {@code SocketAddress} {@code localAddr} or an unbound {@code 406 * DatagramSocket} if the {@code SocketAddress} is {@code null}. 407 * 408 * @param localAddr 409 * the local machine address and port to bind to. 410 * @throws IllegalArgumentException 411 * if the SocketAddress is not supported 412 * @throws SocketException 413 * if a problem occurs creating or binding the socket. 414 */ 415 public DatagramSocket(SocketAddress localAddr) throws SocketException { 416 if (localAddr != null) { 417 if (!(localAddr instanceof InetSocketAddress)) { 418 throw new IllegalArgumentException("Local address not an InetSocketAddress: " + 419 localAddr.getClass()); 420 } 421 checkPort(((InetSocketAddress) localAddr).getPort()); 422 } 423 impl = factory != null ? factory.createDatagramSocketImpl() 424 : new PlainDatagramSocketImpl(); 425 impl.create(); 426 if (localAddr != null) { 427 try { 428 bind(localAddr); 429 } catch (SocketException e) { 430 close(); 431 throw e; 432 } 433 } 434 // SocketOptions.SO_BROADCAST is set by default for DatagramSocket 435 setBroadcast(true); 436 } 437 438 void checkOpen() throws SocketException { 439 if (isClosed()) { 440 throw new SocketException("Socket is closed"); 441 } 442 } 443 444 private void ensureBound() throws SocketException { 445 if (!isBound()) { 446 impl.bind(0, Inet6Address.ANY); 447 isBound = true; 448 } 449 } 450 451 /** 452 * Binds this socket to the local address and port specified by {@code 453 * localAddr}. If this value is {@code null} any free port on a valid local 454 * address is used. 455 * 456 * @param localAddr 457 * the local machine address and port to bind on. 458 * @throws IllegalArgumentException 459 * if the SocketAddress is not supported 460 * @throws SocketException 461 * if the socket is already bound or a problem occurs during 462 * binding. 463 */ 464 public void bind(SocketAddress localAddr) throws SocketException { 465 checkOpen(); 466 int localPort; 467 InetAddress addr; 468 if (localAddr == null) { 469 localPort = 0; 470 addr = Inet6Address.ANY; 471 } else { 472 if (!(localAddr instanceof InetSocketAddress)) { 473 throw new IllegalArgumentException("Local address not an InetSocketAddress: " + 474 localAddr.getClass()); 475 } 476 InetSocketAddress inetAddr = (InetSocketAddress) localAddr; 477 addr = inetAddr.getAddress(); 478 if (addr == null) { 479 throw new SocketException("Host is unresolved: " + inetAddr.getHostName()); 480 } 481 localPort = inetAddr.getPort(); 482 checkPort(localPort); 483 } 484 impl.bind(localPort, addr); 485 isBound = true; 486 } 487 488 /** 489 * Sets the DatagramSocket and its related DatagramSocketImpl state as if a successful bind() 490 * took place, without actually performing an OS bind(). 491 * 492 * @hide used in java.nio 493 */ 494 public void onBind(InetAddress localAddress, int localPort) { 495 isBound = true; 496 impl.onBind(localAddress, localPort); 497 } 498 499 /** 500 * Connects this datagram socket to the address and port specified by {@code peer}. 501 * Future calls to {@link #send} will use this as the default target, and {@link #receive} 502 * will only accept packets from this source. 503 * 504 * @throws SocketException if an error occurs. 505 */ 506 public void connect(SocketAddress peer) throws SocketException { 507 if (peer == null) { 508 throw new IllegalArgumentException("peer == null"); 509 } 510 511 if (!(peer instanceof InetSocketAddress)) { 512 throw new IllegalArgumentException("peer not an InetSocketAddress: " + peer.getClass()); 513 } 514 515 InetSocketAddress isa = (InetSocketAddress) peer; 516 if (isa.getAddress() == null) { 517 throw new SocketException("Host is unresolved: " + isa.getHostName()); 518 } 519 520 synchronized (lock) { 521 checkOpen(); 522 ensureBound(); 523 524 this.address = isa.getAddress(); 525 this.port = isa.getPort(); 526 this.isConnected = true; 527 528 impl.connect(address, port); 529 } 530 } 531 532 /** 533 * Sets the DatagramSocket and its related DatagramSocketImpl state as if a successful connect() 534 * took place, without actually performing an OS connect(). 535 * 536 * @hide used in java.nio 537 */ 538 public void onConnect(InetAddress remoteAddress, int remotePort) { 539 isConnected = true; 540 this.address = remoteAddress; 541 this.port = remotePort; 542 impl.onConnect(remoteAddress, remotePort); 543 } 544 545 /** 546 * Connects this datagram socket to the specific {@code address} and {@code port}. 547 * Future calls to {@link #send} will use this as the default target, and {@link #receive} 548 * will only accept packets from this source. 549 * 550 * <p>Beware: because it can't throw, this method silently ignores failures. 551 * Use {@link #connect(SocketAddress)} instead. 552 */ 553 public void connect(InetAddress address, int port) { 554 if (address == null) { 555 throw new IllegalArgumentException("address == null"); 556 } 557 try { 558 connect(new InetSocketAddress(address, port)); 559 } catch (SocketException connectException) { 560 // TODO: or just use SneakyThrow? There's a clear API bug here. 561 pendingConnectException = connectException; 562 } 563 } 564 565 /** 566 * Returns true if this socket is bound to a local address. See {@link #bind}. 567 */ 568 public boolean isBound() { 569 return isBound; 570 } 571 572 /** 573 * Returns true if this datagram socket is connected to a remote address. See {@link #connect}. 574 */ 575 public boolean isConnected() { 576 return isConnected; 577 } 578 579 /** 580 * Returns the {@code SocketAddress} this socket is connected to, or null for an unconnected 581 * socket. 582 */ 583 public SocketAddress getRemoteSocketAddress() { 584 if (!isConnected()) { 585 return null; 586 } 587 return new InetSocketAddress(getInetAddress(), getPort()); 588 } 589 590 /** 591 * Returns the {@code SocketAddress} this socket is bound to, or {@code null} for an unbound or 592 * closed socket. 593 */ 594 public SocketAddress getLocalSocketAddress() { 595 if (isClosed() || !isBound()) { 596 return null; 597 } 598 return new InetSocketAddress(getLocalAddress(), getLocalPort()); 599 } 600 601 /** 602 * Sets the socket option {@code SocketOptions.SO_REUSEADDR}. This option 603 * has to be enabled if more than one UDP socket wants to be bound to the 604 * same address. That could be needed for receiving multicast packets. 605 * <p> 606 * There is an undefined behavior if this option is set after the socket is 607 * already bound. 608 * 609 * @param reuse 610 * the socket option value to enable or disable this option. 611 * @throws SocketException 612 * if the socket is closed or the option could not be set. 613 */ 614 public void setReuseAddress(boolean reuse) throws SocketException { 615 checkOpen(); 616 impl.setOption(SocketOptions.SO_REUSEADDR, Boolean.valueOf(reuse)); 617 } 618 619 /** 620 * Gets the state of the socket option {@code SocketOptions.SO_REUSEADDR}. 621 * 622 * @return {@code true} if the option is enabled, {@code false} otherwise. 623 * @throws SocketException 624 * if the socket is closed or the option is invalid. 625 */ 626 public boolean getReuseAddress() throws SocketException { 627 checkOpen(); 628 return ((Boolean) impl.getOption(SocketOptions.SO_REUSEADDR)).booleanValue(); 629 } 630 631 /** 632 * Sets the socket option {@code SocketOptions.SO_BROADCAST}. This option 633 * must be enabled to send broadcast messages. 634 * 635 * @param broadcast 636 * the socket option value to enable or disable this option. 637 * @throws SocketException 638 * if the socket is closed or the option could not be set. 639 */ 640 public void setBroadcast(boolean broadcast) throws SocketException { 641 checkOpen(); 642 impl.setOption(SocketOptions.SO_BROADCAST, Boolean.valueOf(broadcast)); 643 } 644 645 /** 646 * Gets the state of the socket option {@code SocketOptions.SO_BROADCAST}. 647 * 648 * @return {@code true} if the option is enabled, {@code false} otherwise. 649 * @throws SocketException 650 * if the socket is closed or the option is invalid. 651 */ 652 public boolean getBroadcast() throws SocketException { 653 checkOpen(); 654 return ((Boolean) impl.getOption(SocketOptions.SO_BROADCAST)).booleanValue(); 655 } 656 657 /** 658 * Sets the {@see SocketOptions#IP_TOS} value for every packet sent by this socket. 659 * 660 * @throws SocketException 661 * if the socket is closed or the option could not be set. 662 */ 663 public void setTrafficClass(int value) throws SocketException { 664 checkOpen(); 665 if (value < 0 || value > 255) { 666 throw new IllegalArgumentException("Value doesn't fit in an unsigned byte: " + value); 667 } 668 impl.setOption(SocketOptions.IP_TOS, Integer.valueOf(value)); 669 } 670 671 /** 672 * Returns this socket's {@see SocketOptions#IP_TOS} setting. 673 * 674 * @throws SocketException 675 * if the socket is closed or the option is invalid. 676 */ 677 public int getTrafficClass() throws SocketException { 678 checkOpen(); 679 return (Integer) impl.getOption(SocketOptions.IP_TOS); 680 } 681 682 /** 683 * Gets the state of this socket. 684 * 685 * @return {@code true} if the socket is closed, {@code false} otherwise. 686 */ 687 public boolean isClosed() { 688 return isClosed; 689 } 690 691 /** 692 * Returns this socket's {@code DatagramChannel}, if one exists. A channel is 693 * available only if this socket wraps a channel. (That is, you can go from a 694 * channel to a socket and back again, but you can't go from an arbitrary socket to a channel.) 695 * In practice, this means that the socket must have been created by 696 * {@link java.nio.channels.DatagramChannel#open}. 697 */ 698 public DatagramChannel getChannel() { 699 return null; 700 } 701 702 /** 703 * @hide internal use only 704 */ 705 public final FileDescriptor getFileDescriptor$() { 706 return impl.fd; 707 } 708} 709