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