1 /*
2  * Copyright (c) 2008, 2009, 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.nio.channels.*;
29 import java.net.InetAddress;
30 import java.net.NetworkInterface;
31 import java.io.IOException;
32 import java.util.HashSet;
33 
34 /**
35  * MembershipKey implementation.
36  */
37 
38 class MembershipKeyImpl
39     extends MembershipKey
40 {
41     private final MulticastChannel ch;
42     private final InetAddress group;
43     private final NetworkInterface interf;
44     private final InetAddress source;
45 
46     // true when key is valid
47     private volatile boolean valid = true;
48 
49     // lock used when creating or accessing blockedSet
50     private Object stateLock = new Object();
51 
52     // set of source addresses that are blocked
53     private HashSet<InetAddress> blockedSet;
54 
MembershipKeyImpl(MulticastChannel ch, InetAddress group, NetworkInterface interf, InetAddress source)55     private MembershipKeyImpl(MulticastChannel ch,
56                               InetAddress group,
57                               NetworkInterface interf,
58                               InetAddress source)
59     {
60         this.ch = ch;
61         this.group = group;
62         this.interf = interf;
63         this.source = source;
64     }
65 
66     /**
67      * MembershipKey will additional context for IPv4 membership
68      */
69     static class Type4 extends MembershipKeyImpl {
70         private final int groupAddress;
71         private final int interfAddress;
72         private final int sourceAddress;
73 
Type4(MulticastChannel ch, InetAddress group, NetworkInterface interf, InetAddress source, int groupAddress, int interfAddress, int sourceAddress)74         Type4(MulticastChannel ch,
75               InetAddress group,
76               NetworkInterface interf,
77               InetAddress source,
78               int groupAddress,
79               int interfAddress,
80               int sourceAddress)
81         {
82             super(ch, group, interf, source);
83             this.groupAddress = groupAddress;
84             this.interfAddress = interfAddress;
85             this.sourceAddress = sourceAddress;
86         }
87 
groupAddress()88         int groupAddress() {
89             return groupAddress;
90         }
91 
interfaceAddress()92         int interfaceAddress() {
93             return interfAddress;
94         }
95 
source()96         int source() {
97             return sourceAddress;
98         }
99     }
100 
101     /**
102      * MembershipKey will additional context for IPv6 membership
103      */
104     static class Type6 extends MembershipKeyImpl {
105         private final byte[] groupAddress;
106         private final int index;
107         private final byte[] sourceAddress;
108 
Type6(MulticastChannel ch, InetAddress group, NetworkInterface interf, InetAddress source, byte[] groupAddress, int index, byte[] sourceAddress)109         Type6(MulticastChannel ch,
110               InetAddress group,
111               NetworkInterface interf,
112               InetAddress source,
113               byte[] groupAddress,
114               int index,
115               byte[] sourceAddress)
116         {
117             super(ch, group, interf, source);
118             this.groupAddress = groupAddress;
119             this.index = index;
120             this.sourceAddress = sourceAddress;
121         }
122 
groupAddress()123         byte[] groupAddress() {
124             return groupAddress;
125         }
126 
index()127         int index() {
128             return index;
129         }
130 
source()131         byte[] source() {
132             return sourceAddress;
133         }
134     }
135 
isValid()136     public boolean isValid() {
137         return valid;
138     }
139 
140     // package-private
invalidate()141     void invalidate() {
142         valid = false;
143     }
144 
drop()145     public void drop() {
146         // delegate to channel
147         ((DatagramChannelImpl)ch).drop(this);
148     }
149 
150     @Override
channel()151     public MulticastChannel channel() {
152         return ch;
153     }
154 
155     @Override
group()156     public InetAddress group() {
157         return group;
158     }
159 
160     @Override
networkInterface()161     public NetworkInterface networkInterface() {
162         return interf;
163     }
164 
165     @Override
sourceAddress()166     public InetAddress sourceAddress() {
167         return source;
168     }
169 
170     @Override
block(InetAddress toBlock)171     public MembershipKey block(InetAddress toBlock)
172         throws IOException
173     {
174         if (source != null)
175             throw new IllegalStateException("key is source-specific");
176 
177         synchronized (stateLock) {
178             if ((blockedSet != null) && blockedSet.contains(toBlock)) {
179                 // already blocked, nothing to do
180                 return this;
181             }
182 
183             ((DatagramChannelImpl)ch).block(this, toBlock);
184 
185             // created blocked set if required and add source address
186             if (blockedSet == null)
187                 blockedSet = new HashSet<InetAddress>();
188             blockedSet.add(toBlock);
189         }
190         return this;
191     }
192 
193     @Override
unblock(InetAddress toUnblock)194     public MembershipKey unblock(InetAddress toUnblock) {
195         synchronized (stateLock) {
196             if ((blockedSet == null) || !blockedSet.contains(toUnblock))
197                 throw new IllegalStateException("not blocked");
198 
199             ((DatagramChannelImpl)ch).unblock(this, toUnblock);
200 
201             blockedSet.remove(toUnblock);
202         }
203         return this;
204     }
205 
206     @Override
toString()207     public String toString() {
208         StringBuilder sb = new StringBuilder(64);
209         sb.append('<');
210         sb.append(group.getHostAddress());
211         sb.append(',');
212         sb.append(interf.getName());
213         if (source != null) {
214             sb.append(',');
215             sb.append(source.getHostAddress());
216         }
217         sb.append('>');
218         return sb.toString();
219     }
220 }
221