@Override public DirectByteBuffer[] getData() { try { if (buffer == null) { if (msg_type == REQUEST_MESSAGE_TYPE_ID) { Map<Object, Object> map = new HashMap<Object, Object>(); map.put("msg_type", msg_type); map.put("piece", piece); buffer = MessagingUtil.convertPayloadToBencodedByteStream( map, DirectByteBuffer.AL_MSG_UT_METADATA); } else if (msg_type == DATA_MESSAGE_TYPE_ID) { Map<Object, Object> map = new HashMap<Object, Object>(); map.put("msg_type", msg_type); map.put("piece", piece); map.put("total_size", total_size); byte[] mapPayload = BEncoder.encode(map); buffer = DirectByteBufferPool.getBuffer( DirectByteBuffer.AL_MSG_UT_METADATA, mapPayload.length + metadata.length); buffer.put(DirectByteBuffer.SS_MSG, mapPayload); buffer.put(DirectByteBuffer.SS_MSG, metadata); buffer.flip(DirectByteBuffer.SS_MSG); } else if (msg_type == REJECT_MESSAGE_TYPE_ID) { Map<Object, Object> map = new HashMap<Object, Object>(); map.put("msg_type", msg_type); map.put("piece", piece); buffer = MessagingUtil.convertPayloadToBencodedByteStream( map, DirectByteBuffer.AL_MSG_UT_METADATA); } else { if (Logger.isEnabled()) { Logger.log( new LogEvent( LOGID, LogEvent.LT_ERROR, "METADATA (UT): No valid msg_type=" + msg_type)); } return null; } } return new DirectByteBuffer[] {buffer}; } catch (Throwable e) { // what is the best way to handle this error? if (Logger.isEnabled()) { Logger.log(new LogEvent(LOGID, LogEvent.LT_ERROR, "METADATA (UT)", e)); } return new DirectByteBuffer[0]; } }
private static byte[] getDummyPacket() throws IOException { DirectByteBuffer dbuffer = DirectByteBufferPool.getBuffer(DirectByteBuffer.AL_MSG, OSF2FMessage.MAX_PAYLOAD_SIZE); while (dbuffer.hasRemaining(DirectByteBuffer.SS_NET)) { dbuffer.put(DirectByteBuffer.SS_NET, (byte) 0); } dbuffer.flip(DirectByteBuffer.SS_NET); DirectByteBuffer[] data = OSF2FMessageFactory.createOSF2FRawMessage( new OSF2FChannelDataMsg(OSF2FMessage.CURRENT_VERSION, 0, -1, dbuffer)) .getRawData(); ByteBuffer buf = ByteBuffer.allocate(OSF2FMessage.MAX_MESSAGE_SIZE + 20); for (int i = 0; i < data.length; i++) { buf.put(data[i].getBuffer(DirectByteBuffer.SS_MSG)); } buf.flip(); byte[] b = new byte[buf.remaining()]; buf.get(b); return b; }
private int postReadProcess() throws IOException { int prot_bytes_read = 0; int data_bytes_read = 0; if (!reading_length_mode && !destroyed) { // reading payload data mode // ensure-restore proper buffer limits payload_buffer.limit(SS, message_length); length_buffer.limit(SS, 4); int read = payload_buffer.position(SS) - pre_read_start_position; if (payload_buffer.position(SS) > 0) { // need to have read the message id first byte if (BTMessageFactory.getMessageType(payload_buffer) == Message.TYPE_DATA_PAYLOAD) { data_bytes_read += read; } else { prot_bytes_read += read; } } if (!payload_buffer.hasRemaining(SS) && !is_paused) { // full message received! payload_buffer.position(SS, 0); DirectByteBuffer ref_buff = payload_buffer; payload_buffer = null; if (reading_handshake_message) { // decode handshake reading_handshake_message = false; DirectByteBuffer handshake_data = DirectByteBufferPool.getBuffer(DirectByteBuffer.AL_MSG_BT_HAND, 68); handshake_data.putInt(SS, HANDSHAKE_FAKE_LENGTH); handshake_data.put(SS, ref_buff); handshake_data.flip(SS); ref_buff.returnToPool(); try { Message handshake = MessageManager.getSingleton() .createMessage(BTMessage.ID_BT_HANDSHAKE_BYTES, handshake_data, (byte) 1); messages_last_read.add(handshake); } catch (MessageException me) { handshake_data.returnToPool(); throw new IOException("BT message decode failed: " + me.getMessage()); } // we need to auto-pause decoding until we're told to start again externally, // as we don't want to accidentally read the next message on the stream if it's an // AZ-format handshake pauseDecoding(); } else { // decode normal message try { messages_last_read.add(createMessage(ref_buff)); } catch (Throwable e) { ref_buff.returnToPoolIfNotFree(); // maintain unexpected errors as such so they get logged later if (e instanceof RuntimeException) { throw ((RuntimeException) e); } throw new IOException("BT message decode failed: " + e.getMessage()); } } reading_length_mode = true; // see if we've already read the next message's length percent_complete = -1; // reset receive percentage } else { // only partial received so far percent_complete = (payload_buffer.position(SS) * 100) / message_length; // compute receive percentage } } if (reading_length_mode && !destroyed) { length_buffer.limit(SS, 4); // ensure proper buffer limit prot_bytes_read += (pre_read_start_buffer == 1) ? length_buffer.position(SS) - pre_read_start_position : length_buffer.position(SS); if (!length_buffer.hasRemaining(SS)) { // done reading the length reading_length_mode = false; length_buffer.position(SS, 0); message_length = length_buffer.getInt(SS); length_buffer.position(SS, 0); // reset it for next length read if (message_length == HANDSHAKE_FAKE_LENGTH) { // handshake message reading_handshake_message = true; message_length = 64; // restore 'real' length payload_buffer = DirectByteBufferPool.getBuffer(DirectByteBuffer.AL_MSG_BT_HAND, message_length); } else if (message_length == 0) { // keep-alive message reading_length_mode = true; last_received_was_keepalive = true; try { Message keep_alive = MessageManager.getSingleton() .createMessage(BTMessage.ID_BT_KEEP_ALIVE_BYTES, null, (byte) 1); messages_last_read.add(keep_alive); } catch (MessageException me) { throw new IOException("BT message decode failed: " + me.getMessage()); } } else if (message_length < MIN_MESSAGE_LENGTH || message_length > MAX_MESSAGE_LENGTH) { throw new IOException( "Invalid message length given for BT message decode: " + message_length); } else { // normal message payload_buffer = DirectByteBufferPool.getBuffer(DirectByteBuffer.AL_MSG_BT_PAYLOAD, message_length); } } } protocol_bytes_last_read += prot_bytes_read; data_bytes_last_read += data_bytes_read; return prot_bytes_read + data_bytes_read; }
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; }
protected void convert(int target_type) throws FMFileManagerException { if (type == target_type) { return; } if (type == FMFile.FT_PIECE_REORDER || target_type == FMFile.FT_PIECE_REORDER) { if (target_type == FMFile.FT_PIECE_REORDER_COMPACT || type == FMFile.FT_PIECE_REORDER_COMPACT) { // these two access modes are in fact identical at the moment type = target_type; return; } throw (new FMFileManagerException("Conversion to/from piece-reorder not supported")); } File file = owner.getLinkedFile(); RandomAccessFile raf = null; boolean ok = false; try { FMFileAccess target_access; if (target_type == FMFile.FT_LINEAR) { target_access = new FMFileAccessLinear(owner); } else { target_access = new FMFileAccessCompact( owner.getOwner().getTorrentFile(), control_dir, controlFileName, new FMFileAccessLinear(owner)); } if (file.exists()) { raf = new RandomAccessFile(file, FMFileImpl.WRITE_ACCESS_MODE); // due to the simplistic implementation of compact we only actually need to deal with // the last piece of the file (first piece is in the right place already) FMFileAccessCompact compact_access; if (target_type == FMFile.FT_LINEAR) { compact_access = (FMFileAccessCompact) file_access; } else { compact_access = (FMFileAccessCompact) target_access; } long length = file_access.getLength(raf); long last_piece_start = compact_access.getLastPieceStart(); long last_piece_length = compact_access.getLastPieceLength(); // see if we have any potential data for the last piece if (last_piece_length > 0 && length > last_piece_start) { long data_length = length - last_piece_start; if (data_length > last_piece_length) { Debug.out( "data length inconsistent: len=" + data_length + ",limit=" + last_piece_length); data_length = last_piece_length; } DirectByteBuffer buffer = DirectByteBufferPool.getBuffer(DirectByteBuffer.AL_FILE, (int) data_length); try { file_access.read(raf, new DirectByteBuffer[] {buffer}, last_piece_start); // see if we need to truncate if (target_type == FMFile.FT_COMPACT) { long first_piece_length = compact_access.getFirstPieceLength(); long physical_length = raf.length(); if (physical_length > first_piece_length) { raf.setLength(first_piece_length); } } buffer.flip(DirectByteBuffer.AL_FILE); target_access.write(raf, new DirectByteBuffer[] {buffer}, last_piece_start); } finally { buffer.returnToPool(); } } else { // no last piece, truncate after the first piece if (target_type == FMFile.FT_COMPACT) { long first_piece_length = compact_access.getFirstPieceLength(); long physical_length = raf.length(); if (physical_length > first_piece_length) { raf.setLength(first_piece_length); } } } target_access.setLength(raf, length); target_access.flush(); } type = target_type; file_access = target_access; ok = true; } catch (Throwable e) { Debug.printStackTrace(e); throw (new FMFileManagerException("convert fails", e)); } finally { try { if (raf != null) { try { raf.close(); } catch (Throwable e) { // override original exception if there isn't one if (ok) { ok = false; throw (new FMFileManagerException("convert fails", e)); } } } } finally { if (!ok) { // conversion failed - replace with linear access, caller is responsible for // handling this (marking file requiring recheck) type = FMFile.FT_LINEAR; file_access = new FMFileAccessLinear(owner); } if (type == FMFile.FT_LINEAR) { new File(control_dir, controlFileName).delete(); } } } }