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();
}
}
}
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 });
}
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;
}
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();
}
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();
}
}
Aggregations