Example #1
0
static int process_nodes_token(jsmn_parser *parser, int src_size, struct kowhai_tree_t *dst_tree, union kowhai_symbol_t *path, int path_len, int *node_count, void *get_name_param, kowhai_get_symbol_t get_name, void *not_found_param, kowhai_node_not_found_t not_found)
{
    int res;
    int t = 0;
    jsmntok_t *path_tok = NULL;
    uint16_t type = KOW_BRANCH_START;
    uint16_t count = 0;
    uint16_t tag = 0;

    while (t < parser->num_tokens)
    {
        // get next token, and check if we are done
        jsmntok_t *tok = &parser->tokens[t++];
        if (tok->end > src_size || tok->end < 0 || tok->start > src_size || tok->start < 0)
            break;
        
        // clear all stored info for the previous kowhai node object
        if (tok->type == JSMN_OBJECT)
        {
            path_tok = NULL;
            type = KOW_BRANCH_START; // invalid value
            count = 0;
            tag = 0;
        }

        // if this is a path token then store a pointer to the path
        if (token_string_match(parser, tok, PATH))
        {
            path_tok = tok + 1;
            t++;
            continue;
        }
        
        // if this is a type token the store the type
        if (token_string_match(parser, tok, TYPE))
        {
            res = get_token_uint16(parser, tok + 1, &type);
            if (res != KOW_STATUS_OK)
                return -1;
            t++;
            continue;
        }

        // if this is a count token then store the count
        if (token_string_match(parser, tok, COUNT))
        {
            res = get_token_uint16(parser, tok + 1, &count);
            if (res != KOW_STATUS_OK)
                return -1;
            t++;
            continue;
        }
        
        // if this is a tag token then store the tag
        if (token_string_match(parser, tok, TAG))
        {
            res = get_token_uint16(parser, tok + 1, &tag);
            if (res != KOW_STATUS_OK)
                return -1;
            t++;
            continue;
        }
        
        // if this is a value token then parse the values and write node to dst_tree
        if (token_string_match(parser, tok, VALUE))
        {
            int i;
            int N;
            int path_syms = 0;
            int size = kowhai_get_node_type_size(type);

            ///@todo check node types match

            // parse path string to kowhai_path
            path_syms = str_to_path(parser, path_tok, path, path_len, get_name_param, get_name);
            if (path_syms < 0)
                return path_syms;

            // skip the [ or " wrappers for array like objects
            if (count > 1)
            {
                t++;
                tok++;
                N = MIN(tok->size, count);
            }
            else
                N = 1;

            // special string case
            if (type == KOW_CHAR)
            {
                char null_buf[1] = {0,};
                int len = MIN(tok->end - tok->start + 1, count) * size;
                res = kowhai_write(dst_tree, path_syms, path, 0, (void *)(parser->js + tok->start), len);
                if (res == KOW_STATUS_INVALID_SYMBOL_PATH)
                {
                    if ((not_found != NULL) && (not_found(not_found_param, path, path_syms) == 0))
                        res = KOW_STATUS_OK;
                }
                if (res != KOW_STATUS_OK)
                    return -2;
                // null terminate all strings !
                res = kowhai_write(dst_tree, path_syms, path, len - size, (void *)null_buf, sizeof(null_buf));
                if (res == KOW_STATUS_INVALID_SYMBOL_PATH)
                {
                    if ((not_found != NULL) && (not_found(not_found_param, path, path_syms) == 0))
                        res = KOW_STATUS_OK;
                }
                if (res != KOW_STATUS_OK)
                    return -2;
                t++;
                continue;
            }

            // process other items 1 value at a time
            for (i = 0; i < N; i++)
            {
                union any_type_t val;

                t++;
                tok++;

                switch (type)
                {
                    case KOW_UINT8:
                    case KOW_INT8:
                    case KOW_CHAR:
                        res = get_token_uint8(parser, tok, &val.ui8);
                        break;
                    case KOW_UINT16:
                    case KOW_INT16:
                        res = get_token_uint16(parser, tok, &val.ui16);
                        break;
                    case KOW_UINT32:
                    case KOW_INT32:
                        res = get_token_uint32(parser, tok, &val.ui32);
                        break;
                    case KOW_FLOAT:
                        res = get_token_float(parser, tok, &val.f);
                        break;
                    case KOW_UINT64:
                    case KOW_INT64:
                        res = get_token_uint64(parser, tok, &val.ui64);
                        break;
                    case KOW_DOUBLE:
                        res = get_token_double(parser, tok, &val.d);
                        break;
                }
                if (res != KOW_STATUS_OK)
                    return -1;

                res = kowhai_write(dst_tree, path_syms, path, 0, &val, size);
                if (res == KOW_STATUS_INVALID_SYMBOL_PATH)
                {
                    if ((not_found != NULL) && (not_found(not_found_param, path, path_syms) == 0))
                        res = KOW_STATUS_OK;
                }
                if (res != KOW_STATUS_OK)
                    return -2;
                path[path_syms - 1].parts.array_index++;
            }
        }

    }

    return 0;
}
int kowhai_server_process_packet(struct kowhai_protocol_server_t* server, void* packet, size_t packet_size)
{
    struct kowhai_protocol_t prot;
    int bytes_required, status;

    if (packet_size > server->max_packet_size)
    {
        printf("    error: packet size too large\n");
        return KOW_STATUS_PACKET_BUFFER_TOO_BIG;
    }

    status = kowhai_protocol_parse(packet, packet_size, &prot);
    if (status != KOW_STATUS_OK && status != KOW_STATUS_INVALID_PROTOCOL_COMMAND)
        return status;

    if (prot.header.tree_id >= 0 && prot.header.tree_id < server->tree_count)
    {
        struct kowhai_tree_t tree;
        tree.desc = *(server->tree_descriptors + prot.header.tree_id);
        tree.data = *(server->tree_data_buffers + prot.header.tree_id);
        switch (prot.header.command)
        {
            case KOW_CMD_WRITE_DATA:
                printf("    CMD write data\n");
                status = kowhai_write(&tree, prot.payload.spec.data.symbols.count, prot.payload.spec.data.symbols.array_, prot.payload.spec.data.memory.offset, prot.payload.buffer, prot.payload.spec.data.memory.size);
                if (status == KOW_STATUS_OK)
                {
                    // call node_written callback
                    struct kowhai_node_t* node;
                    uint16_t offset;
                    kowhai_get_node(tree.desc, prot.payload.spec.data.symbols.count, prot.payload.spec.data.symbols.array_, &offset, &node);
                    server->node_written(server->node_written_param, node);
                    // send response
                    prot.header.command = KOW_CMD_WRITE_DATA_ACK;
                    kowhai_read(&tree, prot.payload.spec.data.symbols.count, prot.payload.spec.data.symbols.array_, prot.payload.spec.data.memory.offset, prot.payload.buffer, prot.payload.spec.data.memory.size);
                    kowhai_protocol_create(server->packet_buffer, server->max_packet_size, &prot, &bytes_required);
                    server->send_packet(server->send_packet_param, server->packet_buffer, bytes_required);
                }
                else
                {
                    switch (status)
                    {
                        case KOW_STATUS_INVALID_SYMBOL_PATH:
                            printf("    invalid symbol path\n");
                            POPULATE_PROTOCOL_CMD(prot, prot.header.tree_id, KOW_CMD_ERROR_INVALID_SYMBOL_PATH);
                            break;
                        case KOW_STATUS_INVALID_OFFSET:
                            printf("    invalid payload offset\n");
                            POPULATE_PROTOCOL_CMD(prot, prot.header.tree_id, KOW_CMD_ERROR_INVALID_PAYLOAD_OFFSET);
                            break;
                        case KOW_STATUS_NODE_DATA_TOO_SMALL:
                            printf("    invalid payload size\n");
                            POPULATE_PROTOCOL_CMD(prot, prot.header.tree_id, KOW_CMD_ERROR_INVALID_PAYLOAD_SIZE);
                            break;
                        default:
                            printf("    unkown error\n");
                            POPULATE_PROTOCOL_CMD(prot, prot.header.tree_id, KOW_CMD_ERROR_UNKNOWN);
                            break;
                    }
                    kowhai_protocol_create(server->packet_buffer, server->max_packet_size, &prot, &bytes_required);
                    server->send_packet(server->send_packet_param, server->packet_buffer, bytes_required);
                }
                break;
            case KOW_CMD_READ_DATA:
            {
                uint16_t node_offset;
                int size, overhead, max_payload_size;
                struct kowhai_node_t* node;
                struct kowhai_protocol_symbol_spec_t symbols = prot.payload.spec.data.symbols;
                printf("    CMD read data\n");
                // get node information

                status = kowhai_get_node(tree.desc, prot.payload.spec.data.symbols.count, prot.payload.spec.data.symbols.array_, &node_offset, &node);
                if (status == KOW_STATUS_OK)
                {
                    union kowhai_symbol_t last_sym = symbols.array_[symbols.count-1];
                    kowhai_get_node_size(node, &size);
                    if (node->count > 1)
                        size = size - size / node->count * last_sym.parts.array_index;
                    // get protocol overhead
                    prot.header.command = KOW_CMD_READ_DATA_ACK;
                    kowhai_protocol_get_overhead(&prot, &overhead);
                    // setup max payload size and payload offset
                    max_payload_size = server->max_packet_size - overhead;
                    prot.payload.spec.data.memory.offset = 0;
                    prot.payload.spec.data.memory.type = node->type;
                    // allocate payload buffer
                    prot.payload.buffer = malloc(server->max_packet_size - overhead);

                    // send packets
                    while (size > max_payload_size)
                    {
                        prot.payload.spec.data.memory.size = max_payload_size;
                        kowhai_read(&tree, prot.payload.spec.data.symbols.count, prot.payload.spec.data.symbols.array_, prot.payload.spec.data.memory.offset, prot.payload.buffer, prot.payload.spec.data.memory.size);
                        kowhai_protocol_create(server->packet_buffer, server->max_packet_size, &prot, &bytes_required);
                        server->send_packet(server->send_packet_param, server->packet_buffer, bytes_required);
                        // increment payload offset and decrement remaining payload size
                        prot.payload.spec.data.memory.offset += max_payload_size;
                        size -= max_payload_size;
                    }
                    // send final packet
                    prot.header.command = KOW_CMD_READ_DATA_ACK_END;
                    prot.payload.spec.data.memory.size = size;
                    kowhai_read(&tree, prot.payload.spec.data.symbols.count, prot.payload.spec.data.symbols.array_, prot.payload.spec.data.memory.offset, prot.payload.buffer, prot.payload.spec.data.memory.size);
                    kowhai_protocol_create(server->packet_buffer, server->max_packet_size, &prot, &bytes_required);
                    server->send_packet(server->send_packet_param, server->packet_buffer, bytes_required);
                    // free payload buffer
                    free(prot.payload.buffer);
                }
                else
                {
                    switch (status)
                    {
                        case KOW_STATUS_INVALID_SYMBOL_PATH:
                            printf("    invalid symbol path\n");
                            POPULATE_PROTOCOL_CMD(prot, prot.header.tree_id, KOW_CMD_ERROR_INVALID_SYMBOL_PATH);
                            break;
                        case KOW_STATUS_INVALID_OFFSET:
                            printf("    invalid payload offset\n");
                            POPULATE_PROTOCOL_CMD(prot, prot.header.tree_id, KOW_CMD_ERROR_INVALID_PAYLOAD_OFFSET);
                            break;
                        case KOW_STATUS_NODE_DATA_TOO_SMALL:
                            printf("    invalid payload size\n");
                            POPULATE_PROTOCOL_CMD(prot, prot.header.tree_id, KOW_CMD_ERROR_INVALID_PAYLOAD_SIZE);
                            break;
                        default:
                            printf("    unkown error\n");
                            POPULATE_PROTOCOL_CMD(prot, prot.header.tree_id, KOW_CMD_ERROR_UNKNOWN);
                            break;
                    }
                    kowhai_protocol_create(server->packet_buffer, server->max_packet_size, &prot, &bytes_required);
                    server->send_packet(server->send_packet_param, server->packet_buffer, bytes_required);
                }
                break;
            }
            case KOW_CMD_READ_DESCRIPTOR:
            {
                int size, overhead, max_payload_size;
                printf("    CMD read descriptor\n");
                // get descriptor size
                size = *(server->tree_descriptor_sizes + prot.header.tree_id);
                // get protocol overhead
                prot.header.command = KOW_CMD_READ_DESCRIPTOR_ACK;
                kowhai_protocol_get_overhead(&prot, &overhead);
                // setup max payload size and payload offset
                max_payload_size = server->max_packet_size - overhead;
                prot.payload.spec.descriptor.offset = 0;
                prot.payload.spec.descriptor.node_count = size / sizeof(struct kowhai_node_t);
                // allocate payload buffer
                prot.payload.buffer = malloc(server->max_packet_size - overhead);

                // send packets
                while (size > max_payload_size)
                {
                    prot.payload.spec.descriptor.size = max_payload_size;
                    memcpy(prot.payload.buffer, (char*)tree.desc + prot.payload.spec.descriptor.offset, prot.payload.spec.descriptor.size);
                    kowhai_protocol_create(server->packet_buffer, server->max_packet_size, &prot, &bytes_required);
                    server->send_packet(server->send_packet_param, server->packet_buffer, bytes_required);
                    // increment payload offset and decrement remaining payload size
                    prot.payload.spec.descriptor.offset += max_payload_size;
                    size -= max_payload_size;
                }
                // send final packet
                prot.header.command = KOW_CMD_READ_DESCRIPTOR_ACK_END;
                prot.payload.spec.descriptor.size = size;
                memcpy(prot.payload.buffer, (char*)tree.desc + prot.payload.spec.descriptor.offset, prot.payload.spec.descriptor.size);
                kowhai_protocol_create(server->packet_buffer, server->max_packet_size, &prot, &bytes_required);
                server->send_packet(server->send_packet_param, server->packet_buffer, bytes_required);
                // free payload buffer
                free(prot.payload.buffer);
                break;
            }
            default:
                printf("    invalid command (%d)\n", prot.header.command);
                POPULATE_PROTOCOL_CMD(prot, prot.header.tree_id, KOW_CMD_ERROR_INVALID_COMMAND);
                kowhai_protocol_create(server->packet_buffer, server->max_packet_size, &prot, &bytes_required);
                server->send_packet(server->send_packet_param, server->packet_buffer, bytes_required);
                break;
        }
    }
    else
    {
        printf("    invalid tree id (%d)\n", prot.header.tree_id);
        POPULATE_PROTOCOL_CMD(prot, prot.header.tree_id, KOW_CMD_ERROR_INVALID_TREE_ID);
        kowhai_protocol_create(server->packet_buffer, server->max_packet_size, &prot, &bytes_required);
        server->send_packet(server->send_packet_param, server->packet_buffer, bytes_required);
    }

    return KOW_STATUS_OK;
}