Search in sources :

Example 6 with RawMessage

use of com.biglybt.core.networkmanager.RawMessage in project BiglyBT by BiglySoftware.

the class OutgoingMessageQueueImpl method removeMessagesOfType.

/**
 * Remove all messages of the given types from the queue.
 * NOTE: Allows for manual listener notification at some later time,
 * using doListenerNotifications(), instead of notifying immediately
 * from within this method.  This is useful if you want to invoke
 * listeners outside of some greater synchronised block to avoid
 * deadlock.
 * @param message_types type to remove
 * @param manual_listener_notify true for manual notification, false for automatic
 */
@Override
public void removeMessagesOfType(Message[] message_types, boolean manual_listener_notify) {
    if (message_types == null)
        return;
    ArrayList<RawMessage> messages_removed = null;
    try {
        queue_mon.enter();
        for (Iterator<RawMessage> i = queue.iterator(); i.hasNext(); ) {
            RawMessage msg = i.next();
            for (int t = 0; t < message_types.length; t++) {
                boolean same_type = message_types[t].getID().equals(msg.getID());
                if (same_type && msg.getRawData()[0].position(DirectByteBuffer.SS_NET) == 0) {
                    // dont remove a half-sent message
                    if (msg == urgent_message)
                        urgent_message = null;
                    DirectByteBuffer[] payload = msg.getRawData();
                    int remaining = 0;
                    for (int x = 0; x < payload.length; x++) {
                        remaining += payload[x].remaining(DirectByteBuffer.SS_NET);
                    }
                    total_size -= remaining;
                    if (msg.getType() == Message.TYPE_DATA_PAYLOAD) {
                        total_data_size -= remaining;
                    }
                    if (manual_listener_notify) {
                        NotificationItem item = new NotificationItem(NotificationItem.MESSAGE_REMOVED);
                        item.message = msg;
                        try {
                            delayed_notifications_mon.enter();
                            delayed_notifications.add(item);
                        } finally {
                            delayed_notifications_mon.exit();
                        }
                    } else {
                        if (messages_removed == null) {
                            messages_removed = new ArrayList<>();
                        }
                        messages_removed.add(msg);
                    }
                    i.remove();
                    break;
                }
            }
        }
        if (queue.isEmpty()) {
            percent_complete = -1;
        }
    } finally {
        queue_mon.exit();
    }
    if (!manual_listener_notify && messages_removed != null) {
        // do listener notifications now
        ArrayList listeners_ref = listeners;
        for (int x = 0; x < messages_removed.size(); x++) {
            RawMessage msg = messages_removed.get(x);
            for (int i = 0; i < listeners_ref.size(); i++) {
                MessageQueueListener listener = (MessageQueueListener) listeners_ref.get(i);
                listener.messageRemoved(msg.getBaseMessage());
            }
            msg.destroy();
        }
    }
}
Also used : ArrayList(java.util.ArrayList) RawMessage(com.biglybt.core.networkmanager.RawMessage) DirectByteBuffer(com.biglybt.core.util.DirectByteBuffer)

Example 7 with RawMessage

use of com.biglybt.core.networkmanager.RawMessage in project BiglyBT by BiglySoftware.

the class OutgoingMessageQueueImpl method deliverToTransport.

/**
 * Deliver (write) message(s) data to the underlying transport.
 *
 * NOTE: Allows for manual listener notification at some later time,
 * using doListenerNotifications(), instead of notifying immediately
 * from within this method.  This is useful if you want to invoke
 * listeners outside of some greater synchronised block to avoid
 * deadlock.
 * @param max_bytes maximum number of bytes to deliver
 * @param manual_listener_notify true for manual notification, false for automatic
 * @return number of bytes delivered
 * @throws IOException on delivery error
 */
@Override
public int[] deliverToTransport(int max_bytes, boolean protocol_is_free, boolean manual_listener_notify) throws IOException {
    if (max_bytes < 1) {
        if (!protocol_is_free) {
            Debug.out("max_bytes < 1: " + max_bytes);
            return (new int[2]);
        }
        // in case it was negative
        max_bytes = 0;
    }
    if (transport == null) {
        throw (new IOException("not ready to deliver data"));
    }
    int data_written = 0;
    int protocol_written = 0;
    ArrayList<RawMessage> messages_sent = null;
    // System.out.println( "deliver: %=" + percent_complete + ", queue=" + queue.size());
    try {
        queue_mon.enter();
        if (!queue.isEmpty()) {
            int buffer_limit = 64;
            ByteBuffer[] raw_buffers = (ByteBuffer[]) rawBufferCache.get();
            if (raw_buffers == null) {
                raw_buffers = new ByteBuffer[buffer_limit];
                rawBufferCache = new WeakReference(raw_buffers);
            } else {
                Arrays.fill(raw_buffers, null);
            }
            int[] orig_positions = (int[]) origPositionsCache.get();
            if (orig_positions == null) {
                orig_positions = new int[buffer_limit];
                origPositionsCache = new WeakReference(orig_positions);
            } else {
                Arrays.fill(orig_positions, 0);
            }
            int buffer_count = 0;
            int total_sofar_excluding_free = 0;
            int total_to_write = 0;
            outer: for (Iterator<RawMessage> i = queue.iterator(); i.hasNext(); ) {
                RawMessage message = i.next();
                boolean msg_is_free = message.getType() == Message.TYPE_PROTOCOL_PAYLOAD && protocol_is_free;
                DirectByteBuffer[] payloads = message.getRawData();
                for (int x = 0; x < payloads.length; x++) {
                    ByteBuffer buff = payloads[x].getBuffer(DirectByteBuffer.SS_NET);
                    raw_buffers[buffer_count] = buff;
                    orig_positions[buffer_count] = buff.position();
                    buffer_count++;
                    int rem = buff.remaining();
                    total_to_write += rem;
                    if (!msg_is_free) {
                        total_sofar_excluding_free += rem;
                        if (total_sofar_excluding_free >= max_bytes) {
                            break outer;
                        }
                    }
                    if (buffer_count == buffer_limit) {
                        int new_buffer_limit = buffer_limit * 2;
                        ByteBuffer[] new_raw_buffers = new ByteBuffer[new_buffer_limit];
                        int[] new_orig_positions = new int[new_buffer_limit];
                        System.arraycopy(raw_buffers, 0, new_raw_buffers, 0, buffer_limit);
                        System.arraycopy(orig_positions, 0, new_orig_positions, 0, buffer_limit);
                        raw_buffers = new_raw_buffers;
                        orig_positions = new_orig_positions;
                        buffer_limit = new_buffer_limit;
                    }
                }
            }
            ByteBuffer last_buff = (ByteBuffer) raw_buffers[buffer_count - 1];
            int orig_last_limit = last_buff.limit();
            if (total_sofar_excluding_free > max_bytes) {
                int reduce_by = total_sofar_excluding_free - max_bytes;
                last_buff.limit(orig_last_limit - reduce_by);
                total_to_write -= reduce_by;
            }
            if (total_to_write <= 0) {
                last_buff.limit(orig_last_limit);
                return (new int[2]);
            }
            transport.write(raw_buffers, 0, buffer_count);
            last_buff.limit(orig_last_limit);
            int pos = 0;
            boolean stop = false;
            while (!queue.isEmpty() && !stop) {
                RawMessage msg = queue.get(0);
                DirectByteBuffer[] payloads = msg.getRawData();
                for (int x = 0; x < payloads.length; x++) {
                    ByteBuffer bb = payloads[x].getBuffer(DirectByteBuffer.SS_NET);
                    int bytes_written = (bb.limit() - bb.remaining()) - orig_positions[pos];
                    total_size -= bytes_written;
                    if (msg.getType() == Message.TYPE_DATA_PAYLOAD) {
                        total_data_size -= bytes_written;
                    }
                    if (x > 0 && msg.getType() == Message.TYPE_DATA_PAYLOAD) {
                        // assumes the first buffer is message header
                        data_written += bytes_written;
                    } else {
                        protocol_written += bytes_written;
                    }
                    if (bb.hasRemaining()) {
                        // still data left to send in this message
                        // so don't bother checking later messages for completion
                        stop = true;
                        // compute send percentage
                        int message_size = 0;
                        int written = 0;
                        for (int i = 0; i < payloads.length; i++) {
                            ByteBuffer buff = payloads[i].getBuffer(DirectByteBuffer.SS_NET);
                            message_size += buff.limit();
                            if (i < x) {
                                // if in front of non-empty buffer
                                written += buff.limit();
                            } else if (i == x) {
                                // is non-empty buffer
                                written += buff.position();
                            }
                        }
                        percent_complete = (written * 100) / message_size;
                        break;
                    } else if (x == payloads.length - 1) {
                        // last payload buffer of message is empty
                        if (msg == urgent_message)
                            urgent_message = null;
                        queue.remove(0);
                        if (TRACE_HISTORY) {
                            prev_sent.addLast(msg);
                            if (prev_sent.size() > MAX_HISTORY_TRACES)
                                prev_sent.removeFirst();
                        }
                        // reset send percentage
                        percent_complete = -1;
                        if (manual_listener_notify) {
                            NotificationItem item = new NotificationItem(NotificationItem.MESSAGE_SENT);
                            item.message = msg;
                            try {
                                delayed_notifications_mon.enter();
                                delayed_notifications.add(item);
                            } finally {
                                delayed_notifications_mon.exit();
                            }
                        } else {
                            if (messages_sent == null) {
                                messages_sent = new ArrayList<>();
                            }
                            messages_sent.add(msg);
                        }
                    }
                    pos++;
                    if (pos >= buffer_count) {
                        stop = true;
                        break;
                    }
                }
            }
        }
    } finally {
        queue_mon.exit();
    }
    if (data_written + protocol_written > 0 || messages_sent != null) {
        if (trace) {
            TimeFormatter.milliTrace("omq:deliver: " + (data_written + protocol_written) + ", q=" + queue.size() + "/" + total_size);
        }
        if (manual_listener_notify) {
            if (data_written > 0) {
                // data bytes notify
                NotificationItem item = new NotificationItem(NotificationItem.DATA_BYTES_SENT);
                item.byte_count = data_written;
                try {
                    delayed_notifications_mon.enter();
                    delayed_notifications.add(item);
                } finally {
                    delayed_notifications_mon.exit();
                }
            }
            if (protocol_written > 0) {
                // protocol bytes notify
                NotificationItem item = new NotificationItem(NotificationItem.PROTOCOL_BYTES_SENT);
                item.byte_count = protocol_written;
                try {
                    delayed_notifications_mon.enter();
                    delayed_notifications.add(item);
                } finally {
                    delayed_notifications_mon.exit();
                }
            }
        } else {
            // do listener notification now
            ArrayList listeners_ref = listeners;
            int num_listeners = listeners_ref.size();
            for (int i = 0; i < num_listeners; i++) {
                MessageQueueListener listener = (MessageQueueListener) listeners_ref.get(i);
                if (data_written > 0)
                    listener.dataBytesSent(data_written);
                if (protocol_written > 0)
                    listener.protocolBytesSent(protocol_written);
                if (messages_sent != null) {
                    for (int x = 0; x < messages_sent.size(); x++) {
                        RawMessage msg = messages_sent.get(x);
                        listener.messageSent(msg.getBaseMessage());
                        if (i == num_listeners - 1) {
                            // the last listener notification, so destroy
                            msg.destroy();
                        }
                    }
                }
            }
        }
    } else {
        if (trace) {
            TimeFormatter.milliTrace("omq:deliver: 0, q=" + queue.size() + "/" + total_size);
        }
    }
    return (new int[] { data_written, protocol_written });
}
Also used : ArrayList(java.util.ArrayList) IOException(java.io.IOException) ByteBuffer(java.nio.ByteBuffer) DirectByteBuffer(com.biglybt.core.util.DirectByteBuffer) WeakReference(java.lang.ref.WeakReference) Iterator(java.util.Iterator) RawMessage(com.biglybt.core.networkmanager.RawMessage) DirectByteBuffer(com.biglybt.core.util.DirectByteBuffer)

Example 8 with RawMessage

use of com.biglybt.core.networkmanager.RawMessage in project BiglyBT by BiglySoftware.

the class OutgoingMessageQueueImpl method removeMessage.

/**
 * Remove a particular message from the queue.
 * NOTE: Only the original message found in the queue will be destroyed upon removal,
 * which may not necessarily be the one passed as the method parameter,
 * as some messages override equals() (i.e. BTRequest messages) instead of using reference
 * equality, and could be a completely different object, and would need to be destroyed
 * manually.  If the message does not override equals, then any such method will likely
 * *not* be found and removed, as internal queued object was a new allocation on insertion.
 * NOTE: Allows for manual listener notification at some later time,
 * using doListenerNotifications(), instead of notifying immediately
 * from within this method.  This is useful if you want to invoke
 * listeners outside of some greater synchronised block to avoid
 * deadlock.
 * @param message to remove
 * @param manual_listener_notify true for manual notification, false for automatic
 * @return true if the message was removed, false otherwise
 */
@Override
public boolean removeMessage(Message message, boolean manual_listener_notify) {
    RawMessage msg_removed = null;
    try {
        queue_mon.enter();
        for (Iterator<RawMessage> it = queue.iterator(); it.hasNext(); ) {
            RawMessage raw = it.next();
            if (message.equals(raw.getBaseMessage())) {
                if (raw.getRawData()[0].position(DirectByteBuffer.SS_NET) == 0) {
                    // dont remove a half-sent message
                    if (raw == urgent_message)
                        urgent_message = null;
                    DirectByteBuffer[] payload = raw.getRawData();
                    int remaining = 0;
                    for (int x = 0; x < payload.length; x++) {
                        remaining += payload[x].remaining(DirectByteBuffer.SS_NET);
                    }
                    total_size -= remaining;
                    if (raw.getType() == Message.TYPE_DATA_PAYLOAD) {
                        total_data_size -= remaining;
                    }
                    queue.remove(raw);
                    msg_removed = raw;
                }
                break;
            }
        }
        if (queue.isEmpty()) {
            percent_complete = -1;
        }
    } finally {
        queue_mon.exit();
    }
    if (msg_removed != null) {
        if (manual_listener_notify) {
            // delayed manual notification
            NotificationItem item = new NotificationItem(NotificationItem.MESSAGE_REMOVED);
            item.message = msg_removed;
            try {
                delayed_notifications_mon.enter();
                delayed_notifications.add(item);
            } finally {
                delayed_notifications_mon.exit();
            }
        } else {
            // do listener notification now
            ArrayList listeners_ref = listeners;
            for (int i = 0; i < listeners_ref.size(); i++) {
                MessageQueueListener listener = (MessageQueueListener) listeners_ref.get(i);
                listener.messageRemoved(msg_removed.getBaseMessage());
            }
            msg_removed.destroy();
        }
        return true;
    }
    return false;
}
Also used : ArrayList(java.util.ArrayList) RawMessage(com.biglybt.core.networkmanager.RawMessage) DirectByteBuffer(com.biglybt.core.util.DirectByteBuffer)

Example 9 with RawMessage

use of com.biglybt.core.networkmanager.RawMessage in project BiglyBT by BiglySoftware.

the class OutgoingMessageQueueImpl method getQueueTrace.

@Override
public String getQueueTrace() {
    StringBuilder trace = new StringBuilder();
    trace.append("**** OUTGOING QUEUE TRACE ****\n");
    try {
        queue_mon.enter();
        int i = 0;
        for (Iterator<RawMessage> it = prev_sent.iterator(); it.hasNext(); ) {
            RawMessage raw = it.next();
            trace.append("[#h").append(i).append("]: ").append(raw.getID()).append(" [").append(raw.getDescription()).append("]").append("\n");
            i++;
        }
        int position = queue.size() - 1;
        for (Iterator<RawMessage> it = queue.iterator(); it.hasNext(); ) {
            RawMessage raw = it.next();
            int pos = raw.getRawData()[0].position(DirectByteBuffer.SS_NET);
            int length = raw.getRawData()[0].limit(DirectByteBuffer.SS_NET);
            trace.append("[#").append(position).append(" ").append(pos).append(":").append(length).append("]: ").append(raw.getID()).append(" [").append(raw.getDescription()).append("]").append("\n");
            position--;
        }
    } finally {
        queue_mon.exit();
    }
    return trace.toString();
}
Also used : RawMessage(com.biglybt.core.networkmanager.RawMessage)

Example 10 with RawMessage

use of com.biglybt.core.networkmanager.RawMessage in project BiglyBT by BiglySoftware.

the class OutgoingMessageQueueImpl method flush.

@Override
public void flush() {
    try {
        queue_mon.enter();
        if (queue.isEmpty()) {
            return;
        }
        for (int i = 0; i < queue.size(); i++) {
            RawMessage msg = queue.get(i);
            msg.setNoDelay();
            if (i == 0) {
                urgent_message = msg;
            }
        }
    } finally {
        queue_mon.exit();
    }
    ArrayList list_ref = listeners;
    for (int i = 0; i < list_ref.size(); i++) {
        MessageQueueListener listener = (MessageQueueListener) list_ref.get(i);
        listener.flush();
    }
}
Also used : ArrayList(java.util.ArrayList) RawMessage(com.biglybt.core.networkmanager.RawMessage)

Aggregations

RawMessage (com.biglybt.core.networkmanager.RawMessage)10 DirectByteBuffer (com.biglybt.core.util.DirectByteBuffer)6 ArrayList (java.util.ArrayList)5 RawMessageImpl (com.biglybt.core.networkmanager.impl.RawMessageImpl)3 Message (com.biglybt.core.peermanager.messaging.Message)2 IOException (java.io.IOException)2 WeakReference (java.lang.ref.WeakReference)1 ByteBuffer (java.nio.ByteBuffer)1 Iterator (java.util.Iterator)1