1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty.handler.ssl;
17
18 import io.netty.internal.tcnative.SSL;
19 import io.netty.util.AsciiString;
20
21 import java.util.ArrayList;
22 import java.util.HashMap;
23 import java.util.HashSet;
24 import java.util.List;
25 import java.util.Map;
26 import java.util.Set;
27
28
29
30
31 final class OpenSslClientSessionCache extends OpenSslSessionCache {
32 private final Map<HostPort, Set<NativeSslSession>> sessions = new HashMap<HostPort, Set<NativeSslSession>>();
33
34 OpenSslClientSessionCache(OpenSslEngineMap engineMap) {
35 super(engineMap);
36 }
37
38 @Override
39 protected boolean sessionCreated(NativeSslSession session) {
40 assert Thread.holdsLock(this);
41 HostPort hostPort = keyFor(session.getPeerHost(), session.getPeerPort());
42 if (hostPort == null) {
43 return false;
44 }
45 Set<NativeSslSession> sessionsForHost = sessions.get(hostPort);
46 if (sessionsForHost == null) {
47
48
49 sessionsForHost = new HashSet<NativeSslSession>(4);
50 sessions.put(hostPort, sessionsForHost);
51 }
52 sessionsForHost.add(session);
53 return true;
54 }
55
56 @Override
57 protected void sessionRemoved(NativeSslSession session) {
58 assert Thread.holdsLock(this);
59 HostPort hostPort = keyFor(session.getPeerHost(), session.getPeerPort());
60 if (hostPort == null) {
61 return;
62 }
63 Set<NativeSslSession> sessionsForHost = sessions.get(hostPort);
64 if (sessionsForHost != null) {
65 sessionsForHost.remove(session);
66 if (sessionsForHost.isEmpty()) {
67 sessions.remove(hostPort);
68 }
69 }
70 }
71
72 @Override
73 boolean setSession(long ssl, OpenSslSession session, String host, int port) {
74 HostPort hostPort = keyFor(host, port);
75 if (hostPort == null) {
76 return false;
77 }
78 NativeSslSession nativeSslSession = null;
79 final boolean reused;
80 boolean singleUsed = false;
81 synchronized (this) {
82 Set<NativeSslSession> sessionsForHost = sessions.get(hostPort);
83 if (sessionsForHost == null) {
84 return false;
85 }
86 if (sessionsForHost.isEmpty()) {
87 sessions.remove(hostPort);
88
89 return false;
90 }
91
92 List<NativeSslSession> toBeRemoved = null;
93
94 for (NativeSslSession sslSession : sessionsForHost) {
95 if (sslSession.isValid()) {
96 nativeSslSession = sslSession;
97 break;
98 } else {
99 if (toBeRemoved == null) {
100 toBeRemoved = new ArrayList<NativeSslSession>(2);
101 }
102 toBeRemoved.add(sslSession);
103 }
104 }
105
106
107 if (toBeRemoved != null) {
108 for (NativeSslSession sslSession : toBeRemoved) {
109 removeSessionWithId(sslSession.sessionId());
110 }
111 }
112 if (nativeSslSession == null) {
113
114 return false;
115 }
116
117
118
119 reused = SSL.setSession(ssl, nativeSslSession.session());
120 if (reused) {
121 singleUsed = nativeSslSession.shouldBeSingleUse();
122 }
123 }
124
125 if (reused) {
126 if (singleUsed) {
127
128 nativeSslSession.invalidate();
129 session.invalidate();
130 }
131 nativeSslSession.setLastAccessedTime(System.currentTimeMillis());
132 session.setSessionDetails(nativeSslSession.getCreationTime(), nativeSslSession.getLastAccessedTime(),
133 nativeSslSession.sessionId(), nativeSslSession.keyValueStorage);
134 }
135 return reused;
136 }
137
138 private static HostPort keyFor(String host, int port) {
139 if (host == null && port < 1) {
140 return null;
141 }
142 return new HostPort(host, port);
143 }
144
145 @Override
146 synchronized void clear() {
147 super.clear();
148 sessions.clear();
149 }
150
151
152
153
154 private static final class HostPort {
155 private final int hash;
156 private final String host;
157 private final int port;
158
159 HostPort(String host, int port) {
160 this.host = host;
161 this.port = port;
162
163 this.hash = 31 * AsciiString.hashCode(host) + port;
164 }
165
166 @Override
167 public int hashCode() {
168 return hash;
169 }
170
171 @Override
172 public boolean equals(Object obj) {
173 if (!(obj instanceof HostPort)) {
174 return false;
175 }
176 HostPort other = (HostPort) obj;
177 return port == other.port && host.equalsIgnoreCase(other.host);
178 }
179
180 @Override
181 public String toString() {
182 return "HostPort{" +
183 "host='" + host + '\'' +
184 ", port=" + port +
185 '}';
186 }
187 }
188 }