// Copyright © 2013 sss // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include #include #include #include #include #include #include "api_protocol.h" #include "packet.h" #include "utilities.h" namespace proto { packet::packet(std::vector& new_data) { data = new_data; } bool packet::assign(packet& p) { data = p.data; return is_good(); } bool packet::assign(std::vector& v) { data = v; return is_good(); } const std::vector &packet::raw() { return data; } bool packet::is_good() { if(data.empty()) return false; if(std::search(data.begin(), data.end(), proto_header, proto_header + sizeof(proto_header)) == data.end()) return false; if(std::search(data.begin(), data.end(), proto_footer, proto_footer + sizeof(proto_footer)) == data.end()) return false; return true; } bool packet::is_client_packet() { std::vector::iterator i = data.begin(); i+= sizeof(proto_header); std::vector cli; cli.push_back(*i); i++; cli.push_back(*i); if(std::search(cli.begin(), cli.end(), cli_packet, cli_packet + sizeof(cli_packet)) != cli.end()) return true; return false; } bool packet::is_server_packet() { std::vector::iterator i = data.begin(); i+= sizeof(proto_header); std::vector srv; srv.push_back(*i); i++; srv.push_back(*i); if(std::search(srv.begin(), srv.end(), serv_packet, serv_packet + sizeof(serv_packet)) != srv.end()) return true; return false; } packet_type packet::get_type() { std::vector::iterator i = data.begin(); i+= (sizeof(proto_header) + 2); std::vector type; type.push_back(*i); i++; type.push_back(*i); if(std::search(type.begin(), type.end(), type_auth, type_auth + sizeof(type_auth)) != type.end()) return TYPE_AUTH; if(std::search(type.begin(), type.end(), type_services, type_services + sizeof(type_services)) != type.end()) return TYPE_SERVICES; if(std::search(type.begin(), type.end(), type_command, type_command + sizeof(type_command)) != type.end()) return TYPE_COMMAND; return TYPE_UNKNOWN; } bool packet::is_status_packet() { const unsigned char *type = to_internal_type(get_type()); std::vector::iterator i = std::search(data.begin(), data.end(), type, type + 2); i += 2; if(*i == STATUS_SUCCESS || *i == STATUS_FAILURE) return true; return false; } packet *packet::cli_make_init_packet() { std::vector v; pack_cli_header(v); pack_buffer(type_auth, sizeof(type_auth), v); v.push_back(proto_version); pack_buffer(proto_footer, sizeof(proto_footer), v); return new packet(v); } packet *packet::cli_make_command_packet(std::string &service, std::string &command) { std::vector v; pack_cli_header(v); pack_buffer(type_command, sizeof(type_command), v); pack_buffer(service, v); v.push_back(delimiter); pack_buffer(command, v); pack_buffer(proto_footer, sizeof(proto_footer), v); return new packet(v); } packet *packet::cli_make_command_packet(const char* service, const char* command) { std::string s = service, c = command; return cli_make_command_packet(s, c); } packet *packet::cli_make_request_services_packet() { std::vector v; pack_cli_header(v); pack_buffer(type_services, sizeof(type_services), v); pack_buffer(proto_footer, sizeof(proto_footer), v); return new packet(v); } std::list *packet::cli_extract_services(packet& p) { std::list *list = new std::list; std::vector::const_iterator i = std::search(p.raw().begin(), p.raw().end(), type_services, type_services + sizeof(type_services)); if(i != p.raw().end()) { i+= sizeof(type_services); std::vector::const_iterator i2 = std::find(i, p.raw().end(), delimiter), i3 = std::find(i, p.raw().end(), block_end); while(i2 != p.raw().end() || i3 != p.raw().end()) { std::string service; std::list cmds; if(i3 != p.raw().end() && i2 != p.raw().end()) { if(i2 < i3) //found service with commands { for(; i < i2; ++i) service.push_back((char)*i); i2++; i = i2; i2 = std::find(i2, i3, delimiter); std::string cmd, desc; while(i2 < i3) { cmd.clear(); desc.clear(); for(; i < i2; ++i) cmd.push_back((char)*i); i2++; i = i2; i2 = std::find(i2, i3, delimiter); for(; i < i2; ++i) desc.push_back((char)*i); service_s::cmd c; c.command = cmd; c.description = desc; cmds.push_back(c); i2++; i = i2; i2 = std::find(i2, i3, delimiter); } } else //found service without commands { for(; i < i3; ++i) service.push_back((char)*i); } i = i3; i2 = std::find(i+1, p.raw().end(), delimiter); i3 = std::find(i+1, p.raw().end(), block_end); } service_s s; s.cmds = cmds; s.service = service; list->push_back(s); i++; } } return list; } std::string packet::cli_parse_command_reply(packet& p) { std::string str; std::vector::const_iterator i = std::search(p.raw().begin(), p.raw().end(), type_command, type_command + sizeof(type_command)); if(i != p.raw().end()) { i += sizeof(type_command); i++; for(std::vector::const_iterator ii = std::search(p.raw().begin(), p.raw().end(), proto_footer, proto_footer + sizeof(proto_footer)); i < ii; ++i) str.push_back((char)*i); } return str; } bool packet::serv_validate_client_proto(packet &p) { if(!p.is_good()) return false; if(!p.is_client_packet()) return false; std::vector::const_iterator i = std::search(p.raw().begin(), p.raw().end(), type_auth, type_auth + sizeof(type_auth)); if(i == p.raw().end()) return false; i += sizeof(type_auth); i++; //wtf ? /*#ifdef DEBUG printf("version found %d\n", *i); printf("actual version %d\n", proto_version); #endif*/ if(*i < proto_version) return false; return true; } packet *packet::serv_make_services_packet(std::list &slist) { std::vector v; if(slist.empty()) return new packet(v); pack_serv_header(v); pack_buffer(type_services, sizeof(type_services), v); for(std::list::iterator i = slist.begin(), end = slist.end(); i != end; ++i) { pack_buffer(i->service, v); if(!i->cmds.empty()) { for(std::list::iterator ii = i->cmds.begin(), eend = i->cmds.end(); ii != eend; ++ii) { v.push_back(delimiter); pack_buffer(ii->command, v); v.push_back(delimiter); pack_buffer(ii->description, v); } } v.push_back(block_end); } pack_buffer(proto_footer, sizeof(proto_footer), v); return new packet(v); } packet *packet::serv_make_command_reply_packet(std::string &str, status s) { std::vector v; pack_serv_header(v); pack_buffer(type_command, sizeof(type_command), v); v.push_back(s); pack_buffer(str, v); pack_buffer(proto_footer, sizeof(proto_footer), v); return new packet(v); } packet *packet::serv_make_command_reply_packet(const char* data, status s) { std::string str = data; return serv_make_command_reply_packet(str, s); } packet *packet::serv_make_command_reply_packet(std::vector& data, status s) { std::vector v; pack_serv_header(v); pack_buffer(type_command, sizeof(type_command), v); v.push_back(s); pack_buffer(data, v); pack_buffer(proto_footer, sizeof(proto_footer), v); return new packet(v); } packet *packet::cli_make_status_packet(packet_type type, status s) { std::vector v; pack_cli_header(v); make_status_packet(type, s, v); return new packet(v); } packet *packet::serv_make_status_packet(packet_type type, status s) { std::vector v; pack_serv_header(v); make_status_packet(type, s, v); return new packet(v); } status packet::get_status() { const unsigned char *type = to_internal_type(get_type()); std::vector::const_iterator i = std::search(data.begin(), data.end(), type, type + 2); if(i != data.end()) { i += 2; return (status)*i; } return STATUS_FAILURE; } svc_cmd packet::serv_extract_command(packet& p) { svc_cmd c; std::vector::const_iterator i = std::search(p.raw().begin(), p.raw().end(), type_command, type_command + sizeof(type_command)); if(i != p.raw().end()) { i+= sizeof(type_command); std::vector::const_iterator i2 = std::find(i, p.raw().end(), delimiter); if(i2 != p.raw().end()) { for(; i < i2; ++i) c.service.push_back((char)*i); i++; i2 = std::search(p.raw().begin(), p.raw().end(), proto_footer, proto_footer + sizeof(proto_footer)); for(; i < i2; ++i) c.command.push_back((char)*i); } } return c; } unsigned char *packet::buf() { if(data.empty()) return NULL; unsigned char *b = new unsigned char [data.size()]; for(size_t i = 0; i < data.size(); i ++) b[i] = data[i]; return b; } };