amqp_field_value_t TableValueImpl::CopyValue(const amqp_field_value_t value, amqp_pool_t &pool) { amqp_field_value_t new_value = value; switch (value.kind) { case AMQP_FIELD_KIND_UTF8: case AMQP_FIELD_KIND_BYTES: amqp_pool_alloc_bytes(&pool, value.value.bytes.len, &new_value.value.bytes); memcpy(new_value.value.bytes.bytes, value.value.bytes.bytes, value.value.bytes.len); return new_value; case AMQP_FIELD_KIND_ARRAY: { new_value.value.array.entries = (amqp_field_value_t*)amqp_pool_alloc(&pool, sizeof(amqp_field_value_t)*value.value.array.num_entries); for (int i = 0; i < value.value.array.num_entries; ++i) { new_value.value.array.entries[i] = CopyValue(value.value.array.entries[i], pool); } return new_value; } case AMQP_FIELD_KIND_TABLE: new_value.value.table = CopyTableInner(value.value.table, pool); return new_value; default: return new_value; } }
amqp_table_t TableValueImpl::CopyTableInner(const amqp_table_t &table, amqp_pool_t &pool) { amqp_table_t new_table; new_table.num_entries = table.num_entries; new_table.entries = (amqp_table_entry_t*)amqp_pool_alloc(&pool, sizeof(amqp_table_entry_t)*table.num_entries); if (NULL == new_table.entries) { throw std::bad_alloc(); } for (int i = 0; i < table.num_entries; ++i) { amqp_table_entry_t *entry = &new_table.entries[i]; amqp_pool_alloc_bytes(&pool, table.entries[i].key.len, &entry->key); if (NULL == entry->key.bytes) { throw std::bad_alloc(); } memcpy(entry->key.bytes, table.entries[i].key.bytes, entry->key.len); entry->value = CopyValue(table.entries[i].value, pool); } return new_table; }
amqp_table_t TableValueImpl::CreateAmqpTableInner(const Table &table, amqp_pool_t &pool) { amqp_table_t new_table; new_table.num_entries = table.size(); new_table.entries = (amqp_table_entry_t*)amqp_pool_alloc(&pool, sizeof(amqp_table_entry_t)*table.size()); if (NULL == new_table.entries) { throw std::bad_alloc(); } amqp_table_entry_t *output_it = new_table.entries; for (Table::const_iterator it = table.begin(); it != table.end(); ++it, ++output_it) { amqp_pool_alloc_bytes(&pool, it->first.size(), &output_it->key); if (NULL == output_it->key.bytes) { throw std::bad_alloc(); } std::copy(it->first.begin(), it->first.end(), (char *)output_it->key.bytes); output_it->value = boost::apply_visitor(TableValueImpl::generate_field_value(pool), it->second.m_impl->m_value); } return new_table; }
static amqp_bytes_t sasl_response(amqp_pool_t *pool, amqp_sasl_method_enum method, va_list args) { amqp_bytes_t response; switch (method) { case AMQP_SASL_METHOD_PLAIN: { char *username = va_arg(args, char *); size_t username_len = strlen(username); char *password = va_arg(args, char *); size_t password_len = strlen(password); char *response_buf; amqp_pool_alloc_bytes(pool, strlen(username) + strlen(password) + 2, &response); if (response.bytes == NULL) /* We never request a zero-length block, because of the +2 above, so a NULL here really is ENOMEM. */ return response; response_buf = response.bytes; response_buf[0] = 0; memcpy(response_buf + 1, username, username_len); response_buf[username_len + 1] = 0; memcpy(response_buf + username_len + 2, password, password_len); break; } default: amqp_abort("Invalid SASL method: %d", (int) method); } return response; }
static amqp_bytes_t sasl_method_name(amqp_sasl_method_enum method) { switch (method) { case AMQP_SASL_METHOD_PLAIN: return (amqp_bytes_t) {.len = 5, .bytes = "PLAIN"}; default: amqp_assert(0, "Invalid SASL method: %d", (int) method); } abort(); /* unreachable */ } static amqp_bytes_t sasl_response(amqp_pool_t *pool, amqp_sasl_method_enum method, va_list args) { amqp_bytes_t response; switch (method) { case AMQP_SASL_METHOD_PLAIN: { char *username = va_arg(args, char *); size_t username_len = strlen(username); char *password = va_arg(args, char *); size_t password_len = strlen(password); amqp_pool_alloc_bytes(pool, strlen(username) + strlen(password) + 2, &response); *BUF_AT(response, 0) = 0; memcpy(((char *) response.bytes) + 1, username, username_len); *BUF_AT(response, username_len + 1) = 0; memcpy(((char *) response.bytes) + username_len + 2, password, password_len); break; } default: amqp_assert(0, "Invalid SASL method: %d", (int) method); } return response; }
amqp_field_value_t TableValueImpl::generate_field_value::operator()(const std::string &value) const { amqp_field_value_t v; v.kind = AMQP_FIELD_KIND_UTF8; amqp_pool_alloc_bytes(&pool, value.size(), &v.value.bytes); memcpy(v.value.bytes.bytes, value.data(), v.value.bytes.len); return v; }
int amqp_handle_input(amqp_connection_state_t state, amqp_bytes_t received_data, amqp_frame_t *decoded_frame) { size_t bytes_consumed; void *raw_frame; /* Returning frame_type of zero indicates either insufficient input, or a complete, ignored frame was read. */ decoded_frame->frame_type = 0; if (received_data.len == 0) { return AMQP_STATUS_OK; } if (state->state == CONNECTION_STATE_IDLE) { state->state = CONNECTION_STATE_HEADER; } bytes_consumed = consume_data(state, &received_data); /* do we have target_size data yet? if not, return with the expectation that more will arrive */ if (state->inbound_offset < state->target_size) { return bytes_consumed; } raw_frame = state->inbound_buffer.bytes; switch (state->state) { case CONNECTION_STATE_INITIAL: /* check for a protocol header from the server */ if (memcmp(raw_frame, "AMQP", 4) == 0) { decoded_frame->frame_type = AMQP_PSEUDOFRAME_PROTOCOL_HEADER; decoded_frame->channel = 0; decoded_frame->payload.protocol_header.transport_high = amqp_d8(raw_frame, 4); decoded_frame->payload.protocol_header.transport_low = amqp_d8(raw_frame, 5); decoded_frame->payload.protocol_header.protocol_version_major = amqp_d8(raw_frame, 6); decoded_frame->payload.protocol_header.protocol_version_minor = amqp_d8(raw_frame, 7); return_to_idle(state); return bytes_consumed; } /* it's not a protocol header; fall through to process it as a regular frame header */ case CONNECTION_STATE_HEADER: { amqp_channel_t channel; amqp_pool_t *channel_pool; /* frame length is 3 bytes in */ channel = amqp_d16(raw_frame, 1); state->target_size = amqp_d32(raw_frame, 3) + HEADER_SIZE + FOOTER_SIZE; if ((size_t)state->frame_max < state->target_size) { return AMQP_STATUS_BAD_AMQP_DATA; } channel_pool = amqp_get_or_create_channel_pool(state, channel); if (NULL == channel_pool) { return AMQP_STATUS_NO_MEMORY; } amqp_pool_alloc_bytes(channel_pool, state->target_size, &state->inbound_buffer); if (NULL == state->inbound_buffer.bytes) { return AMQP_STATUS_NO_MEMORY; } memcpy(state->inbound_buffer.bytes, state->header_buffer, HEADER_SIZE); raw_frame = state->inbound_buffer.bytes; state->state = CONNECTION_STATE_BODY; bytes_consumed += consume_data(state, &received_data); /* do we have target_size data yet? if not, return with the expectation that more will arrive */ if (state->inbound_offset < state->target_size) { return bytes_consumed; } } /* fall through to process body */ case CONNECTION_STATE_BODY: { amqp_bytes_t encoded; int res; amqp_pool_t *channel_pool; /* Check frame end marker (footer) */ if (amqp_d8(raw_frame, state->target_size - 1) != AMQP_FRAME_END) { return AMQP_STATUS_BAD_AMQP_DATA; } decoded_frame->frame_type = amqp_d8(raw_frame, 0); decoded_frame->channel = amqp_d16(raw_frame, 1); channel_pool = amqp_get_or_create_channel_pool(state, decoded_frame->channel); if (NULL == channel_pool) { return AMQP_STATUS_NO_MEMORY; } switch (decoded_frame->frame_type) { case AMQP_FRAME_METHOD: decoded_frame->payload.method.id = amqp_d32(raw_frame, HEADER_SIZE); encoded.bytes = amqp_offset(raw_frame, HEADER_SIZE + 4); encoded.len = state->target_size - HEADER_SIZE - 4 - FOOTER_SIZE; res = amqp_decode_method(decoded_frame->payload.method.id, channel_pool, encoded, &decoded_frame->payload.method.decoded); if (res < 0) { return res; } break; case AMQP_FRAME_HEADER: decoded_frame->payload.properties.class_id = amqp_d16(raw_frame, HEADER_SIZE); /* unused 2-byte weight field goes here */ decoded_frame->payload.properties.body_size = amqp_d64(raw_frame, HEADER_SIZE + 4); encoded.bytes = amqp_offset(raw_frame, HEADER_SIZE + 12); encoded.len = state->target_size - HEADER_SIZE - 12 - FOOTER_SIZE; decoded_frame->payload.properties.raw = encoded; res = amqp_decode_properties(decoded_frame->payload.properties.class_id, channel_pool, encoded, &decoded_frame->payload.properties.decoded); if (res < 0) { return res; } break; case AMQP_FRAME_BODY: decoded_frame->payload.body_fragment.len = state->target_size - HEADER_SIZE - FOOTER_SIZE; decoded_frame->payload.body_fragment.bytes = amqp_offset(raw_frame, HEADER_SIZE); break; case AMQP_FRAME_HEARTBEAT: break; default: /* Ignore the frame */ decoded_frame->frame_type = 0; break; } return_to_idle(state); return bytes_consumed; } default: amqp_abort("Internal error: invalid amqp_connection_state_t->state %d", state->state); return bytes_consumed; } }