static void advance(unsigned char **cursor, qd_buffer_t **buffer, int consume, buffer_process_t handler, void *context) { unsigned char *local_cursor = *cursor; qd_buffer_t *local_buffer = *buffer; int remaining = qd_buffer_size(local_buffer) - (local_cursor - qd_buffer_base(local_buffer)); while (consume > 0) { if (consume < remaining) { if (handler) handler(context, local_cursor, consume); local_cursor += consume; consume = 0; } else { if (handler) handler(context, local_cursor, remaining); consume -= remaining; local_buffer = local_buffer->next; if (local_buffer == 0){ local_cursor = 0; break; } local_cursor = qd_buffer_base(local_buffer); remaining = qd_buffer_size(local_buffer) - (local_cursor - qd_buffer_base(local_buffer)); } } *cursor = local_cursor; *buffer = local_buffer; }
ssize_t qd_message_field_copy(qd_message_t *msg, qd_message_field_t field, void *buffer, size_t *hdr_length) { qd_field_location_t *loc = qd_message_field_location(msg, field); if (!loc) return -1; qd_buffer_t *buf = loc->buffer; size_t bufsize = qd_buffer_size(buf) - loc->offset; void *base = qd_buffer_base(buf) + loc->offset; size_t remaining = loc->length + loc->hdr_length; *hdr_length = loc->hdr_length; while (remaining > 0) { if (bufsize > remaining) bufsize = remaining; memcpy(buffer, base, bufsize); buffer += bufsize; remaining -= bufsize; if (remaining > 0) { buf = buf->next; base = qd_buffer_base(buf); bufsize = qd_buffer_size(buf); } } return loc->length + loc->hdr_length; }
qd_iovec_t *qd_iterator_iovec(const qd_iterator_t *iter) { if (!iter) return 0; // // Count the number of buffers this field straddles // pointer_t pointer = iter->view_start_pointer; int bufcnt = 1; qd_buffer_t *buf = pointer.buffer; size_t bufsize = qd_buffer_size(buf) - (pointer.cursor - qd_buffer_base(pointer.buffer)); ssize_t remaining = pointer.remaining - bufsize; while (remaining > 0) { bufcnt++; buf = buf->next; if (!buf) return 0; remaining -= qd_buffer_size(buf); } // // Allocate an iovec object big enough to hold the number of buffers // qd_iovec_t *iov = qd_iovec(bufcnt); if (!iov) return 0; // // Build out the io vectors with pointers to the segments of the field in buffers // bufcnt = 0; buf = pointer.buffer; bufsize = qd_buffer_size(buf) - (pointer.cursor - qd_buffer_base(pointer.buffer)); void *base = pointer.cursor; remaining = pointer.remaining; while (remaining > 0) { if (bufsize > remaining) bufsize = remaining; qd_iovec_array(iov)[bufcnt].iov_base = base; qd_iovec_array(iov)[bufcnt].iov_len = bufsize; bufcnt++; remaining -= bufsize; if (remaining > 0) { buf = buf->next; base = qd_buffer_base(buf); bufsize = qd_buffer_size(buf); } } return iov; }
unsigned int qd_buffer_list_clone(qd_buffer_list_t *dst, const qd_buffer_list_t *src) { uint32_t len = 0; DEQ_INIT(*dst); qd_buffer_t *buf = DEQ_HEAD(*src); while (buf) { size_t to_copy = qd_buffer_size(buf); unsigned char *src = qd_buffer_base(buf); len += to_copy; while (to_copy) { qd_buffer_t *newbuf = qd_buffer(); size_t count = qd_buffer_capacity(newbuf); // default buffer capacity may have changed, // so don't assume it will fit: if (count > to_copy) count = to_copy; memcpy(qd_buffer_cursor(newbuf), src, count); qd_buffer_insert(newbuf, count); DEQ_INSERT_TAIL(*dst, newbuf); src += count; to_copy -= count; } buf = DEQ_NEXT(buf); } return len; }
unsigned int qd_buffer_list_length(const qd_buffer_list_t *list) { unsigned int len = 0; qd_buffer_t *buf = DEQ_HEAD(*list); while (buf) { len += qd_buffer_size(buf); buf = DEQ_NEXT(buf); } return len; }
static char *test_tracemask(void *context) { qd_bitmask_t *bm = NULL; qd_tracemask_t *tm = qd_tracemask(); qd_buffer_list_t list; static char error[1024]; error[0] = 0; qd_iterator_set_address(false, "0", "ROUTER"); qd_tracemask_add_router(tm, "amqp:/_topo/0/Router.A", 0); qd_tracemask_add_router(tm, "amqp:/_topo/0/Router.B", 1); qd_tracemask_add_router(tm, "amqp:/_topo/0/Router.C", 2); qd_tracemask_add_router(tm, "amqp:/_topo/0/Router.D", 3); qd_tracemask_add_router(tm, "amqp:/_topo/0/Router.E", 4); qd_tracemask_add_router(tm, "amqp:/_topo/0/Router.F", 5); qd_tracemask_set_link(tm, 0, 4); qd_tracemask_set_link(tm, 3, 10); qd_tracemask_set_link(tm, 4, 3); qd_tracemask_set_link(tm, 5, 2); qd_composed_field_t *comp = qd_compose_subfield(0); qd_compose_start_list(comp); qd_compose_insert_string(comp, "0/Router.A"); qd_compose_insert_string(comp, "0/Router.D"); qd_compose_insert_string(comp, "0/Router.E"); qd_compose_end_list(comp); DEQ_INIT(list); qd_compose_take_buffers(comp, &list); qd_compose_free(comp); int length = 0; qd_buffer_t *buf = DEQ_HEAD(list); while (buf) { length += qd_buffer_size(buf); buf = DEQ_NEXT(buf); } qd_iterator_t *iter = qd_iterator_buffer(DEQ_HEAD(list), 0, length, ITER_VIEW_ALL); qd_parsed_field_t *pf = qd_parse(iter); qd_iterator_free(iter); int ingress = -1; bm = qd_tracemask_create(tm, pf, &ingress); if (qd_bitmask_cardinality(bm) != 3) { sprintf(error, "Expected cardinality of 3, got %d", qd_bitmask_cardinality(bm)); goto cleanup; } if (ingress != 0) { sprintf(error, "(A) Expected ingress index of 0, got %d", ingress); goto cleanup; } int total = 0; int bit, c; for (QD_BITMASK_EACH(bm, bit, c)) { total += bit; } if (total != 17) { sprintf(error, "Expected total bit value of 17, got %d", total); goto cleanup; } qd_bitmask_free(bm); bm = 0; qd_tracemask_del_router(tm, 3); qd_tracemask_remove_link(tm, 0); ingress = -1; bm = qd_tracemask_create(tm, pf, &ingress); qd_parse_free(pf); pf = 0; if (qd_bitmask_cardinality(bm) != 1) { sprintf(error, "Expected cardinality of 1, got %d", qd_bitmask_cardinality(bm)); goto cleanup; } if (ingress != 0) { sprintf(error, "(B) Expected ingress index of 0, got %d", ingress); goto cleanup; } total = 0; for (QD_BITMASK_EACH(bm, bit, c)) { total += bit; } if (total != 3) { sprintf(error, "Expected total bit value of 3, got %d", total); // fallthrough } cleanup: qd_parse_free(pf); qd_tracemask_free(tm); qd_bitmask_free(bm); for (qd_buffer_t *buf = DEQ_HEAD(list); buf; buf = DEQ_HEAD(list)) { DEQ_REMOVE_HEAD(list); qd_buffer_free(buf); } return *error ? error : 0; }
void qd_message_send(qd_message_t *in_msg, qd_link_t *link, bool strip_annotations) { qd_message_pvt_t *msg = (qd_message_pvt_t*) in_msg; qd_message_content_t *content = msg->content; qd_buffer_t *buf = DEQ_HEAD(content->buffers); unsigned char *cursor; pn_link_t *pnl = qd_link_pn(link); char repr[qd_message_repr_len()]; qd_log(log_source, QD_LOG_TRACE, "Sending %s on link %s", qd_message_repr(in_msg, repr, sizeof(repr)), pn_link_name(pnl)); qd_buffer_list_t new_ma; DEQ_INIT(new_ma); if (strip_annotations || compose_message_annotations(msg, &new_ma)) { // // This is the case where the message annotations have been modified. // The message send must be divided into sections: The existing header; // the new message annotations; the rest of the existing message. // Note that the original message annotations that are still in the // buffer chain must not be sent. // // Start by making sure that we've parsed the message sections through // the message annotations // // ??? NO LONGER NECESSARY??? if (!qd_message_check(in_msg, QD_DEPTH_MESSAGE_ANNOTATIONS)) { qd_log(log_source, QD_LOG_ERROR, "Cannot send: %s", qd_error_message); return; } // // Send header if present // cursor = qd_buffer_base(buf); if (content->section_message_header.length > 0) { buf = content->section_message_header.buffer; cursor = content->section_message_header.offset + qd_buffer_base(buf); advance(&cursor, &buf, content->section_message_header.length + content->section_message_header.hdr_length, send_handler, (void*) pnl); } // // Send new message annotations // qd_buffer_t *da_buf = DEQ_HEAD(new_ma); while (da_buf) { pn_link_send(pnl, (char*) qd_buffer_base(da_buf), qd_buffer_size(da_buf)); da_buf = DEQ_NEXT(da_buf); } qd_buffer_list_free_buffers(&new_ma); // // Skip over replaced message annotations // if (content->section_message_annotation.length > 0) advance(&cursor, &buf, content->section_message_annotation.hdr_length + content->section_message_annotation.length, 0, 0); // // Send remaining partial buffer // if (buf) { size_t len = qd_buffer_size(buf) - (cursor - qd_buffer_base(buf)); advance(&cursor, &buf, len, send_handler, (void*) pnl); } // Fall through to process the remaining buffers normally // Note that 'advance' will have moved us to the next buffer in the chain. } while (buf) { pn_link_send(pnl, (char*) qd_buffer_base(buf), qd_buffer_size(buf)); buf = DEQ_NEXT(buf); } }
qd_message_t *qd_message_receive(pn_delivery_t *delivery) { pn_link_t *link = pn_delivery_link(delivery); ssize_t rc; qd_buffer_t *buf; qd_message_pvt_t *msg = (qd_message_pvt_t*) pn_delivery_get_context(delivery); // // If there is no message associated with the delivery, this is the first time // we've received anything on this delivery. Allocate a message descriptor and // link it and the delivery together. // if (!msg) { msg = (qd_message_pvt_t*) qd_message(); pn_delivery_set_context(delivery, (void*) msg); } // // Get a reference to the tail buffer on the message. This is the buffer into which // we will store incoming message data. If there is no buffer in the message, allocate // an empty one and add it to the message. // buf = DEQ_TAIL(msg->content->buffers); if (!buf) { buf = qd_buffer(); DEQ_INSERT_TAIL(msg->content->buffers, buf); } while (1) { // // Try to receive enough data to fill the remaining space in the tail buffer. // rc = pn_link_recv(link, (char*) qd_buffer_cursor(buf), qd_buffer_capacity(buf)); // // If we receive PN_EOS, we have come to the end of the message. // if (rc == PN_EOS) { // // If the last buffer in the list is empty, remove it and free it. This // will only happen if the size of the message content is an exact multiple // of the buffer size. // if (qd_buffer_size(buf) == 0) { DEQ_REMOVE_TAIL(msg->content->buffers); qd_buffer_free(buf); } pn_delivery_set_context(delivery, 0); char repr[qd_message_repr_len()]; qd_log(log_source, QD_LOG_TRACE, "Received %s on link %s", qd_message_repr((qd_message_t*)msg, repr, sizeof(repr)), pn_link_name(link)); return (qd_message_t*) msg; } if (rc > 0) { // // We have received a positive number of bytes for the message. Advance // the cursor in the buffer. // qd_buffer_insert(buf, rc); // // If the buffer is full, allocate a new empty buffer and append it to the // tail of the message's list. // if (qd_buffer_capacity(buf) == 0) { buf = qd_buffer(); DEQ_INSERT_TAIL(msg->content->buffers, buf); } } else // // We received zero bytes, and no PN_EOS. This means that we've received // all of the data available up to this point, but it does not constitute // the entire message. We'll be back later to finish it up. // break; } return 0; }
// // Check the buffer chain, starting at cursor to see if it matches the pattern. // If the pattern matches, check the next tag to see if it's in the set of expected // tags. If not, return zero. If so, set the location descriptor to the good // tag and advance the cursor (and buffer, if needed) to the end of the matched section. // // If there is no match, don't advance the cursor. // // Return 0 if the pattern matches but the following tag is unexpected // Return 0 if the pattern matches and the location already has a pointer (duplicate section) // Return 1 if the pattern matches and we've advanced the cursor/buffer // Return 1 if the pattern does not match // static int qd_check_and_advance(qd_buffer_t **buffer, unsigned char **cursor, const unsigned char *pattern, int pattern_length, const unsigned char *expected_tags, qd_field_location_t *location) { qd_buffer_t *test_buffer = *buffer; unsigned char *test_cursor = *cursor; if (!test_cursor) return 1; // no match unsigned char *end_of_buffer = qd_buffer_base(test_buffer) + qd_buffer_size(test_buffer); int idx = 0; while (idx < pattern_length && *test_cursor == pattern[idx]) { idx++; test_cursor++; if (test_cursor == end_of_buffer) { test_buffer = test_buffer->next; if (test_buffer == 0) return 1; // Pattern didn't match test_cursor = qd_buffer_base(test_buffer); end_of_buffer = test_cursor + qd_buffer_size(test_buffer); } } if (idx < pattern_length) return 1; // Pattern didn't match // // Pattern matched, check the tag // while (*expected_tags && *test_cursor != *expected_tags) expected_tags++; if (*expected_tags == 0) return 0; // Unexpected tag if (location->parsed) return 0; // Duplicate section // // Pattern matched and tag is expected. Mark the beginning of the section. // location->parsed = 1; location->buffer = *buffer; location->offset = *cursor - qd_buffer_base(*buffer); location->length = 0; location->hdr_length = pattern_length; // // Advance the pointers to consume the whole section. // int pre_consume = 1; // Count the already extracted tag int consume = 0; unsigned char tag = next_octet(&test_cursor, &test_buffer); if (!test_cursor) return 0; switch (tag) { case 0x45 : // list0 break; case 0xd0 : // list32 case 0xd1 : // map32 case 0xb0 : // vbin32 pre_consume += 3; consume |= ((int) next_octet(&test_cursor, &test_buffer)) << 24; if (!test_cursor) return 0; consume |= ((int) next_octet(&test_cursor, &test_buffer)) << 16; if (!test_cursor) return 0; consume |= ((int) next_octet(&test_cursor, &test_buffer)) << 8; if (!test_cursor) return 0; // Fall through to the next case... case 0xc0 : // list8 case 0xc1 : // map8 case 0xa0 : // vbin8 pre_consume += 1; consume |= (int) next_octet(&test_cursor, &test_buffer); if (!test_cursor) return 0; break; } location->length = pre_consume + consume; if (consume) advance(&test_cursor, &test_buffer, consume, 0, 0); *cursor = test_cursor; *buffer = test_buffer; return 1; }