1 /* 2 * Copyright (c) 2008, 2019, 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 sun.nio.ch; 27 28 import java.net.InetAddress; 29 import java.net.NetworkInterface; 30 import java.nio.channels.MembershipKey; 31 import java.util.HashMap; 32 import java.util.Iterator; 33 import java.util.LinkedList; 34 import java.util.List; 35 import java.util.Map; 36 37 /** 38 * Simple registry of membership keys for a MulticastChannel. 39 * 40 * Instances of this object are not safe by multiple concurrent threads. 41 */ 42 43 class MembershipRegistry { 44 45 // map multicast group to list of keys 46 private Map<InetAddress, List<MembershipKeyImpl>> groups; 47 MembershipRegistry()48 MembershipRegistry() { 49 } 50 51 /** 52 * Checks registry for membership of the group on the given 53 * network interface. 54 */ checkMembership(InetAddress group, NetworkInterface interf, InetAddress source)55 MembershipKey checkMembership(InetAddress group, NetworkInterface interf, 56 InetAddress source) 57 { 58 if (groups != null) { 59 List<MembershipKeyImpl> keys = groups.get(group); 60 if (keys != null) { 61 for (MembershipKeyImpl key: keys) { 62 if (key.networkInterface().equals(interf)) { 63 // already a member to receive all packets so return 64 // existing key or detect conflict 65 if (source == null) { 66 if (key.sourceAddress() == null) 67 return key; 68 throw new IllegalStateException("Already a member to receive all packets"); 69 } 70 71 // already have source-specific membership so return key 72 // or detect conflict 73 if (key.sourceAddress() == null) 74 throw new IllegalStateException("Already have source-specific membership"); 75 if (source.equals(key.sourceAddress())) 76 return key; 77 } 78 } 79 } 80 } 81 return null; 82 } 83 84 /** 85 * Add membership to the registry, returning a new membership key. 86 */ add(MembershipKeyImpl key)87 void add(MembershipKeyImpl key) { 88 InetAddress group = key.group(); 89 List<MembershipKeyImpl> keys; 90 if (groups == null) { 91 groups = new HashMap<>(); 92 keys = null; 93 } else { 94 keys = groups.get(group); 95 } 96 if (keys == null) { 97 keys = new LinkedList<>(); 98 groups.put(group, keys); 99 } 100 keys.add(key); 101 } 102 103 /** 104 * Remove a key from the registry 105 */ remove(MembershipKeyImpl key)106 void remove(MembershipKeyImpl key) { 107 InetAddress group = key.group(); 108 List<MembershipKeyImpl> keys = groups.get(group); 109 if (keys != null) { 110 Iterator<MembershipKeyImpl> i = keys.iterator(); 111 while (i.hasNext()) { 112 if (i.next() == key) { 113 i.remove(); 114 break; 115 } 116 } 117 if (keys.isEmpty()) { 118 groups.remove(group); 119 } 120 } 121 } 122 123 @FunctionalInterface 124 interface ThrowingConsumer<T, X extends Throwable> { accept(T action)125 void accept(T action) throws X; 126 } 127 128 /** 129 * Invoke an action for each key in the registry 130 */ 131 <X extends Throwable> forEach(ThrowingConsumer<MembershipKeyImpl, X> action)132 void forEach(ThrowingConsumer<MembershipKeyImpl, X> action) throws X { 133 if (groups != null) { 134 for (List<MembershipKeyImpl> keys : groups.values()) { 135 for (MembershipKeyImpl key : keys) { 136 action.accept(key); 137 } 138 } 139 } 140 } 141 142 /** 143 * Invalidate all keys in the registry 144 */ invalidateAll()145 void invalidateAll() { 146 forEach(MembershipKeyImpl::invalidate); 147 } 148 } 149