Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/security/pkcs11/SessionManager.java
38919 views
1
/*
2
* Copyright (c) 2003, 2014, 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.security.pkcs11;
27
28
import java.util.*;
29
30
import java.security.ProviderException;
31
32
import sun.security.util.Debug;
33
34
import sun.security.pkcs11.wrapper.*;
35
import static sun.security.pkcs11.wrapper.PKCS11Constants.*;
36
37
import java.util.concurrent.ConcurrentLinkedDeque;
38
import java.util.concurrent.atomic.AtomicInteger;
39
40
/**
41
* Session manager. There is one session manager object per PKCS#11
42
* provider. It allows code to checkout a session, release it
43
* back to the pool, or force it to be closed.
44
*
45
* The session manager pools sessions to minimize the number of
46
* C_OpenSession() and C_CloseSession() that have to be made. It
47
* maintains two pools: one for "object" sessions and one for
48
* "operation" sessions.
49
*
50
* The reason for this separation is how PKCS#11 deals with session objects.
51
* It defines that when a session is closed, all objects created within
52
* that session are destroyed. In other words, we may never close a session
53
* while a Key created it in is still in use. We would like to keep the
54
* number of such sessions low. Note that we occasionally want to explicitly
55
* close a session, see P11Signature.
56
*
57
* NOTE that sessions obtained from this class SHOULD be returned using
58
* either releaseSession() or closeSession() using a finally block when
59
* not needed anymore. Otherwise, they will be left for cleanup via the
60
* PhantomReference mechanism when GC kicks in, but it's best not to rely
61
* on that since GC may not run timely enough since the native PKCS11 library
62
* is also consuming memory.
63
*
64
* Note that sessions are automatically closed when they are not used for a
65
* period of time, see Session.
66
*
67
* @author Andreas Sterbenz
68
* @since 1.5
69
*/
70
final class SessionManager {
71
72
private final static int DEFAULT_MAX_SESSIONS = 32;
73
74
private final static Debug debug = Debug.getInstance("pkcs11");
75
76
// token instance
77
private final Token token;
78
79
// maximum number of sessions to open with this token
80
private final int maxSessions;
81
82
// total number of active sessions
83
private AtomicInteger activeSessions = new AtomicInteger();
84
85
// pool of available object sessions
86
private final Pool objSessions;
87
88
// pool of available operation sessions
89
private final Pool opSessions;
90
91
// maximum number of active sessions during this invocation, for debugging
92
private int maxActiveSessions;
93
private Object maxActiveSessionsLock;
94
95
// flags to use in the C_OpenSession() call
96
private final long openSessionFlags;
97
98
SessionManager(Token token) {
99
long n;
100
if (token.isWriteProtected()) {
101
openSessionFlags = CKF_SERIAL_SESSION;
102
n = token.tokenInfo.ulMaxSessionCount;
103
} else {
104
openSessionFlags = CKF_SERIAL_SESSION | CKF_RW_SESSION;
105
n = token.tokenInfo.ulMaxRwSessionCount;
106
}
107
if (n == CK_EFFECTIVELY_INFINITE) {
108
n = Integer.MAX_VALUE;
109
} else if ((n == CK_UNAVAILABLE_INFORMATION) || (n < 0)) {
110
// choose an arbitrary concrete value
111
n = DEFAULT_MAX_SESSIONS;
112
}
113
maxSessions = (int)Math.min(n, Integer.MAX_VALUE);
114
this.token = token;
115
this.objSessions = new Pool(this);
116
this.opSessions = new Pool(this);
117
if (debug != null) {
118
maxActiveSessionsLock = new Object();
119
}
120
}
121
122
// returns whether only a fairly low number of sessions are
123
// supported by this token.
124
boolean lowMaxSessions() {
125
return (maxSessions <= DEFAULT_MAX_SESSIONS);
126
}
127
128
Session getObjSession() throws PKCS11Exception {
129
Session session = objSessions.poll();
130
if (session != null) {
131
return ensureValid(session);
132
}
133
session = opSessions.poll();
134
if (session != null) {
135
return ensureValid(session);
136
}
137
session = openSession();
138
return ensureValid(session);
139
}
140
141
Session getOpSession() throws PKCS11Exception {
142
Session session = opSessions.poll();
143
if (session != null) {
144
return ensureValid(session);
145
}
146
// create a new session rather than re-using an obj session
147
// that avoids potential expensive cancels() for Signatures & RSACipher
148
if (maxSessions == Integer.MAX_VALUE ||
149
activeSessions.get() < maxSessions) {
150
session = openSession();
151
return ensureValid(session);
152
}
153
session = objSessions.poll();
154
if (session != null) {
155
return ensureValid(session);
156
}
157
throw new ProviderException("Could not obtain session");
158
}
159
160
private Session ensureValid(Session session) {
161
session.id();
162
return session;
163
}
164
165
Session killSession(Session session) {
166
if ((session == null) || (token.isValid() == false)) {
167
return null;
168
}
169
if (debug != null) {
170
String location = new Exception().getStackTrace()[2].toString();
171
System.out.println("Killing session (" + location + ") active: "
172
+ activeSessions.get());
173
}
174
closeSession(session);
175
return null;
176
}
177
178
Session releaseSession(Session session) {
179
if ((session == null) || (token.isValid() == false)) {
180
return null;
181
}
182
183
if (session.hasObjects()) {
184
objSessions.release(session);
185
} else {
186
opSessions.release(session);
187
}
188
return null;
189
}
190
191
void demoteObjSession(Session session) {
192
if (token.isValid() == false) {
193
return;
194
}
195
if (debug != null) {
196
System.out.println("Demoting session, active: " +
197
activeSessions.get());
198
}
199
boolean present = objSessions.remove(session);
200
if (present == false) {
201
// session is currently in use
202
// will be added to correct pool on release, nothing to do now
203
return;
204
}
205
opSessions.release(session);
206
}
207
208
private Session openSession() throws PKCS11Exception {
209
if ((maxSessions != Integer.MAX_VALUE) &&
210
(activeSessions.get() >= maxSessions)) {
211
throw new ProviderException("No more sessions available");
212
}
213
214
long id = token.p11.C_OpenSession
215
(token.provider.slotID, openSessionFlags, null, null);
216
Session session = new Session(token, id);
217
activeSessions.incrementAndGet();
218
if (debug != null) {
219
synchronized(maxActiveSessionsLock) {
220
if (activeSessions.get() > maxActiveSessions) {
221
maxActiveSessions = activeSessions.get();
222
if (maxActiveSessions % 10 == 0) {
223
System.out.println("Open sessions: " + maxActiveSessions);
224
}
225
}
226
}
227
}
228
return session;
229
}
230
231
private void closeSession(Session session) {
232
session.close();
233
activeSessions.decrementAndGet();
234
}
235
236
public static final class Pool {
237
238
private final SessionManager mgr;
239
240
private final ConcurrentLinkedDeque<Session> pool;
241
242
Pool(SessionManager mgr) {
243
this.mgr = mgr;
244
pool = new ConcurrentLinkedDeque<Session>();
245
}
246
247
boolean remove(Session session) {
248
return pool.remove(session);
249
}
250
251
Session poll() {
252
return pool.pollLast();
253
}
254
255
void release(Session session) {
256
pool.offer(session);
257
if (session.hasObjects()) {
258
return;
259
}
260
261
int n = pool.size();
262
if (n < 5) {
263
return;
264
}
265
266
Session oldestSession;
267
long time = System.currentTimeMillis();
268
int i = 0;
269
// Check if the session head is too old and continue through queue
270
// until only one is left.
271
do {
272
oldestSession = pool.peek();
273
if (oldestSession == null || oldestSession.isLive(time) ||
274
!pool.remove(oldestSession)) {
275
break;
276
}
277
278
i++;
279
mgr.closeSession(oldestSession);
280
} while ((n - i) > 1);
281
282
if (debug != null) {
283
System.out.println("Closing " + i + " idle sessions, active: "
284
+ mgr.activeSessions);
285
}
286
}
287
288
}
289
290
}
291
292