Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openanolis
dragonwell8_jdk
提交
1f0f864c
D
dragonwell8_jdk
项目概览
openanolis
/
dragonwell8_jdk
通知
4
Star
2
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
D
dragonwell8_jdk
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
提交
1f0f864c
编写于
4月 03, 2017
作者:
C
coffeys
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
8163958: Improved garbage collection
Reviewed-by: rriggs
上级
4e73f25f
变更
9
显示空白变更内容
内联
并排
Showing
9 changed file
with
903 addition
and
18 deletion
+903
-18
make/GenerateClasses.gmk
make/GenerateClasses.gmk
+1
-2
src/share/classes/sun/rmi/server/UnicastRef.java
src/share/classes/sun/rmi/server/UnicastRef.java
+5
-9
src/share/classes/sun/rmi/server/UnicastServerRef.java
src/share/classes/sun/rmi/server/UnicastServerRef.java
+5
-5
src/share/classes/sun/rmi/transport/ConnectionInputStream.java
...hare/classes/sun/rmi/transport/ConnectionInputStream.java
+9
-1
src/share/classes/sun/rmi/transport/DGCClient.java
src/share/classes/sun/rmi/transport/DGCClient.java
+10
-0
src/share/classes/sun/rmi/transport/DGCImpl_Skel.java
src/share/classes/sun/rmi/transport/DGCImpl_Skel.java
+112
-0
src/share/classes/sun/rmi/transport/DGCImpl_Stub.java
src/share/classes/sun/rmi/transport/DGCImpl_Stub.java
+183
-0
src/share/classes/sun/rmi/transport/StreamRemoteCall.java
src/share/classes/sun/rmi/transport/StreamRemoteCall.java
+8
-1
test/java/rmi/testlibrary/TestSocketFactory.java
test/java/rmi/testlibrary/TestSocketFactory.java
+570
-0
未找到文件。
make/GenerateClasses.gmk
浏览文件 @
1f0f864c
...
...
@@ -79,8 +79,7 @@ $(eval $(call SetupRMICompilation,RMI_12, \
GENCLASSES += $(RMI_12)
$(eval $(call SetupRMICompilation,RMI_11, \
CLASSES := sun.rmi.registry.RegistryImpl \
sun.rmi.transport.DGCImpl, \
CLASSES := sun.rmi.registry.RegistryImpl, \
CLASSES_DIR := $(CLASSES_DIR), \
STUB_CLASSES_DIR := $(STUB_CLASSES_DIR), \
RUN_V11 := true))
...
...
src/share/classes/sun/rmi/server/UnicastRef.java
浏览文件 @
1f0f864c
/*
* Copyright (c) 1996, 201
3
, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1996, 201
7
, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
...
...
@@ -32,7 +32,6 @@ import java.lang.reflect.Method;
import
java.rmi.MarshalException
;
import
java.rmi.Remote
;
import
java.rmi.RemoteException
;
import
java.rmi.ServerException
;
import
java.rmi.UnmarshalException
;
import
java.rmi.server.Operation
;
import
java.rmi.server.RemoteCall
;
...
...
@@ -187,14 +186,11 @@ public class UnicastRef implements RemoteRef {
return
returnValue
;
}
catch
(
IOException
e
)
{
clientRefLog
.
log
(
Log
.
BRIEF
,
"IOException unmarshalling return: "
,
e
);
throw
new
UnmarshalException
(
"error unmarshalling return"
,
e
);
}
catch
(
ClassNotFoundException
e
)
{
}
catch
(
IOException
|
ClassNotFoundException
e
)
{
// disable saving any refs in the inputStream for GC
((
StreamRemoteCall
)
call
).
discardPendingRefs
();
clientRefLog
.
log
(
Log
.
BRIEF
,
"ClassNotFoundException unmarshalling return: "
,
e
);
e
.
getClass
().
getName
()
+
" unmarshalling return: "
,
e
);
throw
new
UnmarshalException
(
"error unmarshalling return"
,
e
);
}
finally
{
try
{
...
...
src/share/classes/sun/rmi/server/UnicastServerRef.java
浏览文件 @
1f0f864c
/*
* Copyright (c) 1996, 201
6
, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1996, 201
7
, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
...
...
@@ -57,6 +57,7 @@ import java.util.concurrent.atomic.AtomicInteger;
import
sun.misc.ObjectInputFilter
;
import
sun.rmi.runtime.Log
;
import
sun.rmi.transport.LiveRef
;
import
sun.rmi.transport.StreamRemoteCall
;
import
sun.rmi.transport.Target
;
import
sun.rmi.transport.tcp.TCPTransport
;
import
sun.security.action.GetBooleanAction
;
...
...
@@ -330,10 +331,9 @@ public class UnicastServerRef extends UnicastRef
try
{
unmarshalCustomCallData
(
in
);
params
=
unmarshalParameters
(
obj
,
method
,
marshalStream
);
}
catch
(
java
.
io
.
IOException
e
)
{
throw
new
UnmarshalException
(
"error unmarshalling arguments"
,
e
);
}
catch
(
ClassNotFoundException
e
)
{
}
catch
(
java
.
io
.
IOException
|
ClassNotFoundException
e
)
{
// disable saving any refs in the inputStream for GC
((
StreamRemoteCall
)
call
).
discardPendingRefs
();
throw
new
UnmarshalException
(
"error unmarshalling arguments"
,
e
);
}
finally
{
...
...
src/share/classes/sun/rmi/transport/ConnectionInputStream.java
浏览文件 @
1f0f864c
/*
* Copyright (c) 1996, 201
2
, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1996, 201
7
, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
...
...
@@ -81,6 +81,14 @@ class ConnectionInputStream extends MarshalInputStream {
refList
.
add
(
ref
);
}
/**
* Discard the saved incoming refs so there is nothing to register
* when {@code registerRefs} is called.
*/
void
discardRefs
()
{
incomingRefTable
.
clear
();
}
/**
* Add references to DGC table (and possibly send dirty call).
* RegisterRefs now calls DGCClient.referenced on all
...
...
src/share/classes/sun/rmi/transport/DGCClient.java
浏览文件 @
1f0f864c
...
...
@@ -24,9 +24,11 @@
*/
package
sun.rmi.transport
;
import
java.io.InvalidClassException
;
import
java.lang.ref.PhantomReference
;
import
java.lang.ref.ReferenceQueue
;
import
java.net.SocketPermission
;
import
java.rmi.UnmarshalException
;
import
java.security.AccessController
;
import
java.security.PrivilegedAction
;
import
java.util.HashMap
;
...
...
@@ -41,7 +43,9 @@ import java.rmi.dgc.DGC;
import
java.rmi.dgc.Lease
;
import
java.rmi.dgc.VMID
;
import
java.rmi.server.ObjID
;
import
sun.misc.GC
;
import
sun.rmi.runtime.Log
;
import
sun.rmi.runtime.NewThreadAction
;
import
sun.rmi.server.UnicastRef
;
import
sun.rmi.server.Util
;
...
...
@@ -393,6 +397,12 @@ final class DGCClient {
synchronized
(
this
)
{
dirtyFailures
++;
if
(
e
instanceof
UnmarshalException
&&
e
.
getCause
()
instanceof
InvalidClassException
)
{
DGCImpl
.
dgcLog
.
log
(
Log
.
BRIEF
,
"InvalidClassException exception in DGC dirty call"
,
e
);
return
;
// protocol error, do not register these refs
}
if
(
dirtyFailures
==
1
)
{
/*
* If this was the first recent failed dirty call,
...
...
src/share/classes/sun/rmi/transport/DGCImpl_Skel.java
0 → 100644
浏览文件 @
1f0f864c
/*
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package
sun.rmi.transport
;
/**
* Skeleton to dispatch DGC methods.
* Originally generated by RMIC but frozen to match the stubs.
*/
@SuppressWarnings
({
"deprecation"
,
"serial"
})
public
final
class
DGCImpl_Skel
implements
java
.
rmi
.
server
.
Skeleton
{
private
static
final
java
.
rmi
.
server
.
Operation
[]
operations
=
{
new
java
.
rmi
.
server
.
Operation
(
"void clean(java.rmi.server.ObjID[], long, java.rmi.dgc.VMID, boolean)"
),
new
java
.
rmi
.
server
.
Operation
(
"java.rmi.dgc.Lease dirty(java.rmi.server.ObjID[], long, java.rmi.dgc.Lease)"
)
};
private
static
final
long
interfaceHash
=
-
669196253586618813L
;
public
java
.
rmi
.
server
.
Operation
[]
getOperations
()
{
return
operations
.
clone
();
}
public
void
dispatch
(
java
.
rmi
.
Remote
obj
,
java
.
rmi
.
server
.
RemoteCall
call
,
int
opnum
,
long
hash
)
throws
java
.
lang
.
Exception
{
if
(
hash
!=
interfaceHash
)
throw
new
java
.
rmi
.
server
.
SkeletonMismatchException
(
"interface hash mismatch"
);
sun
.
rmi
.
transport
.
DGCImpl
server
=
(
sun
.
rmi
.
transport
.
DGCImpl
)
obj
;
switch
(
opnum
)
{
case
0
:
// clean(ObjID[], long, VMID, boolean)
{
java
.
rmi
.
server
.
ObjID
[]
$param_arrayOf_ObjID_1
;
long
$param_long_2
;
java
.
rmi
.
dgc
.
VMID
$param_VMID_3
;
boolean
$param_boolean_4
;
try
{
java
.
io
.
ObjectInput
in
=
call
.
getInputStream
();
$param_arrayOf_ObjID_1
=
(
java
.
rmi
.
server
.
ObjID
[])
in
.
readObject
();
$param_long_2
=
in
.
readLong
();
$param_VMID_3
=
(
java
.
rmi
.
dgc
.
VMID
)
in
.
readObject
();
$param_boolean_4
=
in
.
readBoolean
();
}
catch
(
java
.
io
.
IOException
e
)
{
throw
new
java
.
rmi
.
UnmarshalException
(
"error unmarshalling arguments"
,
e
);
}
catch
(
java
.
lang
.
ClassNotFoundException
e
)
{
throw
new
java
.
rmi
.
UnmarshalException
(
"error unmarshalling arguments"
,
e
);
}
finally
{
call
.
releaseInputStream
();
}
server
.
clean
(
$param_arrayOf_ObjID_1
,
$param_long_2
,
$param_VMID_3
,
$param_boolean_4
);
try
{
call
.
getResultStream
(
true
);
}
catch
(
java
.
io
.
IOException
e
)
{
throw
new
java
.
rmi
.
MarshalException
(
"error marshalling return"
,
e
);
}
break
;
}
case
1
:
// dirty(ObjID[], long, Lease)
{
java
.
rmi
.
server
.
ObjID
[]
$param_arrayOf_ObjID_1
;
long
$param_long_2
;
java
.
rmi
.
dgc
.
Lease
$param_Lease_3
;
try
{
java
.
io
.
ObjectInput
in
=
call
.
getInputStream
();
$param_arrayOf_ObjID_1
=
(
java
.
rmi
.
server
.
ObjID
[])
in
.
readObject
();
$param_long_2
=
in
.
readLong
();
$param_Lease_3
=
(
java
.
rmi
.
dgc
.
Lease
)
in
.
readObject
();
}
catch
(
java
.
io
.
IOException
e
)
{
throw
new
java
.
rmi
.
UnmarshalException
(
"error unmarshalling arguments"
,
e
);
}
catch
(
java
.
lang
.
ClassNotFoundException
e
)
{
throw
new
java
.
rmi
.
UnmarshalException
(
"error unmarshalling arguments"
,
e
);
}
finally
{
call
.
releaseInputStream
();
}
java
.
rmi
.
dgc
.
Lease
$result
=
server
.
dirty
(
$param_arrayOf_ObjID_1
,
$param_long_2
,
$param_Lease_3
);
try
{
java
.
io
.
ObjectOutput
out
=
call
.
getResultStream
(
true
);
out
.
writeObject
(
$result
);
}
catch
(
java
.
io
.
IOException
e
)
{
throw
new
java
.
rmi
.
MarshalException
(
"error marshalling return"
,
e
);
}
break
;
}
default
:
throw
new
java
.
rmi
.
UnmarshalException
(
"invalid method number"
);
}
}
}
src/share/classes/sun/rmi/transport/DGCImpl_Stub.java
0 → 100644
浏览文件 @
1f0f864c
/*
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package
sun.rmi.transport
;
import
java.io.ObjectInputStream
;
import
java.rmi.dgc.Lease
;
import
java.rmi.dgc.VMID
;
import
java.rmi.server.UID
;
import
java.security.AccessController
;
import
java.security.PrivilegedAction
;
import
sun.misc.ObjectInputFilter
;
import
sun.rmi.server.UnicastRef
;
import
sun.rmi.transport.tcp.TCPConnection
;
/**
* Stubs to invoke DGC remote methods.
* Originally generated from RMIC but frozen to insert serialFilter.
*/
@SuppressWarnings
({
"deprecation"
,
"serial"
})
public
final
class
DGCImpl_Stub
extends
java
.
rmi
.
server
.
RemoteStub
implements
java
.
rmi
.
dgc
.
DGC
{
private
static
final
java
.
rmi
.
server
.
Operation
[]
operations
=
{
new
java
.
rmi
.
server
.
Operation
(
"void clean(java.rmi.server.ObjID[], long, java.rmi.dgc.VMID, boolean)"
),
new
java
.
rmi
.
server
.
Operation
(
"java.rmi.dgc.Lease dirty(java.rmi.server.ObjID[], long, java.rmi.dgc.Lease)"
)
};
private
static
final
long
interfaceHash
=
-
669196253586618813L
;
/** Registry max depth of remote invocations. **/
private
static
int
DGCCLIENT_MAX_DEPTH
=
6
;
/** Registry maximum array size in remote invocations. **/
private
static
int
DGCCLIENT_MAX_ARRAY_SIZE
=
10000
;
// constructors
public
DGCImpl_Stub
()
{
super
();
}
public
DGCImpl_Stub
(
java
.
rmi
.
server
.
RemoteRef
ref
)
{
super
(
ref
);
}
// methods from remote interfaces
// implementation of clean(ObjID[], long, VMID, boolean)
public
void
clean
(
java
.
rmi
.
server
.
ObjID
[]
$param_arrayOf_ObjID_1
,
long
$param_long_2
,
java
.
rmi
.
dgc
.
VMID
$param_VMID_3
,
boolean
$param_boolean_4
)
throws
java
.
rmi
.
RemoteException
{
try
{
java
.
rmi
.
server
.
RemoteCall
call
=
ref
.
newCall
((
java
.
rmi
.
server
.
RemoteObject
)
this
,
operations
,
0
,
interfaceHash
);
try
{
java
.
io
.
ObjectOutput
out
=
call
.
getOutputStream
();
out
.
writeObject
(
$param_arrayOf_ObjID_1
);
out
.
writeLong
(
$param_long_2
);
out
.
writeObject
(
$param_VMID_3
);
out
.
writeBoolean
(
$param_boolean_4
);
}
catch
(
java
.
io
.
IOException
e
)
{
throw
new
java
.
rmi
.
MarshalException
(
"error marshalling arguments"
,
e
);
}
ref
.
invoke
(
call
);
ref
.
done
(
call
);
}
catch
(
java
.
lang
.
RuntimeException
e
)
{
throw
e
;
}
catch
(
java
.
rmi
.
RemoteException
e
)
{
throw
e
;
}
catch
(
java
.
lang
.
Exception
e
)
{
throw
new
java
.
rmi
.
UnexpectedException
(
"undeclared checked exception"
,
e
);
}
}
// implementation of dirty(ObjID[], long, Lease)
public
java
.
rmi
.
dgc
.
Lease
dirty
(
java
.
rmi
.
server
.
ObjID
[]
$param_arrayOf_ObjID_1
,
long
$param_long_2
,
java
.
rmi
.
dgc
.
Lease
$param_Lease_3
)
throws
java
.
rmi
.
RemoteException
{
try
{
java
.
rmi
.
server
.
RemoteCall
call
=
ref
.
newCall
((
java
.
rmi
.
server
.
RemoteObject
)
this
,
operations
,
1
,
interfaceHash
);
try
{
java
.
io
.
ObjectOutput
out
=
call
.
getOutputStream
();
out
.
writeObject
(
$param_arrayOf_ObjID_1
);
out
.
writeLong
(
$param_long_2
);
out
.
writeObject
(
$param_Lease_3
);
}
catch
(
java
.
io
.
IOException
e
)
{
throw
new
java
.
rmi
.
MarshalException
(
"error marshalling arguments"
,
e
);
}
ref
.
invoke
(
call
);
java
.
rmi
.
dgc
.
Lease
$result
;
Connection
connection
=
((
StreamRemoteCall
)
call
).
getConnection
();
try
{
java
.
io
.
ObjectInput
in
=
call
.
getInputStream
();
if
(
in
instanceof
ObjectInputStream
)
{
/**
* Set a filter on the stream for the return value.
*/
ObjectInputStream
ois
=
(
ObjectInputStream
)
in
;
AccessController
.
doPrivileged
((
PrivilegedAction
<
Void
>)()
->
{
ObjectInputFilter
.
Config
.
setObjectInputFilter
(
ois
,
DGCImpl_Stub:
:
leaseFilter
);
return
null
;
});
}
$result
=
(
java
.
rmi
.
dgc
.
Lease
)
in
.
readObject
();
}
catch
(
java
.
io
.
IOException
|
java
.
lang
.
ClassNotFoundException
e
)
{
if
(
connection
instanceof
TCPConnection
)
{
// Modified to prevent re-use of the connection after an exception
((
TCPConnection
)
connection
).
getChannel
().
free
(
connection
,
false
);
}
throw
new
java
.
rmi
.
UnmarshalException
(
"error unmarshalling return"
,
e
);
}
finally
{
ref
.
done
(
call
);
}
return
$result
;
}
catch
(
java
.
lang
.
RuntimeException
e
)
{
throw
e
;
}
catch
(
java
.
rmi
.
RemoteException
e
)
{
throw
e
;
}
catch
(
java
.
lang
.
Exception
e
)
{
throw
new
java
.
rmi
.
UnexpectedException
(
"undeclared checked exception"
,
e
);
}
}
/**
* ObjectInputFilter to filter DGCClient return value (a Lease).
* The list of acceptable classes is very short and explicit.
* The depth and array sizes are limited.
*
* @param filterInfo access to class, arrayLength, etc.
* @return {@link ObjectInputFilter.Status#ALLOWED} if allowed,
* {@link ObjectInputFilter.Status#REJECTED} if rejected,
* otherwise {@link ObjectInputFilter.Status#UNDECIDED}
*/
private
static
ObjectInputFilter
.
Status
leaseFilter
(
ObjectInputFilter
.
FilterInfo
filterInfo
)
{
if
(
filterInfo
.
depth
()
>
DGCCLIENT_MAX_DEPTH
)
{
return
ObjectInputFilter
.
Status
.
REJECTED
;
}
Class
<?>
clazz
=
filterInfo
.
serialClass
();
if
(
clazz
!=
null
)
{
while
(
clazz
.
isArray
())
{
if
(
filterInfo
.
arrayLength
()
>=
0
&&
filterInfo
.
arrayLength
()
>
DGCCLIENT_MAX_ARRAY_SIZE
)
{
return
ObjectInputFilter
.
Status
.
REJECTED
;
}
// Arrays are allowed depending on the component type
clazz
=
clazz
.
getComponentType
();
}
if
(
clazz
.
isPrimitive
())
{
// Arrays of primitives are allowed
return
ObjectInputFilter
.
Status
.
ALLOWED
;
}
return
(
clazz
==
UID
.
class
||
clazz
==
VMID
.
class
||
clazz
==
Lease
.
class
)
?
ObjectInputFilter
.
Status
.
ALLOWED
:
ObjectInputFilter
.
Status
.
REJECTED
;
}
// Not a class, not size limited
return
ObjectInputFilter
.
Status
.
UNDECIDED
;
}
}
src/share/classes/sun/rmi/transport/StreamRemoteCall.java
浏览文件 @
1f0f864c
/*
* Copyright (c) 1996, 201
3
, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1996, 201
7
, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
...
...
@@ -167,6 +167,13 @@ public class StreamRemoteCall implements RemoteCall {
}
}
/**
* Discard any post-processing of refs the InputStream.
*/
public
void
discardPendingRefs
()
{
in
.
discardRefs
();
}
/**
* Returns an output stream (may put out header information
* relating to the success of the call).
...
...
test/java/rmi/testlibrary/TestSocketFactory.java
0 → 100644
浏览文件 @
1f0f864c
/*
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import
java.io.ByteArrayOutputStream
;
import
java.io.FilterInputStream
;
import
java.io.IOException
;
import
java.io.InputStream
;
import
java.io.OutputStream
;
import
java.io.Serializable
;
import
java.net.InetAddress
;
import
java.net.ServerSocket
;
import
java.net.Socket
;
import
java.net.SocketAddress
;
import
java.net.SocketException
;
import
java.net.SocketOption
;
import
java.nio.channels.ServerSocketChannel
;
import
java.nio.channels.SocketChannel
;
import
java.rmi.server.RMIClientSocketFactory
;
import
java.rmi.server.RMIServerSocketFactory
;
import
java.rmi.server.RMISocketFactory
;
import
java.util.ArrayList
;
import
java.util.Arrays
;
import
java.util.List
;
import
java.util.Objects
;
import
java.util.Set
;
import
org.testng.Assert
;
import
org.testng.TestNG
;
import
org.testng.annotations.Test
;
import
org.testng.annotations.DataProvider
;
/**
* A RMISocketFactory utility factory to log RMI stream contents and to
* match and replace output stream contents to simulate failures.
*/
public
class
TestSocketFactory
extends
RMISocketFactory
implements
RMIClientSocketFactory
,
RMIServerSocketFactory
,
Serializable
{
private
static
final
long
serialVersionUID
=
1L
;
private
volatile
transient
byte
[]
matchBytes
;
private
volatile
transient
byte
[]
replaceBytes
;
private
transient
final
List
<
InterposeSocket
>
sockets
=
new
ArrayList
<>();
private
transient
final
List
<
InterposeServerSocket
>
serverSockets
=
new
ArrayList
<>();
public
static
final
boolean
DEBUG
=
false
;
/**
* Debugging output can be synchronized with logging of RMI actions.
*
* @param format a printf format
* @param args any args
*/
private
static
void
DEBUG
(
String
format
,
Object
...
args
)
{
if
(
DEBUG
)
{
System
.
err
.
printf
(
format
,
args
);
}
}
/**
* Create a socket factory that creates InputStreams that log
* and OutputStreams that log .
*/
public
TestSocketFactory
()
{
this
.
matchBytes
=
new
byte
[
0
];
this
.
replaceBytes
=
this
.
matchBytes
;
System
.
out
.
printf
(
"Creating TestSocketFactory()%n"
);
}
public
void
setMatchReplaceBytes
(
byte
[]
matchBytes
,
byte
[]
replaceBytes
)
{
this
.
matchBytes
=
Objects
.
requireNonNull
(
matchBytes
,
"matchBytes"
);
this
.
replaceBytes
=
Objects
.
requireNonNull
(
replaceBytes
,
"replaceBytes"
);
sockets
.
forEach
(
s
->
s
.
setMatchReplaceBytes
(
matchBytes
,
replaceBytes
));
serverSockets
.
forEach
(
s
->
s
.
setMatchReplaceBytes
(
matchBytes
,
replaceBytes
));
}
@Override
public
Socket
createSocket
(
String
host
,
int
port
)
throws
IOException
{
Socket
socket
=
RMISocketFactory
.
getDefaultSocketFactory
()
.
createSocket
(
host
,
port
);
InterposeSocket
s
=
new
InterposeSocket
(
socket
,
matchBytes
,
replaceBytes
);
sockets
.
add
(
s
);
return
s
;
}
/**
* Return the current list of sockets.
* @return Return a snapshot of the current list of sockets
*/
public
List
<
InterposeSocket
>
getSockets
()
{
List
<
InterposeSocket
>
snap
=
new
ArrayList
<>(
sockets
);
return
snap
;
}
@Override
public
ServerSocket
createServerSocket
(
int
port
)
throws
IOException
{
ServerSocket
serverSocket
=
RMISocketFactory
.
getDefaultSocketFactory
()
.
createServerSocket
(
port
);
InterposeServerSocket
ss
=
new
InterposeServerSocket
(
serverSocket
,
matchBytes
,
replaceBytes
);
serverSockets
.
add
(
ss
);
return
ss
;
}
/**
* Return the current list of server sockets.
* @return Return a snapshot of the current list of server sockets
*/
public
List
<
InterposeServerSocket
>
getServerSockets
()
{
List
<
InterposeServerSocket
>
snap
=
new
ArrayList
<>(
serverSockets
);
return
snap
;
}
/**
* An InterposeSocket wraps a socket that produces InputStreams
* and OutputStreams that log the traffic.
* The OutputStreams it produces match an array of bytes and replace them.
* Useful for injecting protocol and content errors.
*/
public
static
class
InterposeSocket
extends
Socket
{
private
final
Socket
socket
;
private
InputStream
in
;
private
MatchReplaceOutputStream
out
;
private
volatile
byte
[]
matchBytes
;
private
volatile
byte
[]
replaceBytes
;
private
final
ByteArrayOutputStream
inLogStream
;
private
final
ByteArrayOutputStream
outLogStream
;
private
final
String
name
;
private
static
volatile
int
num
=
0
;
// index for created InterposeSockets
public
InterposeSocket
(
Socket
socket
,
byte
[]
matchBytes
,
byte
[]
replaceBytes
)
{
this
.
socket
=
socket
;
this
.
matchBytes
=
Objects
.
requireNonNull
(
matchBytes
,
"matchBytes"
);
this
.
replaceBytes
=
Objects
.
requireNonNull
(
replaceBytes
,
"replaceBytes"
);
this
.
inLogStream
=
new
ByteArrayOutputStream
();
this
.
outLogStream
=
new
ByteArrayOutputStream
();
this
.
name
=
"IS"
+
++
num
+
"::"
+
Thread
.
currentThread
().
getName
()
+
": "
+
socket
.
getLocalPort
()
+
" < "
+
socket
.
getPort
();
}
public
void
setMatchReplaceBytes
(
byte
[]
matchBytes
,
byte
[]
replaceBytes
)
{
this
.
matchBytes
=
matchBytes
;
this
.
replaceBytes
=
replaceBytes
;
out
.
setMatchReplaceBytes
(
matchBytes
,
replaceBytes
);
}
@Override
public
void
connect
(
SocketAddress
endpoint
)
throws
IOException
{
socket
.
connect
(
endpoint
);
}
@Override
public
void
connect
(
SocketAddress
endpoint
,
int
timeout
)
throws
IOException
{
socket
.
connect
(
endpoint
,
timeout
);
}
@Override
public
void
bind
(
SocketAddress
bindpoint
)
throws
IOException
{
socket
.
bind
(
bindpoint
);
}
@Override
public
InetAddress
getInetAddress
()
{
return
socket
.
getInetAddress
();
}
@Override
public
InetAddress
getLocalAddress
()
{
return
socket
.
getLocalAddress
();
}
@Override
public
int
getPort
()
{
return
socket
.
getPort
();
}
@Override
public
int
getLocalPort
()
{
return
socket
.
getLocalPort
();
}
@Override
public
SocketAddress
getRemoteSocketAddress
()
{
return
socket
.
getRemoteSocketAddress
();
}
@Override
public
SocketAddress
getLocalSocketAddress
()
{
return
socket
.
getLocalSocketAddress
();
}
@Override
public
SocketChannel
getChannel
()
{
return
socket
.
getChannel
();
}
@Override
public
synchronized
void
close
()
throws
IOException
{
socket
.
close
();
}
@Override
public
String
toString
()
{
return
"InterposeSocket "
+
name
+
": "
+
socket
.
toString
();
}
@Override
public
boolean
isConnected
()
{
return
socket
.
isConnected
();
}
@Override
public
boolean
isBound
()
{
return
socket
.
isBound
();
}
@Override
public
boolean
isClosed
()
{
return
socket
.
isClosed
();
}
@Override
public
synchronized
InputStream
getInputStream
()
throws
IOException
{
if
(
in
==
null
)
{
in
=
socket
.
getInputStream
();
String
name
=
Thread
.
currentThread
().
getName
()
+
": "
+
socket
.
getLocalPort
()
+
" < "
+
socket
.
getPort
();
in
=
new
LoggingInputStream
(
in
,
name
,
inLogStream
);
DEBUG
(
"Created new InterposeInputStream: %s%n"
,
name
);
}
return
in
;
}
@Override
public
synchronized
OutputStream
getOutputStream
()
throws
IOException
{
if
(
out
==
null
)
{
OutputStream
o
=
socket
.
getOutputStream
();
String
name
=
Thread
.
currentThread
().
getName
()
+
": "
+
socket
.
getLocalPort
()
+
" > "
+
socket
.
getPort
();
out
=
new
MatchReplaceOutputStream
(
o
,
name
,
outLogStream
,
matchBytes
,
replaceBytes
);
DEBUG
(
"Created new MatchReplaceOutputStream: %s%n"
,
name
);
}
return
out
;
}
/**
* Return the bytes logged from the input stream.
* @return Return the bytes logged from the input stream.
*/
public
byte
[]
getInLogBytes
()
{
return
inLogStream
.
toByteArray
();
}
/**
* Return the bytes logged from the output stream.
* @return Return the bytes logged from the output stream.
*/
public
byte
[]
getOutLogBytes
()
{
return
outLogStream
.
toByteArray
();
}
}
/**
* InterposeServerSocket is a ServerSocket that wraps each Socket it accepts
* with an InterposeSocket so that its input and output streams can be monitored.
*/
public
static
class
InterposeServerSocket
extends
ServerSocket
{
private
final
ServerSocket
socket
;
private
volatile
byte
[]
matchBytes
;
private
volatile
byte
[]
replaceBytes
;
private
final
List
<
InterposeSocket
>
sockets
=
new
ArrayList
<>();
public
InterposeServerSocket
(
ServerSocket
socket
,
byte
[]
matchBytes
,
byte
[]
replaceBytes
)
throws
IOException
{
this
.
socket
=
socket
;
this
.
matchBytes
=
Objects
.
requireNonNull
(
matchBytes
,
"matchBytes"
);
this
.
replaceBytes
=
Objects
.
requireNonNull
(
replaceBytes
,
"replaceBytes"
);
}
public
void
setMatchReplaceBytes
(
byte
[]
matchBytes
,
byte
[]
replaceBytes
)
{
this
.
matchBytes
=
matchBytes
;
this
.
replaceBytes
=
replaceBytes
;
sockets
.
forEach
(
s
->
s
.
setMatchReplaceBytes
(
matchBytes
,
replaceBytes
));
}
/**
* Return a snapshot of the current list of sockets created from this server socket.
* @return Return a snapshot of the current list of sockets
*/
public
List
<
InterposeSocket
>
getSockets
()
{
List
<
InterposeSocket
>
snap
=
new
ArrayList
<>(
sockets
);
return
snap
;
}
@Override
public
void
bind
(
SocketAddress
endpoint
)
throws
IOException
{
socket
.
bind
(
endpoint
);
}
@Override
public
void
bind
(
SocketAddress
endpoint
,
int
backlog
)
throws
IOException
{
socket
.
bind
(
endpoint
,
backlog
);
}
@Override
public
InetAddress
getInetAddress
()
{
return
socket
.
getInetAddress
();
}
@Override
public
int
getLocalPort
()
{
return
socket
.
getLocalPort
();
}
@Override
public
SocketAddress
getLocalSocketAddress
()
{
return
socket
.
getLocalSocketAddress
();
}
@Override
public
Socket
accept
()
throws
IOException
{
Socket
s
=
socket
.
accept
();
InterposeSocket
socket
=
new
InterposeSocket
(
s
,
matchBytes
,
replaceBytes
);
sockets
.
add
(
socket
);
return
socket
;
}
@Override
public
void
close
()
throws
IOException
{
socket
.
close
();
}
@Override
public
ServerSocketChannel
getChannel
()
{
return
socket
.
getChannel
();
}
@Override
public
boolean
isClosed
()
{
return
socket
.
isClosed
();
}
@Override
public
String
toString
()
{
return
socket
.
toString
();
}
@Override
public
synchronized
void
setSoTimeout
(
int
timeout
)
throws
SocketException
{
socket
.
setSoTimeout
(
timeout
);
}
@Override
public
synchronized
int
getSoTimeout
()
throws
IOException
{
return
socket
.
getSoTimeout
();
}
}
/**
* LoggingInputStream is a stream and logs all bytes read to it.
* For identification it is given a name.
*/
public
static
class
LoggingInputStream
extends
FilterInputStream
{
private
int
bytesIn
=
0
;
private
final
String
name
;
private
final
OutputStream
log
;
public
LoggingInputStream
(
InputStream
in
,
String
name
,
OutputStream
log
)
{
super
(
in
);
this
.
name
=
name
;
this
.
log
=
log
;
}
@Override
public
int
read
()
throws
IOException
{
int
b
=
super
.
read
();
if
(
b
>=
0
)
{
log
.
write
(
b
);
bytesIn
++;
}
return
b
;
}
@Override
public
int
read
(
byte
[]
b
,
int
off
,
int
len
)
throws
IOException
{
int
bytes
=
super
.
read
(
b
,
off
,
len
);
if
(
bytes
>
0
)
{
log
.
write
(
b
,
off
,
bytes
);
bytesIn
+=
bytes
;
}
return
bytes
;
}
@Override
public
int
read
(
byte
[]
b
)
throws
IOException
{
return
read
(
b
,
0
,
b
.
length
);
}
@Override
public
void
close
()
throws
IOException
{
super
.
close
();
}
@Override
public
String
toString
()
{
return
String
.
format
(
"%s: In: (%d)"
,
name
,
bytesIn
);
}
}
/**
* An OutputStream that replaces one string of bytes with another.
* If any range matches, the match starts after the partial match.
*/
static
class
MatchReplaceOutputStream
extends
OutputStream
{
private
final
OutputStream
out
;
private
final
String
name
;
private
volatile
byte
[]
matchBytes
;
private
volatile
byte
[]
replaceBytes
;
int
matchIndex
;
private
int
bytesOut
=
0
;
private
final
OutputStream
log
;
MatchReplaceOutputStream
(
OutputStream
out
,
String
name
,
OutputStream
log
,
byte
[]
matchBytes
,
byte
[]
replaceBytes
)
{
this
.
out
=
out
;
this
.
name
=
name
;
this
.
matchBytes
=
Objects
.
requireNonNull
(
matchBytes
,
"matchBytes"
);
this
.
replaceBytes
=
Objects
.
requireNonNull
(
replaceBytes
,
"replaceBytes"
);
matchIndex
=
0
;
this
.
log
=
log
;
}
public
void
setMatchReplaceBytes
(
byte
[]
matchBytes
,
byte
[]
replaceBytes
)
{
this
.
matchBytes
=
matchBytes
;
this
.
replaceBytes
=
replaceBytes
;
matchIndex
=
0
;
}
public
void
write
(
int
b
)
throws
IOException
{
b
=
b
&
0xff
;
if
(
matchBytes
.
length
==
0
)
{
out
.
write
(
b
);
log
.
write
(
b
);
bytesOut
++;
return
;
}
if
(
b
==
(
matchBytes
[
matchIndex
]
&
0xff
))
{
if
(++
matchIndex
>=
matchBytes
.
length
)
{
matchIndex
=
0
;
DEBUG
(
"TestSocketFactory MatchReplace %s replaced %d bytes at offset: %d (x%04x)%n"
,
name
,
replaceBytes
.
length
,
bytesOut
,
bytesOut
);
out
.
write
(
replaceBytes
);
log
.
write
(
replaceBytes
);
bytesOut
+=
replaceBytes
.
length
;
}
}
else
{
if
(
matchIndex
>
0
)
{
// mismatch, write out any that matched already
if
(
matchIndex
>
0
)
// Only non-trivial matches
DEBUG
(
"Partial match %s matched %d bytes at offset: %d (0x%04x), expected: x%02x, actual: x%02x%n"
,
name
,
matchIndex
,
bytesOut
,
bytesOut
,
matchBytes
[
matchIndex
],
b
);
out
.
write
(
matchBytes
,
0
,
matchIndex
);
log
.
write
(
matchBytes
,
0
,
matchIndex
);
bytesOut
+=
matchIndex
;
matchIndex
=
0
;
}
if
(
b
==
(
matchBytes
[
matchIndex
]
&
0xff
))
{
matchIndex
++;
}
else
{
out
.
write
(
b
);
log
.
write
(
b
);
bytesOut
++;
}
}
}
@Override
public
String
toString
()
{
return
String
.
format
(
"%s: Out: (%d)"
,
name
,
bytesOut
);
}
}
private
static
byte
[]
orig
=
new
byte
[]{
(
byte
)
0x80
,
0x05
,
0x73
,
0x72
,
0x00
,
0x12
,
// TC_OBJECT, TC_CLASSDESC, length = 18
0x6A
,
0x61
,
0x76
,
0x61
,
0x2E
,
0x72
,
0x6D
,
0x69
,
0x2E
,
// "java.rmi."
0x64
,
0x67
,
0x63
,
0x2E
,
0x4C
,
0x65
,
0x61
,
0x73
,
0x65
// "dgc.Lease"
};
private
static
byte
[]
repl
=
new
byte
[]{
(
byte
)
0x80
,
0x05
,
0x73
,
0x72
,
0x00
,
0x12
,
// TC_OBJECT, TC_CLASSDESC, length = 18
0x6A
,
0x61
,
0x76
,
0x61
,
0x2E
,
(
byte
)
'l'
,
(
byte
)
'a'
,
(
byte
)
'n'
,
(
byte
)
'g'
,
0x2E
,
(
byte
)
'R'
,
(
byte
)
'u'
,
(
byte
)
'n'
,
(
byte
)
'n'
,
(
byte
)
'a'
,
(
byte
)
'b'
,
(
byte
)
'l'
,
(
byte
)
'e'
};
@DataProvider
(
name
=
"MatchReplaceData"
)
static
Object
[][]
matchReplaceData
()
{
byte
[]
empty
=
new
byte
[
0
];
byte
[]
byte1
=
new
byte
[]{
1
,
2
,
3
,
4
,
5
,
6
};
byte
[]
bytes2
=
new
byte
[]{
1
,
2
,
4
,
3
,
5
,
6
};
byte
[]
bytes3
=
new
byte
[]{
6
,
5
,
4
,
3
,
2
,
1
};
byte
[]
bytes4
=
new
byte
[]{
1
,
2
,
0x10
,
0x20
,
0x30
,
0x40
,
5
,
6
};
byte
[]
bytes4a
=
new
byte
[]{
1
,
2
,
0x10
,
0x20
,
0x30
,
0x40
,
5
,
7
};
// mostly matches bytes4
byte
[]
bytes5
=
new
byte
[]{
0x30
,
0x40
,
5
,
6
};
byte
[]
bytes6
=
new
byte
[]{
1
,
2
,
0x10
,
0x20
,
0x30
};
return
new
Object
[][]{
{
new
byte
[]{},
new
byte
[]{},
empty
,
empty
},
{
new
byte
[]{},
new
byte
[]{},
byte1
,
byte1
},
{
new
byte
[]{
3
,
4
},
new
byte
[]{
4
,
3
},
byte1
,
bytes2
},
//swap bytes
{
new
byte
[]{
3
,
4
},
new
byte
[]{
0x10
,
0x20
,
0x30
,
0x40
},
byte1
,
bytes4
},
// insert
{
new
byte
[]{
1
,
2
,
0x10
,
0x20
},
new
byte
[]{},
bytes4
,
bytes5
},
// delete head
{
new
byte
[]{
0x40
,
5
,
6
},
new
byte
[]{},
bytes4
,
bytes6
},
// delete tail
{
new
byte
[]{
0x40
,
0x50
},
new
byte
[]{
0x60
,
0x50
},
bytes4
,
bytes4
},
// partial match, replace nothing
{
bytes4a
,
bytes3
,
bytes4
,
bytes4
},
// long partial match, not replaced
{
orig
,
repl
,
orig
,
repl
},
};
}
@Test
(
enabled
=
true
,
dataProvider
=
"MatchReplaceData"
)
static
void
test3
(
byte
[]
match
,
byte
[]
replace
,
byte
[]
input
,
byte
[]
expected
)
{
System
.
out
.
printf
(
"match: %s, replace: %s%n"
,
Arrays
.
toString
(
match
),
Arrays
.
toString
(
replace
));
try
(
ByteArrayOutputStream
output
=
new
ByteArrayOutputStream
();
ByteArrayOutputStream
log
=
new
ByteArrayOutputStream
();
OutputStream
out
=
new
MatchReplaceOutputStream
(
output
,
"test3"
,
log
,
match
,
replace
))
{
out
.
write
(
input
);
byte
[]
actual
=
output
.
toByteArray
();
if
(!
Arrays
.
equals
(
actual
,
expected
))
{
System
.
out
.
printf
(
"actual: %s%n"
,
Arrays
.
toString
(
actual
));
System
.
out
.
printf
(
"expected: %s%n"
,
Arrays
.
toString
(
expected
));
}
Assert
.
assertEquals
(
actual
,
expected
,
"match/replace fail"
);
}
catch
(
IOException
ioe
)
{
Assert
.
fail
(
"unexpected exception"
,
ioe
);
}
}
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录