KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > knowgate > jcifs > smb > AndXServerMessageBlock


1 /* jcifs smb client library in Java
2  * Copyright (C) 2000 "Michael B. Allen" <jcifs at samba dot org>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17  */

18
19 package com.knowgate.jcifs.smb;
20
21 import java.io.InputStream JavaDoc;
22 import java.io.IOException JavaDoc;
23
24 import com.knowgate.misc.Gadgets;
25
26 abstract class AndXServerMessageBlock extends ServerMessageBlock {
27
28     private static final int ANDX_COMMAND_OFFSET = 1;
29     private static final int ANDX_RESERVED_OFFSET = 2;
30     private static final int ANDX_OFFSET_OFFSET = 3;
31
32     private byte andxCommand = (byte)0xFF;
33     private int andxOffset = 0;
34
35     ServerMessageBlock andx = null;
36
37     AndXServerMessageBlock() {
38     }
39     AndXServerMessageBlock( ServerMessageBlock andx ) {
40         this.andx = andx;
41         if( andx != null ) {
42             andxCommand = andx.command;
43         }
44     }
45
46     /* The SmbComReadAndXResponse can read from the InputStream
47      * directly by implementing this method. The default
48      * behavior is to arraycopy all bytes into the buffer and call
49      * readBytesWireFormat. The alternative would have been to overload
50      * the readAndXWireFormat method but that would have resulted in
51      * copying a fairly large chunck of code into the subclass.
52      */

53
54     abstract int readBytesDirectWireFormat( InputStream JavaDoc in, int byteCount,
55                 byte[] buffer, int bufferIndex ) throws IOException JavaDoc;
56
57     int getBatchLimit( byte command ) {
58         /* the default limit is 0 batched messages before this
59          * one, meaning this message cannot be batched.
60          */

61         return 0;
62     }
63
64     /*
65      * We overload this method from ServerMessageBlock because
66      * we want writeAndXWireFormat to write the parameterWords
67      * and bytes. This is so we can write batched smbs because
68      * all but the first smb of the chaain do not have a header
69      * and therefore we do not want to writeHeaderWireFormat. We
70      * just recursivly call writeAndXWireFormat.
71      */

72
73     int writeWireFormat( byte[] dst, int dstIndex ) {
74         int start = headerStart = dstIndex;
75
76         dstIndex += writeHeaderWireFormat( dst, dstIndex );
77         dstIndex += writeAndXWireFormat( dst, dstIndex );
78         length = dstIndex - start;
79
80         if( digest != null ) {
81             digest.sign( dst, headerStart, length, this, response );
82         }
83
84         return length;
85     }
86
87     /*
88      * We overload this because we want readAndXWireFormat to
89      * read the parameter words and bytes. This is so when
90      * commands are batched together we can recursivly call
91      * readAndXWireFormat without reading the non-existent header.
92      */

93
94     int readWireFormat( InputStream JavaDoc in,
95                                     byte[] buffer,
96                                     int bufferIndex )
97                                     throws IOException JavaDoc {
98         int start = bufferIndex;
99
100         if( in.read( buffer, bufferIndex, HEADER_LENGTH ) != HEADER_LENGTH ) {
101             throw new IOException JavaDoc( "unexpected EOF reading smb header" );
102         }
103         bufferIndex += readHeaderWireFormat( buffer, bufferIndex );
104         bufferIndex += readAndXWireFormat( in, buffer, bufferIndex );
105
106         length = bufferIndex - start;
107         return length;
108     }
109     int writeAndXWireFormat( byte[] dst, int dstIndex ) {
110         int start = dstIndex;
111
112         wordCount = writeParameterWordsWireFormat( dst,
113                                                 start + ANDX_OFFSET_OFFSET + 2 );
114         wordCount += 4; // for command, reserved, and offset
115
dstIndex += wordCount + 1;
116         wordCount /= 2;
117         dst[start] = (byte)( wordCount & 0xFF );
118
119         byteCount = writeBytesWireFormat( dst, dstIndex + 2 );
120         dst[dstIndex++] = (byte)( byteCount & 0xFF );
121         dst[dstIndex++] = (byte)(( byteCount >> 8 ) & 0xFF );
122         dstIndex += byteCount;
123
124         /* Normally, without intervention everything would batch
125          * with everything else. If the below clause evaluates true
126          * the andx command will not be written and therefore the
127          * response will not read a batched command and therefore
128          * the 'received' member of the response object will not
129          * be set to true indicating the send and sendTransaction
130          * methods that the next part should be sent. This is a
131          * very indirect and simple batching control mechanism.
132          */

133
134
135         if( andx == null || USE_BATCHING == false ||
136                                 batchLevel >= getBatchLimit( andx.command )) {
137             andxCommand = (byte)0xFF;
138             andx = null;
139
140             dst[start + ANDX_COMMAND_OFFSET] = (byte)0xFF;
141             dst[start + ANDX_RESERVED_OFFSET] = (byte)0x00;
142             dst[start + ANDX_OFFSET_OFFSET] = (byte)0x00;
143             dst[start + ANDX_OFFSET_OFFSET + 1] = (byte)0x00;
144
145             // andx not used; return
146
return dstIndex - start;
147         }
148
149         /* The message provided to batch has a batchLimit that is
150          * higher than the current batchLevel so we will now encode
151          * that chained message. Before doing so we must increment
152          * the batchLevel of the andx message in case it itself is an
153          * andx message and needs to perform the same check as above.
154          */

155
156         andx.batchLevel = batchLevel + 1;
157
158
159         dst[start + ANDX_COMMAND_OFFSET] = andxCommand;
160         dst[start + ANDX_RESERVED_OFFSET] = (byte)0x00;
161         andxOffset = dstIndex - headerStart;
162         writeInt2( andxOffset, dst, start + ANDX_OFFSET_OFFSET );
163
164         andx.useUnicode = useUnicode;
165         if( andx instanceof AndXServerMessageBlock ) {
166
167             /*
168              * A word about communicating header info to andx smbs
169              *
170              * This is where we recursively invoke the provided andx smb
171              * object to write it's parameter words and bytes to our outgoing
172              * array. Incedentally when these andx smbs are created they are not
173              * necessarily populated with header data because they're not writing
174              * the header, only their body. But for whatever reason one might wish
175              * to populate fields if the writeXxx operation needs this header data
176              * for whatever reason. I copy over the uid here so it appears correct
177              * in logging output. Logging of andx segments of messages inadvertantly
178              * print header information because of the way toString always makes a
179              * super.toString() call(see toString() at the end of all smbs classes).
180              */

181
182             andx.uid = uid;
183             dstIndex += ((AndXServerMessageBlock)andx).writeAndXWireFormat( dst, dstIndex );
184         } else {
185             // the andx smb is not of type andx so lets just write it here and
186
// were done.
187
int andxStart = dstIndex;
188             andx.wordCount = andx.writeParameterWordsWireFormat( dst, dstIndex );
189             dstIndex += andx.wordCount + 1;
190             andx.wordCount /= 2;
191             dst[andxStart] = (byte)( andx.wordCount & 0xFF );
192
193             andx.byteCount = andx.writeBytesWireFormat( dst, dstIndex + 2 );
194             dst[dstIndex++] = (byte)( andx.byteCount & 0xFF );
195             dst[dstIndex++] = (byte)(( andx.byteCount >> 8 ) & 0xFF );
196             dstIndex += andx.byteCount;
197         }
198
199         return dstIndex - start;
200     }
201     int readAndXWireFormat( InputStream JavaDoc in,
202                                     byte[] buffer,
203                                     int bufferIndex )
204                                     throws IOException JavaDoc {
205         int start = bufferIndex;
206
207         /*
208          * read wordCount
209          */

210
211         if(( wordCount = in.read() ) == -1 ) {
212             throw new IOException JavaDoc( "unexpected EOF reading smb wordCount" );
213         }
214         buffer[bufferIndex++] = (byte)( wordCount & 0xFF );
215
216         /*
217          * read parameterWords
218          */

219
220         if( wordCount != 0 ) {
221             if( in.read( buffer, bufferIndex, wordCount * 2 ) != ( wordCount * 2 )) {
222                 throw new IOException JavaDoc( "unexpected EOF reading andx parameter words" );
223             }
224
225             /*
226              * these fields are common to all andx commands
227              * so let's populate them here
228              */

229
230             andxCommand = buffer[bufferIndex];
231             bufferIndex += 2;
232             andxOffset = readInt2( buffer, bufferIndex );
233             bufferIndex += 2;
234
235             if( andxOffset == 0 ) { /* Snap server workaround */
236                 andxCommand = (byte)0xFF;
237             }
238
239             /*
240              * no point in calling readParameterWordsWireFormat if there are no more
241              * parameter words. besides, win98 doesn't return "OptionalSupport" field
242              */

243
244             if( wordCount > 2 ) {
245                 bufferIndex += readParameterWordsWireFormat( buffer, bufferIndex );
246             }
247         }
248
249         /*
250          * read byteCount
251          */

252
253         if( in.read( buffer, bufferIndex, 2 ) != 2 ) {
254             throw new IOException JavaDoc( "unexpected EOF reading smb byteCount" );
255         }
256         byteCount = readInt2( buffer, bufferIndex );
257         bufferIndex += 2;
258
259         /*
260          * read bytes
261          */

262
263         if( byteCount != 0 ) {
264             int n;
265             n = readBytesDirectWireFormat( in, byteCount, buffer, bufferIndex );
266             if( n == 0 ) {
267                 if( in.read( buffer, bufferIndex, byteCount ) != byteCount ) {
268                     throw new IOException JavaDoc( "unexpected EOF reading andx bytes" );
269                 }
270                 n = readBytesWireFormat( buffer, bufferIndex );
271             }
272             bufferIndex += byteCount;
273         }
274
275         /*
276          * if there is an andx and it itself is an andx then just recur by
277          * calling this method for it. otherwise just read it's parameter words
278          * and bytes as usual. Note how we can't just call andx.readWireFormat
279          * because there's no header.
280          */

281
282         if( errorCode != 0 || andxCommand == (byte)0xFF ) {
283             andxCommand = (byte)0xFF;
284             andx = null;
285         } else if( andx == null ) {
286             andxCommand = (byte)0xFF;
287             throw new IOException JavaDoc( "no andx command supplied with response" );
288         } else {
289
290             /*
291              * This is where we take into account andxOffset
292              *
293              * Before we call readAndXWireFormat on the next andx
294              * part we must take into account the andxOffset. The
295              * input stream must be positioned at this location. The
296              * new location is the just read andxOffset(say 68)
297              * minus the current bufferIndex(say 65). But this packet
298              * construction/deconstruction technique does not require that
299              * the bufferIndex begin at 0. The header might be at another
300              * location(say 4). So we must subtract the current buffer
301              * index from the real start of the header and substract that
302              * from the andxOffset(like 68 - ( 65 - 0 ) if headerStart
303              * were 0 or 68 - ( 69 - 4 ) if the headerStart were 4. We
304              * also need to communicate to our newly instantiated andx
305              * smb the headerStart value so that it may perform the same
306              * calculation as this is a recursive process.
307              */

308
309             bufferIndex += in.read( buffer, bufferIndex,
310                                     andxOffset - ( bufferIndex - headerStart ));
311
312             andx.headerStart = headerStart;
313             andx.command = andxCommand;
314             andx.errorCode = errorCode;
315             andx.flags = flags;
316             andx.flags2 = flags2;
317             andx.tid = tid;
318             andx.pid = pid;
319             andx.uid = uid;
320             andx.mid = mid;
321             andx.useUnicode = useUnicode;
322
323             if( andx instanceof AndXServerMessageBlock ) {
324                 bufferIndex += ((AndXServerMessageBlock)andx).readAndXWireFormat(
325                                                 in, buffer, andxOffset - headerStart );
326             } else {
327
328                 /*
329                  * Just a plain smb. Read it as normal.
330                  */

331
332                 /*
333                  * read wordCount
334                  */

335
336                 if(( andx.wordCount = in.read() ) == -1 ) {
337                     throw new IOException JavaDoc( "unexpected EOF reading smb wordCount" );
338                 }
339                 buffer[bufferIndex++] = (byte)( andx.wordCount & 0xFF );
340
341                 /*
342                  * read parameterWords
343                  */

344
345                 if( andx.wordCount != 0 ) {
346                     if( in.read( buffer, bufferIndex, andx.wordCount * 2 ) !=
347                                                                 ( andx.wordCount * 2 )) {
348                         throw new IOException JavaDoc( "unexpected EOF reading andx parameter words" );
349                     }
350
351                     /*
352                      * no point in calling readParameterWordsWireFormat if there are no more
353                      * parameter words. besides, win98 doesn't return "OptionalSupport" field
354                      */

355
356                     if( andx.wordCount > 2 ) {
357                         bufferIndex +=
358                                 andx.readParameterWordsWireFormat( buffer, bufferIndex );
359                     }
360                 }
361
362                 /*
363                  * read byteCount
364                  */

365
366                 if( in.read( buffer, bufferIndex, 2 ) != 2 ) {
367                     throw new IOException JavaDoc( "unexpected EOF reading smb byteCount" );
368                 }
369                 andx.byteCount = readInt2( buffer, bufferIndex );
370                 bufferIndex += 2;
371
372                 /*
373                  * read bytes
374                  */

375
376                 if( andx.byteCount != 0 ) {
377                     if( in.read( buffer, bufferIndex, andx.byteCount ) != andx.byteCount ) {
378                         throw new IOException JavaDoc( "unexpected EOF reading andx bytes" );
379                     }
380                     andx.readBytesWireFormat( buffer, bufferIndex );
381                     bufferIndex += andx.byteCount;
382                 }
383             }
384             andx.received = true;
385         }
386
387         return bufferIndex - start;
388     }
389
390     public String JavaDoc toString() {
391         return new String JavaDoc( super.toString() +
392             ",andxCommand=0x" + Gadgets.toHexString( andxCommand, 2 ) +
393             ",andxOffset=" + andxOffset );
394     }
395 }
396
Popular Tags