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; }
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"); } } }
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; }
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; }
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); }
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); }
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; }
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; }
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; }
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; }
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; }
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; } }
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; } }