//############################################################################## //############################################################################## BerkeleyDBCXXDb::record_type BerkeleyDBCXXDb::get_type_from_keyname(const std::string &fullkey) { BOOST_LOG_FUNCTION(); std::string type_prefix; type_prefix.reserve(5); for (char c : fullkey) { if (c == '\a') break; type_prefix.push_back(c); } if (type_prefix.size() > 0) { return record_type(std::atoi(type_prefix.c_str())); } return record_type::UNKNOWN; }
HTTPCode BillingTask::parse_body(std::string call_id, bool timer_interim, std::string reqbody, Message** msg, SAS::TrailId trail) { rapidjson::Document* body = new rapidjson::Document(); std::string bodys = reqbody; body->Parse<0>(bodys.c_str()); std::vector<std::string> ccfs; uint32_t session_refresh_time = 0; role_of_node_t role_of_node; node_functionality_t node_functionality; // Log the body early so we still see it if we later determine it's invalid. if (Log::enabled(Log::DEBUG_LEVEL)) { if (body->HasParseError()) { // Print the body from the source string. We can't pretty print an // invalid document. TRC_DEBUG("Handling request, Body:\n%s", reqbody.c_str()); } else { rapidjson::StringBuffer s; rapidjson::PrettyWriter<rapidjson::StringBuffer> w(s); body->Accept(w); TRC_DEBUG("Handling request, body:\n%s", s.GetString()); } } // Verify that the body is correct JSON with an "event" element if (!(*body).IsObject() || !(*body).HasMember("event") || !(*body)["event"].IsObject()) { TRC_WARNING("JSON document was either not valid or did not have an 'event' key"); delete body; return HTTP_BAD_REQUEST; } // Verify the Role-Of-Node and Node-Functionality AVPs are present (we use these // to distinguish devices in path for the same SIP call ID. if ((!(*body)["event"].HasMember("Service-Information")) || (!(*body)["event"]["Service-Information"].IsObject()) || (!(*body)["event"]["Service-Information"].HasMember("IMS-Information")) || (!(*body)["event"]["Service-Information"]["IMS-Information"].IsObject())) { TRC_ERROR("IMS-Information not included in the event description"); delete body; return HTTP_BAD_REQUEST; } else { rapidjson::Value& ims_information_json = (*body)["event"]["Service-Information"]["IMS-Information"]; rapidjson::Value::MemberIterator role_of_node_json = ims_information_json.FindMember("Role-Of-Node"); if ((role_of_node_json == ims_information_json.MemberEnd()) || !(role_of_node_json->value.IsInt())) { TRC_ERROR("No Role-Of-Node in IMS-Information"); delete body; return HTTP_BAD_REQUEST; } role_of_node = (role_of_node_t)role_of_node_json->value.GetInt(); rapidjson::Value::MemberIterator node_function_json = ims_information_json.FindMember("Node-Functionality"); if ((node_function_json == ims_information_json.MemberEnd()) || !(node_function_json->value.IsInt())) { TRC_ERROR("No Node-Functionality in IMS-Information"); delete body; return HTTP_BAD_REQUEST; } node_functionality = (node_functionality_t)node_function_json->value.GetInt(); } // Verify that there is an Accounting-Record-Type and it is one of // the four valid types if (!((*body)["event"].HasMember("Accounting-Record-Type") && ((*body)["event"]["Accounting-Record-Type"].IsInt()))) { TRC_WARNING("Accounting-Record-Type not available in JSON"); delete body; return HTTP_BAD_REQUEST; } Rf::AccountingRecordType record_type((*body)["event"]["Accounting-Record-Type"].GetInt()); if (!record_type.isValid()) { TRC_ERROR("Accounting-Record-Type was not one of START/INTERIM/STOP/EVENT"); delete body; return HTTP_BAD_REQUEST; } // Parsed enough to SAS-log the message. SAS::Event incoming(trail, SASEvent::INCOMING_REQUEST, 0); incoming.add_static_param(record_type.code()); incoming.add_static_param(node_functionality); SAS::report_event(incoming); // Get the Acct-Interim-Interval if present if ((*body)["event"].HasMember("Acct-Interim-Interval") && (*body)["event"]["Acct-Interim-Interval"].IsInt()) { session_refresh_time = (*body)["event"]["Acct-Interim-Interval"].GetInt(); } // If we have a START or EVENT Accounting-Record-Type, we must have // a list of CCFs to use as peers. // If these are missing, Ralf can't send the ACR onto a CDF, but it has // successfully processed the request. Log this and return 200 OK with // no further processing. if (record_type.isStart() || record_type.isEvent()) { if (!((body->HasMember("peers")) && (*body)["peers"].IsObject())) { TRC_ERROR("JSON lacked a 'peers' object (mandatory for START/EVENT)"); SAS::Event missing_peers(trail, SASEvent::INCOMING_REQUEST_NO_PEERS, 0); missing_peers.add_static_param(record_type.code()); SAS::report_event(missing_peers); delete body; return HTTP_OK; } if (!((*body)["peers"].HasMember("ccf")) || !((*body)["peers"]["ccf"].IsArray()) || ((*body)["peers"]["ccf"].Size() == 0)) { TRC_ERROR("JSON lacked a 'ccf' array, or the array was empty (mandatory for START/EVENT)"); delete body; return HTTP_BAD_REQUEST; } for (rapidjson::SizeType i = 0; i < (*body)["peers"]["ccf"].Size(); i++) { if (!(*body)["peers"]["ccf"][i].IsString()) { TRC_ERROR("JSON contains a 'ccf' array but not all the elements are strings"); delete body; return HTTP_BAD_REQUEST; } TRC_DEBUG("Adding CCF %s", (*body)["peers"]["ccf"][i].GetString()); ccfs.push_back((*body)["peers"]["ccf"][i].GetString()); } } *msg = new Message(call_id, role_of_node, node_functionality, body, record_type, session_refresh_time, trail, timer_interim); if (!ccfs.empty()) { (*msg)->ccfs = ccfs; } return HTTP_OK; }