1f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
2f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Copyright (C) 2009 The Android Open Source Project
3f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
4f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
5f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * you may not use this file except in compliance with the License.
6f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * You may obtain a copy of the License at
7f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
8f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
9f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
10f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
11f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
12f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * See the License for the specific language governing permissions and
14f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * limitations under the License.
15f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
16f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
17f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectpackage org.apache.harmony.xnet.provider.jsse;
18f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
19f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.util.LinkedHashMap;
20f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.util.Map;
21f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.util.Iterator;
22f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.util.ArrayList;
23f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.util.Arrays;
24f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
25f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport javax.net.ssl.SSLSession;
26f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
27f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/**
28f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Caches server sessions. Indexes by session ID. Users typically look up
29f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * sessions using the ID provided by an SSL client.
30f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
31f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectpublic class ServerSessionContext extends AbstractSessionContext {
32f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
33f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /*
34f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * TODO: Expire timed-out sessions more pro-actively.
35f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
36f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
37f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private final Map<ByteArray, SSLSession> sessions
38f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            = new LinkedHashMap<ByteArray, SSLSession>() {
39f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        @Override
40f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        protected boolean removeEldestEntry(
41f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                Map.Entry<ByteArray, SSLSession> eldest) {
42f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return maximumSize > 0 && size() > maximumSize;
43f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
44f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    };
45f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
46f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private final SSLServerSessionCache persistentCache;
47f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
48f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public ServerSessionContext(SSLParameters parameters,
49f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            SSLServerSessionCache persistentCache) {
50f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        super(parameters, 100, 0);
51f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.persistentCache = persistentCache;
52f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
53f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
54f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    Iterator<SSLSession> sessionIterator() {
55f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        synchronized (sessions) {
56f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            SSLSession[] array = sessions.values().toArray(
57f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    new SSLSession[sessions.size()]);
58f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return Arrays.asList(array).iterator();
59f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
60f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
61f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
62f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    void trimToSize() {
63f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        synchronized (sessions) {
64f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            int size = sessions.size();
65f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (size > maximumSize) {
66f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                int removals = size - maximumSize;
67f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                Iterator<SSLSession> i = sessions.values().iterator();
68f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                do {
69f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    i.next();
70f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    i.remove();
71f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                } while (--removals > 0);
72f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
73f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
74f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
75f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
76f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public void setSessionTimeout(int seconds)
77f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            throws IllegalArgumentException {
78f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (seconds < 0) {
79f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            throw new IllegalArgumentException("seconds < 0");
80f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
81f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        timeout = seconds;
82f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
83f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
84f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public SSLSession getSession(byte[] sessionId) {
85f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        ByteArray key = new ByteArray(sessionId);
86f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        synchronized (sessions) {
87f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            SSLSession session = sessions.get(key);
88f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (session != null) {
89f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                return session;
90f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
91f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
92f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
93f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        // Check persistent cache.
94f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (persistentCache != null) {
95f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            byte[] data = persistentCache.getSessionData(sessionId);
96f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (data != null) {
97f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                SSLSession session = toSession(data, null, -1);
98f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                if (session != null) {
99f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    synchronized (sessions) {
100f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        sessions.put(key, session);
101f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    }
102f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    return session;
103f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
104f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
105f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
106f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
107f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return null;
108f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
109f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
110f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    void putSession(SSLSession session) {
111f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        ByteArray key = new ByteArray(session.getId());
112f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        synchronized (sessions) {
113f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            sessions.put(key, session);
114f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
115f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
116f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        // TODO: In background thread.
117f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (persistentCache != null) {
118f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            byte[] data = toBytes(session);
119f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (data != null) {
120f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                persistentCache.putSessionData(session, data);
121f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
122f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
123f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
124f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
125