private int preReadProcess(int allowed) { if (allowed < 1) { Debug.out("allowed < 1"); } decode_array[0] = payload_buffer == null ? null : payload_buffer.getBuffer( SS); // ensure the decode array has the latest payload pointer int bytes_available = 0; boolean shrink_remaining_buffers = false; int start_buff = reading_length_mode ? 1 : 0; boolean marked = false; for (int i = start_buff; i < 2; i++) { // set buffer limits according to bytes allowed ByteBuffer bb = decode_array[i]; if (bb == null) { Debug.out("preReadProcess:: bb[" + i + "] == null, decoder destroyed=" + destroyed); throw (new RuntimeException("decoder destroyed")); } if (shrink_remaining_buffers) { bb.limit(0); // ensure no read into this next buffer is possible } else { int remaining = bb.remaining(); if (remaining < 1) continue; // skip full buffer if (!marked) { pre_read_start_buffer = i; pre_read_start_position = bb.position(); marked = true; } if (remaining > allowed) { // read only part of this buffer bb.limit(bb.position() + allowed); // limit current buffer bytes_available += bb.remaining(); shrink_remaining_buffers = true; // shrink any tail buffers } else { // full buffer is allowed to be read bytes_available += remaining; allowed -= remaining; // count this buffer toward allowed and move on to the next } } } return bytes_available; }
public int performStreamDecode(Transport transport, int max_bytes) throws IOException { try { protocol_bytes_last_read = 0; data_bytes_last_read = 0; int bytes_remaining = max_bytes; while (bytes_remaining > 0) { if (destroyed) { // destruction currently isn't thread safe so one thread can destroy the decoder (e.g. // when closing a connection) // while the read-controller is still actively processing the us // throw( new IOException( "BTMessageDecoder already destroyed" )); break; } if (is_paused) { break; } int bytes_possible = preReadProcess(bytes_remaining); if (bytes_possible < 1) { Debug.out("ERROR BT: bytes_possible < 1"); break; } if (reading_length_mode) { transport.read(decode_array, 1, 1); // only read into length buffer } else { transport.read( decode_array, 0, 2); // read into payload buffer, and possibly next message length } int bytes_read = postReadProcess(); bytes_remaining -= bytes_read; if (bytes_read < bytes_possible) { break; } if (reading_length_mode && last_received_was_keepalive) { // hack to stop a 0-byte-read after receiving a keep-alive message // otherwise we won't realize there's nothing left on the line until trying to read again last_received_was_keepalive = false; break; } } return max_bytes - bytes_remaining; } catch (NullPointerException e) { // due to lack of synchronization here the buffers can be nullified by a concurrent 'destroy' // turn this into something less scarey throw (new IOException("Decoder has most likely been destroyed")); } }
public ByteBuffer destroy() { if (destroyed) { Debug.out("Trying to redestroy message decoder, stack trace follows: " + this); Debug.outStackTrace(); } is_paused = true; destroyed = true; // there's a concurrency issue with the decoder whereby it can be destroyed while will being // messed with. Don't // have the energy to look into it properly atm so just try to ensure that it doesn't bork too // badly (parg: 29/04/2012) // only occasional but does have potential to generate direct buffer mem leak ;( int lbuff_read = 0; int pbuff_read = 0; length_buffer.limit(SS, 4); DirectByteBuffer plb = payload_buffer; if (reading_length_mode) { lbuff_read = length_buffer.position(SS); } else { // reading payload length_buffer.position(SS, 4); lbuff_read = 4; pbuff_read = plb == null ? 0 : plb.position(SS); } ByteBuffer unused = ByteBuffer.allocate(lbuff_read + pbuff_read); // TODO convert to direct? length_buffer.flip(SS); unused.put(length_buffer.getBuffer(SS)); try { if (plb != null) { plb.flip(SS); unused.put( plb.getBuffer( SS)); // Got a buffer overflow exception here in the past - related to PEX? } } catch (RuntimeException e) { Debug.out("hit known threading issue"); } unused.flip(); length_buffer.returnToPool(); if (plb != null) { plb.returnToPool(); payload_buffer = null; } try { for (int i = 0; i < messages_last_read.size(); i++) { Message msg = (Message) messages_last_read.get(i); msg.destroy(); } } catch (RuntimeException e) { // happens if messages modified by alt thread... Debug.out("hit known threading issue"); } messages_last_read.clear(); return unused; }