// drop all pending requests for the given UID from the global list static void network_drop_pending_requests(uint32_t uid) { Node *pending_request_global_node = _pending_request_sentinel.next; Node *pending_request_global_node_next; PendingRequest *pending_request; char base58[BASE58_MAX_LENGTH]; int count = 0; while (pending_request_global_node != &_pending_request_sentinel) { pending_request = containerof(pending_request_global_node, PendingRequest, global_node); pending_request_global_node_next = pending_request_global_node->next; if (pending_request->header.uid == uid) { pending_request_remove_and_free(pending_request); ++count; } pending_request_global_node = pending_request_global_node_next; } if (count > 0) { log_warn("Dropped %d pending request(s) (uid: %s)", count, base58_encode(base58, uint32_from_le(uid))); } }
void client_destroy(Client *client) { bool destroy_pending_requests = false; PendingRequest *pending_request; if (client->pending_request_count > 0) { log_warn("Destroying client ("CLIENT_SIGNATURE_FORMAT") while %d request(s) are still pending", client_expand_signature(client), client->pending_request_count); if (network_create_zombie(client) < 0) { log_error("Could not create zombie for %d pending request(s) of ("CLIENT_SIGNATURE_FORMAT")", client->pending_request_count, client_expand_signature(client)); destroy_pending_requests = true; } } writer_destroy(&client->response_writer); event_remove_source(client->io->handle, EVENT_SOURCE_TYPE_GENERIC); io_destroy(client->io); free(client->io); if (destroy_pending_requests) { while (client->pending_request_sentinel.next != &client->pending_request_sentinel) { pending_request = containerof(client->pending_request_sentinel.next, PendingRequest, client_node); pending_request_remove_and_free(pending_request); } } if (client->destroy_done != NULL) { client->destroy_done(); } }
void network_client_expects_response(Client *client, Packet *request) { PendingRequest *pending_request; char packet_signature[PACKET_MAX_SIGNATURE_LENGTH]; if (client->pending_request_count >= CLIENT_MAX_PENDING_REQUESTS) { log_warn("Pending requests list for client ("CLIENT_SIGNATURE_FORMAT") is full, dropping %d pending request(s)", client_expand_signature(client), client->pending_request_count - CLIENT_MAX_PENDING_REQUESTS + 1); while (client->pending_request_count >= CLIENT_MAX_PENDING_REQUESTS) { pending_request = containerof(client->pending_request_sentinel.next, PendingRequest, client_node); pending_request_remove_and_free(pending_request); } } pending_request = calloc(1, sizeof(PendingRequest)); if (pending_request == NULL) { log_error("Could not allocate pending request: %s (%d)", get_errno_name(ENOMEM), ENOMEM); return; } node_reset(&pending_request->global_node); node_insert_before(&_pending_request_sentinel, &pending_request->global_node); node_reset(&pending_request->client_node); node_insert_before(&client->pending_request_sentinel, &pending_request->client_node); ++client->pending_request_count; pending_request->client = client; pending_request->zombie = NULL; memcpy(&pending_request->header, &request->header, sizeof(PacketHeader)); #ifdef BRICKD_WITH_PROFILING pending_request->arrival_time = microseconds(); #endif log_packet_debug("Added pending request (%s) for client ("CLIENT_SIGNATURE_FORMAT")", packet_get_request_signature(packet_signature, request), client_expand_signature(client)); }
void client_dispatch_response(Client *client, PendingRequest *pending_request, Packet *response, bool force, bool ignore_authentication) { Node *pending_request_client_node = NULL; int enqueued = 0; #ifdef BRICKD_WITH_PROFILING uint64_t elapsed; #endif if (!ignore_authentication && client->authentication_state != CLIENT_AUTHENTICATION_STATE_DISABLED && client->authentication_state != CLIENT_AUTHENTICATION_STATE_DONE) { log_packet_debug("Ignoring non-authenticated client ("CLIENT_SIGNATURE_FORMAT")", client_expand_signature(client)); goto cleanup; } // find matching pending request if not forced and no pending request is // already given. do this before the disconnect check to ensure that even // for a disconnected client the pending request list is updated correctly if (!force && pending_request == NULL) { pending_request_client_node = client->pending_request_sentinel.next; while (pending_request_client_node != &client->pending_request_sentinel) { pending_request = containerof(pending_request_client_node, PendingRequest, client_node); if (packet_is_matching_response(response, &pending_request->header)) { break; } pending_request_client_node = pending_request_client_node->next; } if (pending_request_client_node == &client->pending_request_sentinel) { pending_request = NULL; goto cleanup; } } if (client->disconnected) { log_debug("Ignoring disconnected client ("CLIENT_SIGNATURE_FORMAT")", client_expand_signature(client)); goto cleanup; } if (force || pending_request != NULL) { enqueued = writer_write(&client->response_writer, response); if (enqueued < 0) { goto cleanup; } if (force) { log_packet_debug("Forced to %s response to client ("CLIENT_SIGNATURE_FORMAT")", enqueued ? "enqueue" : "send", client_expand_signature(client)); } else { #ifdef BRICKD_WITH_PROFILING elapsed = microseconds() - pending_request->arrival_time; log_packet_debug("%s response to client ("CLIENT_SIGNATURE_FORMAT"), was requested %u.%03u msec ago, %d request(s) still pending", enqueued ? "Enqueued" : "Sent", client_expand_signature(client), (unsigned int)(elapsed / 1000), (unsigned int)(elapsed % 1000), client->pending_request_count - 1); #else log_packet_debug("%s response to client ("CLIENT_SIGNATURE_FORMAT"), %d request(s) still pending", enqueued ? "Enqueued" : "Sent", client_expand_signature(client), client->pending_request_count - 1); #endif } } cleanup: if (pending_request != NULL) { pending_request_remove_and_free(pending_request); } }