1 /* 2 * Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package java.net; 27 28 import java.io.FileDescriptor; 29 import java.io.IOException; 30 import java.io.InterruptedIOException; 31 import java.util.Set; 32 import java.util.HashSet; 33 34 /** 35 * Abstract datagram and multicast socket implementation base class. 36 * @author Pavani Diwanji 37 * @since 1.1 38 */ 39 40 public abstract class DatagramSocketImpl implements SocketOptions { 41 42 /** 43 * The local port number. 44 */ 45 protected int localPort; 46 47 /** 48 * The file descriptor object. 49 */ 50 protected FileDescriptor fd; 51 52 /** 53 * The DatagramSocket or MulticastSocket 54 * that owns this impl 55 */ 56 DatagramSocket socket; 57 58 void setDatagramSocket(DatagramSocket socket) { 59 this.socket = socket; 60 } 61 62 DatagramSocket getDatagramSocket() { 63 return socket; 64 } 65 66 int dataAvailable() { 67 // default impl returns zero, which disables the calling 68 // functionality 69 return 0; 70 } 71 72 /** 73 * Creates a datagram socket. 74 * @exception SocketException if there is an error in the 75 * underlying protocol, such as a TCP error. 76 */ 77 protected abstract void create() throws SocketException; 78 79 /** 80 * Binds a datagram socket to a local port and address. 81 * @param lport the local port 82 * @param laddr the local address 83 * @exception SocketException if there is an error in the 84 * underlying protocol, such as a TCP error. 85 */ 86 protected abstract void bind(int lport, InetAddress laddr) throws SocketException; 87 88 /** 89 * Sends a datagram packet. The packet contains the data and the 90 * destination address to send the packet to. 91 * @param p the packet to be sent. 92 * @exception IOException if an I/O exception occurs while sending the 93 * datagram packet. 94 * @exception PortUnreachableException may be thrown if the socket is connected 95 * to a currently unreachable destination. Note, there is no guarantee that 96 * the exception will be thrown. 97 */ 98 protected abstract void send(DatagramPacket p) throws IOException; 99 100 /** 101 * Connects a datagram socket to a remote destination. This associates the remote 102 * address with the local socket so that datagrams may only be sent to this destination 103 * and received from this destination. This may be overridden to call a native 104 * system connect. 105 * 106 * <p>If the remote destination to which the socket is connected does not 107 * exist, or is otherwise unreachable, and if an ICMP destination unreachable 108 * packet has been received for that address, then a subsequent call to 109 * send or receive may throw a PortUnreachableException. 110 * Note, there is no guarantee that the exception will be thrown. 111 * @param address the remote InetAddress to connect to 112 * @param port the remote port number 113 * @exception SocketException may be thrown if the socket cannot be 114 * connected to the remote destination 115 * @since 1.4 116 */ 117 protected void connect(InetAddress address, int port) throws SocketException {} 118 119 /** 120 * Disconnects a datagram socket from its remote destination. 121 * @since 1.4 122 */ 123 protected void disconnect() {} 124 125 /** 126 * Peek at the packet to see who it is from. Updates the specified {@code InetAddress} 127 * to the address which the packet came from. 128 * @param i an InetAddress object 129 * @return the port number which the packet came from. 130 * @exception IOException if an I/O exception occurs 131 * @exception PortUnreachableException may be thrown if the socket is connected 132 * to a currently unreachable destination. Note, there is no guarantee that the 133 * exception will be thrown. 134 */ 135 protected abstract int peek(InetAddress i) throws IOException; 136 137 /** 138 * Peek at the packet to see who it is from. The data is copied into the specified 139 * {@code DatagramPacket}. The data is returned, 140 * but not consumed, so that a subsequent peekData/receive operation 141 * will see the same data. 142 * @param p the Packet Received. 143 * @return the port number which the packet came from. 144 * @exception IOException if an I/O exception occurs 145 * @exception PortUnreachableException may be thrown if the socket is connected 146 * to a currently unreachable destination. Note, there is no guarantee that the 147 * exception will be thrown. 148 * @since 1.4 149 */ 150 protected abstract int peekData(DatagramPacket p) throws IOException; 151 /** 152 * Receive the datagram packet. 153 * @param p the Packet Received. 154 * @exception IOException if an I/O exception occurs 155 * while receiving the datagram packet. 156 * @exception PortUnreachableException may be thrown if the socket is connected 157 * to a currently unreachable destination. Note, there is no guarantee that the 158 * exception will be thrown. 159 */ 160 protected abstract void receive(DatagramPacket p) throws IOException; 161 162 /** 163 * Set the TTL (time-to-live) option. 164 * @param ttl a byte specifying the TTL value 165 * 166 * @deprecated use setTimeToLive instead. 167 * @exception IOException if an I/O exception occurs while setting 168 * the time-to-live option. 169 * @see #getTTL() 170 */ 171 @Deprecated 172 protected abstract void setTTL(byte ttl) throws IOException; 173 174 /** 175 * Retrieve the TTL (time-to-live) option. 176 * 177 * @exception IOException if an I/O exception occurs 178 * while retrieving the time-to-live option 179 * @deprecated use getTimeToLive instead. 180 * @return a byte representing the TTL value 181 * @see #setTTL(byte) 182 */ 183 @Deprecated 184 protected abstract byte getTTL() throws IOException; 185 186 /** 187 * Set the TTL (time-to-live) option. 188 * @param ttl an {@code int} specifying the time-to-live value 189 * @exception IOException if an I/O exception occurs 190 * while setting the time-to-live option. 191 * @see #getTimeToLive() 192 */ 193 protected abstract void setTimeToLive(int ttl) throws IOException; 194 195 /** 196 * Retrieve the TTL (time-to-live) option. 197 * @exception IOException if an I/O exception occurs 198 * while retrieving the time-to-live option 199 * @return an {@code int} representing the time-to-live value 200 * @see #setTimeToLive(int) 201 */ 202 protected abstract int getTimeToLive() throws IOException; 203 204 /** 205 * Join the multicast group. 206 * @param inetaddr multicast address to join. 207 * @exception IOException if an I/O exception occurs 208 * while joining the multicast group. 209 */ 210 protected abstract void join(InetAddress inetaddr) throws IOException; 211 212 /** 213 * Leave the multicast group. 214 * @param inetaddr multicast address to leave. 215 * @exception IOException if an I/O exception occurs 216 * while leaving the multicast group. 217 */ 218 protected abstract void leave(InetAddress inetaddr) throws IOException; 219 220 /** 221 * Join the multicast group. 222 * @param mcastaddr address to join. 223 * @param netIf specifies the local interface to receive multicast 224 * datagram packets 225 * @throws IOException if an I/O exception occurs while joining 226 * the multicast group 227 * @since 1.4 228 */ 229 protected abstract void joinGroup(SocketAddress mcastaddr, 230 NetworkInterface netIf) 231 throws IOException; 232 233 /** 234 * Leave the multicast group. 235 * @param mcastaddr address to leave. 236 * @param netIf specified the local interface to leave the group at 237 * @throws IOException if an I/O exception occurs while leaving 238 * the multicast group 239 * @since 1.4 240 */ 241 protected abstract void leaveGroup(SocketAddress mcastaddr, 242 NetworkInterface netIf) 243 throws IOException; 244 245 /** 246 * Close the socket. 247 */ 248 protected abstract void close(); 249 250 /** 251 * Gets the local port. 252 * @return an {@code int} representing the local port value 253 */ 254 protected int getLocalPort() { 255 return localPort; 256 } 257 258 /** 259 * Gets the datagram socket file descriptor. 260 * @return a {@code FileDescriptor} object representing the datagram socket 261 * file descriptor 262 */ 263 protected FileDescriptor getFileDescriptor() { 264 return fd; 265 } 266 267 /** 268 * Called to set a socket option. 269 * 270 * @param <T> The type of the socket option value 271 * @param name The socket option 272 * 273 * @param value The value of the socket option. A value of {@code null} 274 * may be valid for some options. 275 * 276 * @throws UnsupportedOperationException if the DatagramSocketImpl does not 277 * support the option 278 * 279 * @throws NullPointerException if name is {@code null} 280 * @throws IOException if an I/O problem occurs while attempting to set the option 281 * @since 1.9 282 */ 283 protected <T> void setOption(SocketOption<T> name, T value) throws IOException { 284 if (name == StandardSocketOptions.SO_SNDBUF) { 285 setOption(SocketOptions.SO_SNDBUF, value); 286 } else if (name == StandardSocketOptions.SO_RCVBUF) { 287 setOption(SocketOptions.SO_RCVBUF, value); 288 } else if (name == StandardSocketOptions.SO_REUSEADDR) { 289 setOption(SocketOptions.SO_REUSEADDR, value); 290 } else if (name == StandardSocketOptions.IP_TOS) { 291 setOption(SocketOptions.IP_TOS, value); 292 } else if (name == StandardSocketOptions.IP_MULTICAST_IF && 293 (getDatagramSocket() instanceof MulticastSocket)) { 294 setOption(SocketOptions.IP_MULTICAST_IF2, value); 295 } else if (name == StandardSocketOptions.IP_MULTICAST_TTL && 296 (getDatagramSocket() instanceof MulticastSocket)) { 297 if (! (value instanceof Integer)) { 298 throw new IllegalArgumentException("not an integer"); 299 } 300 setTimeToLive((Integer)value); 301 } else if (name == StandardSocketOptions.IP_MULTICAST_LOOP && 302 (getDatagramSocket() instanceof MulticastSocket)) { 303 setOption(SocketOptions.IP_MULTICAST_LOOP, value); 304 } else { 305 throw new UnsupportedOperationException("unsupported option"); 306 } 307 } 308 309 /** 310 * Called to get a socket option. 311 * 312 * @return the socket option 313 * @param <T> The type of the socket option value 314 * @param name The socket option 315 * 316 * @throws UnsupportedOperationException if the DatagramSocketImpl does not 317 * support the option 318 * 319 * @throws NullPointerException if name is {@code null} 320 * @throws IOException if an I/O problem occurs while attempting to set the option 321 * 322 * @since 1.9 323 */ 324 @SuppressWarnings("unchecked") 325 protected <T> T getOption(SocketOption<T> name) throws IOException { 326 if (name == StandardSocketOptions.SO_SNDBUF) { 327 return (T) getOption(SocketOptions.SO_SNDBUF); 328 } else if (name == StandardSocketOptions.SO_RCVBUF) { 329 return (T) getOption(SocketOptions.SO_RCVBUF); 330 } else if (name == StandardSocketOptions.SO_REUSEADDR) { 331 return (T) getOption(SocketOptions.SO_REUSEADDR); 332 } else if (name == StandardSocketOptions.IP_TOS) { 333 return (T) getOption(SocketOptions.IP_TOS); 334 } else if (name == StandardSocketOptions.IP_MULTICAST_IF && 335 (getDatagramSocket() instanceof MulticastSocket)) { 336 return (T) getOption(SocketOptions.IP_MULTICAST_IF2); 337 } else if (name == StandardSocketOptions.IP_MULTICAST_TTL && 338 (getDatagramSocket() instanceof MulticastSocket)) { 339 Integer ttl = getTimeToLive(); 340 return (T)ttl; 341 } else if (name == StandardSocketOptions.IP_MULTICAST_LOOP && 342 (getDatagramSocket() instanceof MulticastSocket)) { 343 return (T) getOption(SocketOptions.IP_MULTICAST_LOOP); 344 } else { 345 throw new UnsupportedOperationException("unsupported option"); 346 } 347 } 348 349 private static final Set<SocketOption<?>> dgSocketOptions = 350 new HashSet<>(); 351 352 private static final Set<SocketOption<?>> mcSocketOptions = 353 new HashSet<>(); 354 355 static { 356 dgSocketOptions.add(StandardSocketOptions.SO_SNDBUF); 357 dgSocketOptions.add(StandardSocketOptions.SO_RCVBUF); 358 dgSocketOptions.add(StandardSocketOptions.SO_REUSEADDR); 359 dgSocketOptions.add(StandardSocketOptions.IP_TOS); 360 361 mcSocketOptions.add(StandardSocketOptions.SO_SNDBUF); 362 mcSocketOptions.add(StandardSocketOptions.SO_RCVBUF); 363 mcSocketOptions.add(StandardSocketOptions.SO_REUSEADDR); 364 mcSocketOptions.add(StandardSocketOptions.IP_TOS); 365 mcSocketOptions.add(StandardSocketOptions.IP_MULTICAST_IF); 366 mcSocketOptions.add(StandardSocketOptions.IP_MULTICAST_TTL); 367 mcSocketOptions.add(StandardSocketOptions.IP_MULTICAST_LOOP); 368 }; 369 370 /** 371 * Returns a set of SocketOptions supported by this impl 372 * and by this impl's socket (DatagramSocket or MulticastSocket) 373 * 374 * @return a Set of SocketOptions 375 */ 376 protected Set<SocketOption<?>> supportedOptions() { 377 if (getDatagramSocket() instanceof MulticastSocket) { 378 return mcSocketOptions; 379 } else { 380 return dgSocketOptions; 381 } 382 } 383 }