1 | /* |
2 | |
3 | Derby - Class org.apache.derby.client.net.NetPackageRequest |
4 | |
5 | Copyright (c) 2001, 2005 The Apache Software Foundation or its licensors, where applicable. |
6 | |
7 | Licensed under the Apache License, Version 2.0 (the "License"); |
8 | you may not use this file except in compliance with the License. |
9 | You may obtain a copy of the License at |
10 | |
11 | http://www.apache.org/licenses/LICENSE-2.0 |
12 | |
13 | Unless required by applicable law or agreed to in writing, software |
14 | distributed under the License is distributed on an "AS IS" BASIS, |
15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
16 | See the License for the specific language governing permissions and |
17 | limitations under the License. |
18 | |
19 | */ |
20 | package org.apache.derby.client.net; |
21 | |
22 | import org.apache.derby.client.am.Configuration; |
23 | import org.apache.derby.client.am.Section; |
24 | import org.apache.derby.client.am.SqlException; |
25 | import org.apache.derby.client.am.ClientMessageId; |
26 | import org.apache.derby.shared.common.reference.SQLState; |
27 | |
28 | |
29 | public class NetPackageRequest extends NetConnectionRequest { |
30 | static final String COLLECTIONNAME = "NULLID"; |
31 | |
32 | NetPackageRequest(NetAgent netAgent, CcsidManager ccsidManager, int bufferSize) { |
33 | super(netAgent, ccsidManager, bufferSize); |
34 | } |
35 | |
36 | // RDB Package Name, Consistency Token |
37 | // Scalar Object specifies the fully qualified name of a relational |
38 | // database package and its consistency token. |
39 | // |
40 | // To accomodate larger lengths, the Scalar Data Length |
41 | // (SCLDTALEN) Field is used to specify the length of the instance |
42 | // variable which follows. |
43 | static final String collectionName = "NULLID"; |
44 | |
45 | void buildCommonPKGNAMinfo(Section section) throws SqlException { |
46 | String collectionToFlow = COLLECTIONNAME; |
47 | // the scalar data length field may or may not be required. it depends |
48 | // on the level of support and length of the data. |
49 | // check the lengths of the RDBNAM, RDBCOLID, and PKGID. |
50 | // Determine if the lengths require an SCLDTALEN object. |
51 | // Note: if an SQLDTALEN is required for ONE of them, |
52 | // it is needed for ALL of them. This is why this check is |
53 | // up front. |
54 | // the SQLAM level dictates the maximum size for |
55 | // RDB Collection Identifier (RDBCOLID) |
56 | // Relational Database Name (RDBNAM) |
57 | // RDB Package Identifier (PKGID) |
58 | int maxIdentifierLength = NetConfiguration.PKG_IDENTIFIER_MAX_LEN; |
59 | |
60 | boolean scldtalenRequired = false; |
61 | scldtalenRequired = checkPKGNAMlengths(netAgent_.netConnection_.databaseName_, |
62 | maxIdentifierLength, |
63 | NetConfiguration.PKG_IDENTIFIER_FIXED_LEN); |
64 | |
65 | if (!scldtalenRequired) { |
66 | scldtalenRequired = checkPKGNAMlengths(collectionToFlow, |
67 | maxIdentifierLength, |
68 | NetConfiguration.PKG_IDENTIFIER_FIXED_LEN); |
69 | } |
70 | |
71 | if (!scldtalenRequired) { |
72 | scldtalenRequired = checkPKGNAMlengths(section.getPackageName(), |
73 | maxIdentifierLength, |
74 | NetConfiguration.PKG_IDENTIFIER_FIXED_LEN); |
75 | } |
76 | |
77 | // the format is different depending on if an SCLDTALEN is required. |
78 | if (!scldtalenRequired) { |
79 | writeScalarPaddedString(netAgent_.netConnection_.databaseName_, |
80 | NetConfiguration.PKG_IDENTIFIER_FIXED_LEN); |
81 | writeScalarPaddedString(collectionToFlow, |
82 | NetConfiguration.PKG_IDENTIFIER_FIXED_LEN); |
83 | writeScalarPaddedString(section.getPackageName(), |
84 | NetConfiguration.PKG_IDENTIFIER_FIXED_LEN); |
85 | } else { |
86 | buildSCLDTA(netAgent_.netConnection_.databaseName_, NetConfiguration.PKG_IDENTIFIER_FIXED_LEN); |
87 | buildSCLDTA(collectionToFlow, NetConfiguration.PKG_IDENTIFIER_FIXED_LEN); |
88 | buildSCLDTA(section.getPackageName(), NetConfiguration.PKG_IDENTIFIER_FIXED_LEN); |
89 | } |
90 | } |
91 | |
92 | private void buildSCLDTA(String identifier, int minimumLength) throws SqlException { |
93 | if (identifier.length() <= minimumLength) { |
94 | write2Bytes(minimumLength); |
95 | writeScalarPaddedString(identifier, minimumLength); |
96 | } else { |
97 | write2Bytes(identifier.length()); |
98 | writeScalarPaddedString(identifier, identifier.length()); |
99 | } |
100 | } |
101 | |
102 | |
103 | // this specifies the fully qualified package name, |
104 | // consistency token, and section number within the package being used |
105 | // to execute the SQL. If the connection supports reusing the previous |
106 | // package information and this information is the same except for the section |
107 | // number then only the section number needs to be sent to the server. |
108 | void buildPKGNAMCSN(Section section) throws SqlException { |
109 | if (!canCommandUseDefaultPKGNAMCSN()) { |
110 | markLengthBytes(CodePoint.PKGNAMCSN); |
111 | // If PKGNAMCBytes is already available, copy the bytes to the request buffer directly. |
112 | if (section.getPKGNAMCBytes() != null) { |
113 | writeStoredPKGNAMCBytes(section); |
114 | } else { |
115 | // Mark the beginning of PKGNAMCSN bytes. |
116 | markForCachingPKGNAMCSN(); |
117 | buildCommonPKGNAMinfo(section); |
118 | writeScalarPaddedBytes(Configuration.dncPackageConsistencyToken, |
119 | NetConfiguration.PKGCNSTKN_FIXED_LEN, |
120 | NetConfiguration.NON_CHAR_DDM_DATA_PAD_BYTE); |
121 | // store the PKGNAMCbytes |
122 | storePKGNAMCBytes(section); |
123 | } |
124 | write2Bytes(section.getSectionNumber()); |
125 | updateLengthBytes(); |
126 | } else { |
127 | writeScalar2Bytes(CodePoint.PKGSN, section.getSectionNumber()); |
128 | } |
129 | } |
130 | |
131 | private void storePKGNAMCBytes(Section section) { |
132 | // Get the locaton where we started writing PKGNAMCSN |
133 | int startPos = popMarkForCachingPKGNAMCSN(); |
134 | int copyLength = offset_ - startPos; |
135 | byte[] b = new byte[copyLength]; |
136 | System.arraycopy(bytes_, |
137 | startPos, |
138 | b, |
139 | 0, |
140 | copyLength); |
141 | section.setPKGNAMCBytes(b); |
142 | } |
143 | |
144 | private void writeStoredPKGNAMCBytes(Section section) { |
145 | byte[] b = section.getPKGNAMCBytes(); |
146 | |
147 | // Mare sure request buffer has enough space to write this byte array. |
148 | ensureLength(offset_ + b.length); |
149 | |
150 | System.arraycopy(b, |
151 | 0, |
152 | bytes_, |
153 | offset_, |
154 | b.length); |
155 | |
156 | offset_ += b.length; |
157 | } |
158 | |
159 | private boolean canCommandUseDefaultPKGNAMCSN() { |
160 | return false; |
161 | } |
162 | |
163 | |
164 | // throws an exception if lengths exceed the maximum. |
165 | // returns a boolean indicating if SLCDTALEN is required. |
166 | private boolean checkPKGNAMlengths(String identifier, |
167 | int maxIdentifierLength, |
168 | int lengthRequiringScldta) throws SqlException { |
169 | int length = identifier.length(); |
170 | if (length > maxIdentifierLength) { |
171 | throw new SqlException(netAgent_.logWriter_, |
172 | new ClientMessageId(SQLState.LANG_IDENTIFIER_TOO_LONG), |
173 | identifier, new Integer(maxIdentifierLength)); |
174 | } |
175 | |
176 | return (length > lengthRequiringScldta); |
177 | } |
178 | |
179 | private byte[] getBytes(String string, String encoding) throws SqlException { |
180 | try { |
181 | return string.getBytes(encoding); |
182 | } catch (java.lang.Exception e) { |
183 | throw new SqlException(netAgent_.logWriter_, |
184 | new ClientMessageId(SQLState.JAVA_EXCEPTION), |
185 | e.getClass().getName(), e.getMessage(), e); |
186 | } |
187 | } |
188 | |
189 | private void buildNOCMorNOCS(String string) throws SqlException { |
190 | if (string == null) { |
191 | write2Bytes(0xffff); |
192 | } else { |
193 | byte[] sqlBytes = null; |
194 | |
195 | if (netAgent_.typdef_.isCcsidMbcSet()) { |
196 | sqlBytes = getBytes(string, netAgent_.typdef_.getCcsidMbcEncoding()); |
197 | write1Byte(0x00); |
198 | write4Bytes(sqlBytes.length); |
199 | writeBytes(sqlBytes, sqlBytes.length); |
200 | write1Byte(0xff); |
201 | } else { |
202 | sqlBytes = getBytes(string, netAgent_.typdef_.getCcsidSbcEncoding()); |
203 | write1Byte(0xff); |
204 | write1Byte(0x00); |
205 | write4Bytes(sqlBytes.length); |
206 | writeBytes(sqlBytes, sqlBytes.length); |
207 | } |
208 | } |
209 | } |
210 | |
211 | // SQLSTTGRP : FDOCA EARLY GROUP |
212 | // SQL Statement Group Description |
213 | // |
214 | // FORMAT FOR SQLAM <= 6 |
215 | // SQLSTATEMENT_m; PROTOCOL TYPE LVCM; ENVLID 0x40; Length Override 32767 |
216 | // SQLSTATEMENT_s; PROTOCOL TYPE LVCS; ENVLID 0x34; Length Override 32767 |
217 | // |
218 | // FORMAT FOR SQLAM >= 7 |
219 | // SQLSTATEMENT_m; PROTOCOL TYPE NOCM; ENVLID 0xCF; Length Override 4 |
220 | // SQLSTATEMENT_s; PROTOCOL TYPE NOCS; ENVLID 0xCB; Length Override 4 |
221 | private void buildSQLSTTGRP(String string) throws SqlException { |
222 | buildNOCMorNOCS(string); |
223 | return; |
224 | } |
225 | |
226 | // SQLSTT : FDOCA EARLY ROW |
227 | // SQL Statement Row Description |
228 | // |
229 | // FORMAT FOR ALL SQLAM LEVELS |
230 | // SQLSTTGRP; GROUP LID 0x5C; ELEMENT TAKEN 0(all); REP FACTOR 1 |
231 | private void buildSQLSTT(String string) throws SqlException { |
232 | buildSQLSTTGRP(string); |
233 | } |
234 | |
235 | protected void buildSQLSTTcommandData(String sql) throws SqlException { |
236 | createEncryptedCommandData(); |
237 | int loc = offset_; |
238 | markLengthBytes(CodePoint.SQLSTT); |
239 | buildSQLSTT(sql); |
240 | updateLengthBytes(); |
241 | if (netAgent_.netConnection_.getSecurityMechanism() == |
242 | NetConfiguration.SECMEC_EUSRIDDTA || |
243 | netAgent_.netConnection_.getSecurityMechanism() == |
244 | NetConfiguration.SECMEC_EUSRPWDDTA) { |
245 | encryptDataStream(loc); |
246 | } |
247 | |
248 | } |
249 | |
250 | |
251 | protected void buildSQLATTRcommandData(String sql) throws SqlException { |
252 | createEncryptedCommandData(); |
253 | int loc = offset_; |
254 | markLengthBytes(CodePoint.SQLATTR); |
255 | buildSQLSTT(sql); |
256 | updateLengthBytes(); |
257 | if (netAgent_.netConnection_.getSecurityMechanism() == |
258 | NetConfiguration.SECMEC_EUSRIDDTA || |
259 | netAgent_.netConnection_.getSecurityMechanism() == |
260 | NetConfiguration.SECMEC_EUSRPWDDTA) { |
261 | encryptDataStream(loc); |
262 | } |
263 | |
264 | } |
265 | |
266 | |
267 | public void encryptDataStream(int lengthLocation) throws SqlException { |
268 | byte[] clearedBytes = new byte[offset_ - lengthLocation]; |
269 | byte[] encryptedBytes; |
270 | for (int i = lengthLocation; i < offset_; i++) { |
271 | clearedBytes[i - lengthLocation] = bytes_[i]; |
272 | } |
273 | |
274 | encryptedBytes = netAgent_.netConnection_.getEncryptionManager(). |
275 | encryptData(clearedBytes, |
276 | NetConfiguration.SECMEC_EUSRIDPWD, |
277 | netAgent_.netConnection_.getTargetPublicKey(), |
278 | netAgent_.netConnection_.getTargetPublicKey()); |
279 | |
280 | int length = encryptedBytes.length; |
281 | |
282 | if (bytes_.length >= lengthLocation + length) { |
283 | System.arraycopy(encryptedBytes, 0, bytes_, lengthLocation, length); |
284 | } else { |
285 | byte[] largeByte = new byte[lengthLocation + length]; |
286 | System.arraycopy(bytes_, 0, largeByte, 0, lengthLocation); |
287 | System.arraycopy(encryptedBytes, 0, largeByte, lengthLocation, length); |
288 | bytes_ = largeByte; |
289 | } |
290 | |
291 | offset_ += length - clearedBytes.length; |
292 | |
293 | //we need to update the length in DSS header here. |
294 | |
295 | bytes_[lengthLocation - 6] = (byte) ((length >>> 8) & 0xff); |
296 | bytes_[lengthLocation - 5] = (byte) (length & 0xff); |
297 | } |
298 | |
299 | } |