1 /* 2 * Copyright (c) 2004, 2012, 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 26 package sun.security.ssl; 27 28 import java.nio.*; 29 30 /* 31 * A multi-purpose class which handles all of the SSLEngine arguments. 32 * It validates arguments, checks for RO conditions, does space 33 * calculations, performs scatter/gather, etc. 34 * 35 * @author Brad R. Wetmore 36 */ 37 class EngineArgs { 38 39 /* 40 * Keep track of the input parameters. 41 */ 42 ByteBuffer netData; 43 ByteBuffer [] appData; 44 45 private int offset; // offset/len for the appData array. 46 private int len; 47 48 /* 49 * The initial pos/limit conditions. This is useful because we can 50 * quickly calculate the amount consumed/produced in successful 51 * operations, or easily return the buffers to their pre-error 52 * conditions. 53 */ 54 private int netPos; 55 private int netLim; 56 57 private int [] appPoss; 58 private int [] appLims; 59 60 /* 61 * Sum total of the space remaining in all of the appData buffers 62 */ 63 private int appRemaining = 0; 64 65 private boolean wrapMethod; 66 67 /* 68 * Called by the SSLEngine.wrap() method. 69 */ 70 EngineArgs(ByteBuffer [] appData, int offset, int len, 71 ByteBuffer netData) { 72 this.wrapMethod = true; 73 init(netData, appData, offset, len); 74 } 75 76 /* 77 * Called by the SSLEngine.unwrap() method. 78 */ 79 EngineArgs(ByteBuffer netData, ByteBuffer [] appData, int offset, 80 int len) { 81 this.wrapMethod = false; 82 init(netData, appData, offset, len); 83 } 84 85 /* 86 * The main initialization method for the arguments. Most 87 * of them are pretty obvious as to what they do. 88 * 89 * Since we're already iterating over appData array for validity 90 * checking, we also keep track of how much remainging space is 91 * available. Info is used in both unwrap (to see if there is 92 * enough space available in the destination), and in wrap (to 93 * determine how much more we can copy into the outgoing data 94 * buffer. 95 */ 96 private void init(ByteBuffer netData, ByteBuffer [] appData, 97 int offset, int len) { 98 99 if ((netData == null) || (appData == null)) { 100 throw new IllegalArgumentException("src/dst is null"); 101 } 102 103 if ((offset < 0) || (len < 0) || (offset > appData.length - len)) { 104 throw new IndexOutOfBoundsException(); 105 } 106 107 if (wrapMethod && netData.isReadOnly()) { 108 throw new ReadOnlyBufferException(); 109 } 110 111 netPos = netData.position(); 112 netLim = netData.limit(); 113 114 appPoss = new int [appData.length]; 115 appLims = new int [appData.length]; 116 117 for (int i = offset; i < offset + len; i++) { 118 if (appData[i] == null) { 119 throw new IllegalArgumentException( 120 "appData[" + i + "] == null"); 121 } 122 123 /* 124 * If we're unwrapping, then check to make sure our 125 * destination bufffers are writable. 126 */ 127 if (!wrapMethod && appData[i].isReadOnly()) { 128 throw new ReadOnlyBufferException(); 129 } 130 131 appRemaining += appData[i].remaining(); 132 133 appPoss[i] = appData[i].position(); 134 appLims[i] = appData[i].limit(); 135 } 136 137 /* 138 * Ok, looks like we have a good set of args, let's 139 * store the rest of this stuff. 140 */ 141 this.netData = netData; 142 this.appData = appData; 143 this.offset = offset; 144 this.len = len; 145 } 146 147 /* 148 * Given spaceLeft bytes to transfer, gather up that much data 149 * from the appData buffers (starting at offset in the array), 150 * and transfer it into the netData buffer. 151 * 152 * The user has already ensured there is enough room. 153 */ 154 void gather(int spaceLeft) { 155 for (int i = offset; (i < (offset + len)) && (spaceLeft > 0); i++) { 156 int amount = Math.min(appData[i].remaining(), spaceLeft); 157 appData[i].limit(appData[i].position() + amount); 158 netData.put(appData[i]); 159 appRemaining -= amount; 160 spaceLeft -= amount; 161 } 162 } 163 164 /* 165 * Using the supplied buffer, scatter the data into the appData buffers 166 * (starting at offset in the array). 167 * 168 * The user has already ensured there is enough room. 169 */ 170 void scatter(ByteBuffer readyData) { 171 int amountLeft = readyData.remaining(); 172 173 for (int i = offset; (i < (offset + len)) && (amountLeft > 0); 174 i++) { 175 int amount = Math.min(appData[i].remaining(), amountLeft); 176 readyData.limit(readyData.position() + amount); 177 appData[i].put(readyData); 178 amountLeft -= amount; 179 } 180 assert(readyData.remaining() == 0); 181 } 182 183 int getAppRemaining() { 184 return appRemaining; 185 } 186 187 /* 188 * Calculate the bytesConsumed/byteProduced. Aren't you glad 189 * we saved this off earlier? 190 */ 191 int deltaNet() { 192 return (netData.position() - netPos); 193 } 194 195 /* 196 * Calculate the bytesConsumed/byteProduced. Aren't you glad 197 * we saved this off earlier? 198 */ 199 int deltaApp() { 200 int sum = 0; // Only calculating 2^14 here, don't need a long. 201 202 for (int i = offset; i < offset + len; i++) { 203 sum += appData[i].position() - appPoss[i]; 204 } 205 206 return sum; 207 } 208 209 /* 210 * In the case of Exception, we want to reset the positions 211 * to appear as though no data has been consumed or produced. 212 * 213 * Currently, this method is only called as we are preparing to 214 * fail out, and thus we don't need to actually recalculate 215 * appRemaining. If that assumption changes, that variable should 216 * be updated here. 217 */ 218 void resetPos() { 219 netData.position(netPos); 220 for (int i = offset; i < offset + len; i++) { 221 // See comment above about recalculating appRemaining. 222 appData[i].position(appPoss[i]); 223 } 224 } 225 226 /* 227 * We are doing lots of ByteBuffer manipulations, in which case 228 * we need to make sure that the limits get set back correctly. 229 * This is one of the last things to get done before returning to 230 * the user. 231 */ 232 void resetLim() { 233 netData.limit(netLim); 234 for (int i = offset; i < offset + len; i++) { 235 appData[i].limit(appLims[i]); 236 } 237 } 238 } 239