Example #1
0
int amqp_simple_wait_method(amqp_connection_state_t state,
			    amqp_channel_t expected_channel,
			    amqp_method_number_t expected_method,
			    amqp_method_t *output)
{
  amqp_frame_t frame;
  int res = amqp_simple_wait_frame(state, &frame);
  if (res < 0)
    return res;

  if (frame.channel != expected_channel)
    amqp_abort("Expected 0x%08X method frame on channel %d, got frame on channel %d",
	       expected_method,
	       expected_channel,
	       frame.channel);
  if (frame.frame_type != AMQP_FRAME_METHOD)
    amqp_abort("Expected 0x%08X method frame on channel %d, got frame type %d",
	       expected_method,
	       expected_channel,
	       frame.frame_type);
  if (frame.payload.method.id != expected_method)
    amqp_abort("Expected method ID 0x%08X on channel %d, got ID 0x%08X",
	       expected_method,
	       expected_channel,
	       frame.payload.method.id);
  *output = frame.payload.method;
  return 0;
}
Example #2
0
void
amqp_ssl_locking_callback(int mode, int n,
                          AMQP_UNUSED const char *file,
                          AMQP_UNUSED int line)
{
  if (mode & CRYPTO_LOCK) {
    if (pthread_mutex_lock(&amqp_openssl_lockarray[n])) {
      amqp_abort("Runtime error: Failure in trying to lock OpenSSL mutex");
    }
  } else {
    if (pthread_mutex_unlock(&amqp_openssl_lockarray[n])) {
      amqp_abort("Runtime error: Failure in trying to unlock OpenSSL mutex");
    }
  }
}
Example #3
0
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;
}
Example #4
0
int amqp_ssl_socket_set_ssl_versions(amqp_socket_t *base,
                                     amqp_tls_version_t min,
                                     amqp_tls_version_t max) {
  struct amqp_ssl_socket_t *self;
  if (base->klass != &amqp_ssl_socket_class) {
    amqp_abort("<%p> is not of type amqp_ssl_socket_t", base);
  }
  self = (struct amqp_ssl_socket_t *)base;

  {
    long clear_options;
    long set_options = 0;
#if defined(SSL_OP_NO_TLSv1_2)
    amqp_tls_version_t max_supported = AMQP_TLSv1_2;
    clear_options = SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1_2;
#elif defined(SSL_OP_NO_TLSv1_1)
    amqp_tls_version_t max_supported = AMQP_TLSv1_1;
    clear_options = SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1;
#elif defined(SSL_OP_NO_TLSv1)
    amqp_tls_version_t max_supported = AMQP_TLSv1;
    clear_options = SSL_OP_NO_TLSv1;
#else
# error "Need a version of OpenSSL that can support TLSv1 or greater."
#endif

    if (AMQP_TLSvLATEST == max) {
      max = max_supported;
    }
    if (AMQP_TLSvLATEST == min) {
      min = max_supported;
    }

    if (min > max) {
      return AMQP_STATUS_INVALID_PARAMETER;
    }

    if (max > max_supported || min > max_supported) {
      return AMQP_STATUS_UNSUPPORTED;
    }

    if (min > AMQP_TLSv1) {
      set_options |= SSL_OP_NO_TLSv1;
    }
#ifdef SSL_OP_NO_TLSv1_1
    if (min > AMQP_TLSv1_1 || max < AMQP_TLSv1_1) {
      set_options |= SSL_OP_NO_TLSv1_1;
    }
#endif
#ifdef SSL_OP_NO_TLSv1_2
    if (max < AMQP_TLSv1_2) {
      set_options |= SSL_OP_NO_TLSv1_2;
    }
#endif
    SSL_CTX_clear_options(self->ctx, clear_options);
    SSL_CTX_set_options(self->ctx, set_options);
  }

  return AMQP_STATUS_OK;
}
Example #5
0
static int
password_cb(AMQP_UNUSED char *buffer,
            AMQP_UNUSED int length,
            AMQP_UNUSED int rwflag,
            AMQP_UNUSED void *user_data)
{
  amqp_abort("rabbitmq-c does not support password protected keys");
}
void amqp_set_sockfd(amqp_connection_state_t state,
                     int sockfd)
{
  amqp_socket_t *socket = amqp_tcp_socket_new(state);
  if (!socket) {
    amqp_abort("%s", strerror(errno));
  }
  amqp_tcp_socket_set_sockfd(socket, sockfd);
}
Example #7
0
void amqp_release_buffers(amqp_connection_state_t state) {
  ENFORCE_STATE(state, CONNECTION_STATE_IDLE);

  if (state->first_queued_frame)
    amqp_abort("Programming error: attempt to amqp_release_buffers while waiting events enqueued");

  recycle_amqp_pool(&state->frame_pool);
  recycle_amqp_pool(&state->decoding_pool);
}
Example #8
0
void amqp_ssl_socket_set_verify_hostname(amqp_socket_t *base,
                                         amqp_boolean_t verify) {
  struct amqp_ssl_socket_t *self;
  if (base->klass != &amqp_ssl_socket_class) {
    amqp_abort("<%p> is not of type amqp_ssl_socket_t", base);
  }
  self = (struct amqp_ssl_socket_t *)base;
  self->verify_hostname = verify;
}
Example #9
0
void
amqp_tcp_socket_set_sockfd(amqp_socket_t *base, int sockfd)
{
  struct amqp_tcp_socket_t *self;
  if (base->klass != &amqp_tcp_socket_class) {
    amqp_abort("<%p> is not of type amqp_tcp_socket_t", base);
  }
  self = (struct amqp_tcp_socket_t *)base;
  self->sockfd = sockfd;
}
Example #10
0
static amqp_bytes_t sasl_method_name(amqp_sasl_method_enum method) {
  amqp_bytes_t res;

  switch (method) {
  case AMQP_SASL_METHOD_PLAIN:
    res.bytes = "PLAIN";
    res.len = 5;
    break;

  default:
    amqp_abort("Invalid SASL method: %d", (int) method);
  }

  return res;
}
Example #11
0
int
amqp_ssl_socket_set_cert(amqp_socket_t *base,
                         const char *cert)
{
  int status;
  struct amqp_ssl_socket_t *self;
  if (base->klass != &amqp_ssl_socket_class) {
    amqp_abort("<%p> is not of type amqp_ssl_socket_t", base);
  }
  self = (struct amqp_ssl_socket_t *)base;
  status = SSL_CTX_use_certificate_chain_file(self->ctx, cert);
  if (1 != status) {
    return AMQP_STATUS_SSL_ERROR;
  }
  return AMQP_STATUS_OK;
}
Example #12
0
int
amqp_ssl_socket_set_cacert(amqp_socket_t *base,
                           const char *cacert)
{
  int status;
  struct amqp_ssl_socket_t *self;
  if (base->klass != &amqp_ssl_socket_class) {
    amqp_abort("<%p> is not of type amqp_ssl_socket_t", base);
  }
  self = (struct amqp_ssl_socket_t *)base;
  status = SSL_CTX_load_verify_locations(self->ctx, cacert, NULL);
  if (1 != status) {
    return AMQP_STATUS_SSL_ERROR;
  }
  return AMQP_STATUS_OK;
}
Example #13
0
int
amqp_ssl_socket_set_key_buffer(amqp_socket_t *base,
                               const char *cert,
                               const void *key,
                               size_t n)
{
  int status = AMQP_STATUS_OK;
  BIO *buf = NULL;
  RSA *rsa = NULL;
  struct amqp_ssl_socket_t *self;
  if (base->klass != &amqp_ssl_socket_class) {
    amqp_abort("<%p> is not of type amqp_ssl_socket_t", base);
  }
  if (n > INT_MAX) {
    return AMQP_STATUS_INVALID_PARAMETER;
  }
  self = (struct amqp_ssl_socket_t *)base;
  status = SSL_CTX_use_certificate_chain_file(self->ctx, cert);
  if (1 != status) {
    return AMQP_STATUS_SSL_ERROR;
  }
  buf = BIO_new_mem_buf((void *)key, (int)n);
  if (!buf) {
    goto error;
  }
  rsa = PEM_read_bio_RSAPrivateKey(buf, NULL, password_cb, NULL);
  if (!rsa) {
    goto error;
  }
  status = SSL_CTX_use_RSAPrivateKey(self->ctx, rsa);
  if (1 != status) {
    goto error;
  }
exit:
  BIO_vfree(buf);
  RSA_free(rsa);
  return status;
error:
  status = AMQP_STATUS_SSL_ERROR;
  goto exit;
}
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;
  }
}
Example #15
0
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 0;

  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 -ERROR_NO_MEMORY;

    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:
    /* frame length is 3 bytes in */
    state->target_size
           = amqp_d32(raw_frame, 3) + HEADER_SIZE + FOOTER_SIZE;
    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;

    /* Check frame end marker (footer) */
    if (amqp_d8(raw_frame, state->target_size - 1) != AMQP_FRAME_END)
      return -ERROR_BAD_AMQP_DATA;

    decoded_frame->frame_type = amqp_d8(raw_frame, 0);
    decoded_frame->channel = amqp_d16(raw_frame, 1);

    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,
			       &state->decoding_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,
                                   &state->decoding_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);

    if (decoded_frame->frame_type == AMQP_FRAME_METHOD) {
        if (decoded_frame->payload.method.id == AMQP_BASIC_RETURN_METHOD) {
	  amqp_basic_return_t *m = decoded_frame->payload.method.decoded;
	  if(state->basic_return_callback)
	      state->basic_return_callback(decoded_frame->channel, m,
					   state->basic_return_callback_data);
	}
	else if (decoded_frame->payload.method.id == AMQP_CHANNEL_CLOSE_METHOD) {
	    amqp_channel_close_t *m = decoded_frame->payload.method.decoded;
	    if (state->channel_close_callback)
		state->channel_close_callback(decoded_frame->channel, m,
					      state->channel_close_callback_data);
	}
    }
      
    return bytes_consumed;
  }

  default:
    amqp_abort("Internal error: invalid amqp_connection_state_t->state %d", state->state);
    return bytes_consumed;
  }
}