#include #include #include #include "google/protobuf/message.h" #include "proto_man.h" #define MAX_PF_MAP_SIZE 1024 #define CMD_HEADER 8 static int g_proto_type = PROTO_BUF; static char* g_pf_map[MAX_PF_MAP_SIZE]; static int g_cmd_count = 0; void proto_man::init(int proto_type) { g_proto_type = proto_type; } int proto_man::proto_type() { return g_proto_type; } void proto_man::register_pf_cmd_map(char** pf_map, int len) { len = (MAX_PF_MAP_SIZE - g_cmd_count) < len ? ((MAX_PF_MAP_SIZE - g_cmd_count)) : len; for (int i = 0; i < len; i++) { g_pf_map[g_cmd_count + i] = strdup(pf_map[i]); } g_cmd_count += len; } static google::protobuf::Message* create_message(const char* type_name) { google::protobuf::Message* message = NULL; const google::protobuf::Descriptor* descriptor = google::protobuf::DescriptorPool::generated_pool()->FindMessageTypeByName(type_name); if (descriptor) { const google::protobuf::Message* prototype = google::protobuf::MessageFactory::generated_factory()->GetPrototype(descriptor); if (prototype) { message = prototype->New(); } } return message; } static void release_message(google::protobuf::Message* m) { delete m; } // stype(2 byte) | ctype(2byte) | utag(4byte) | body bool proto_man::decode_cmd_msg(unsigned char* cmd, int cmd_len, struct cmd_msg** out_msg) { *out_msg = NULL; if (cmd_len < CMD_HEADER) { return false; } struct cmd_msg* msg = (struct cmd_msg*)malloc(sizeof(struct cmd_msg)); msg->stype = cmd[0] | (cmd[1] << 8); msg->ctype = cmd[2] | (cmd[3] << 8); msg->utag = cmd[4] | (cmd[5] << 8) | (cmd[6] << 16) | (cmd[7] << 24); msg->body = NULL; *out_msg = msg; if (cmd_len == CMD_HEADER) { return true; } if (g_proto_type == PROTO_JSON) { int json_len = cmd_len - CMD_HEADER; char* json_str = (char*)malloc(json_len + 1); memcpy(json_str, cmd + CMD_HEADER, json_len); json_str[json_len] = 0; msg->body = (void*)json_str; } else { // protobuf if (msg->ctype < 0 || msg->ctype >= g_cmd_count || g_pf_map[msg->ctype] == NULL) { free(msg); *out_msg = NULL; return false; } google::protobuf::Message* p_m = create_message(g_pf_map[msg->ctype]); if (p_m == NULL) { free(msg); *out_msg = NULL; return false; } if (!p_m->ParseFromArray(cmd + CMD_HEADER, cmd_len - CMD_HEADER)) { free(msg); *out_msg = NULL; release_message(p_m); return false; } msg->body = p_m; } return true; } void proto_man::cmd_msg_free(struct cmd_msg* msg) { if (msg->body) { if (g_proto_type == PROTO_JSON) { free(msg->body); msg->body = NULL; } else { google::protobuf::Message* p_m = (google::protobuf::Message*) msg->body; delete p_m; msg->body = NULL; } } free(msg); } unsigned char* proto_man::encode_msg_to_raw(const struct cmd_msg* msg, int* out_len) { int raw_len = 0; unsigned char* raw_data = NULL; *out_len = 0; if (g_proto_type == PROTO_JSON) { char* json_str = (char*)msg->body; int len = strlen(json_str) + 1; raw_data = (unsigned char*)malloc(CMD_HEADER + len); memcpy(raw_data + CMD_HEADER, json_str, len - 1); raw_data[8 + len] = 0; *out_len = (len + CMD_HEADER); } else { // protobuf google::protobuf::Message* p_m = (google::protobuf::Message*)msg->body; int pf_len = p_m->ByteSize(); raw_data = (unsigned char*)malloc(CMD_HEADER + pf_len); if (!p_m->SerializePartialToArray(raw_data + CMD_HEADER, pf_len)) { free(raw_data); return NULL; } *out_len = (pf_len + CMD_HEADER); } // header raw_data[0] = (msg->stype & 0x000000ff); raw_data[1] = ((msg->stype & 0x0000ff00) >> 8); raw_data[2] = (msg->ctype & 0x000000ff); raw_data[3] = ((msg->ctype & 0x0000ff00) >> 8); memcpy(raw_data + 4, &msg->utag, 4); // return raw_data; } void proto_man::msg_raw_free(unsigned char* raw) { free(raw); }