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 
  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 valid;
 138     }
 139 
 140     // package-private
 141     void invalidate() {
 142         valid = false;
 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<InetAddress>();
 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 }