qd_connector_t *qd_dispatch_configure_connector(qd_dispatch_t *qd, qd_entity_t *entity) { qd_connection_manager_t *cm = qd->connection_manager; qd_connector_t *ct = qd_server_connector(qd->server); if (ct && load_server_config(qd, &ct->config, entity, false) == QD_ERROR_NONE) { DEQ_ITEM_INIT(ct); DEQ_INSERT_TAIL(cm->connectors, ct); log_config(cm->log_source, &ct->config, "Connector"); // // Add the first item to the ct->conn_info_list // The initial connection information and any backup connection information is stored in the conn_info_list // qd_failover_item_t *item = NEW(qd_failover_item_t); ZERO(item); item->scheme = 0; item->host = strdup(ct->config.host); item->port = strdup(ct->config.port); item->hostname = 0; int hplen = strlen(item->host) + strlen(item->port) + 2; item->host_port = malloc(hplen); snprintf(item->host_port, hplen, "%s:%s", item->host , item->port); DEQ_INSERT_TAIL(ct->conn_info_list, item); return ct; } qd_log(cm->log_source, QD_LOG_ERROR, "Unable to create connector: %s", qd_error_message()); qd_connector_decref(ct); return 0; }
qd_listener_t *qd_dispatch_configure_listener(qd_dispatch_t *qd, qd_entity_t *entity) { qd_connection_manager_t *cm = qd->connection_manager; qd_listener_t *li = qd_server_listener(qd->server); if (!li || load_server_config(qd, &li->config, entity, true) != QD_ERROR_NONE) { qd_log(cm->log_source, QD_LOG_ERROR, "Unable to create listener: %s", qd_error_message()); qd_listener_decref(li); return 0; } char *fol = qd_entity_opt_string(entity, "failoverList", 0); if (fol) { li->config.failover_list = qd_failover_list(fol); free(fol); if (li->config.failover_list == 0) { qd_log(cm->log_source, QD_LOG_ERROR, "Unable to create listener, bad failover list: %s", qd_error_message()); qd_listener_decref(li); return 0; } } else { li->config.failover_list = 0; } DEQ_ITEM_INIT(li); DEQ_INSERT_TAIL(cm->listeners, li); log_config(cm->log_source, &li->config, "Listener"); return li; }
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; }
qd_config_connector_t *qd_dispatch_configure_connector(qd_dispatch_t *qd, qd_entity_t *entity) { qd_error_clear(); qd_connection_manager_t *cm = qd->connection_manager; qd_config_connector_t *cc = NEW(qd_config_connector_t); ZERO(cc); cc->is_connector = true; qd_config_ssl_profile_t *ssl_profile = 0; if (load_server_config(qd, &cc->configuration, entity, &ssl_profile) != QD_ERROR_NONE) { qd_log(cm->log_source, QD_LOG_ERROR, "Unable to create config connector: %s", qd_error_message()); qd_config_connector_free(qd->connection_manager, cc); return 0; } cc->ssl_profile = ssl_profile; DEQ_ITEM_INIT(cc); DEQ_INSERT_TAIL(cm->config_connectors, cc); qd_log(cm->log_source, QD_LOG_INFO, "Configured Connector: %s:%s proto=%s, role=%s %s%s", cc->configuration.host, cc->configuration.port, cc->configuration.protocol_family ? cc->configuration.protocol_family : "any", cc->configuration.role, cc->ssl_profile ? ", sslProfile=":"", cc->ssl_profile ? cc->ssl_profile->name:""); return cc; }
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); }
qd_message_t *qd_message() { qd_message_pvt_t *msg = (qd_message_pvt_t*) new_qd_message_t(); if (!msg) return 0; DEQ_ITEM_INIT(msg); DEQ_INIT(msg->ma_to_override); DEQ_INIT(msg->ma_trace); DEQ_INIT(msg->ma_ingress); msg->content = new_qd_message_content_t(); if (msg->content == 0) { free_qd_message_t((qd_message_t*) msg); return 0; } memset(msg->content, 0, sizeof(qd_message_content_t)); msg->content->lock = sys_mutex(); msg->content->ref_count = 1; msg->content->parse_depth = QD_DEPTH_NONE; msg->content->parsed_message_annotations = 0; return (qd_message_t*) msg; }
qd_config_ssl_profile_t *qd_dispatch_configure_ssl_profile(qd_dispatch_t *qd, qd_entity_t *entity) { qd_error_clear(); qd_connection_manager_t *cm = qd->connection_manager; qd_config_ssl_profile_t *ssl_profile = NEW(qd_config_ssl_profile_t); DEQ_ITEM_INIT(ssl_profile); DEQ_INSERT_TAIL(cm->config_ssl_profiles, ssl_profile); ssl_profile->name = qd_entity_opt_string(entity, "name", 0); CHECK(); ssl_profile->ssl_certificate_file = qd_entity_opt_string(entity, "certFile", 0); CHECK(); ssl_profile->ssl_private_key_file = qd_entity_opt_string(entity, "keyFile", 0); CHECK(); ssl_profile->ssl_password = qd_entity_opt_string(entity, "password", 0); CHECK(); ssl_profile->ssl_trusted_certificate_db = qd_entity_opt_string(entity, "certDb", 0); CHECK(); ssl_profile->ssl_trusted_certificates = qd_entity_opt_string(entity, "trustedCerts", 0); CHECK(); ssl_profile->ssl_uid_format = qd_entity_opt_string(entity, "uidFormat", 0); CHECK(); ssl_profile->ssl_display_name_file = qd_entity_opt_string(entity, "displayNameFile", 0); CHECK(); sys_atomic_init(&ssl_profile->ref_count, 0); qd_log(cm->log_source, QD_LOG_INFO, "Created SSL Profile with name %s ", ssl_profile->name); return ssl_profile; error: qd_log(cm->log_source, QD_LOG_ERROR, "Unable to create ssl profile: %s", qd_error_message()); qd_config_ssl_profile_free(cm, ssl_profile); return 0; }
void qdr_add_delivery_ref_CT(qdr_delivery_ref_list_t *list, qdr_delivery_t *dlv) { qdr_delivery_ref_t *ref = new_qdr_delivery_ref_t(); DEQ_ITEM_INIT(ref); ref->dlv = dlv; DEQ_INSERT_TAIL(*list, ref); }
static void dx_alloc_init(dx_alloc_type_desc_t *desc) { sys_mutex_lock(init_lock); desc->total_size = desc->type_size; if (desc->additional_size) desc->total_size += *desc->additional_size; //dx_log("ALLOC", LOG_TRACE, "Initialized Allocator - type=%s type-size=%d total-size=%d", // desc->type_name, desc->type_size, desc->total_size); if (!desc->global_pool) { if (desc->config == 0) desc->config = desc->total_size > 256 ? &dx_alloc_default_config_big : &dx_alloc_default_config_small; assert (desc->config->local_free_list_max >= desc->config->transfer_batch_size); desc->global_pool = NEW(dx_alloc_pool_t); DEQ_INIT(desc->global_pool->free_list); desc->lock = sys_mutex(); desc->stats = NEW(dx_alloc_stats_t); memset(desc->stats, 0, sizeof(dx_alloc_stats_t)); } item_t *type_item = NEW(item_t); DEQ_ITEM_INIT(type_item); type_item->desc = desc; DEQ_INSERT_TAIL(type_list, type_item); sys_mutex_unlock(init_lock); }
qd_config_listener_t *qd_dispatch_configure_listener(qd_dispatch_t *qd, qd_entity_t *entity) { qd_error_clear(); qd_connection_manager_t *cm = qd->connection_manager; qd_config_listener_t *cl = NEW(qd_config_listener_t); cl->is_connector = false; cl->state = QD_BIND_NONE; cl->listener = 0; qd_config_ssl_profile_t *ssl_profile = 0; if (load_server_config(qd, &cl->configuration, entity, &ssl_profile) != QD_ERROR_NONE) { qd_log(cm->log_source, QD_LOG_ERROR, "Unable to create config listener: %s", qd_error_message()); qd_config_listener_free(qd->connection_manager, cl); return 0; } cl->ssl_profile = ssl_profile; DEQ_ITEM_INIT(cl); DEQ_INSERT_TAIL(cm->config_listeners, cl); qd_log(cm->log_source, QD_LOG_INFO, "Configured Listener: %s:%s proto=%s, role=%s%s%s", cl->configuration.host, cl->configuration.port, cl->configuration.protocol_family ? cl->configuration.protocol_family : "any", cl->configuration.role, cl->ssl_profile ? ", sslProfile=":"", cl->ssl_profile ? cl->ssl_profile->name:""); return cl; }
void qdr_add_connection_ref(qdr_connection_ref_list_t *ref_list, qdr_connection_t *conn) { qdr_connection_ref_t *ref = new_qdr_connection_ref_t(); DEQ_ITEM_INIT(ref); ref->conn = conn; DEQ_INSERT_TAIL(*ref_list, ref); }
/** * Creates and returns a new qd_hash_segment_t and initializes it. */ static qd_hash_segment_t *qd_iterator_hash_segment(void) { qd_hash_segment_t *hash_segment = new_qd_hash_segment_t(); DEQ_ITEM_INIT(hash_segment); hash_segment->hash = 0; hash_segment->segment_length = 0; return hash_segment; }
static entity_event_t *entity_event(action_t action, const char *type, void *object) { entity_event_t *event = NEW(entity_event_t); DEQ_ITEM_INIT(event); event->action = action; event->type = type; event->object = object; return event; }
void qdr_add_node_ref(qdr_router_ref_list_t *ref_list, qdr_node_t *rnode) { qdr_router_ref_t *ref = new_qdr_router_ref_t(); DEQ_ITEM_INIT(ref); ref->router = rnode; rnode->ref_count++; DEQ_INSERT_TAIL(*ref_list, ref); }
qd_buffer_t *qd_buffer(void) { size_locked = 1; qd_buffer_t *buf = new_qd_buffer_t(); DEQ_ITEM_INIT(buf); buf->size = 0; sys_atomic_init(&buf->bfanout, 0); return buf; }
void qdr_add_link_ref(qdr_link_ref_list_t *ref_list, qdr_link_t *link, int cls) { if (link->ref[cls] != 0) return; qdr_link_ref_t *ref = new_qdr_link_ref_t(); DEQ_ITEM_INIT(ref); ref->link = link; link->ref[cls] = ref; DEQ_INSERT_TAIL(*ref_list, ref); }
void qdr_post_general_work_CT(qdr_core_t *core, qdr_general_work_t *work) { bool notify; sys_mutex_lock(core->work_lock); DEQ_ITEM_INIT(work); DEQ_INSERT_TAIL(core->work_list, work); notify = DEQ_SIZE(core->work_list) == 1; sys_mutex_unlock(core->work_lock); if (notify) qd_timer_schedule(core->work_timer, 0); }
static void qdr_subscribe_CT(qdr_core_t *core, qdr_action_t *action, bool discard) { qdr_field_t *address = action->args.io.address; qdr_subscription_t *sub = action->args.io.subscription; if (!discard) { char aclass = action->args.io.address_class; char phase = action->args.io.address_phase; qdr_address_t *addr = 0; char *astring = (char*) qd_field_iterator_copy(address->iterator); qd_log(core->log, QD_LOG_INFO, "In-process subscription %c/%s", aclass, astring); free(astring); qd_address_iterator_override_prefix(address->iterator, aclass); if (aclass == 'M') qd_address_iterator_set_phase(address->iterator, phase); qd_address_iterator_reset_view(address->iterator, ITER_VIEW_ADDRESS_HASH); qd_hash_retrieve(core->addr_hash, address->iterator, (void**) &addr); if (!addr) { addr = qdr_address_CT(core, action->args.io.treatment); qd_hash_insert(core->addr_hash, address->iterator, addr, &addr->hash_handle); DEQ_ITEM_INIT(addr); DEQ_INSERT_TAIL(core->addrs, addr); } sub->addr = addr; DEQ_ITEM_INIT(sub); DEQ_INSERT_TAIL(addr->subscriptions, sub); qdr_addr_start_inlinks_CT(core, addr); } else free(sub); qdr_field_free(address); }
/// Caller must hold the log_source_lock static qd_log_source_t *qd_log_source_lh(const char *module) { qd_log_source_t *log_source = lookup_log_source_lh(module); if (!log_source) { log_source = NEW(qd_log_source_t); memset(log_source, 0, sizeof(qd_log_source_t)); DEQ_ITEM_INIT(log_source); log_source->module = (char*) malloc(strlen(module) + 1); strcpy(log_source->module, module); qd_log_source_defaults(log_source); DEQ_INSERT_TAIL(source_list, log_source); } return log_source; }
static void qdr_map_destination_CT(qdr_core_t *core, qdr_action_t *action, bool discard) { // // TODO - handle the class-prefix and phase explicitly // int router_maskbit = action->args.route_table.router_maskbit; qdr_field_t *address = action->args.route_table.address; if (discard) { qdr_field_free(address); return; } do { if (router_maskbit >= qd_bitmask_width() || router_maskbit < 0) { qd_log(core->log, QD_LOG_CRITICAL, "map_destination: Router maskbit out of range: %d", router_maskbit); break; } if (core->routers_by_mask_bit[router_maskbit] == 0) { qd_log(core->log, QD_LOG_CRITICAL, "map_destination: Router not found"); break; } qd_field_iterator_t *iter = address->iterator; qdr_address_t *addr = 0; qd_hash_retrieve(core->addr_hash, iter, (void**) &addr); if (!addr) { addr = qdr_address_CT(core, qdr_treatment_for_address_hash_CT(core, iter)); qd_hash_insert(core->addr_hash, iter, addr, &addr->hash_handle); DEQ_ITEM_INIT(addr); DEQ_INSERT_TAIL(core->addrs, addr); } qdr_node_t *rnode = core->routers_by_mask_bit[router_maskbit]; qd_bitmask_set_bit(addr->rnodes, router_maskbit); rnode->ref_count++; qdr_addr_start_inlinks_CT(core, addr); // // TODO - If this affects a waypoint, create the proper side effects // } while (false); qdr_field_free(address); }
qdr_query_t *qdr_query(qdr_core_t *core, void *context, qd_router_entity_type_t type, qd_composed_field_t *body) { qdr_query_t *query = new_qdr_query_t(); DEQ_ITEM_INIT(query); ZERO(query); query->core = core; query->entity_type = type; query->context = context; query->body = body; query->more = false; return query; }
qd_node_t *qd_container_create_node(qd_dispatch_t *qd, const qd_node_type_t *nt, const char *name, void *context, qd_dist_mode_t supported_dist, qd_lifetime_policy_t life_policy) { qd_container_t *container = qd->container; int result; qd_node_t *node = new_qd_node_t(); if (!node) return 0; DEQ_ITEM_INIT(node); node->container = container; node->ntype = nt; node->name = 0; node->context = context; node->supported_dist = supported_dist; node->life_policy = life_policy; if (name) { qd_field_iterator_t *iter = qd_field_iterator_string(name); sys_mutex_lock(container->lock); result = qd_hash_insert(container->node_map, iter, node, 0); if (result >= 0) DEQ_INSERT_HEAD(container->nodes, node); sys_mutex_unlock(container->lock); qd_field_iterator_free(iter); if (result < 0) { free_qd_node_t(node); return 0; } node->name = (char*) malloc(strlen(name) + 1); strcpy(node->name, name); } if (name) qd_log(container->log_source, QD_LOG_TRACE, "Node of type '%s' created with name '%s'", nt->type_name, name); return node; }
qd_config_sasl_plugin_t *qd_dispatch_configure_sasl_plugin(qd_dispatch_t *qd, qd_entity_t *entity) { qd_error_clear(); qd_connection_manager_t *cm = qd->connection_manager; qd_config_sasl_plugin_t *sasl_plugin = NEW(qd_config_sasl_plugin_t); DEQ_ITEM_INIT(sasl_plugin); DEQ_INSERT_TAIL(cm->config_sasl_plugins, sasl_plugin); sasl_plugin->name = qd_entity_opt_string(entity, "name", 0); CHECK(); sasl_plugin->auth_service = qd_entity_opt_string(entity, "authService", 0); CHECK(); sasl_plugin->sasl_init_hostname = qd_entity_opt_string(entity, "saslInitHostname", 0); CHECK(); sasl_plugin->auth_ssl_profile = qd_entity_opt_string(entity, "authSslProfile", 0); CHECK(); qd_log(cm->log_source, QD_LOG_INFO, "Created SASL plugin config with name %s", sasl_plugin->name); return sasl_plugin; error: qd_log(cm->log_source, QD_LOG_ERROR, "Unable to create SASL plugin config: %s", qd_error_message()); config_sasl_plugin_free(cm, sasl_plugin); return 0; }
qdr_address_t *qdr_add_local_address_CT(qdr_core_t *core, char aclass, const char *address, qd_address_treatment_t treatment) { char addr_string[1000]; qdr_address_t *addr = 0; qd_field_iterator_t *iter = 0; snprintf(addr_string, sizeof(addr_string), "%c%s", aclass, address); iter = qd_address_iterator_string(addr_string, ITER_VIEW_ALL); qd_hash_retrieve(core->addr_hash, iter, (void**) &addr); if (!addr) { addr = qdr_address_CT(core, treatment); qd_hash_insert(core->addr_hash, iter, addr, &addr->hash_handle); DEQ_ITEM_INIT(addr); DEQ_INSERT_TAIL(core->addrs, addr); addr->block_deletion = true; addr->local = (aclass == 'L'); } qd_field_iterator_free(iter); return addr; }
static qd_hash_item_t *qd_hash_internal_insert(qd_hash_t *h, qd_field_iterator_t *key, int *exists, qd_hash_handle_t **handle) { unsigned long idx = qd_iterator_hash_function(key) & h->bucket_mask; qd_hash_item_t *item = DEQ_HEAD(h->buckets[idx].items); while (item) { if (qd_field_iterator_equal(key, item->key)) break; item = item->next; } if (item) { *exists = 1; if (handle) *handle = 0; return item; } item = new_qd_hash_item_t(); if (!item) return 0; DEQ_ITEM_INIT(item); item->key = qd_field_iterator_copy(key); DEQ_INSERT_TAIL(h->buckets[idx].items, item); h->size++; *exists = 0; // // If a pointer to a handle-pointer was supplied, create a handle for this item. // if (handle) { *handle = new_qd_hash_handle_t(); (*handle)->bucket = &h->buckets[idx]; (*handle)->item = item; } return item; }
qd_message_t *qd_message_copy(qd_message_t *in_msg) { qd_message_pvt_t *msg = (qd_message_pvt_t*) in_msg; qd_message_content_t *content = msg->content; qd_message_pvt_t *copy = (qd_message_pvt_t*) new_qd_message_t(); if (!copy) return 0; DEQ_ITEM_INIT(copy); qd_buffer_list_clone(©->ma_to_override, &msg->ma_to_override); qd_buffer_list_clone(©->ma_trace, &msg->ma_trace); qd_buffer_list_clone(©->ma_ingress, &msg->ma_ingress); copy->content = content; sys_mutex_lock(content->lock); content->ref_count++; sys_mutex_unlock(content->lock); return (qd_message_t*) copy; }
int qd_container_register_node_type(qd_dispatch_t *qd, const qd_node_type_t *nt) { qd_container_t *container = qd->container; int result; qd_field_iterator_t *iter = qd_field_iterator_string(nt->type_name); qdc_node_type_t *nt_item = NEW(qdc_node_type_t); DEQ_ITEM_INIT(nt_item); nt_item->ntype = nt; sys_mutex_lock(container->lock); result = qd_hash_insert_const(container->node_type_map, iter, nt, 0); DEQ_INSERT_TAIL(container->node_type_list, nt_item); sys_mutex_unlock(container->lock); qd_field_iterator_free(iter); if (result < 0) return result; qd_log(container->log_source, QD_LOG_TRACE, "Node Type Registered - %s", nt->type_name); return 0; }
static qd_parsed_field_t *qd_parse_internal(qd_iterator_t *iter, qd_parsed_field_t *p) { qd_parsed_field_t *field = new_qd_parsed_field_t(); if (!field) return 0; DEQ_ITEM_INIT(field); DEQ_INIT(field->children); field->parent = p; field->raw_iter = 0; field->typed_iter = qd_iterator_dup(iter); uint32_t size = 0; uint32_t count = 0; uint32_t length_of_count = 0; uint32_t length_of_size = 0; field->parse_error = get_type_info(iter, &field->tag, &size, &count, &length_of_size, &length_of_count); if (!field->parse_error) { qd_iterator_trim_view(field->typed_iter, size + length_of_size + 1); // + 1 accounts for the tag length field->raw_iter = qd_iterator_sub(iter, size - length_of_count); qd_iterator_advance(iter, size - length_of_count); for (uint32_t idx = 0; idx < count; idx++) { qd_parsed_field_t *child = qd_parse_internal(field->raw_iter, field); DEQ_INSERT_TAIL(field->children, child); if (!qd_parse_ok(child)) { field->parse_error = child->parse_error; break; } } } return field; }
/** * New Incoming Link Handler */ static int router_incoming_link_handler(void* context, dx_link_t *link) { dx_router_t *router = (dx_router_t*) context; dx_link_item_t *item = new_dx_link_item_t(); pn_link_t *pn_link = dx_link_pn(link); if (item) { DEQ_ITEM_INIT(item); item->link = link; sys_mutex_lock(router->lock); DEQ_INSERT_TAIL(router->in_links, item); sys_mutex_unlock(router->lock); pn_terminus_copy(pn_link_source(pn_link), pn_link_remote_source(pn_link)); pn_terminus_copy(pn_link_target(pn_link), pn_link_remote_target(pn_link)); pn_link_flow(pn_link, 8); pn_link_open(pn_link); } else { pn_link_close(pn_link); } return 0; }
static char* test_deq_basic(void *context) { item_list_t list; item_t item[10]; item_t *ptr; int idx; char *subtest; DEQ_INIT(list); if (DEQ_SIZE(list) != 0) return "Expected zero initial size"; for (idx = 0; idx < 10; idx++) { DEQ_ITEM_INIT(&item[idx]); item[idx].letter = 'A' + idx; DEQ_INSERT_TAIL(list, &item[idx]); } if (DEQ_SIZE(list) != 10) return "Expected 10 items in list"; ptr = DEQ_HEAD(list); if (!ptr) return "Expected valid head item"; if (DEQ_PREV(ptr)) return "Head item has non-null previous link"; if (ptr->letter != 'A') return "Expected item A at the head"; if (DEQ_NEXT(ptr) == 0) return "Head item has null next link"; subtest = list_well_formed(list, "ABCDEFGHIJ"); if (subtest) return subtest; DEQ_REMOVE_HEAD(list); if (DEQ_SIZE(list) != 9) return "Expected 9 items in list"; ptr = DEQ_HEAD(list); if (ptr->letter != 'B') return "Expected item B at the head"; subtest = list_well_formed(list, "BCDEFGHIJ"); if (subtest) return subtest; DEQ_REMOVE_TAIL(list); if (DEQ_SIZE(list) != 8) return "Expected 8 items in list"; ptr = DEQ_TAIL(list); if (ptr->letter != 'I') return "Expected item I at the tail"; subtest = list_well_formed(list, "BCDEFGHI"); if (subtest) return subtest; DEQ_REMOVE(list, &item[4]); if (DEQ_SIZE(list) != 7) return "Expected 7 items in list"; subtest = list_well_formed(list, "BCDFGHI"); if (subtest) return subtest; DEQ_REMOVE(list, &item[1]); if (DEQ_SIZE(list) != 6) return "Expected 6 items in list"; subtest = list_well_formed(list, "CDFGHI"); if (subtest) return subtest; DEQ_REMOVE(list, &item[8]); if (DEQ_SIZE(list) != 5) return "Expected 5 items in list"; subtest = list_well_formed(list, "CDFGH"); if (subtest) return subtest; DEQ_INSERT_HEAD(list, &item[8]); if (DEQ_SIZE(list) != 6) return "Expected 6 items in list"; ptr = DEQ_HEAD(list); if (ptr->letter != 'I') return "Expected item I at the head"; subtest = list_well_formed(list, "ICDFGH"); if (subtest) return subtest; DEQ_INSERT_AFTER(list, &item[4], &item[7]); if (DEQ_SIZE(list) != 7) return "Expected 7 items in list"; ptr = DEQ_TAIL(list); if (ptr->letter != 'E') return "Expected item E at the head"; subtest = list_well_formed(list, "ICDFGHE"); if (subtest) return subtest; DEQ_INSERT_AFTER(list, &item[1], &item[5]); if (DEQ_SIZE(list) != 8) return "Expected 8 items in list"; subtest = list_well_formed(list, "ICDFBGHE"); if (subtest) return subtest; if (item[0].prev || item[0].next) return "Unlisted item A has non-null pointers"; if (item[9].prev || item[9].next) return "Unlisted item J has non-null pointers"; return 0; }