History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/sun/security/pkcs11/SessionManager.java (1 of 18352 files). Show all

Unified · Split

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