1 /* 2 * Copyright (c) 2008, 2018, 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.io.IOException; 31 import java.nio.channels.MembershipKey; 32 import java.nio.channels.MulticastChannel; 33 import java.util.HashSet; 34 35 /** 36 * MembershipKey implementation. 37 */ 38 39 class MembershipKeyImpl 40 extends MembershipKey 41 { 42 private final MulticastChannel ch; 43 private final InetAddress group; 44 private final NetworkInterface interf; 45 private final InetAddress source; 46 47 private volatile boolean invalid; 48 49 // lock used when creating or accessing blockedSet 50 private final Object stateLock = new Object(); 51 52 // set of source addresses that are blocked 53 private HashSet<InetAddress> blockedSet; 54 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 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 88 int groupAddress() { 89 return groupAddress; 90 } 91 92 int interfaceAddress() { 93 return interfAddress; 94 } 95 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 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 123 byte[] groupAddress() { 124 return groupAddress; 125 } 126 127 int index() { 128 return index; 129 } 130 131 byte[] source() { 132 return sourceAddress; 133 } 134 } 135 136 public boolean isValid() { 137 return !invalid; 138 } 139 140 // package-private 141 void invalidate() { 142 invalid = true; 143 } 144 145 public void drop() { 146 // delegate to channel 147 ((DatagramChannelImpl)ch).drop(this); 148 } 149 150 @Override 151 public MulticastChannel channel() { 152 return ch; 153 } 154 155 @Override 156 public InetAddress group() { 157 return group; 158 } 159 160 @Override 161 public NetworkInterface networkInterface() { 162 return interf; 163 } 164 165 @Override 166 public InetAddress sourceAddress() { 167 return source; 168 } 169 170 @Override 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<>(); 188 blockedSet.add(toBlock); 189 } 190 return this; 191 } 192 193 @Override 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 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 }