amqp_channel_t ChannelImpl::GetNextChannelId() { int max_channels = amqp_get_channel_max(m_connection); int channel_count = static_cast<int>(m_open_channels.size()); if (0 == max_channels) { if (std::numeric_limits<boost::uint16_t>::max() <= channel_count) { throw std::runtime_error("Too many channels open"); } } else if (max_channels <= channel_count) { throw std::runtime_error("Too many channels open"); } while (m_open_channels.end() != m_open_channels.find(++m_next_channel_id)) { /* Empty */ } m_open_channels.insert(std::make_pair(m_next_channel_id, frame_queue_t())); return m_next_channel_id; }
amqp_connection_resource *connection_resource_constructor(amqp_connection_params *params, zend_bool persistent TSRMLS_DC) { struct timeval tv = {0}; struct timeval *tv_ptr = &tv; char *std_datetime; amqp_table_entry_t client_properties_entries[5]; amqp_table_t client_properties_table; amqp_table_entry_t custom_properties_entries[1]; amqp_table_t custom_properties_table; amqp_connection_resource *resource; /* Allocate space for the connection resource */ resource = (amqp_connection_resource *)pecalloc(1, sizeof(amqp_connection_resource), persistent); /* Create the connection */ resource->connection_state = amqp_new_connection(); /* Create socket object */ resource->socket = amqp_tcp_socket_new(resource->connection_state); if (params->connect_timeout > 0) { tv.tv_sec = (long int) params->connect_timeout; tv.tv_usec = (long int) ((params->connect_timeout - tv.tv_sec) * 1000000); } else { tv_ptr = NULL; } /* Try to connect and verify that no error occurred */ if (amqp_socket_open_noblock(resource->socket, params->host, params->port, tv_ptr)) { zend_throw_exception(amqp_connection_exception_class_entry, "Socket error: could not connect to host.", 0 TSRMLS_CC); connection_resource_destructor(resource, persistent TSRMLS_CC); return NULL; } if (!php_amqp_set_resource_read_timeout(resource, params->read_timeout TSRMLS_CC)) { connection_resource_destructor(resource, persistent TSRMLS_CC); return NULL; } if (!php_amqp_set_resource_write_timeout(resource, params->write_timeout TSRMLS_CC)) { connection_resource_destructor(resource, persistent TSRMLS_CC); return NULL; } std_datetime = php_std_date(time(NULL) TSRMLS_CC); client_properties_entries[0].key = amqp_cstring_bytes("type"); client_properties_entries[0].value.kind = AMQP_FIELD_KIND_UTF8; client_properties_entries[0].value.value.bytes = amqp_cstring_bytes("php-amqp extension"); client_properties_entries[1].key = amqp_cstring_bytes("version"); client_properties_entries[1].value.kind = AMQP_FIELD_KIND_UTF8; client_properties_entries[1].value.value.bytes = amqp_cstring_bytes(PHP_AMQP_VERSION); client_properties_entries[2].key = amqp_cstring_bytes("revision"); client_properties_entries[2].value.kind = AMQP_FIELD_KIND_UTF8; client_properties_entries[2].value.value.bytes = amqp_cstring_bytes(PHP_AMQP_REVISION); client_properties_entries[3].key = amqp_cstring_bytes("connection type"); client_properties_entries[3].value.kind = AMQP_FIELD_KIND_UTF8; client_properties_entries[3].value.value.bytes = amqp_cstring_bytes(persistent ? "persistent" : "transient"); client_properties_entries[4].key = amqp_cstring_bytes("connection started"); client_properties_entries[4].value.kind = AMQP_FIELD_KIND_UTF8; client_properties_entries[4].value.value.bytes = amqp_cstring_bytes(std_datetime); client_properties_table.entries = client_properties_entries; client_properties_table.num_entries = sizeof(client_properties_entries) / sizeof(amqp_table_entry_t); custom_properties_entries[0].key = amqp_cstring_bytes("client"); custom_properties_entries[0].value.kind = AMQP_FIELD_KIND_TABLE; custom_properties_entries[0].value.value.table = client_properties_table; custom_properties_table.entries = custom_properties_entries; custom_properties_table.num_entries = sizeof(custom_properties_entries) / sizeof(amqp_table_entry_t); /* We can assume that connection established here but it is not true, real handshake goes during login */ assert(params->frame_max > 0); amqp_rpc_reply_t res = amqp_login_with_properties( resource->connection_state, params->vhost, params->channel_max, params->frame_max, params->heartbeat, &custom_properties_table, AMQP_SASL_METHOD_PLAIN, params->login, params->password ); efree(std_datetime); if (res.reply_type != AMQP_RESPONSE_NORMAL) { char *message, *long_message; php_amqp_connection_resource_error(res, &message, resource, 0 TSRMLS_CC); spprintf(&long_message, 0, "%s - Potential login failure.", message); zend_throw_exception(amqp_connection_exception_class_entry, long_message, 0 TSRMLS_CC); efree(message); efree(long_message); /* https://www.rabbitmq.com/resources/specs/amqp0-9-1.pdf * * 2.2.4 The Connection Class: * ... a peer that detects an error MUST close the socket without sending any further data. * * 4.10.2 Denial of Service Attacks: * ... The general response to any exceptional condition in the connection negotiation is to pause that connection * (presumably a thread) for a period of several seconds and then to close the network connection. This * includes syntax errors, over-sized data, and failed attempts to authenticate. */ connection_resource_destructor(resource, persistent TSRMLS_CC); return NULL; } /* Allocate space for the channel slots in the ring buffer */ resource->max_slots = (amqp_channel_t) amqp_get_channel_max(resource->connection_state); assert(resource->max_slots > 0); resource->slots = (amqp_channel_resource **)pecalloc(resource->max_slots + 1, sizeof(amqp_channel_object*), persistent); resource->is_connected = '\1'; return resource; }