#include #include #include #include #include "log.h" #include "mpack.h" #include "utils.h" #include "ctrl_packet.h" const char *session_state_to_string(enum session_state state) { switch (state) { case SESSION_STATE_OPENING: return "opening"; case SESSION_STATE_CLOSING: return "closing"; case SESSION_STATE_ACTIVE: return "active"; case SESSION_STATE_RESETALL: return "resetall"; default: return "unknown"; } } void ctrl_packet_parser_init(struct ctrl_pkt_parser *handler) { memset(handler, 0, sizeof(struct ctrl_pkt_parser)); } // return 0 : success // return -1 : error int ctrl_packet_parser_mpack(struct ctrl_pkt_parser *handler, const char *data, size_t length) { mpack_tree_t tree; mpack_node_t root; mpack_node_t temp; mpack_node_t item; mpack_error_t ret; char buffer[16]; mpack_tree_init_data(&tree, data, length); mpack_tree_parse(&tree); root = mpack_tree_root(&tree); if (mpack_node_is_nil(root)) { LOG_ERROR("%s: unexpected control packet: (invalid mpack format)", LOG_TAG_CTRLPKT); goto error_out; } // tsync temp = mpack_node_map_cstr(root, "tsync"); if (mpack_node_is_nil(temp)) { LOG_ERROR("%s: unexpected control packet: (tsync no found)", LOG_TAG_CTRLPKT); goto error_out; } mpack_node_copy_cstr(temp, handler->tsync, sizeof(handler->tsync)); if (strcasecmp(handler->tsync, "2.0") != 0) { LOG_ERROR("%s: unexpected control packet: (invalid tsync value) %s", LOG_TAG_CTRLPKT, handler->tsync); goto error_out; } // session_id temp = mpack_node_map_cstr(root, "session_id"); if (mpack_node_is_nil(temp)) { LOG_ERROR("%s: unexpected control packet: (session_id no found)", LOG_TAG_CTRLPKT); goto error_out; } handler->session_id = mpack_node_u64(temp); if (handler->session_id == 0) { LOG_ERROR("%s: unexpected control packet: (invalid session_id value) %lu", LOG_TAG_CTRLPKT, handler->session_id); goto error_out; } // state temp = mpack_node_map_cstr(root, "state"); if (mpack_node_is_nil(temp)) { LOG_ERROR("%s: unexpected control packet: (state no found)", LOG_TAG_CTRLPKT); goto error_out; } mpack_node_copy_cstr(temp, buffer, sizeof(buffer)); if (strcasecmp(buffer, "opening") == 0) { handler->state = SESSION_STATE_OPENING; } else if (strcasecmp(buffer, "active") == 0) { handler->state = SESSION_STATE_ACTIVE; } else if (strcasecmp(buffer, "closing") == 0) { handler->state = SESSION_STATE_CLOSING; } else if (strcasecmp(buffer, "resetall") == 0) { handler->state = SESSION_STATE_RESETALL; } else { LOG_ERROR("%s: unexpected control packet: (invalid state value) %s", LOG_TAG_CTRLPKT, buffer); goto error_out; } if (handler->state != SESSION_STATE_ACTIVE) { goto success_out; } // method temp = mpack_node_map_cstr(root, "method"); if (mpack_node_is_nil(temp)) { LOG_ERROR("%s: unexpected control packet: (method no found)", LOG_TAG_CTRLPKT); goto error_out; } mpack_node_copy_cstr(temp, handler->method, sizeof(handler->method)); if (strcasecmp(handler->method, "policy_update") != 0) { LOG_ERROR("%s: unexpected control packet: (invalid method value) %s", LOG_TAG_CTRLPKT, handler->method); goto error_out; } // params temp = mpack_node_map_cstr(root, "params"); if (mpack_node_is_nil(temp)) { LOG_ERROR("%s: unexpected control packet: (params no found)", LOG_TAG_CTRLPKT); goto error_out; } // params->sce temp = mpack_node_map_cstr(temp, "sce"); if (mpack_node_is_nil(temp)) { LOG_ERROR("%s: unexpected control packet: (sce no found)", LOG_TAG_CTRLPKT); goto error_out; } // params->sce->rule_ids temp = mpack_node_map_cstr(temp, "rule_ids"); if (mpack_node_is_nil(temp)) { LOG_ERROR("%s: unexpected control packet: (rule_ids no found)", LOG_TAG_CTRLPKT); goto error_out; } handler->rule_id_num = MIN(mpack_node_array_length(temp), (int)(sizeof(handler->rule_ids) / sizeof(handler->rule_ids[0]))); if (handler->rule_id_num <= 0) { LOG_ERROR("%s: unexpected control packet: (invalid rule id num) %ld", LOG_TAG_CTRLPKT, mpack_node_array_length(temp)); goto error_out; } for (int i = 0; i < handler->rule_id_num; i++) { item = mpack_node_array_at(temp, i); handler->rule_ids[i] = mpack_node_u64(item); } success_out: ret = mpack_tree_destroy(&tree); if (ret != mpack_ok) { LOG_ERROR("%s: unexpected control packet: (mpack return error) %d", LOG_TAG_CTRLPKT, ret); return -1; } return 0; error_out: mpack_tree_destroy(&tree); return -1; } // return 0 : success // return -1 : error int ctrl_packet_parser_cjson(struct ctrl_pkt_parser *handler, const char *data, size_t length) { int iter = 0; cJSON *item = NULL; cJSON *elem = NULL; cJSON *json = NULL; json = cJSON_Parse(data); if (json == NULL) { LOG_ERROR("%s: unexpected control packet: (invalid json format) %s", LOG_TAG_CTRLPKT, data); return -1; } // tsync item = cJSON_GetObjectItem(json, "tsync"); if (!item || !cJSON_IsString(item)) { LOG_ERROR("%s: unexpected control packet: (invalid tsync format) %s", LOG_TAG_CTRLPKT, data); goto error_out; } memcpy(handler->tsync, item->valuestring, MIN(sizeof(handler->tsync), strlen(item->valuestring))); // session_id item = cJSON_GetObjectItem(json, "session_id"); if (!item || !cJSON_IsString(item)) { LOG_ERROR("%s: unexpected control packet: (invalid session_id format) %s", LOG_TAG_CTRLPKT, data); goto error_out; } handler->session_id = atoll(item->valuestring); // state item = cJSON_GetObjectItem(json, "state"); if (!item || !cJSON_IsString(item)) { LOG_ERROR("%s: unexpected control packet: (invalid state format) %s", LOG_TAG_CTRLPKT, data); goto error_out; } if (strcasecmp(item->valuestring, "opening") == 0) { handler->state = SESSION_STATE_OPENING; } else if (strcasecmp(item->valuestring, "active") == 0) { handler->state = SESSION_STATE_ACTIVE; } else if (strcasecmp(item->valuestring, "closing") == 0) { handler->state = SESSION_STATE_CLOSING; } else if (strcasecmp(item->valuestring, "resetall") == 0) { handler->state = SESSION_STATE_RESETALL; } else { LOG_ERROR("%s: unexpected control packet: (invalid state value) %s", LOG_TAG_CTRLPKT, data); goto error_out; } if (handler->state != SESSION_STATE_ACTIVE) { goto success_out; } // method item = cJSON_GetObjectItem(json, "method"); if (!item || !cJSON_IsString(item)) { LOG_ERROR("%s: unexpected control packet: (invalid method format) %s", LOG_TAG_CTRLPKT, data); goto error_out; } memcpy(handler->method, item->valuestring, MIN(sizeof(handler->method), strlen(item->valuestring))); if (strcasecmp(item->valuestring, "policy_update") != 0) { LOG_ERROR("%s: unexpected control packet: (invalid method value) %s", LOG_TAG_CTRLPKT, data); goto error_out; } // params item = cJSON_GetObjectItem(json, "params"); if (!item || !cJSON_IsObject(item)) { LOG_ERROR("%s: unexpected control packet: (invalid params format) %s", LOG_TAG_CTRLPKT, data); goto error_out; } item = cJSON_GetObjectItem(item, "service_chaining"); if (!item || !cJSON_IsArray(item) || !cJSON_GetArraySize(item)) { LOG_ERROR("%s: unexpected control packet: (invalid service_chaining format) %s", LOG_TAG_CTRLPKT, data); goto error_out; } handler->rule_id_num = MIN(cJSON_GetArraySize(item), (int)(sizeof(handler->rule_ids) / sizeof(handler->rule_ids[0]))); cJSON_ArrayForEach(elem, item) { if (!cJSON_IsNumber(elem)) { LOG_ERROR("%s: unexpected control packet: (invalid service_chaining value) %s", LOG_TAG_POLICY, data); continue; } handler->rule_ids[iter] = elem->valueint; iter++; if (iter == handler->rule_id_num) { break; } } success_out: cJSON_Delete(json); return 0; error_out: cJSON_Delete(json); return -1; } // return 0 : success // return -1 : error int ctrl_packet_parser_parse(struct ctrl_pkt_parser *handler, const char *data, size_t length) { // return ctrl_packet_parser_cjson(handler, data, length); return ctrl_packet_parser_mpack(handler, data, length); } void ctrl_packet_parser_dump(struct ctrl_pkt_parser *handler) { if (handler) { LOG_INFO("%s: tsync : %s", LOG_TAG_POLICY, handler->tsync); LOG_INFO("%s: session_id : %lu", LOG_TAG_POLICY, handler->session_id); LOG_INFO("%s: state : %s", LOG_TAG_POLICY, session_state_to_string(handler->state)); LOG_INFO("%s: method : %s", LOG_TAG_POLICY, handler->method); LOG_INFO("%s: rule_id_num : %d", LOG_TAG_POLICY, handler->rule_id_num); for (int i = 0; i < handler->rule_id_num; i++) { LOG_INFO("%s: rule_ids[%03d] : %lu", LOG_TAG_POLICY, i, handler->rule_ids[i]); } } }