Esempio n. 1
0
/** Enumerates all entries in queue in order (from first to last item).
 * Returns false immediately iff proc returns false.
 * Returns true if every call to proc returned true. */
bool queue_enum(queue_enum_proc proc, void *data)
{
#if NABTO_APPREQ_QUEUE_SIZE > 1
    queue_entry* entry;
    if (queueLastAdd) {
        //At least one record in queue.
        //queue may be full. queue_first_used == queue_next_free means full.
        UNABTO_ASSERT(!queue_empty());
        UNABTO_ASSERT(queue_first_used->state != APPREQ_FREE);
        entry = queue_first_used;
        do {
            // If queue->state == APPREQ_FREE, we have an empty (already answered) slot
            // in the queue. Don't use (requests are inserted in strict order to start
            // treatment in the same order).
            if (entry->state != APPREQ_FREE) {
                  // Let caller determine whether to proceed.
                  if (!(*proc)(&entry->data, data)) {
                      return false;
                  }
            }
            queue_inc(entry);
        } while (entry != queue_next_free);
    } else {
        //queue may be empty. queue_first_used == queue_next_free means empty.
        UNABTO_ASSERT(!queue_full());
        entry = queue_first_used;
        while (entry != queue_next_free) {
            // If queue->state == APPREQ_FREE, we have an empty (already answered) slot
            // in the queue. Don't use (requests are inserted in strict order to start
            // treatment in the same order).
            if (entry->state != APPREQ_FREE) {
                  // Let caller determine whether to proceed.
                  if (!(*proc)(&entry->data, data)) {
                      return false;
                  }
            }
            queue_inc(entry);
        }
    }
#else //NABTO_APPREQ_QUEUE_SIZE == 1
    if (!queue_empty()) {
         // Let caller determine whether to proceed.
         if (!(*proc)(&queue[0].data, data)) {
             return false;
         }
    }
#endif
    return true;
}
void unabto_tcp_fallback_handle_write(nabto_connect* con) {
	ssize_t status;
    int dataToSend;
    unabto_tcp_fallback_connection* fbConn = &fbConns[nabto_connection_index(con)];
    UNABTO_ASSERT(fbConn->sendBufferSent <= fbConn->sendBufferLength); 
    dataToSend = fbConn->sendBufferLength - fbConn->sendBufferSent;
    
    status = send(fbConn->socket, fbConn->sendBuffer + fbConn->sendBufferSent, dataToSend, MSG_NOSIGNAL);
    if (status > 0) {
        fbConn->sendBufferSent += status;
    } else if (status < 0) {
        int err = errno;
        if ((err == EAGAIN) || err == EWOULDBLOCK) {
        } else {
            NABTO_LOG_ERROR((PRI_tcp_fb "Send of tcp packet failed", TCP_FB_ARGS(con)));
            close_tcp_socket(con);
            return; 
        }
    }

    if (fbConn->sendBufferSent > fbConn->sendBufferLength) {
        NABTO_LOG_FATAL(("fbConn->sendBufferSent(%" PRIsize ") > fbConn->sendBufferLength(%" PRIsize "), that should not be possible", fbConn->sendBufferSent, fbConn->sendBufferLength));
    }
    
    if (fbConn->sendBufferSent == fbConn->sendBufferLength) {
        fbConn->sendBufferLength = 0;
    }
}
uint8_t* insert_connection_stats_payload(uint8_t* ptr, uint8_t* end, nabto_connect* con) {
    nabto_stamp_t now;
    uint32_t connectionAge;

    UNABTO_ASSERT(ptr <= end);
    if (end-ptr < NP_PAYLOAD_CONNECTION_STATS_BYTELENGTH) {
        return NULL;
    }

    ptr = insert_payload(ptr, NP_PAYLOAD_TYPE_CONNECTION_STATS, 0, 21);
    
    WRITE_FORWARD_U8(ptr, NP_PAYLOAD_CONNECTION_STATS_VERSION);
    
    now = nabtoGetStamp();
    connectionAge = nabtoStampDiff2ms(nabtoStampDiff(&now, &con->stats.connectionStart));

    WRITE_FORWARD_U32(ptr, connectionAge);

    WRITE_FORWARD_U32(ptr, con->stats.packetsReceived);
    WRITE_FORWARD_U32(ptr, con->stats.packetsSent);
    WRITE_FORWARD_U32(ptr, con->stats.bytesReceived);
    WRITE_FORWARD_U32(ptr, con->stats.bytesSent);

    return ptr;
}
Esempio n. 4
0
/* 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();
}
Esempio n. 5
0
/* Ask for an event handle corresponding to the given client request (in
 * ASYNC mode). The event handle must be released again using the
 * framework_release_handle function.
 * The return value is NAF_QUERY_NEW if this is the first time the client
 * request is seen (i.e. a new event handle is created). In this case
 * the buffer pointed to by handle will be assigned the new event handle.
 * Note that this handle will never be 0 (to distinguish the case when
 * calling this function in the SYNC model).
 * The return value is NAF_QUERY_QUEUED if the client request is already
 * known (and is pending to be processed). In this case the buffer pointed
 * to by handle is left unctouched.
 * The return value is NAF_QUERY_OUT_OF_RESOURCES if no more memory is
 * available for a new client request. The buffer pointed to by handle is
 * left unchanged. */
naf_query framework_event_query(const char* clientId, uint16_t reqId, naf_handle* handle)
{
    client_req_query query;
    queue_entry* entry;

    NABTO_LOG_TRACE(("APPREQ framework_event_query: client=" PRI_client_id2, CLIENT_ID_ARGS2(clientId, reqId)));

    /* First look for the request in the queue of pending requests. */
    query.clientId = clientId;
    query.reqId = reqId;
    query.found = NULL;
    queue_enum(is_client_request_cb, &query);
    if (query.found) {
        //The client request was found in the queue
        LOG_APPREQ_STATE("framework_event_query", "QUEUED", query.found);
        LOG_APPREQ_QUEUE();
        return NAF_QUERY_QUEUED;
    }

    /* Now the request was not found.
     * Reserve the next free entry in the queue. */
    entry = queue_alloc();
    if (!entry) {
        //The queue is full
        LOG_APPREQ_ERROR("framework_event_query", "OUT_OF_RESOURCES");
        LOG_APPREQ_QUEUE();
        return NAF_QUERY_OUT_OF_RESOURCES;
    }

    UNABTO_ASSERT(entry->state == APPREQ_FREE);
    if (entry->state != APPREQ_FREE) {
        //Hmmm - that's strange!. The new entry should have been free.
        if (clientId == entry->data.applicationRequest.clientId && reqId == entry->data.header.seq) {
            // - and it seems to be ourself!!
            LOG_APPREQ_STATE("framework_event_query", "QUEUED?", entry);
            LOG_APPREQ_QUEUE();
            return NAF_QUERY_QUEUED;
        }
        // The new entry belongs to someone else. The queue must be full !?
        LOG_APPREQ_ERROR("framework_event_query", "OUT_OF_RESOURCES?");
        LOG_APPREQ_QUEUE();
        return NAF_QUERY_OUT_OF_RESOURCES;
    }

    // Now we have a new request

    // Be sure we "own" the entry - advance to next free entry in the queue
    entry->state = APPREQ_WAITING;
    queue_push();

    // *handle cannot be initialized yet, as the received packet has not
    // yet been decrypted.
    // See framework_event() for initialization of handle.
    *handle = &entry->data;

    LOG_APPREQ_STATE("framework_event_query", "NEW", entry);
    LOG_APPREQ_QUEUE();
    return NAF_QUERY_NEW;
}
application_event_result application_poll(application_request* request, buffer_read_t* r_b, buffer_write_t* w_b)
{
    application_event_result res = AER_REQ_SYSTEM_ERROR;
    if (saved_app_req == 0) {
        NABTO_LOG_FATAL(("No queued request"));
    } else if (request != saved_app_req) {
        NABTO_LOG_FATAL(("queued request and parameters doesn't match"));
    } else {
        UNABTO_ASSERT(r_b == 0);
        r_b = &saved_params.r_b;
        UNABTO_ASSERT(r_b != 0);
        res = weather_station_application(saved_app_req, r_b, w_b);
        PGR_LOG_APPREQ_RES(application_poll, (int)res);
        // hand the saved application request to the caller with the resulting response
        saved_app_req = 0;
    }
    return res;
}
Esempio n. 7
0
void unabto_tunnel_stream_accept(unabto_stream* stream) {
    tunnel* t = &tunnels[unabto_stream_index(stream)];
    NABTO_LOG_TRACE(("Accepting stream and assigning it to tunnel %i", t));
    UNABTO_ASSERT(t->state == TS_IDLE);
    unabto_tunnel_reset_tunnel_struct(t);

    t->stream = stream;
    t->state = TS_READ_COMMAND;
    t->tunnelId = tunnelCounter++;
}
Esempio n. 8
0
/** Search for the first running or first pending requrest in the requesst
 * queue. Returns the first running requrest if found. Otherwise the first
 * pending request is returned. If neither is found NULL is returned.
 */
queue_entry* find_any_request_in_queue(void)
{
#if NABTO_APPREQ_QUEUE_SIZE > 1
    queue_entry* first_pending;
    queue_entry* first_running;
    queue_entry* entry;

    //At least one record must be present in the queue (for loop to be
    //finite).
    //queue may be full. queue_first_used == queue_next_free means full.
    UNABTO_ASSERT(!queue_empty());

    first_running = NULL;
    first_pending = NULL;
    entry = queue_first_used;
    do {
        if (!first_pending && entry->state == APPREQ_WAITING) {
            first_pending = entry;
            if (first_running)
                break;
        }
        if (!first_running && entry->state == APPREQ_IN_APP) {
            first_running = entry;
            if (first_pending)
                break;
        }
        queue_inc(entry);
    } while (entry != queue_next_free);

    if (first_running)
        return first_running;
    if (first_pending)
        return first_pending;
    return NULL;
#else //NABTO_APPREQ_QUEUE_SIZE == 1
    UNABTO_ASSERT(!queue_empty());
    return queue_top();
#endif
}
uint8_t* insert_rendezvous_stats_payload(uint8_t* ptr, uint8_t* end, nabto_connect* con) {
    UNABTO_ASSERT(ptr <= end);
    if (end-ptr < NP_PAYLOAD_RENDEZVOUS_STATS_BYTELENGTH) {
        return NULL;
    }
    ptr = insert_payload(ptr, NP_PAYLOAD_TYPE_RENDEZVOUS_STATS, 0, 7);
    
    WRITE_FORWARD_U8(ptr, NP_PAYLOAD_RENDEZVOUS_STATS_VERSION);
    WRITE_FORWARD_U8(ptr, con->clientNatType);
    WRITE_FORWARD_U8(ptr, nmc.context.natType);
    WRITE_FORWARD_U16(ptr, con->rendezvousConnectState.portsOpened);
    WRITE_FORWARD_U16(ptr, con->rendezvousConnectState.socketsOpened);

    return ptr;
}
uint8_t* insert_cp_id_payload(uint8_t* ptr, uint8_t* end, nabto_connect* con) {
    size_t cpIdLength = strlen(con->clientId);

    UNABTO_ASSERT(ptr <= end);
    if ((size_t)(end - ptr) < NP_PAYLOAD_CP_ID_BYTELENGTH + cpIdLength) {
        return NULL;
    }

    ptr = insert_payload(ptr, NP_PAYLOAD_TYPE_CP_ID, 0, 1+cpIdLength);

    WRITE_FORWARD_U8(ptr, NP_PAYLOAD_CP_ID_TYPE_MAIL);
    memcpy(ptr, (const void*) con->clientId, cpIdLength);
    
    ptr += cpIdLength;

    return ptr;
}
Esempio n. 11
0
bool unabto_tcp_fallback_handle_write(nabto_connect* con) {
    ssize_t status;
    int dataToSend;
    bool canMaybeSendMoreData = false;
    unabto_tcp_fallback_connection* fbConn = &fbConns[nabto_connection_index(con)];
    UNABTO_ASSERT(fbConn->sendBufferSent <= fbConn->sendBufferLength); 
    dataToSend = fbConn->sendBufferLength - fbConn->sendBufferSent;

    if (dataToSend == 0) {
        return false;
    }
    
    NABTO_LOG_TRACE(("data to send %i, sendBufferLength %i, sendBufferSent %i", dataToSend, fbConn->sendBufferLength, fbConn->sendBufferSent));
    
    status = send(fbConn->socket, fbConn->sendBuffer + fbConn->sendBufferSent, dataToSend, MSG_NOSIGNAL);
    NABTO_LOG_TRACE(("tcp send status: %i", status));
    if (status > 0) {
        fbConn->sendBufferSent += status;
        canMaybeSendMoreData = true;
    } else if (status < 0) {
        int err = errno;
        if ((err == EAGAIN) || err == EWOULDBLOCK) {
            canMaybeSendMoreData = false;
        } else {
            NABTO_LOG_ERROR((PRI_tcp_fb "Send of tcp packet failed", TCP_FB_ARGS(con)));
            close_tcp_socket(con);
            canMaybeSendMoreData = false;
            return canMaybeSendMoreData; 
        }
    }

    if (fbConn->sendBufferSent > fbConn->sendBufferLength) {
        NABTO_LOG_FATAL(("fbConn->sendBufferSent(%" PRIsize ") > fbConn->sendBufferLength(%" PRIsize "), that should not be possible", fbConn->sendBufferSent, fbConn->sendBufferLength));
    }
    
    if (fbConn->sendBufferSent == fbConn->sendBufferLength) {
        fbConn->sendBufferLength = 0;
        fbConn->sendBufferSent = 0;
        canMaybeSendMoreData = false;
    }

    NABTO_LOG_TRACE(("state after send, sendBufferLength %i, sendBufferSent %i", fbConn->sendBufferLength, fbConn->sendBufferSent));
    
    return canMaybeSendMoreData;
}
Esempio n. 12
0
/* Handle application event in SYNC model.
 * Call application_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)
{
    application_request      req;
    unabto_buffer            w_buf;
    unabto_query_response    w_b;
    unabto_buffer            r_buf;
    unabto_query_request     r_b;
    application_event_result ret;

    /* framework_event_query always returns a zero handle in SYNC mode */
    UNABTO_ASSERT(handle == 0);

    // When trying to respond immediately, the position to write the response is exactly
    // the same as the position of the request (we use the same buffer, i.e. iobuf).
    unabto_buffer_init(&w_buf, iobuf, size);
    unabto_query_response_init(&w_b, &w_buf);

    unabto_buffer_init(&r_buf, iobuf, ilen);
    unabto_query_request_init(&r_b, &r_buf);

    ret = framework_first_event(&req, &r_b, &w_b, con, hdr);

    if (ret != AER_REQ_RESPONSE_READY) {
        // pass the result to caller as an exception packet
        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)));
    }
    *olen = unabto_query_response_used(&w_b);

    NABTO_LOG_TRACE(("APPREQ framework_event: returns %" PRItext, result_s(ret)));
    return ret;
}
uint8_t* insert_connect_stats_payload(uint8_t* ptr, uint8_t* end, nabto_connect* con) {
    uint8_t connectionType;

    UNABTO_ASSERT(ptr <= end);
    if (end-ptr < NP_PAYLOAD_CONNECT_STATS_BYTELENGTH) {
        return NULL;
    }

    ptr = insert_payload(ptr, NP_PAYLOAD_TYPE_CONNECT_STATS, 0, 2);

    switch (get_connection_type(con)) {
    case NCT_LOCAL:              connectionType = NP_PAYLOAD_CONNECT_STATS_CONNECTION_TYPE_LOCAL; break;
    case NCT_CONNECTING:         connectionType = NP_PAYLOAD_CONNECT_STATS_CONNECTION_TYPE_CONNECTING; break;
    case NCT_REMOTE_RELAY:       connectionType = NP_PAYLOAD_CONNECT_STATS_CONNECTION_TYPE_UDP_RELAY; break;
    case NCT_REMOTE_RELAY_MICRO: connectionType = NP_PAYLOAD_CONNECT_STATS_CONNECTION_TYPE_TCP_RELAY; break;
    case NCT_REMOTE_P2P:         connectionType = NP_PAYLOAD_CONNECT_STATS_CONNECTION_TYPE_P2P; break;
    }

    WRITE_FORWARD_U8(ptr, NP_PAYLOAD_CONNECT_STATS_VERSION);
    WRITE_FORWARD_U8(ptr, connectionType);

    return ptr;
}
Esempio n. 14
0
void unabto_hmac_sha256_buffers(const buffer_t keys[], uint8_t keys_size,
                                const buffer_t messages[], uint8_t messages_size,
                                uint8_t *mac, uint16_t mac_size)
{
    uint16_t fill = 0;
    uint16_t num;
    const uint8_t *key_used;
    uint8_t i;
    uint8_t key_temp[SHA256_BLOCK_LENGTH];
    uint8_t digest_temp[SHA256_DIGEST_LENGTH];

    uint16_t key_size = 0;
    for (i = 0; i < keys_size; i++) {
        key_size += keys[i].size;
    }


    if (key_size <= SHA256_BLOCK_LENGTH) {
        uint8_t* ptr = key_temp;
        for (i = 0; i < keys_size; i++) {
            memcpy(ptr, (const void*)keys[i].data, keys[i].size);
            ptr += keys[i].size;
        }
        key_used = (const uint8_t*) key_temp;
        num = key_size;
    } else { // key_size > SHA256_BLOCK_LENGTH
        num = SHA256_DIGEST_LENGTH;
        //NABTO_LOG_TRACE(("key size %i", key_size));
        //NABTO_LOG_BUFFER(key, key_size);
        unabto_sha256_init(&sha_ctx);
        for (i = 0; i < keys_size; i++) {
            unabto_sha256_update(&sha_ctx, keys[i].data, keys[i].size);
        }
        unabto_sha256_final(&sha_ctx,key_temp);
        
        //sha256(key, key_size, key_temp);
        //NABTO_LOG_BUFFER(key_temp, SHA256_DIGEST_LENGTH);
        key_used = (const unsigned char*)key_temp;
    }
    fill = SHA256_BLOCK_LENGTH - num;

    memset(block_pad + num, 0x36, fill);
    for (i = 0; i < num; i++) {
        block_pad[i] = key_used[i] ^ 0x36;
    }
//    print_sha256_ctx(sha_ctx);
    unabto_sha256_init(&sha_ctx);
//    print_sha256_ctx(sha_ctx);
    unabto_sha256_update(&sha_ctx, block_pad, SHA256_BLOCK_LENGTH);
//    print_sha256_ctx(sha_ctx);
    for (i = 0; i < messages_size; i++) {
        unabto_sha256_update(&sha_ctx, messages[i].data, messages[i].size);
    }
//    print_sha256_ctx(sha_ctx);
    unabto_sha256_final(&sha_ctx, digest_temp);
//    print_sha256_ctx(sha_ctx);
    memset(block_pad + num, 0x5c, fill);
    for (i = 0; i < num; i++) {
        block_pad[i] = key_used[i] ^ 0x5c;
    }
   
    unabto_sha256_init(&sha_ctx);
//    print_sha256_ctx(sha_ctx);
    unabto_sha256_update(&sha_ctx, block_pad, SHA256_BLOCK_LENGTH);
//    print_sha256_ctx(sha_ctx);
    unabto_sha256_update(&sha_ctx, digest_temp, SHA256_DIGEST_LENGTH);
//    print_sha256_ctx(sha_ctx);
    unabto_sha256_final(&sha_ctx, digest_temp);
    
    UNABTO_ASSERT(mac_size <= 32 );
    memcpy(mac, (void*)digest_temp, mac_size);
}
Esempio n. 15
0
/* 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;
}
Esempio n. 16
0
/* 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;
}