1/*
2 * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package sun.security.ssl;
27
28import java.io.ByteArrayOutputStream;
29import java.io.IOException;
30
31/**
32 * Output stream for handshake data.  This is used only internally
33 * to the SSL classes.
34 *
35 * MT note:  one thread at a time is presumed be writing handshake
36 * messages, but (after initial connection setup) it's possible to
37 * have other threads reading/writing application data.  It's the
38 * SSLSocketImpl class that synchronizes record writes.
39 *
40 * @author  David Brownell
41 */
42public class HandshakeOutStream extends ByteArrayOutputStream {
43
44    OutputRecord outputRecord;      // May be null if not actually used to
45                                    // output handshake message records.
46
47    HandshakeOutStream(OutputRecord outputRecord) {
48        super();
49        this.outputRecord = outputRecord;
50    }
51
52    // Complete a handshakin message writing. Called by HandshakeMessage.
53    void complete() throws IOException {
54        if (size() < 4) {       // 4: handshake message header size
55            // internal_error alert will be triggered
56            throw new RuntimeException("handshake message is not available");
57        }
58
59        // outputRecord cannot be null
60        outputRecord.encodeHandshake(buf, 0, count);
61
62        // reset the byte array output stream
63        reset();
64    }
65
66    //
67    // overridden ByteArrayOutputStream methods
68    //
69
70    @Override
71    public void write(byte[] b, int off, int len) {
72        // The maximum fragment size is 24 bytes.
73        checkOverflow(len, Record.OVERFLOW_OF_INT24);
74        super.write(b, off, len);
75    }
76
77    @Override
78    public void flush() throws IOException {
79        outputRecord.flush();
80    }
81
82    //
83    // handshake output stream management functions
84    //
85
86    /*
87     * Put integers encoded in standard 8, 16, 24, and 32 bit
88     * big endian formats. Note that OutputStream.write(int) only
89     * writes the least significant 8 bits and ignores the rest.
90     */
91    void putInt8(int i) throws IOException {
92        checkOverflow(i, Record.OVERFLOW_OF_INT08);
93        super.write(i);
94    }
95
96    void putInt16(int i) throws IOException {
97        checkOverflow(i, Record.OVERFLOW_OF_INT16);
98        super.write(i >> 8);
99        super.write(i);
100    }
101
102    void putInt24(int i) throws IOException {
103        checkOverflow(i, Record.OVERFLOW_OF_INT24);
104        super.write(i >> 16);
105        super.write(i >> 8);
106        super.write(i);
107    }
108
109    /*
110     * Put byte arrays with length encoded as 8, 16, 24 bit
111     * integers in big-endian format.
112     */
113    void putBytes8(byte[] b) throws IOException {
114        if (b == null) {
115            putInt8(0);
116        } else {
117            putInt8(b.length);
118            super.write(b, 0, b.length);
119        }
120    }
121
122    public void putBytes16(byte[] b) throws IOException {
123        if (b == null) {
124            putInt16(0);
125        } else {
126            putInt16(b.length);
127            super.write(b, 0, b.length);
128        }
129    }
130
131    void putBytes24(byte[] b) throws IOException {
132        if (b == null) {
133            putInt24(0);
134        } else {
135            putInt24(b.length);
136            super.write(b, 0, b.length);
137        }
138    }
139
140    /*
141     * Does the specified length overflow the limitation?
142     */
143    private static void checkOverflow(int length, int limit) {
144        if (length >= limit) {
145            // internal_error alert will be triggered
146            throw new RuntimeException(
147                    "Field length overflow, the field length (" +
148                    length + ") should be less than " + limit);
149        }
150    }
151}
152