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