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