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; }