in src/router_core/connections.c [2018:2200]
static void qdr_link_inbound_detach_CT(qdr_core_t *core, qdr_action_t *action, bool discard)
{
qdr_connection_t *conn = safe_deref_qdr_connection_t(action->args.connection.conn);
qdr_link_t *link = safe_deref_qdr_link_t(action->args.connection.link);
qdr_error_t *error = action->args.connection.error;
qd_detach_type_t dt = action->args.connection.dt;
if (discard || !conn || !link) {
qdr_error_free(error);
return;
}
if (link->detach_received)
return;
link->detach_received = true;
++link->detach_count;
if (link->core_endpoint) {
qdrc_endpoint_do_detach_CT(core, link->core_endpoint, error, dt);
return;
}
//
// ensure a pooled link is no longer available for use
//
if (link->streaming) {
if (link->in_streaming_pool) {
DEQ_REMOVE_N(STREAMING_POOL, conn->streaming_link_pool, link);
link->in_streaming_pool = false;
}
}
//
// For routed links, propagate the detach
//
if (link->connected_link) {
//
// If the connected link is outgoing and there is a delivery on the connected link's undelivered
// list that is not receive-complete, we must flag that delivery as aborted or it will forever
// block the propagation of the detach.
//
if (link->connected_link->link_direction == QD_OUTGOING)
qdr_link_abort_undelivered_CT(core, link->connected_link);
if (dt != QD_LOST)
qdr_link_outbound_detach_CT(core, link->connected_link, error, QDR_CONDITION_NONE, dt == QD_CLOSED);
else {
qdr_link_outbound_detach_CT(core, link->connected_link, 0, QDR_CONDITION_ROUTED_LINK_LOST, !link->terminus_survives_disconnect);
qdr_error_free(error);
}
//
// If the link is completely detached, release its resources
//
if (link->detach_send_done)
qdr_link_cleanup_protected_CT(core, conn, link, "Link detached");
return;
}
//
// For auto links, switch the auto link to failed state and record the error
//
if (link->auto_link) {
link->auto_link->link = 0;
link->auto_link->state = QDR_AUTO_LINK_STATE_FAILED;
free(link->auto_link->last_error);
link->auto_link->last_error = qdr_error_description(error);
//
// The auto link has failed. Periodically retry setting up the auto link until
// it succeeds.
//
qdr_route_auto_link_detached_CT(core, link);
}
qdr_address_t *addr = link->owning_addr;
if (addr)
addr->ref_count++;
if (link->link_direction == QD_INCOMING) {
qdrc_event_link_raise(core, QDRC_EVENT_LINK_IN_DETACHED, link);
//
// Handle incoming link cases
//
switch (link->link_type) {
case QD_LINK_ENDPOINT:
if (addr) {
//
// Drain the undelivered list to ensure deliveries don't get dropped by a detach.
//
qdr_drain_inbound_undelivered_CT(core, link, addr);
//
// Unbind the address and the link.
//
qdr_core_unbind_address_link_CT(core, addr, link);
//
// If this is an edge data link, raise a link event to indicate its detachment.
//
if (link->conn->role == QDR_ROLE_EDGE_CONNECTION)
qdrc_event_link_raise(core, QDRC_EVENT_LINK_EDGE_DATA_DETACHED, link);
}
break;
case QD_LINK_CONTROL:
break;
case QD_LINK_ROUTER:
break;
case QD_LINK_EDGE_DOWNLINK:
break;
}
} else {
//
// Handle outgoing link cases
//
qdrc_event_link_raise(core, QDRC_EVENT_LINK_OUT_DETACHED, link);
switch (link->link_type) {
case QD_LINK_ENDPOINT:
case QD_LINK_EDGE_DOWNLINK:
if (addr) {
qdr_core_unbind_address_link_CT(core, addr, link);
}
break;
case QD_LINK_CONTROL:
qdr_detach_link_control_CT(core, conn, link);
break;
case QD_LINK_ROUTER:
qdr_detach_link_data_CT(core, conn, link);
break;
}
}
//
// We had increased the ref_count if the link->no_route was true. Now reduce the ref_count
//
if (addr && link->no_route && link->no_route_bound) {
addr->ref_count--;
}
link->owning_addr = 0;
if (link->detach_count == 1) {
//
// Handle the disposition of any deliveries that remain on the link
//
qdr_link_cleanup_deliveries_CT(core, conn, link, false);
//
// If the detach occurred via protocol, send a detach back.
//
if (dt != QD_LOST) {
qdr_link_outbound_detach_CT(core, link, 0, QDR_CONDITION_NONE, dt == QD_CLOSED);
} else {
// no detach can be sent out because the connection was lost
qdr_link_cleanup_protected_CT(core, conn, link, "Link lost");
}
} else if (link->detach_send_done) { // detach count indicates detach has been scheduled
// I/O thread is finished sending detach, ok to free link now
qdr_link_cleanup_protected_CT(core, conn, link, "Link detached");
}
//
// If there was an address associated with this link, check to see if any address-related
// cleanup has to be done.
//
if (addr) {
addr->ref_count--;
qdr_check_addr_CT(core, addr);
}
if (error)
qdr_error_free(error);
}