• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 /*
18  * Copyright 2017 The Netty Project
19  *
20  * The Netty Project licenses this file to you under the Apache License,
21  * version 2.0 (the "License"); you may not use this file except in compliance
22  * with the License. You may obtain a copy of the License at:
23  *
24  *   http://www.apache.org/licenses/LICENSE-2.0
25  *
26  * Unless required by applicable law or agreed to in writing, software
27  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
28  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
29  * License for the specific language governing permissions and limitations
30  * under the License.
31  */
32 
33 package org.conscrypt;
34 
35 import java.nio.ByteBuffer;
36 import javax.net.ssl.SSLEngine;
37 import javax.net.ssl.SSLEngineResult;
38 import javax.net.ssl.SSLEngineResult.HandshakeStatus;
39 import javax.net.ssl.SSLException;
40 
41 /**
42  * Benchmark comparing handshake performance of various engine implementations to conscrypt.
43  */
44 public final class EngineHandshakeBenchmark {
45     /**
46      * Provider for the benchmark configuration
47      */
48     interface Config {
bufferType()49         BufferType bufferType();
engineFactory()50         EngineFactory engineFactory();
cipher()51         String cipher();
useAlpn()52         boolean useAlpn();
protocol()53         BenchmarkProtocol protocol();
rttMillis()54         int rttMillis();
55     }
56 
57     private static final ByteBuffer EMPTY_BUFFER = ByteBuffer.allocateDirect(0);
58 
59     private final EngineFactory engineFactory;
60     private final String cipher;
61     private final boolean useAlpn;
62     private final String[] protocols;
63     private final int rttMillis;
64 
65     private final ByteBuffer clientApplicationBuffer;
66     private final ByteBuffer clientPacketBuffer;
67     private final ByteBuffer serverApplicationBuffer;
68     private final ByteBuffer serverPacketBuffer;
69 
EngineHandshakeBenchmark(Config config)70     EngineHandshakeBenchmark(Config config) throws Exception {
71         engineFactory = config.engineFactory();
72         cipher = config.cipher();
73         useAlpn = config.useAlpn();
74         protocols = config.protocol().getProtocols();
75         rttMillis = config.rttMillis();
76         BufferType bufferType = config.bufferType();
77 
78         SSLEngine clientEngine = engineFactory.newClientEngine(cipher, useAlpn);
79         SSLEngine serverEngine = engineFactory.newServerEngine(cipher, useAlpn);
80 
81         // Create the application and packet buffers for both endpoints.
82         clientApplicationBuffer = bufferType.newApplicationBuffer(clientEngine);
83         serverApplicationBuffer = bufferType.newApplicationBuffer(serverEngine);
84         clientPacketBuffer = bufferType.newPacketBuffer(clientEngine);
85         serverPacketBuffer = bufferType.newPacketBuffer(serverEngine);
86 
87         engineFactory.dispose(clientEngine);
88         engineFactory.dispose(serverEngine);
89     }
90 
handshake()91     void handshake() throws SSLException {
92         SSLEngine client = engineFactory.newClientEngine(cipher, useAlpn);
93         SSLEngine server = engineFactory.newServerEngine(cipher, useAlpn);
94         clientApplicationBuffer.clear();
95         clientPacketBuffer.clear();
96         serverApplicationBuffer.clear();
97         serverPacketBuffer.clear();
98 
99         client.setEnabledProtocols(protocols);
100         server.setEnabledProtocols(protocols);
101 
102         client.beginHandshake();
103         server.beginHandshake();
104 
105         doHandshake(client, server);
106 
107         engineFactory.dispose(client);
108         engineFactory.dispose(server);
109     }
110 
doHandshake(SSLEngine client, SSLEngine server)111     private void doHandshake(SSLEngine client, SSLEngine server) throws SSLException {
112         while (true) {
113             // Send as many client-to-server messages as possible
114             doHalfHandshake(client, server, clientPacketBuffer, serverApplicationBuffer);
115 
116             if (client.getHandshakeStatus() == HandshakeStatus.NOT_HANDSHAKING
117                     && server.getHandshakeStatus() == HandshakeStatus.NOT_HANDSHAKING) {
118                 return;
119             }
120 
121             // Do the same with server-to-client messages
122             doHalfHandshake(server, client, serverPacketBuffer, clientApplicationBuffer);
123 
124             if (client.getHandshakeStatus() == HandshakeStatus.NOT_HANDSHAKING
125                     && server.getHandshakeStatus() == HandshakeStatus.NOT_HANDSHAKING) {
126                 return;
127             }
128         }
129     }
130 
doHalfHandshake(SSLEngine sender, SSLEngine receiver, ByteBuffer senderPacketBuffer, ByteBuffer receiverApplicationBuffer)131     private void doHalfHandshake(SSLEngine sender, SSLEngine receiver,
132             ByteBuffer senderPacketBuffer, ByteBuffer receiverApplicationBuffer)
133             throws SSLException {
134         SSLEngineResult senderResult;
135         SSLEngineResult receiverResult;
136 
137         do {
138             senderResult = sender.wrap(EMPTY_BUFFER, senderPacketBuffer);
139             runDelegatedTasks(senderResult, sender);
140             senderPacketBuffer.flip();
141             receiverResult = receiver.unwrap(senderPacketBuffer, receiverApplicationBuffer);
142             runDelegatedTasks(receiverResult, receiver);
143             senderPacketBuffer.compact();
144         } while (senderResult.getHandshakeStatus() == HandshakeStatus.NEED_WRAP);
145 
146         if (rttMillis > 0) {
147             try {
148                 Thread.sleep(rttMillis / 2);
149             } catch (InterruptedException e) {
150                 throw new RuntimeException(e);
151             }
152         }
153     }
154 
runDelegatedTasks(SSLEngineResult result, SSLEngine engine)155     private static void runDelegatedTasks(SSLEngineResult result, SSLEngine engine) {
156         if (result.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.NEED_TASK) {
157             for (;;) {
158                 Runnable task = engine.getDelegatedTask();
159                 if (task == null) {
160                     break;
161                 }
162                 task.run();
163             }
164         }
165     }
166 }
167