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.buffer.ByteBufAllocator;
19 import io.netty.util.IllegalReferenceCountException;
20
21 import javax.net.ssl.X509KeyManager;
22 import java.util.concurrent.ConcurrentHashMap;
23
24
25
26
27
28
29
30
31
32
33
34 final class OpenSslCachingKeyMaterialProvider extends OpenSslKeyMaterialProvider {
35
36 private final int maxCachedEntries;
37 private final ConcurrentHashMap<String, OpenSslKeyMaterial> cache =
38 new ConcurrentHashMap<String, OpenSslKeyMaterial>();
39 private volatile boolean destroyed;
40
41 OpenSslCachingKeyMaterialProvider(X509KeyManager keyManager, String password, int maxEntries) {
42 super(keyManager, password);
43 maxCachedEntries = maxEntries;
44 }
45
46
47
48
49
50
51 private OpenSslKeyMaterial getAndRetain(String alias) {
52 OpenSslKeyMaterial m = cache.get(alias);
53 if (m != null) {
54 try {
55 return m.retain();
56 } catch (IllegalReferenceCountException e) {
57 return null;
58 }
59 }
60 return null;
61 }
62
63
64
65
66 private OpenSslKeyMaterial putIfAbsentAndRetain(String alias, OpenSslKeyMaterial material) {
67 return cache.compute(alias, (k, existing) -> {
68 if (existing != null) {
69 existing.retain();
70 return existing;
71 }
72 material.retain();
73 return material;
74 });
75 }
76
77
78
79
80 private void removeAndRelease(String alias) {
81 cache.computeIfPresent(alias, (k, v) -> {
82 v.release();
83 return null;
84 });
85 }
86
87 private void evictStaleEntries() {
88 for (String alias : cache.keySet()) {
89 if (keyManager().getCertificateChain(alias) == null) {
90 removeAndRelease(alias);
91 }
92 }
93 }
94
95 @Override
96 OpenSslKeyMaterial chooseKeyMaterial(ByteBufAllocator allocator, String alias) throws Exception {
97 OpenSslKeyMaterial material = getAndRetain(alias);
98 if (material == null) {
99 material = super.chooseKeyMaterial(allocator, alias);
100 if (material == null) {
101 return null;
102 }
103
104 if (cache.size() >= maxCachedEntries) {
105 evictStaleEntries();
106 if (cache.size() >= maxCachedEntries) {
107 return material;
108 }
109 }
110
111 OpenSslKeyMaterial old = putIfAbsentAndRetain(alias, material);
112 if (old != material) {
113 material.release();
114 material = old;
115 } else if (destroyed) {
116
117 removeAndReleaseAllEntries();
118 }
119 }
120 return material;
121 }
122
123 int cacheSize() {
124 return cache.size();
125 }
126
127 @Override
128 void destroy() {
129 destroyed = true;
130 try {
131 removeAndReleaseAllEntries();
132 } finally {
133 super.destroy();
134 }
135 }
136
137 private void removeAndReleaseAllEntries() {
138 do {
139 for (String alias : cache.keySet()) {
140 removeAndRelease(alias);
141 }
142 } while (!cache.isEmpty());
143 }
144 }