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