[jcifs] problem with TransactNamedPipeInputStream
Michael B. Allen
miallen at eskimo.com
Fri Sep 27 19:56:42 EST 2002
On Thu, 26 Sep 2002 12:48:06 -0700 (PDT)
sharath reddy <sharathreddy at yahoo.com> wrote:
>
> Hi Michael,
>
> I was experimenting with some DCE/RPC stuff and I ran
> across the following problem:
>
> I'm using named pipes and ran into a problem when I do
> consecutive reads from TransactNamedPipeInputStream.
> Here's what (i think) happens:
>
> The first time I read data from the pipe, I retrieve
> 68 bytes of data from the pipe. This sets the value
> of the variables: beg_idx = nxt_idx = 68.
>
> The next time data is being written into the pipe (via
> the 'receive' funtion), turns out the buffer is too
> small. So a new, larger buffer is created, and the
> data is copied over from the old buffer into the new:
>
> System.arraycopy( tmp, beg_idx, pipe_buf, 0, used );
> beg_idx = 0;
>
> However, when I do another read from the pipe, I seem
> to have 68 bytes of zeros, then my data. The last
> 68 bytes of my data is missing.
>
> I was able to fix this by adding the following line:
> nxt_idx -= beg_idx;
>
> before setting beg_idx to zero, after resizing the
> buffer.
I have just looked at this more closely. I have found two bugs, one of
which is the one you describe. Just to clarify and describe the bugs I'll
inline the code with little annotations:
58 public int read( byte[] b, int off, int len ) throws IOException {
59 int result = -1;
60 int i;
61
62 if( len <= 0 ) {
63 return 0;
64 }
65 synchronized( lock ) {
66 try {
67 while( used == 0 ) {
68 lock.wait();
69 }
70 } catch( InterruptedException ie ) {
71 throw new IOException( ie.getMessage() );
72 }
We've woken up because we've received some data so let's copy it into the
callers buffer. This pipe (like most pipes I imagine) is a circular buffer
so you have two cases; one where all data is in one segment and two where
there's a tail fragment and a beginning fragement. Note if there are two
fragments they have to be on the ends or the data would not be continuous.
Apparently i is the length of the tail region. The result variable is
either everything we've got to give or the exact length they asked for.
73 i = pipe_buf.length - beg_idx;
74 result = len > used ? used : len;
used is how much data is in the buffer. If there's more in the buffer than
what's the tail then this is the second case so we need to copy from the
tail and then the head fragment with separate copys. Unless of course
result is not that much in which case we can do a single copy.
75 if( used > i && result > i ) {
76 System.arraycopy( pipe_buf, beg_idx, b, off, i );
77 off += i;
Here's a bug. After copy the tail over we proceed to copy the full result
amount. This sound be result - i:
System.arraycopy( pipe_buf, 0, b, off, result - i );
and not just result.
78 System.arraycopy( pipe_buf, 0, b, off, result );
79 } else {
80 System.arraycopy( pipe_buf, beg_idx, b, off, result );
81 }
We decrement used and increase beg_idx accordingly. No need to update
nxt_idx here. It's the beginning of the free area and we have only removed
data before it (and possibly right up to it like you described in your
scenario).
82 used -= result;
83 beg_idx = ( beg_idx + result ) % pipe_buf.length;
84 }
85 return result;
86 }
92 int receive( byte[] b, int off, int len ) {
93 int i;
This method is called by a different thread when there's data to be placed
into the pipe. Another thread is used because the caller is blocked.
Classic reader/writer problem.
If the len being put in exceeds our buffer increase to accomodate.
94
95 if( len > ( pipe_buf.length - used )) {
96 byte[] tmp;
97 int new_size;
98
99 new_size = pipe_buf.length * 2;
100 if( len > ( new_size - used )) {
101 new_size = len + used;
102 }
103 tmp = pipe_buf;
104 pipe_buf = new byte[new_size];
105 i = pipe_buf.length - beg_idx;
Same sort of thing as before. i is the length of the tail fragment. If the
amount of data in the buffer exceeds that tail fragment then we have to
copy the tail and then the head with two separate arraycopies. Notice we
*do* subtract i from the total copy amount unlike the analygous buggy
operation above.
106 if( used > i ) {
107 System.arraycopy( tmp, beg_idx, pipe_buf, 0, i );
108 System.arraycopy( tmp, 0, pipe_buf, i, used - i );
Here is the problem. We just reordered the two fragments to the beginning
of the new bigger array. We moved the tail. So if we moved the tail we need
to make nxt_idx point at the end of it. If all the data's at the beginning
of the array now that position is simply:
nxt_idx = used;
109 } else {
110 System.arraycopy( tmp, beg_idx, pipe_buf, 0, used );
111 }
112 beg_idx = 0;
114 tmp = null;
115 }
116
117 i = pipe_buf.length - nxt_idx;
118 if( len > i ) {
119 System.arraycopy( b, off, pipe_buf, nxt_idx, i );
120 off += i;
121 System.arraycopy( b, off, pipe_buf, 0, len - i );
122 } else {
123 System.arraycopy( b, off, pipe_buf, nxt_idx, len );
124 }
125 nxt_idx = ( nxt_idx + len ) % pipe_buf.length;
126 used += len;
127 return len;
128 }
>
> Please let me know if I am missing something.
> BTW, your method 'Log.printHexDump' is very cool!
>
> Regards,
> Sharath
>
>
> =====
> Sharath Reddy
> Cell : 512 689 4360
>
> __________________________________________________
> Do you Yahoo!?
> New DSL Internet Access from SBC & Yahoo!
> http://sbc.yahoo.com
--
A program should be written to model the concepts of the task it
performs rather than the physical world or a process because this
maximizes the potential for it to be applied to tasks that are
conceptually similar and more importantly to tasks that have not
yet been conceived.
More information about the jcifs
mailing list