263 } |
264 } |
264 |
265 |
265 /** |
266 /** |
266 * Called to set a socket option. |
267 * Called to set a socket option. |
267 * |
268 * |
|
269 * @implSpec |
|
270 * The default implementation of this method first checks that the given |
|
271 * socket option {code name} is not null, then throws {@code |
|
272 * UnsupportedOperationException}. Subclasses should override this method |
|
273 * with an appropriate implementation. |
|
274 * |
268 * @param <T> The type of the socket option value |
275 * @param <T> The type of the socket option value |
269 * @param name The socket option |
276 * @param name The socket option |
270 * |
|
271 * @param value The value of the socket option. A value of {@code null} |
277 * @param value The value of the socket option. A value of {@code null} |
272 * may be valid for some options. |
278 * may be valid for some options. |
273 * |
279 * |
274 * @throws UnsupportedOperationException if the DatagramSocketImpl does not |
280 * @throws UnsupportedOperationException if the DatagramSocketImpl does not |
275 * support the option |
281 * support the option |
276 * |
282 * @throws IllegalArgumentException if the value is not valid for |
|
283 * the option |
|
284 * @throws IOException if an I/O error occurs, or if the socket is closed |
277 * @throws NullPointerException if name is {@code null} |
285 * @throws NullPointerException if name is {@code null} |
278 * @throws IOException if an I/O problem occurs while attempting to set the option |
286 * |
279 * @since 9 |
287 * @since 9 |
280 */ |
288 */ |
281 protected <T> void setOption(SocketOption<T> name, T value) throws IOException { |
289 protected <T> void setOption(SocketOption<T> name, T value) throws IOException { |
282 if (name == StandardSocketOptions.SO_SNDBUF) { |
290 Objects.requireNonNull(name); |
283 setOption(SocketOptions.SO_SNDBUF, value); |
291 throw new UnsupportedOperationException("'" + name + "' not supported"); |
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 } |
292 } |
309 |
293 |
310 /** |
294 /** |
311 * Called to get a socket option. |
295 * Called to get a socket option. |
312 * |
296 * |
313 * @return the socket option |
297 * @implSpec |
|
298 * The default implementation of this method first checks that the given |
|
299 * socket option {code name} is not null, then throws {@code |
|
300 * UnsupportedOperationException}. Subclasses should override this method |
|
301 * with an appropriate implementation. |
|
302 * |
314 * @param <T> The type of the socket option value |
303 * @param <T> The type of the socket option value |
315 * @param name The socket option |
304 * @param name The socket option |
|
305 * @return the socket option |
316 * |
306 * |
317 * @throws UnsupportedOperationException if the DatagramSocketImpl does not |
307 * @throws UnsupportedOperationException if the DatagramSocketImpl does not |
318 * support the option |
308 * support the option |
319 * |
309 * @throws IOException if an I/O error occurs, or if the socket is closed |
320 * @throws NullPointerException if name is {@code null} |
310 * @throws NullPointerException if name is {@code null} |
321 * @throws IOException if an I/O problem occurs while attempting to set the option |
|
322 * |
311 * |
323 * @since 9 |
312 * @since 9 |
324 */ |
313 */ |
325 @SuppressWarnings("unchecked") |
|
326 protected <T> T getOption(SocketOption<T> name) throws IOException { |
314 protected <T> T getOption(SocketOption<T> name) throws IOException { |
327 if (name == StandardSocketOptions.SO_SNDBUF) { |
315 Objects.requireNonNull(name); |
328 return (T) getOption(SocketOptions.SO_SNDBUF); |
316 throw new UnsupportedOperationException("'" + name + "' not supported"); |
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 } |
317 } |
371 |
318 |
372 /** |
319 /** |
373 * Returns a set of SocketOptions supported by this impl |
320 * Returns a set of SocketOptions supported by this impl |
374 * and by this impl's socket (DatagramSocket or MulticastSocket) |
321 * and by this impl's socket (DatagramSocket or MulticastSocket) |
375 * |
322 * |
|
323 * @implSpec |
|
324 * The default implementation of this method returns an empty set. |
|
325 * Subclasses should override this method with an appropriate implementation. |
|
326 * |
376 * @return a Set of SocketOptions |
327 * @return a Set of SocketOptions |
377 * |
328 * |
378 * @since 9 |
329 * @since 9 |
379 */ |
330 */ |
380 protected Set<SocketOption<?>> supportedOptions() { |
331 protected Set<SocketOption<?>> supportedOptions() { |
381 if (getDatagramSocket() instanceof MulticastSocket) { |
332 return Set.of(); |
382 return mcSocketOptions; |
|
383 } else { |
|
384 return dgSocketOptions; |
|
385 } |
|
386 } |
333 } |
387 } |
334 } |