示例#1
0
static int inner_send_frame(amqp_connection_state_t state,
			    amqp_frame_t const *frame,
			    amqp_bytes_t *encoded,
			    int *payload_len)
{
  int separate_body;

  E_8(state->outbound_buffer, 0, frame->frame_type);
  E_16(state->outbound_buffer, 1, frame->channel);
  switch (frame->frame_type) {
    case AMQP_FRAME_METHOD:
      E_32(state->outbound_buffer, HEADER_SIZE, frame->payload.method.id);
      encoded->len = state->outbound_buffer.len - (HEADER_SIZE + 4 + FOOTER_SIZE);
      encoded->bytes = D_BYTES(state->outbound_buffer, HEADER_SIZE + 4, encoded->len);
      *payload_len = AMQP_CHECK_RESULT(amqp_encode_method(frame->payload.method.id,
							  frame->payload.method.decoded,
							  *encoded)) + 4;
      separate_body = 0;
      break;

    case AMQP_FRAME_HEADER:
      E_16(state->outbound_buffer, HEADER_SIZE, frame->payload.properties.class_id);
      E_16(state->outbound_buffer, HEADER_SIZE+2, 0); /* "weight" */
      E_64(state->outbound_buffer, HEADER_SIZE+4, frame->payload.properties.body_size);
      encoded->len = state->outbound_buffer.len - (HEADER_SIZE + 12 + FOOTER_SIZE);
      encoded->bytes = D_BYTES(state->outbound_buffer, HEADER_SIZE + 12, encoded->len);
      *payload_len = AMQP_CHECK_RESULT(amqp_encode_properties(frame->payload.properties.class_id,
							      frame->payload.properties.decoded,
							      *encoded)) + 12;
      separate_body = 0;
      break;

    case AMQP_FRAME_BODY:
      *encoded = frame->payload.body_fragment;
      *payload_len = encoded->len;
      separate_body = 1;
      break;

    case AMQP_FRAME_HEARTBEAT:
      *encoded = AMQP_EMPTY_BYTES;
      *payload_len = 0;
      separate_body = 0;
      break;

    default:
      return -EINVAL;
  }

  E_32(state->outbound_buffer, 3, *payload_len);
  if (!separate_body) {
    E_8(state->outbound_buffer, *payload_len + HEADER_SIZE, AMQP_FRAME_END);
  }

#if 0
  if (separate_body) {
    printf("sending body frame (header):\n");
    amqp_dump(state->outbound_buffer.bytes, HEADER_SIZE);
    printf("sending body frame (payload):\n");
    amqp_dump(encoded->bytes, *payload_len);
  } else {
    printf("sending:\n");
    amqp_dump(state->outbound_buffer.bytes, *payload_len + HEADER_SIZE + FOOTER_SIZE);
  }
#endif

  return separate_body;
}
示例#2
0
int amqp_decode_table(amqp_bytes_t encoded,
		      amqp_pool_t *pool,
		      amqp_table_t *output,
		      int *offsetptr)
{
  int offset = *offsetptr;
  uint32_t tablesize = D_32(encoded, offset);
  int num_entries = 0;
  amqp_table_entry_t *entries = malloc(INITIAL_TABLE_SIZE * sizeof(amqp_table_entry_t));
  int allocated_entries = INITIAL_TABLE_SIZE;
  int limit;

  if (entries == NULL) {
    return -ENOMEM;
  }

  offset += 4;
  limit = offset + tablesize;

  while (offset < limit) {
    size_t keylen;
    amqp_table_entry_t *entry;

    keylen = D_8(encoded, offset);
    offset++;

    if (num_entries >= allocated_entries) {
      void *newentries;
      allocated_entries = allocated_entries * 2;
      newentries = realloc(entries, allocated_entries * sizeof(amqp_table_entry_t));
      if (newentries == NULL) {
	free(entries);
	return -ENOMEM;
      }
      entries = newentries;
    }
    entry = &entries[num_entries];

    entry->key.len = keylen;
    entry->key.bytes = D_BYTES(encoded, offset, keylen);
    offset += keylen;

    entry->kind = D_8(encoded, offset);
    offset++;

    switch (entry->kind) {
      case 'S':
	entry->value.bytes.len = D_32(encoded, offset);
	offset += 4;
	entry->value.bytes.bytes = D_BYTES(encoded, offset, entry->value.bytes.len);
	offset += entry->value.bytes.len;
	break;
      case 'I':
	entry->value.i32 = (int32_t) D_32(encoded, offset);
	offset += 4;
	break;
      case 'D':
	entry->value.decimal.decimals = D_8(encoded, offset);
	offset++;
	entry->value.decimal.value = D_32(encoded, offset);
	offset += 4;
	break;
      case 'T':
	entry->value.u64 = D_64(encoded, offset);
	offset += 8;
	break;
      case 'F':
	AMQP_CHECK_RESULT(amqp_decode_table(encoded, pool, &(entry->value.table), &offset));
	break;
      case 't':
	entry->value.boolean = D_8(encoded, offset);
	offset += 1;
	break;
      default:
	return -EINVAL;
    }

    num_entries++;
  }

  output->num_entries = num_entries;
  output->entries = amqp_pool_alloc(pool, num_entries * sizeof(amqp_table_entry_t));
  output->size = num_entries;
  memcpy(output->entries, entries, num_entries * sizeof(amqp_table_entry_t));

  *offsetptr = offset;
  return 0;
}
示例#3
0
int amqp_handle_input(amqp_connection_state_t state,
		      amqp_bytes_t received_data,
		      amqp_frame_t *decoded_frame)
{
  int total_bytes_consumed = 0;
  int bytes_consumed;

  /* Returning frame_type of zero indicates either insufficient input,
     or a complete, ignored frame was read. */
  decoded_frame->frame_type = 0;

 read_more:
  if (received_data.len == 0) {
    return total_bytes_consumed;
  }

  if (state->state == CONNECTION_STATE_IDLE) {
    state->inbound_buffer.bytes = amqp_pool_alloc(&state->frame_pool, state->inbound_buffer.len);
    if (state->inbound_buffer.bytes == NULL) {
      /* state->inbound_buffer.len is always nonzero, because it
	 corresponds to frame_max, which is not permitted to be less
	 than AMQP_FRAME_MIN_SIZE (currently 4096 bytes). */
      return -ENOMEM;
    }
    state->state = CONNECTION_STATE_WAITING_FOR_HEADER;
  }

  bytes_consumed = state->target_size - state->inbound_offset;
  if (received_data.len < bytes_consumed) {
    bytes_consumed = received_data.len;
  }

  E_BYTES(state->inbound_buffer, state->inbound_offset, bytes_consumed, received_data.bytes);
  state->inbound_offset += bytes_consumed;
  total_bytes_consumed += bytes_consumed;

  assert(state->inbound_offset <= state->target_size);

  if (state->inbound_offset < state->target_size) {
    return total_bytes_consumed;
  }

  switch (state->state) {
    case CONNECTION_STATE_WAITING_FOR_HEADER:
      if (D_8(state->inbound_buffer, 0) == AMQP_PSEUDOFRAME_PROTOCOL_HEADER &&
	  D_16(state->inbound_buffer, 1) == AMQP_PSEUDOFRAME_PROTOCOL_CHANNEL)
      {
	state->target_size = 8;
	state->state = CONNECTION_STATE_WAITING_FOR_PROTOCOL_HEADER;
      } else {
	state->target_size = D_32(state->inbound_buffer, 3) + HEADER_SIZE + FOOTER_SIZE;
	state->state = CONNECTION_STATE_WAITING_FOR_BODY;
      }

      /* Wind buffer forward, and try to read some body out of it. */
      received_data.len -= bytes_consumed;
      received_data.bytes = ((char *) received_data.bytes) + bytes_consumed;
      goto read_more;

    case CONNECTION_STATE_WAITING_FOR_BODY: {
      int frame_type = D_8(state->inbound_buffer, 0);

#if 0
      printf("recving:\n");
      amqp_dump(state->inbound_buffer.bytes, state->target_size);
#endif

      /* Check frame end marker (footer) */
      if (D_8(state->inbound_buffer, state->target_size - 1) != AMQP_FRAME_END) {
	return -EINVAL;
      }

      decoded_frame->channel = D_16(state->inbound_buffer, 1);

      switch (frame_type) {
	case AMQP_FRAME_METHOD: {
	  amqp_bytes_t encoded;

	  /* Four bytes of method ID before the method args. */
	  encoded.len = state->target_size - (HEADER_SIZE + 4 + FOOTER_SIZE);
	  encoded.bytes = D_BYTES(state->inbound_buffer, HEADER_SIZE + 4, encoded.len);

	  decoded_frame->frame_type = AMQP_FRAME_METHOD;
	  decoded_frame->payload.method.id = D_32(state->inbound_buffer, HEADER_SIZE);
	  AMQP_CHECK_RESULT(amqp_decode_method(decoded_frame->payload.method.id,
					       &state->decoding_pool,
					       encoded,
					       &decoded_frame->payload.method.decoded));
	  break;
	}

	case AMQP_FRAME_HEADER: {
	  amqp_bytes_t encoded;

	  /* 12 bytes for properties header. */
	  encoded.len = state->target_size - (HEADER_SIZE + 12 + FOOTER_SIZE);
	  encoded.bytes = D_BYTES(state->inbound_buffer, HEADER_SIZE + 12, encoded.len);

	  decoded_frame->frame_type = AMQP_FRAME_HEADER;
	  decoded_frame->payload.properties.class_id = D_16(state->inbound_buffer, HEADER_SIZE);
	  decoded_frame->payload.properties.body_size = D_64(state->inbound_buffer, HEADER_SIZE+4);
	  decoded_frame->payload.properties.raw = encoded;
	  AMQP_CHECK_RESULT(amqp_decode_properties(decoded_frame->payload.properties.class_id,
						   &state->decoding_pool,
						   encoded,
						   &decoded_frame->payload.properties.decoded));
	  break;
	}

	case AMQP_FRAME_BODY: {
	  size_t fragment_len = state->target_size - (HEADER_SIZE + FOOTER_SIZE);

	  decoded_frame->frame_type = AMQP_FRAME_BODY;
	  decoded_frame->payload.body_fragment.len = fragment_len;
	  decoded_frame->payload.body_fragment.bytes =
	    D_BYTES(state->inbound_buffer, HEADER_SIZE, fragment_len);
	  break;
	}

	case AMQP_FRAME_HEARTBEAT:
	  decoded_frame->frame_type = AMQP_FRAME_HEARTBEAT;
	  break;

	default:
	  /* Ignore the frame by not changing frame_type away from 0. */
	  break;
      }

      return_to_idle(state);
      return total_bytes_consumed;
    }

    case CONNECTION_STATE_WAITING_FOR_PROTOCOL_HEADER:
      decoded_frame->frame_type = AMQP_PSEUDOFRAME_PROTOCOL_HEADER;
      decoded_frame->channel = AMQP_PSEUDOFRAME_PROTOCOL_CHANNEL;
      amqp_assert(D_8(state->inbound_buffer, 3) == (uint8_t) 'P',
		  "Invalid protocol header received");
      decoded_frame->payload.protocol_header.transport_high = D_8(state->inbound_buffer, 4);
      decoded_frame->payload.protocol_header.transport_low = D_8(state->inbound_buffer, 5);
      decoded_frame->payload.protocol_header.protocol_version_major = D_8(state->inbound_buffer, 6);
      decoded_frame->payload.protocol_header.protocol_version_minor = D_8(state->inbound_buffer, 7);

      return_to_idle(state);
      return total_bytes_consumed;

    default:
      amqp_assert(0, "Internal error: invalid amqp_connection_state_t->state %d", state->state);
  }
}