void qd_message_free(qd_message_t *in_msg) { if (!in_msg) return; uint32_t rc; qd_message_pvt_t *msg = (qd_message_pvt_t*) in_msg; qd_buffer_list_free_buffers(&msg->ma_to_override); qd_buffer_list_free_buffers(&msg->ma_trace); qd_buffer_list_free_buffers(&msg->ma_ingress); qd_message_content_t *content = msg->content; sys_mutex_lock(content->lock); rc = --content->ref_count; sys_mutex_unlock(content->lock); if (rc == 0) { if (content->parsed_message_annotations) qd_parse_free(content->parsed_message_annotations); qd_buffer_t *buf = DEQ_HEAD(content->buffers); while (buf) { DEQ_REMOVE_HEAD(content->buffers); qd_buffer_free(buf); buf = DEQ_HEAD(content->buffers); } sys_mutex_free(content->lock); free_qd_message_content_t(content); } free_qd_message_t((qd_message_t*) msg); }
void qdr_route_connection_opened_CT(qdr_core_t *core, qdr_connection_t *conn, qdr_field_t *container_field, qdr_field_t *connection_field) { if (conn->role != QDR_ROLE_ROUTE_CONTAINER) return; qdr_conn_identifier_t *cid = qdr_route_declare_id_CT(core, container_field?container_field->iterator:0, connection_field?connection_field->iterator:0); qdr_add_connection_ref(&cid->connection_refs, conn); conn->conn_id = cid; // // Activate all link-routes associated with this remote container. // qdr_link_route_t *lr = DEQ_HEAD(cid->link_route_refs); while (lr) { qdr_link_route_activate_CT(core, lr, conn); lr = DEQ_NEXT_N(REF, lr); } // // Activate all auto-links associated with this remote container. // qdr_auto_link_t *al = DEQ_HEAD(cid->auto_link_refs); while (al) { qdr_auto_link_activate_CT(core, al, conn); al = DEQ_NEXT_N(REF, al); } }
void qdr_route_connection_closed_CT(qdr_core_t *core, qdr_connection_t *conn) { if (conn->role != QDR_ROLE_ROUTE_CONTAINER) return; qdr_conn_identifier_t *cid = conn->conn_id; if (cid) { // // Deactivate all link-routes associated with this remote container. // qdr_link_route_t *lr = DEQ_HEAD(cid->link_route_refs); while (lr) { qdr_link_route_deactivate_CT(core, lr, conn); lr = DEQ_NEXT_N(REF, lr); } // // Deactivate all auto-links associated with this remote container. // qdr_auto_link_t *al = DEQ_HEAD(cid->auto_link_refs); while (al) { qdr_auto_link_deactivate_CT(core, al, conn); al = DEQ_NEXT_N(REF, al); } // // Remove our own entry in the connection list // qdr_del_connection_ref(&cid->connection_refs, conn); conn->conn_id = 0; qdr_route_check_id_for_deletion_CT(core, cid); } }
void qd_connection_manager_start(qd_dispatch_t *qd) { static bool first_start = true; qd_listener_t *li = DEQ_HEAD(qd->connection_manager->listeners); qd_connector_t *ct = DEQ_HEAD(qd->connection_manager->connectors); while (li) { if (!li->pn_listener) { if (!qd_listener_listen(li) && first_start) { qd_log(qd->connection_manager->log_source, QD_LOG_CRITICAL, "Listen on %s failed during initial config", li->config.host_port); exit(1); } else { li->exit_on_error = first_start; } } li = DEQ_NEXT(li); } while (ct) { qd_connector_connect(ct); ct = DEQ_NEXT(ct); } first_start = false; }
// get the link route by either name or id static qdr_link_route_t *_find_link_route_CT(qdr_connection_t *conn, qd_iterator_t *name, qd_iterator_t *identity) { qdr_link_route_t *lr = NULL; // if both id and name provided, prefer id // if (identity) { char buf[64]; uint64_t id = 0; assert(qd_iterator_length(identity) < sizeof(buf)); qd_iterator_strncpy(identity, buf, sizeof(buf)); if (sscanf(buf, "%"SCNu64, &id) != 1) { return NULL; } lr = DEQ_HEAD(conn->conn_link_routes); while (lr) { if (id == lr->identity) break; lr = DEQ_NEXT(lr); } } else if (name) { lr = DEQ_HEAD(conn->conn_link_routes); while (lr) { if (qd_iterator_equal(name, (unsigned char *)lr->name)) break; lr = DEQ_NEXT(lr); } } return lr; }
void qd_buffer_list_free_buffers(qd_buffer_list_t *list) { qd_buffer_t *buf = DEQ_HEAD(*list); while (buf) { DEQ_REMOVE_HEAD(*list); qd_buffer_free(buf); buf = DEQ_HEAD(*list); } }
static void qd_iterator_free_hash_segments(qd_iterator_t *iter) { qd_hash_segment_t *seg = DEQ_HEAD(iter->hash_segments); while (seg) { DEQ_REMOVE_HEAD(iter->hash_segments); free_qd_hash_segment_t(seg); seg = DEQ_HEAD(iter->hash_segments); } }
void qdr_core_free(qdr_core_t *core) { // // Stop and join the thread // core->running = false; sys_cond_signal(core->action_cond); sys_thread_join(core->thread); // // Free the core resources // sys_thread_free(core->thread); sys_cond_free(core->action_cond); sys_mutex_free(core->action_lock); sys_mutex_free(core->work_lock); sys_mutex_free(core->id_lock); qd_timer_free(core->work_timer); //we can't call qdr_core_unsubscribe on the subscriptions because the action processing thread has //already been shut down. But, all the action would have done at this point is free the subscriptions //so we just do that directly. free(core->agent_subscription_mobile); free(core->agent_subscription_local); for (int i = 0; i <= QD_TREATMENT_LINK_BALANCED; ++i) { if (core->forwarders[i]) { free(core->forwarders[i]); } } qdr_address_t *addr = 0; while ( (addr = DEQ_HEAD(core->addrs)) ) { qdr_core_remove_address(core, addr); } qdr_address_config_t *addr_config = 0; while ( (addr_config = DEQ_HEAD(core->addr_config))) { qdr_core_remove_address_config(core, addr_config); } qd_hash_free(core->addr_hash); qd_hash_free(core->conn_id_hash); //TODO what about the actual connection identifier objects? qdr_node_t *rnode = 0; while ( (rnode = DEQ_HEAD(core->routers)) ) { qdr_router_node_free(core, rnode); } if (core->query_lock) sys_mutex_free(core->query_lock); if (core->routers_by_mask_bit) free(core->routers_by_mask_bit); if (core->control_links_by_mask_bit) free(core->control_links_by_mask_bit); if (core->data_links_by_mask_bit) free(core->data_links_by_mask_bit); if (core->neighbor_free_mask) qd_bitmask_free(core->neighbor_free_mask); free(core); }
void qdr_core_remove_address(qdr_core_t *core, qdr_address_t *addr) { qdr_address_config_t *config = addr->config; if (config && --config->ref_count == 0) free_address_config(config); // Remove the address from the list, hash index, and parse tree DEQ_REMOVE(core->addrs, addr); if (addr->hash_handle) { const char *a_str = (const char *)qd_hash_key_by_handle(addr->hash_handle); if (QDR_IS_LINK_ROUTE(a_str[0])) { qd_iterator_t *iter = qd_iterator_string(a_str, ITER_VIEW_ALL); qdr_link_route_unmap_pattern_CT(core, iter); qd_iterator_free(iter); } qd_hash_remove_by_handle(core->addr_hash, addr->hash_handle); qd_hash_handle_free(addr->hash_handle); } // Free resources associated with this address DEQ_APPEND(addr->rlinks, addr->inlinks); qdr_link_ref_t *lref = DEQ_HEAD(addr->rlinks); while (lref) { qdr_link_t *link = lref->link; assert(link->owning_addr == addr); link->owning_addr = 0; qdr_del_link_ref(&addr->rlinks, link, QDR_LINK_LIST_CLASS_ADDRESS); lref = DEQ_HEAD(addr->rlinks); } qd_bitmask_free(addr->rnodes); if (addr->treatment == QD_TREATMENT_ANYCAST_CLOSEST) { qd_bitmask_free(addr->closest_remotes); } else if (addr->treatment == QD_TREATMENT_ANYCAST_BALANCED) { free(addr->outstanding_deliveries); } qdr_connection_ref_t *cr = DEQ_HEAD(addr->conns); while (cr) { qdr_del_connection_ref(&addr->conns, cr->conn); cr = DEQ_HEAD(addr->conns); } if (!!addr->fallback) { addr->fallback->fallback_for = 0; qdr_check_addr_CT(core, addr->fallback); } free(addr->add_prefix); free(addr->del_prefix); free_qdr_address_t(addr); }
void qd_connection_manager_free(qd_connection_manager_t *cm) { if (!cm) return; qd_listener_t *li = DEQ_HEAD(cm->listeners); while (li) { DEQ_REMOVE_HEAD(cm->listeners); qd_listener_decref(li); li = DEQ_HEAD(cm->listeners); } qd_connector_t *c = DEQ_HEAD(cm->connectors); while (c) { DEQ_REMOVE_HEAD(cm->connectors); qd_connector_decref(c); c = DEQ_HEAD(cm->connectors); } qd_config_ssl_profile_t *sslp = DEQ_HEAD(cm->config_ssl_profiles); while (sslp) { config_ssl_profile_free(cm, sslp); sslp = DEQ_HEAD(cm->config_ssl_profiles); } qd_config_sasl_plugin_t *saslp = DEQ_HEAD(cm->config_sasl_plugins); while (saslp) { config_sasl_plugin_free(cm, saslp); saslp = DEQ_HEAD(cm->config_sasl_plugins); } }
void dx_dealloc(dx_alloc_type_desc_t *desc, dx_alloc_pool_t **tpool, void *p) { item_t *item = ((item_t*) p) - 1; int idx; // // If this is the thread's first pass through here, allocate the // thread-local pool for this type. // if (*tpool == 0) { *tpool = NEW(dx_alloc_pool_t); DEQ_INIT((*tpool)->free_list); } dx_alloc_pool_t *pool = *tpool; DEQ_INSERT_TAIL(pool->free_list, item); if (DEQ_SIZE(pool->free_list) <= desc->config->local_free_list_max) return; // // We've exceeded the maximum size of the local free list. A batch must be // rebalanced back to the global list. // sys_mutex_lock(desc->lock); desc->stats->batches_rebalanced_to_global++; desc->stats->held_by_threads -= desc->config->transfer_batch_size; for (idx = 0; idx < desc->config->transfer_batch_size; idx++) { item = DEQ_HEAD(pool->free_list); DEQ_REMOVE_HEAD(pool->free_list); DEQ_INSERT_TAIL(desc->global_pool->free_list, item); } // // If there's a global_free_list size limit, remove items until the limit is // not exceeded. // if (desc->config->global_free_list_max != 0) { while (DEQ_SIZE(desc->global_pool->free_list) > desc->config->global_free_list_max) { item = DEQ_HEAD(desc->global_pool->free_list); DEQ_REMOVE_HEAD(desc->global_pool->free_list); free(item); desc->stats->total_free_to_heap++; } } sys_mutex_unlock(desc->lock); }
static int writable_handler(qd_container_t *container, pn_connection_t *conn, qd_connection_t* qd_conn) { const qd_node_type_t *nt; int event_count = 0; // // Note the locking structure in this function. Generally this would be unsafe, but since // this particular list is only ever appended to and never has items inserted or deleted, // this usage is safe in this case. // sys_mutex_lock(container->lock); qdc_node_type_t *nt_item = DEQ_HEAD(container->node_type_list); sys_mutex_unlock(container->lock); while (nt_item) { nt = nt_item->ntype; if (nt->writable_handler) event_count += nt->writable_handler(nt->type_context, qd_conn, 0); sys_mutex_lock(container->lock); nt_item = DEQ_NEXT(nt_item); sys_mutex_unlock(container->lock); } return event_count; }
qdr_field_t *qdr_field_from_iter(qd_iterator_t *iter) { if (!iter) return 0; qdr_field_t *field = new_qdr_field_t(); qd_buffer_t *buf; int remaining; int length; ZERO(field); qd_iterator_reset(iter); remaining = qd_iterator_remaining(iter); length = remaining; while (remaining) { buf = qd_buffer(); size_t cap = qd_buffer_capacity(buf); int copied = qd_iterator_ncopy(iter, qd_buffer_cursor(buf), cap); qd_buffer_insert(buf, copied); DEQ_INSERT_TAIL(field->buffers, buf); remaining = qd_iterator_remaining(iter); } field->iterator = qd_iterator_buffer(DEQ_HEAD(field->buffers), 0, length, ITER_VIEW_ALL); return field; }
qdr_field_t *qdr_field(const char *text) { size_t length = text ? strlen(text) : 0; size_t ilength = length; if (length == 0) return 0; qdr_field_t *field = new_qdr_field_t(); qd_buffer_t *buf; ZERO(field); while (length > 0) { buf = qd_buffer(); size_t cap = qd_buffer_capacity(buf); size_t copy = length > cap ? cap : length; memcpy(qd_buffer_cursor(buf), text, copy); qd_buffer_insert(buf, copy); length -= copy; text += copy; DEQ_INSERT_TAIL(field->buffers, buf); } field->iterator = qd_iterator_buffer(DEQ_HEAD(field->buffers), 0, ilength, ITER_VIEW_ALL); return field; }
static void notify_opened(qd_container_t *container, qd_connection_t *conn, void *context) { const qd_node_type_t *nt; // // Note the locking structure in this function. Generally this would be unsafe, but since // this particular list is only ever appended to and never has items inserted or deleted, // this usage is safe in this case. // sys_mutex_lock(container->lock); qdc_node_type_t *nt_item = DEQ_HEAD(container->node_type_list); sys_mutex_unlock(container->lock); while (nt_item) { nt = nt_item->ntype; if (qd_connection_inbound(conn)) { if (nt->inbound_conn_opened_handler) nt->inbound_conn_opened_handler(nt->type_context, conn, context); } else { if (nt->outbound_conn_opened_handler) nt->outbound_conn_opened_handler(nt->type_context, conn, context); } sys_mutex_lock(container->lock); nt_item = DEQ_NEXT(nt_item); sys_mutex_unlock(container->lock); } }
void qd_message_compose_3(qd_message_t *msg, qd_composed_field_t *field1, qd_composed_field_t *field2) { qd_message_content_t *content = MSG_CONTENT(msg); qd_buffer_list_t *field1_buffers = qd_compose_buffers(field1); qd_buffer_list_t *field2_buffers = qd_compose_buffers(field2); content->buffers = *field1_buffers; DEQ_INIT(*field1_buffers); qd_buffer_t *buf = DEQ_HEAD(*field2_buffers); while (buf) { DEQ_REMOVE_HEAD(*field2_buffers); DEQ_INSERT_TAIL(content->buffers, buf); buf = DEQ_HEAD(*field2_buffers); } }
static char* list_well_formed(item_list_t list, char *key) { item_t *ptr; item_t *last = 0; int size = DEQ_SIZE(list); int count = 0; char str[32]; ptr = DEQ_HEAD(list); while (ptr) { str[count] = ptr->letter; count++; if (DEQ_PREV(ptr) != last) return "Corrupt previous link"; last = ptr; ptr = DEQ_NEXT(ptr); } str[count] = '\0'; if (strcmp(str, key) != 0) return "Invalid key"; if (count != size) return "Size different from number of items (forward)"; count = 0; last = 0; ptr = DEQ_TAIL(list); while (ptr) { count++; if (DEQ_NEXT(ptr) != last) return "Corrupt next link"; last = ptr; ptr = DEQ_PREV(ptr); } if (count != size) return "Size different from number of items (backward)"; return 0; }
void qdra_config_link_route_get_next_CT(qdr_core_t *core, qdr_query_t *query) { qdr_link_route_t *lr = 0; if (query->next_offset < DEQ_SIZE(core->link_routes)) { lr = DEQ_HEAD(core->link_routes); for (int i = 0; i < query->next_offset && lr; i++) lr = DEQ_NEXT(lr); } if (lr) { // // Write the columns of the addr entity into the response body. // qdr_agent_write_config_link_route_CT(query, lr); // // Advance to the next object // qdr_manage_advance_config_link_route_CT(query, lr); } else query->more = false; // // Enqueue the response. // qdr_agent_enqueue_response_CT(core, query); }
unsigned int qd_buffer_list_clone(qd_buffer_list_t *dst, const qd_buffer_list_t *src) { uint32_t len = 0; DEQ_INIT(*dst); qd_buffer_t *buf = DEQ_HEAD(*src); while (buf) { size_t to_copy = qd_buffer_size(buf); unsigned char *src = qd_buffer_base(buf); len += to_copy; while (to_copy) { qd_buffer_t *newbuf = qd_buffer(); size_t count = qd_buffer_capacity(newbuf); // default buffer capacity may have changed, // so don't assume it will fit: if (count > to_copy) count = to_copy; memcpy(qd_buffer_cursor(newbuf), src, count); qd_buffer_insert(newbuf, count); DEQ_INSERT_TAIL(*dst, newbuf); src += count; to_copy -= count; } buf = DEQ_NEXT(buf); } return len; }
void qdra_link_get_next_CT(qdr_core_t *core, qdr_query_t *query) { qdr_link_t *link = 0; if (query->next_offset < DEQ_SIZE(core->open_links)) { link = DEQ_HEAD(core->open_links); for (int i = 0; i < query->next_offset && link; i++) link = DEQ_NEXT(link); } if (link) { // // Write the columns of the link entity into the response body. // qdr_agent_write_link_CT(query, link); // // Advance to the next link // qdr_manage_advance_link_CT(query, link); } else query->more = false; // // Enqueue the response. // qdr_agent_enqueue_response_CT(core, query); }
static int get_failover_info_length(qd_failover_item_list_t conn_info_list) { int arr_length = 0; qd_failover_item_t *item = DEQ_HEAD(conn_info_list); item = DEQ_NEXT(item); while(item) { if (item->scheme) { // The +3 is for the '://' arr_length += strlen(item->scheme) + 3; } if (item->host_port) { arr_length += strlen(item->host_port); } item = DEQ_NEXT(item); if (item) { // This is for the comma between the items arr_length += 2; } } if (arr_length > 0) // This is for the final '\0' arr_length += 1; return arr_length; }
void qdra_config_auto_link_get_next_CT(qdr_core_t *core, qdr_query_t *query) { qdr_auto_link_t *al = 0; if (query->next_offset < DEQ_SIZE(core->auto_links)) { al = DEQ_HEAD(core->auto_links); for (int i = 0; i < query->next_offset && al; i++) al = DEQ_NEXT(al); } if (al) { // // Write the columns of the addr entity into the response body. // qdr_agent_write_config_auto_link_CT(query, al); // // Advance to the next object // qdr_manage_advance_config_auto_link_CT(query, al); } else query->more = false; // // Enqueue the response. // qdr_agent_enqueue_response_CT(core, query); }
void qdr_route_del_auto_link_CT(qdr_core_t *core, qdr_auto_link_t *al) { // // Disassociate from the connection identifier. Check to see if the identifier // should be removed. // qdr_conn_identifier_t *cid = al->conn_id; if (cid) { qdr_connection_ref_t * cref = DEQ_HEAD(cid->connection_refs); while (cref) { qdr_auto_link_deactivate_CT(core, al, cref->conn); cref = DEQ_NEXT(cref); } DEQ_REMOVE_N(REF, cid->auto_link_refs, al); qdr_route_check_id_for_deletion_CT(core, cid); } // // Disassociate the auto link from its address. Check to see if the address // should be removed. // qdr_address_t *addr = al->addr; if (addr && --addr->ref_count == 0) qdr_check_addr_CT(core, addr, false); // // Remove the auto link from the core list. // DEQ_REMOVE(core->auto_links, al); free(al->name); free(al->external_addr); free_qdr_auto_link_t(al); }
static hash_item_t *hash_internal_insert(hash_t *h, nx_field_iterator_t *key, int *error) { unsigned long idx = hash_function(key) & h->bucket_mask; hash_item_t *item = DEQ_HEAD(h->buckets[idx].items); *error = 0; while (item) { if (nx_field_iterator_equal(key, item->key)) break; item = item->next; } if (item) { *error = -1; return 0; } item = new_hash_item_t(); if (!item) { *error = -2; return 0; } DEQ_ITEM_INIT(item); item->key = nx_field_iterator_copy(key); DEQ_INSERT_TAIL(h->buckets[idx].items, item); h->size++; return item; }
void qd_log_impl(qd_log_source_t *source, qd_log_level_t level, const char *file, int line, const char *fmt, ...) { if (!qd_log_enabled(source, level)) return; qd_log_entry_t *entry = new_qd_log_entry_t(); DEQ_ITEM_INIT(entry); entry->module = source->module; entry->level = level; entry->file = file ? strdup(file) : 0; entry->line = line; time(&entry->time); va_list ap; va_start(ap, fmt); vsnprintf(entry->text, TEXT_MAX, fmt, ap); va_end(ap); write_log(source, entry); // Bounded buffer of log entries, keep most recent. sys_mutex_lock(log_lock); DEQ_INSERT_TAIL(entries, entry); if (DEQ_SIZE(entries) > LIST_MAX) qd_log_entry_free_lh(DEQ_HEAD(entries)); sys_mutex_unlock(log_lock); }
void *router_core_thread(void *arg) { qdr_core_t *core = (qdr_core_t*) arg; qdr_action_list_t action_list; qdr_action_t *action; qdr_forwarder_setup_CT(core); qdr_route_table_setup_CT(core); qdr_agent_setup_CT(core); qd_log(core->log, QD_LOG_INFO, "Router Core thread running. %s/%s", core->router_area, core->router_id); while (core->running) { // // Use the lock only to protect the condition variable and the action list // sys_mutex_lock(core->action_lock); // // Block on the condition variable when there is no action to do // while (core->running && DEQ_IS_EMPTY(core->action_list)) sys_cond_wait(core->action_cond, core->action_lock); // // Move the entire action list to a private list so we can process it without // holding the lock // DEQ_MOVE(core->action_list, action_list); sys_mutex_unlock(core->action_lock); // // Process and free all of the action items in the list // action = DEQ_HEAD(action_list); while (action) { DEQ_REMOVE_HEAD(action_list); if (action->label) qd_log(core->log, QD_LOG_TRACE, "Core action '%s'%s", action->label, core->running ? "" : " (discard)"); action->action_handler(core, action, !core->running); free_qdr_action_t(action); action = DEQ_HEAD(action_list); } } qd_log(core->log, QD_LOG_INFO, "Router Core thread exited"); return 0; }
void qd_connection_manager_start(qd_dispatch_t *qd) { qd_config_listener_t *cl = DEQ_HEAD(qd->connection_manager->config_listeners); qd_config_connector_t *cc = DEQ_HEAD(qd->connection_manager->config_connectors); while (cl) { if (cl->listener == 0) cl->listener = qd_server_listen(qd, &cl->configuration, cl); cl = DEQ_NEXT(cl); } while (cc) { if (cc->connector == 0) cc->connector = qd_server_connect(qd, &cc->configuration, cc); cc = DEQ_NEXT(cc); } }
/// Caller must hold log_source_lock static qd_log_source_t* lookup_log_source_lh(const char *module) { if (strcasecmp(module, SOURCE_DEFAULT) == 0) return default_log_source; qd_log_source_t *src = DEQ_HEAD(source_list); DEQ_FIND(src, strcasecmp(module, src->module) == 0); return src; }
// Get events in the add/remove cache into a python list of (action, type, pointer) // Locks the entity cache so entities can be updated safely (prevent entities from being deleted.) // Do not processs any entities if return error code != 0 // Must call qd_entity_refresh_end when done, regardless of error code. qd_error_t qd_entity_refresh_begin(PyObject *list) { if (!event_lock) return QD_ERROR_NONE; /* Unit tests don't call qd_entity_cache_initialize */ qd_error_clear(); sys_mutex_lock(event_lock); entity_event_t *event = DEQ_HEAD(event_list); while (event) { PyObject *tuple = Py_BuildValue("(isl)", (int)event->action, event->type, (long)event->object); if (!tuple) { qd_error_py(); break; } int err = PyList_Append(list, tuple); Py_DECREF(tuple); if (err) { qd_error_py(); break; } DEQ_REMOVE_HEAD(event_list); free(event); event = DEQ_HEAD(event_list); } return qd_error_code(); }
static void release_buffer_chain(qd_buffer_list_t *chain) { while (DEQ_SIZE(*chain)) { qd_buffer_t *buf = DEQ_HEAD(*chain); DEQ_REMOVE_HEAD(*chain); qd_buffer_free(buf); } }