1 /*
   2  * Copyright (c) 1996, 2008, 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 java.rmi.dgc;
  27 
  28 import java.io.*;
  29 import java.net.*;
  30 import java.rmi.server.UID;
  31 import java.security.*;
  32 
  33 /**
  34  * A VMID is a identifier that is unique across all Java virtual
  35  * machines.  VMIDs are used by the distributed garbage collector
  36  * to identify client VMs.
  37  *
  38  * @author      Ann Wollrath
  39  * @author      Peter Jones
  40  */
  41 public final class VMID implements java.io.Serializable {
  42 
  43     /** array of bytes uniquely identifying this host */
  44     private static byte[] localAddr = computeAddressHash();
  45 
  46     /**
  47      * @serial array of bytes uniquely identifying host created on
  48      */
  49     private byte[] addr;
  50 
  51     /**
  52      * @serial unique identifier with respect to host created on
  53      */
  54     private UID uid;
  55 
  56     /** indicate compatibility with JDK 1.1.x version of class */
  57     private static final long serialVersionUID = -538642295484486218L;
  58 
  59     /**
  60      * Create a new VMID.  Each new VMID returned from this constructor
  61      * is unique for all Java virtual machines under the following
  62      * conditions: a) the conditions for uniqueness for objects of
  63      * the class <code>java.rmi.server.UID</code> are satisfied, and b) an
  64      * address can be obtained for this host that is unique and constant
  65      * for the lifetime of this object.  <p>
  66      */
  67     public VMID() {
  68         addr = localAddr;
  69         uid = new UID();
  70     }
  71 
  72     /**
  73      * Return true if an accurate address can be determined for this
  74      * host.  If false, reliable VMID cannot be generated from this host
  75      * @return true if host address can be determined, false otherwise
  76      * @deprecated
  77      */
  78     @Deprecated
  79     public static boolean isUnique() {
  80         return true;
  81     }
  82 
  83     /**
  84      * Compute hash code for this VMID.
  85      */
  86     public int hashCode() {
  87         return uid.hashCode();
  88     }
  89 
  90     /**
  91      * Compare this VMID to another, and return true if they are the
  92      * same identifier.
  93      */
  94     public boolean equals(Object obj) {
  95         if (obj instanceof VMID) {
  96             VMID vmid = (VMID) obj;
  97             if (!uid.equals(vmid.uid))
  98                 return false;
  99             if ((addr == null) ^ (vmid.addr == null))
 100                 return false;
 101             if (addr != null) {
 102                 if (addr.length != vmid.addr.length)
 103                     return false;
 104                 for (int i = 0; i < addr.length; ++ i)
 105                     if (addr[i] != vmid.addr[i])
 106                         return false;
 107             }
 108             return true;
 109         } else {
 110             return false;
 111         }
 112     }
 113 
 114     /**
 115      * Return string representation of this VMID.
 116      */
 117     public String toString() {
 118         StringBuffer result = new StringBuffer();
 119         if (addr != null)
 120             for (int i = 0; i < addr.length; ++ i) {
 121                 int x = addr[i] & 0xFF;
 122                 result.append((x < 0x10 ? "0" : "") +
 123                               Integer.toString(x, 16));
 124             }
 125         result.append(':');
 126         result.append(uid.toString());
 127         return result.toString();
 128     }
 129 
 130     /**
 131      * Compute the hash an IP address.  The hash is the first 8 bytes
 132      * of the SHA digest of the IP address.
 133      */
 134     private static byte[] computeAddressHash() {
 135 
 136         /*
 137          * Get the local host's IP address.
 138          */
 139         byte[] addr = java.security.AccessController.doPrivileged(
 140             new PrivilegedAction<byte[]>() {
 141             public byte[] run() {
 142                 try {
 143                     return InetAddress.getLocalHost().getAddress();
 144                 } catch (Exception e) {
 145                 }
 146                 return new byte[] { 0, 0, 0, 0 };
 147             }
 148         });
 149 
 150         byte[] addrHash;
 151         final int ADDR_HASH_LENGTH = 8;
 152 
 153         try {
 154             /*
 155              * Calculate message digest of IP address using SHA.
 156              */
 157             MessageDigest md = MessageDigest.getInstance("SHA");
 158             ByteArrayOutputStream sink = new ByteArrayOutputStream(64);
 159             DataOutputStream out = new DataOutputStream(
 160                 new DigestOutputStream(sink, md));
 161             out.write(addr, 0, addr.length);
 162             out.flush();
 163 
 164             byte digest[] = md.digest();
 165             int hashlength = Math.min(ADDR_HASH_LENGTH, digest.length);
 166             addrHash = new byte[hashlength];
 167             System.arraycopy(digest, 0, addrHash, 0, hashlength);
 168 
 169         } catch (IOException ignore) {
 170             /* can't happen, but be deterministic anyway. */
 171             addrHash = new byte[0];
 172         } catch (NoSuchAlgorithmException complain) {
 173             throw new InternalError(complain.toString(), complain);
 174         }
 175         return addrHash;
 176     }
 177 }