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