1 /* 2 * Copyright (c) 1998, 2016, 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. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 /* 25 */ 26 27 import java.rmi.*; 28 import sun.rmi.transport.*; 29 import java.io.*; 30 import java.lang.reflect.*; 31 import java.rmi.dgc.*; 32 import java.util.*; 33 import java.rmi.registry.*; 34 import java.rmi.server.*; 35 36 public class TestImpl extends RegistryRunner 37 implements Test { 38 static Thread locker = null; 39 static TestImpl foo = null; 40 static TestImpl bar = null; 41 TestImpl()42 TestImpl() throws RemoteException { 43 } 44 echo(String msg)45 public String echo(String msg) throws RemoteException { 46 47 if (locker == null) { 48 // hold the target if not already held 49 locker = lockTargetExpireLeases(foo, DGCDeadLock.HOLD_TARGET_TIME); 50 } 51 return "Message received: " + msg; 52 } 53 main(String[] args)54 static public void main(String[] args) { 55 try { 56 int registryPort = RegistryRunner.init(args); 57 58 //export "Foo" 59 foo = new TestImpl(); 60 Naming.rebind("rmi://:" + 61 registryPort 62 + "/Foo", foo); 63 64 try { 65 //export "Bar" after leases have been expired. 66 bar = new TestImpl(); 67 Naming.rebind("rmi://localhost:" + 68 registryPort 69 + "/Bar", bar); 70 } catch (Exception e) { 71 throw new RemoteException(e.getMessage()); 72 } 73 74 RegistryRunner.notify(registryPort); 75 } catch (Exception e) { 76 System.err.println(e.getMessage()); 77 e.printStackTrace(); 78 } 79 } 80 lockTargetExpireLeases(Remote toLock, int timeOut)81 static Thread lockTargetExpireLeases(Remote toLock, int timeOut) { 82 Thread t = new Thread((Runnable) new TargetLocker(toLock, timeOut)); 83 t.start(); 84 return t; 85 } 86 87 static class TargetLocker implements Runnable { 88 89 Remote toLock = null; 90 int timeOut = 0; 91 TargetLocker(Remote toLock, int timeOut)92 TargetLocker(Remote toLock, int timeOut) { 93 this.toLock = toLock; 94 this.timeOut = timeOut; 95 } 96 run()97 public void run() { 98 try { 99 // give dgc dirty calls time to finish. 100 Thread.currentThread().sleep(4000); 101 102 java.security.AccessController. 103 doPrivileged(new LockTargetCheckLeases(toLock, 104 timeOut)); 105 106 } catch (Exception e) { 107 System.err.println(e.getMessage()); 108 e.printStackTrace(); 109 System.exit(1); 110 } 111 } 112 } 113 114 static class LockTargetCheckLeases 115 implements java.security.PrivilegedAction { 116 117 Remote toLock = null; 118 int timeOut = 0; 119 LockTargetCheckLeases(Remote toLock, int timeOut)120 LockTargetCheckLeases(Remote toLock, int timeOut) { 121 this.toLock = toLock; 122 this.timeOut = timeOut; 123 } 124 run()125 public Object run() { 126 try { 127 128 Class args[] = new Class[1]; 129 130 Class objTableClass = Class.forName 131 ("sun.rmi.transport.ObjectTable"); 132 133 /* get the Target that corresponds to toLock from the 134 * ObjectTable 135 */ 136 args[0] = Class.forName("java.rmi.Remote"); 137 Method objTableGetTarget = 138 objTableClass.getDeclaredMethod("getTarget", args ); 139 objTableGetTarget.setAccessible(true); 140 141 Target lockTarget = 142 ((Target) objTableGetTarget.invoke 143 (null , new Object [] {toLock} )); 144 145 // make sure the lease on this object has expired. 146 expireLeases(lockTarget); 147 148 // stop other threads from using the target for toLock. 149 synchronized (lockTarget) { 150 System.err.println("Locked the relevant target, sleeping " + 151 timeOut/1000 + " seconds"); 152 Thread.currentThread().sleep(timeOut); 153 System.err.println("Target unlocked"); 154 } 155 156 } catch (Exception e) { 157 System.err.println(e.getMessage()); 158 e.printStackTrace(); 159 System.exit(1); 160 } 161 return null; 162 } 163 } 164 165 /* leases have long values, so no dirty calls which would lock out 166 * a clean call, but the leases need to expire anyway, so we do it 167 * explicitly. 168 */ expireLeases(Target t)169 static void expireLeases(Target t) throws Exception { 170 171 final Target target = t; 172 173 java.security.AccessController.doPrivileged( 174 175 // put this into another class? 176 new java.security.PrivilegedAction() { 177 public Object run() { 178 try { 179 180 Class DGCClass = Class.forName("sun.rmi.transport.DGCImpl"); 181 Method getDGCImpl = 182 DGCClass.getDeclaredMethod("getDGCImpl", null ); 183 getDGCImpl.setAccessible(true); 184 185 // make sure the lease on this object has expired. 186 DGC dgcImpl = ((DGC) getDGCImpl.invoke(null, null)); 187 188 /* Get the lease table from the DGCImpl. */ 189 Field reflectedLeaseTable = 190 dgcImpl.getClass().getDeclaredField("leaseTable"); 191 reflectedLeaseTable.setAccessible(true); 192 193 Map leaseTable = (Map) reflectedLeaseTable.get(dgcImpl); 194 195 // dont really need this synchronization... 196 synchronized (leaseTable) { 197 Iterator en = leaseTable.values().iterator(); 198 while (en.hasNext()) { 199 Object info = en.next(); 200 201 /* Get the notifySet in the leaseInfo object. */ 202 Field notifySetField = 203 info.getClass().getDeclaredField("notifySet"); 204 notifySetField.setAccessible(true); 205 HashSet notifySet = (HashSet) notifySetField.get(info); 206 207 Iterator iter = notifySet.iterator(); 208 while (iter.hasNext()) { 209 Target notified = (Target) iter.next(); 210 211 if (notified == target) { 212 213 /* Get and set the expiration field from the info object. */ 214 Field expirationField = info.getClass(). 215 getDeclaredField("expiration"); 216 expirationField.setAccessible(true); 217 expirationField.setLong(info, 0); 218 } 219 } 220 } 221 } 222 } catch (Exception e) { 223 System.err.println(e.getMessage()); 224 e.printStackTrace(); 225 System.exit(1); 226 } 227 // no interesting return value for this privileged action 228 return null; 229 } 230 }); 231 } 232 } 233