void queue_foreach(struct queue *queue, queue_foreach_func_t function, void *user_data) { struct queue_entry *entry; if (!queue || !function) return; entry = queue->head; if (!entry) return; queue_ref(queue); while (entry && queue->ref_count > 1) { struct queue_entry *tmp = entry; entry = tmp->next; function(tmp->data, user_data); if (!queue_find_entry(queue, entry)) break; } queue_unref(queue); }
/* Release the event handle returned by framework_event_query. * In the ASYNC model we must remove the event handle from the FIFO request * queue. */ void framework_release_handle(naf_handle handle) { queue_entry* entry; if (!handle) { return; } if (queue_empty()) { /* Why do the application try to release a handle on an empty queue? */ NABTO_LOG_FATAL(("SW error: Calling framework_release_handle on an empty queue")); return; } /* Find the entry containing the handle */ entry = queue_find_entry(handle); /* The given handle must belong to the queue */ UNABTO_ASSERT(entry); entry->state = APPREQ_FREE; LOG_APPREQ_WHERE("framework_release_handle", entry); /* Remove top entry from FIFO queue - and remove all consecutive * entries that have expired/finished in the mean time. */ while (!queue_empty()) { if (queue_top()->state != APPREQ_FREE) break; queue_pop(); } LOG_APPREQ_QUEUE(); }
/* Poll a pending event. * Returns true if a response is ready (from any event in the queue). * If this function fails (returns false) all buffers are unmodified. */ bool framework_event_poll(uint8_t* buf, uint16_t size, uint16_t* olen, nabto_connect** con) { queue_entry *entry; application_event_result ret; application_request *req; struct naf_handle_s *handle; request_query find; if (queue_empty()) { // no requests queued in this framework, // hence no requests pending in application return false; } //Loop through the queue and find the running (IN_APP) request, //if any - and find the first waiting request. Then do the below. //OLD: entry = queue_top(); entry = find_any_request_in_queue(); if (!entry) { return false; } switch (entry->state) { case APPREQ_FREE: // first request has been released, // hence no requests pending in application return false; case APPREQ_IN_APP: // A request is pending in the application, continue break; default: // Unknown state - ??? UNABTO_ASSERT(0); return false; } //The application is waiting for this framework to call it. //Ask for the request in the application req = NULL; if (!application_poll_query(&req)) { // The application isn't ready with a response yet, poll again later return false; } //If application_poll_query returns true - it must return a request handle if (!req) { LOG_APPERR_0(entry, "Response dropped because the application returned a NULL request !?"); goto drop_poll; } //Find the handle holding the given request find.req = (const application_request*) req; find.found = NULL; queue_enum(find_request_cb, &find); handle = find.found; if (!handle) { LOG_APPERR_0(entry, "Response dropped because the application returned a request that isn't known by the framework"); goto drop_poll; } UNABTO_ASSERT(req == &handle->applicationRequest); entry = queue_find_entry(handle); //The request must be part of a handle in the queue if (!entry) { LOG_APPERR_0(entry, "Response dropped because the application returned a request that isn't known by the framework queue"); goto drop_poll; } UNABTO_ASSERT(handle == &entry->data); if (handle->connection->spnsi != handle->spnsi) { // the connection has changed, the request/response is dropped NABTO_LOG_TRACE(("Response dropped because the connection (" PRI_client_id ") is gone", CLIENT_ID_ARGH(*handle))); goto drop_poll; } NABTO_LOG_TRACE(("APPREQ: polling=%" PRI_index, queue_index(entry))); ret = framework_poll_event(&entry->data, buf, size, olen); if (ret != AER_REQ_RESPONSE_READY) { // pass the result to caller to become an exception if (!framework_write_exception(ret, &entry->data.header, buf, size, olen)) { LOG_APPERR_1(entry, "Response dropped because an exception packet with error code %i couldn't be generated", (int)ret); goto drop_poll; } } *con = entry->data.connection; framework_release_handle(handle); LOG_APPREQ_BYTES("framework_event_poll", "true", entry, *olen); LOG_APPREQ_QUEUE(); return true; drop_poll: application_poll_drop(req); framework_release_handle(&entry->data); LOG_APPREQ_BYTES("framework_event_poll", "false", entry, 0); LOG_APPREQ_QUEUE(); return false; }
/* Handle application event in ASYNC model. * Initialize the handle and call applicaion_event. */ application_event_result framework_event(naf_handle handle, uint8_t* iobuf, uint16_t size, uint16_t ilen, uint16_t* olen, nabto_connect* con, nabto_packet_header* hdr) { queue_entry* entry; unabto_buffer w_buf; unabto_query_response w_b; application_event_result ret; /* Find the entry containing the handle */ entry = queue_find_entry(handle); /* The given handle must belong to the queue */ UNABTO_ASSERT(entry); /* Handle must have been returned by framework_event_query(). */ if (entry->state != APPREQ_WAITING) { LOG_APPREQ_QUEUE(); LOG_APPREQ_EWAIT("framework_event", entry); } /* Initialize entry in queue. */ entry->data.connection = con; if (con && hdr) { memcpy(&entry->data.header, (const void*)hdr, sizeof(entry->data.header)); entry->data.spnsi = con->spnsi; } else { memset(&entry->data.header, 0, sizeof(entry->data.header)); entry->data.spnsi = 0; } /* Set up a write buffer to write into iobuf. */ unabto_buffer_init(&w_buf, iobuf, size); unabto_query_response_init(&w_b, &w_buf); /* Set up a read buffer that reads from local space or iobuf. */ unabto_buffer_init(&entry->data.applicationRequestBuffer, iobuf, ilen); unabto_query_request_init(&entry->data.readBuffer, &entry->data.applicationRequestBuffer); ret = framework_try_event(entry, &entry->data.readBuffer, &w_b, con, hdr); /* Handle errors */ switch (ret) { case AER_REQ_RESPONSE_READY: //ok - do nothing break; case AER_REQ_ACCEPTED: LOG_APPREQ_LEAVE("framework_event", ret, handle); LOG_APPREQ_QUEUE(); return ret; default: // pass the result to caller as an exception unabto_query_response_init(&w_b, &w_buf); // reset the response unabto_query_write_uint32(&w_b, ret); hdr->flags |= NP_PACKET_HDR_FLAG_EXCEPTION; // caller copies flags to send buffer! NABTO_LOG_TRACE(("Inserting EXCEPTION %i in buffer: %" PRItext, ret, result_s(ret))); break; } *olen = unabto_query_response_used(&w_b); LOG_APPREQ_LEAVE("framework_event", ret, handle); LOG_APPREQ_QUEUE(); return ret; }