1/* 2 * Copyright (C) 2010 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 17package libcore.javax.net.ssl; 18 19import java.util.concurrent.Callable; 20import java.util.concurrent.ExecutionException; 21import java.util.concurrent.ExecutorService; 22import java.util.concurrent.Executors; 23import java.util.concurrent.Future; 24import java.util.concurrent.TimeUnit; 25import javax.net.ssl.SSLSocket; 26 27/** 28 * TestSSLSocketPair is a convenience class for other tests that want 29 * a pair of connected and handshaked client and server SSLSockets for 30 * testing. 31 */ 32public final class TestSSLSocketPair { 33 public final TestSSLContext c; 34 public final SSLSocket server; 35 public final SSLSocket client; 36 37 private TestSSLSocketPair (TestSSLContext c, 38 SSLSocket server, 39 SSLSocket client) { 40 this.c = c; 41 this.server = server; 42 this.client = client; 43 } 44 45 public void close() { 46 c.close(); 47 try { 48 server.close(); 49 client.close(); 50 } catch (Exception e) { 51 throw new RuntimeException(e); 52 } 53 } 54 55 /** 56 * based on test_SSLSocket_startHandshake 57 */ 58 public static TestSSLSocketPair create () { 59 TestSSLContext c = TestSSLContext.create(); 60 SSLSocket[] sockets = connect(c, null, null); 61 return new TestSSLSocketPair(c, sockets[0], sockets[1]); 62 } 63 64 /** 65 * Create a new connected server/client socket pair within a 66 * existing SSLContext. Optionally specify clientCipherSuites to 67 * allow forcing new SSLSession to test SSLSessionContext 68 * caching. Optionally specify serverCipherSuites for testing 69 * cipher suite negotiation. 70 */ 71 public static SSLSocket[] connect (final TestSSLContext context, 72 final String[] clientCipherSuites, 73 final String[] serverCipherSuites) { 74 try { 75 final SSLSocket client = (SSLSocket) 76 context.clientContext.getSocketFactory().createSocket(context.host, context.port); 77 final SSLSocket server = (SSLSocket) context.serverSocket.accept(); 78 79 ExecutorService executor = Executors.newFixedThreadPool(2); 80 Future s = executor.submit(new Callable<Void>() { 81 public Void call() throws Exception { 82 if (serverCipherSuites != null) { 83 server.setEnabledCipherSuites(serverCipherSuites); 84 } 85 server.startHandshake(); 86 return null; 87 } 88 }); 89 Future c = executor.submit(new Callable<Void>() { 90 public Void call() throws Exception { 91 if (clientCipherSuites != null) { 92 client.setEnabledCipherSuites(clientCipherSuites); 93 } 94 client.startHandshake(); 95 return null; 96 } 97 }); 98 executor.shutdown(); 99 100 // catch client and server exceptions separately so we can 101 // potentially log both. 102 Exception serverException; 103 try { 104 s.get(30, TimeUnit.SECONDS); 105 serverException = null; 106 } catch (Exception e) { 107 serverException = e; 108 e.printStackTrace(); 109 } 110 Exception clientException; 111 try { 112 c.get(30, TimeUnit.SECONDS); 113 clientException = null; 114 } catch (Exception e) { 115 clientException = e; 116 e.printStackTrace(); 117 } 118 if (serverException != null) { 119 throw serverException; 120 } 121 if (clientException != null) { 122 throw clientException; 123 } 124 return new SSLSocket[] { server, client }; 125 } catch (RuntimeException e) { 126 throw e; 127 } catch (Exception e) { 128 throw new RuntimeException(e); 129 } 130 } 131} 132 133