Commit d01bad06 authored by Tien-Thinh Nguyen's avatar Tien-Thinh Nguyen

Merge branch 'curl_multi_interface' into 'develop'

Curl multi interface

See merge request oai/cn5g/oai-cn5g-smf!77
parents 1dbaa4c5 0bdaca9f
......@@ -68,6 +68,7 @@ COPY --from=oai-smf-builder /usr/local/lib/libpistache.so /usr/local/lib/
COPY --from=oai-smf-builder /usr/local/lib/libnghttp2_asio.so.1 /usr/local/lib/
COPY --from=oai-smf-builder /usr/lib/x86_64-linux-gnu/libboost_system.so.1.65.1 /usr/lib/x86_64-linux-gnu/
COPY --from=oai-smf-builder /usr/lib/x86_64-linux-gnu/libboost_thread.so.1.65.1 /usr/lib/x86_64-linux-gnu/
COPY --from=oai-smf-builder /usr/lib/x86_64-linux-gnu/libboost_chrono.so.1.65.1 /usr/lib/x86_64-linux-gnu/
COPY --from=oai-smf-builder /openair-smf/build/smf/build/nas/libNAS.so /usr/local/lib/
RUN ldconfig
......
......@@ -93,6 +93,7 @@ COPY --from=oai-smf-builder /usr/lib64/libdouble-conversion.so.1 /usr/lib64/
COPY --from=oai-smf-builder /usr/lib64/libconfig++.so.9 /usr/lib64/
COPY --from=oai-smf-builder /usr/lib64/libboost_system.so.1.66.0 /usr/lib64/
COPY --from=oai-smf-builder /usr/lib64/libboost_thread.so.1.66.0 /usr/lib64/
COPY --from=oai-smf-builder /usr/lib64/libboost_chrono.so.1.66.0 /usr/lib64/
COPY --from=oai-smf-builder /usr/local/lib/libnghttp2_asio.so.1 /usr/lib64/
COPY --from=oai-smf-builder /usr/lib64/libasan.so.5 /usr/lib64/
COPY --from=oai-smf-builder /openair-smf/build/smf/build/nas/libNAS.so /usr/lib64/
......
......@@ -81,6 +81,7 @@ COPY --from=oai-smf-builder /usr/local/lib/libpistache.so /usr/local/lib/
COPY --from=oai-smf-builder /usr/local/lib/libnghttp2_asio.so.1 /usr/local/lib/
COPY --from=oai-smf-builder /usr/lib/x86_64-linux-gnu/libboost_system.so.1.65.1 /usr/lib/x86_64-linux-gnu/
COPY --from=oai-smf-builder /usr/lib/x86_64-linux-gnu/libboost_thread.so.1.65.1 /usr/lib/x86_64-linux-gnu/
COPY --from=oai-smf-builder /usr/lib/x86_64-linux-gnu/libboost_chrono.so.1.65.1 /usr/lib/x86_64-linux-gnu/
COPY --from=oai-smf-builder /openair-smf/build/smf/build/nas/libNAS.so /usr/local/lib/
RUN ldconfig
......
......@@ -143,7 +143,6 @@ void IndividualSMContextApiImpl::update_sm_context(
Logger::smf_api_server().debug("Got result for promise ID %d", promise_id);
nlohmann::json json_data = {};
mime_parser parser = {};
std::string body = {};
std::string json_format;
......@@ -153,7 +152,7 @@ void IndividualSMContextApiImpl::update_sm_context(
if (sm_context_response.n1_sm_msg_is_set() and
sm_context_response.n2_sm_info_is_set()) {
parser.create_multipart_related_content(
mime_parser::create_multipart_related_content(
body, json_data.dump(), CURL_MIME_BOUNDARY,
sm_context_response.get_n1_sm_message(),
sm_context_response.get_n2_sm_information(), json_format);
......@@ -161,7 +160,7 @@ void IndividualSMContextApiImpl::update_sm_context(
Pistache::Http::Mime::MediaType(
"multipart/related; boundary=" + std::string(CURL_MIME_BOUNDARY)));
} else if (sm_context_response.n1_sm_msg_is_set()) {
parser.create_multipart_related_content(
mime_parser::create_multipart_related_content(
body, json_data.dump(), CURL_MIME_BOUNDARY,
sm_context_response.get_n1_sm_message(),
multipart_related_content_part_e::NAS, json_format);
......@@ -169,7 +168,7 @@ void IndividualSMContextApiImpl::update_sm_context(
Pistache::Http::Mime::MediaType(
"multipart/related; boundary=" + std::string(CURL_MIME_BOUNDARY)));
} else if (sm_context_response.n2_sm_info_is_set()) {
parser.create_multipart_related_content(
mime_parser::create_multipart_related_content(
body, json_data.dump(), CURL_MIME_BOUNDARY,
sm_context_response.get_n2_sm_information(),
multipart_related_content_part_e::NGAP, json_format);
......
......@@ -41,6 +41,12 @@
#include "smf_config.hpp"
#include "3gpp_conversions.hpp"
#include "mime_parser.hpp"
#include <boost/thread.hpp>
#include <boost/thread/future.hpp>
#include <boost/chrono.hpp>
#include <boost/chrono/chrono.hpp>
#include <boost/chrono/duration.hpp>
#include <boost/chrono/system_clocks.hpp>
extern smf::smf_config smf_cfg;
......@@ -98,40 +104,51 @@ void SMContextsCollectionApiImpl::post_sm_contexts(
itti_msg->http_version = 1;
m_smf_app->handle_pdu_session_create_sm_context_request(itti_msg);
// Wait for the result from APP and send reply to AMF
smf::pdu_session_create_sm_context_response sm_context_response = f.get();
Logger::smf_api_server().debug("Got result for promise ID %d", promise_id);
nlohmann::json json_data = {};
mime_parser parser = {};
std::string json_format = {};
std::string body = {};
sm_context_response.get_json_data(json_data);
sm_context_response.get_json_format(json_format);
if (sm_context_response.n1_sm_msg_is_set()) { // add N1 container if
// available
parser.create_multipart_related_content(
body, json_data.dump(), CURL_MIME_BOUNDARY,
sm_context_response.get_n1_sm_message(),
multipart_related_content_part_e::NAS, json_format);
response.headers().add<Pistache::Http::Header::ContentType>(
Pistache::Http::Mime::MediaType(
"multipart/related; boundary=" + std::string(CURL_MIME_BOUNDARY)));
} else if (!json_data.empty()) { // if not, include json data if available
response.headers().add<Pistache::Http::Header::Location>(
sm_context_response.get_smf_context_uri()); // Location header
response.headers().add<Pistache::Http::Header::ContentType>(
Pistache::Http::Mime::MediaType(json_format));
body = json_data.dump().c_str();
} else { // otherwise, send reply without content
response.send(Pistache::Http::Code(sm_context_response.get_http_code()));
return;
boost::future_status status;
// wait for timeout or ready
status = f.wait_for(boost::chrono::milliseconds(FUTURE_STATUS_TIMEOUT_MS));
if (status == boost::future_status::ready) {
assert(f.is_ready());
assert(f.has_value());
assert(!f.has_exception());
// Wait for the result from APP and send reply to AMF
smf::pdu_session_create_sm_context_response sm_context_response = f.get();
Logger::smf_api_server().debug("Got result for promise ID %d", promise_id);
nlohmann::json json_data = {};
std::string json_format = {};
std::string body = {};
sm_context_response.get_json_data(json_data);
sm_context_response.get_json_format(json_format);
if (sm_context_response.n1_sm_msg_is_set()) { // add N1 container if
// available
mime_parser::create_multipart_related_content(
body, json_data.dump(), CURL_MIME_BOUNDARY,
sm_context_response.get_n1_sm_message(),
multipart_related_content_part_e::NAS, json_format);
response.headers().add<Pistache::Http::Header::ContentType>(
Pistache::Http::Mime::MediaType(
"multipart/related; boundary=" +
std::string(CURL_MIME_BOUNDARY)));
} else if (!json_data.empty()) { // if not, include json data if available
response.headers().add<Pistache::Http::Header::Location>(
sm_context_response.get_smf_context_uri()); // Location header
response.headers().add<Pistache::Http::Header::ContentType>(
Pistache::Http::Mime::MediaType(json_format));
body = json_data.dump().c_str();
} else { // otherwise, send reply without content
response.send(Pistache::Http::Code(sm_context_response.get_http_code()));
return;
}
response.send(
Pistache::Http::Code(sm_context_response.get_http_code()), body);
} else {
response.send(Pistache::Http::Code::Request_Timeout);
}
response.send(
Pistache::Http::Code(sm_context_response.get_http_code()), body);
}
} // namespace api
} // namespace smf_server
......
......@@ -420,7 +420,6 @@ void smf_http2_server::update_sm_context_handler(
Logger::smf_api_server().debug("Got result for promise ID %d", promise_id);
nlohmann::json json_data = {};
mime_parser parser = {};
std::string body = {};
header_map h = {};
std::string json_format = {};
......@@ -431,7 +430,7 @@ void smf_http2_server::update_sm_context_handler(
if (sm_context_response.n1_sm_msg_is_set() and
sm_context_response.n2_sm_info_is_set()) {
parser.create_multipart_related_content(
mime_parser::create_multipart_related_content(
body, json_data.dump(), CURL_MIME_BOUNDARY,
sm_context_response.get_n1_sm_message(),
sm_context_response.get_n2_sm_information(), json_format);
......@@ -439,7 +438,7 @@ void smf_http2_server::update_sm_context_handler(
"content-type", header_value{"multipart/related; boundary=" +
std::string(CURL_MIME_BOUNDARY)});
} else if (sm_context_response.n1_sm_msg_is_set()) {
parser.create_multipart_related_content(
mime_parser::create_multipart_related_content(
body, json_data.dump(), CURL_MIME_BOUNDARY,
sm_context_response.get_n1_sm_message(),
multipart_related_content_part_e::NAS, json_format);
......@@ -447,7 +446,7 @@ void smf_http2_server::update_sm_context_handler(
"content-type", header_value{"multipart/related; boundary=" +
std::string(CURL_MIME_BOUNDARY)});
} else if (sm_context_response.n2_sm_info_is_set()) {
parser.create_multipart_related_content(
mime_parser::create_multipart_related_content(
body, json_data.dump(), CURL_MIME_BOUNDARY,
sm_context_response.get_n2_sm_information(),
multipart_related_content_part_e::NGAP, json_format);
......
......@@ -194,18 +194,20 @@ typedef struct qos_profile_s {
#define NNRF_NFM_BASE "/nnrf-nfm/"
#define NNRF_NF_REGISTER_URL "/nf-instances/"
#define NNRF_NF_STATUS_SUBSCRIBE_URL "/subscriptions"
#define NRF_CURL_TIMEOUT_MS 100L
// for CURL
#define AMF_CURL_TIMEOUT_MS 100L
#define NF_CURL_TIMEOUT_MS 100L
#define MAX_WAIT_MSECS 10000 // 1 second
#define AMF_NUMBER_RETRIES 3
#define UDM_CURL_TIMEOUT_MS 100L
#define UDM_NUMBER_RETRIES 3
constexpr auto CURL_MIME_BOUNDARY = "----Boundary";
// for N1N2
#define BUF_LEN 512
// FOR FUTURE PROMISE
#define FUTURE_STATUS_TIMEOUT_MS 100
// for PFCP
constexpr uint64_t SECONDS_SINCE_FIRST_EPOCH = 2208988800;
// 8.22 Fully Qualified TEID (F-TEID) - 3GPP TS 29.274 V16.0.0
......
......@@ -23,6 +23,10 @@
#include "logger.hpp"
#include "conversions.hpp"
extern "C" {
#include "dynamic_memory_check.h"
}
bool mime_parser::parse(const std::string& str) {
std::string CRLF = "\r\n";
Logger::smf_app().debug("Parsing the message with Simple Parser");
......@@ -127,6 +131,10 @@ void mime_parser::create_multipart_related_content(
body.append(CRLF);
body.append(std::string((char*) n2_msg_hex, n2_message.length() / 2) + CRLF);
body.append("--" + boundary + "--" + CRLF);
// free memory
free_wrapper((void**) &n1_msg_hex);
free_wrapper((void**) &n2_msg_hex);
}
//------------------------------------------------------------------------------
......@@ -158,4 +166,7 @@ void mime_parser::create_multipart_related_content(
body.append(CRLF);
body.append(std::string((char*) msg_hex, message.length() / 2) + CRLF);
body.append("--" + boundary + "--" + CRLF);
// free memory
free_wrapper((void**) &msg_hex);
}
......@@ -62,7 +62,7 @@ class mime_parser {
* @param [const std::string&] str: input string
* @return String represents string in hex format
*/
unsigned char* format_string_as_hex(const std::string& str);
static unsigned char* format_string_as_hex(const std::string& str);
/*
* Create HTTP body content for multipart/related message
......@@ -73,7 +73,7 @@ class mime_parser {
* @param [std::string] n2_message: N2 (NGAP) part
* @return void
*/
void create_multipart_related_content(
void static create_multipart_related_content(
std::string& body, const std::string& json_part,
const std::string boundary, const std::string& n1_message,
const std::string& n2_message,
......@@ -88,7 +88,7 @@ class mime_parser {
* @param [uint8_t] content_type: 1 for NAS content, else NGAP content
* @return void
*/
void create_multipart_related_content(
void static create_multipart_related_content(
std::string& body, const std::string& json_part,
const std::string boundary, const std::string& message,
const multipart_related_content_part_e content_type,
......
......@@ -320,5 +320,5 @@ IF(STATIC_LINKING)
ENDIF(STATIC_LINKING)
target_link_libraries (smf ${ASAN}
-Wl,--start-group CN_UTILS SMF UDP PFCP 3GPP_COMMON_TYPES SMF_API -lnettle ${NETTLE_LIBRARIES} ${CRYPTO_LIBRARIES} -lnghttp2_asio -lboost_system -lboost_thread -lssl -lcrypto NAS gflags glog dl double-conversion folly -Wl,--end-group pthread m rt config++ event boost_system pistache curl)
-Wl,--start-group CN_UTILS SMF UDP PFCP 3GPP_COMMON_TYPES SMF_API -lnettle ${NETTLE_LIBRARIES} ${CRYPTO_LIBRARIES} -lnghttp2_asio -lboost_system -lboost_thread -lssl -lcrypto NAS gflags glog dl double-conversion folly -Wl,--end-group pthread m rt config++ event boost_system boost_chrono pistache curl)
\ No newline at end of file
......@@ -363,6 +363,13 @@ smf_app::smf_app(const std::string& config_file)
Logger::smf_app().startup("Started");
}
//------------------------------------------------------------------------------
smf_app::~smf_app() {
Logger::smf_app().debug("Delete SMF_APP instance...");
// TODO: Unregister NRF
if (smf_n4_inst) delete smf_n4_inst;
if (smf_sbi_inst) delete smf_sbi_inst;
}
//------------------------------------------------------------------------------
void smf_app::start_upf_association(const pfcp::node_id_t& node_id) {
std::time_t time_epoch = std::time(nullptr);
......
......@@ -206,11 +206,7 @@ class smf_app {
public:
explicit smf_app(const std::string& config_file);
smf_app(smf_app const&) = delete;
virtual ~smf_app() {
Logger::smf_app().debug("Delete SMF_APP instance...");
// TODO: Unregister NRF
}
virtual ~smf_app();
void operator=(smf_app const&) = delete;
......
......@@ -781,7 +781,7 @@ void smf_context::handle_itti_msg(
// std::string(inet_ntoa(
// *((struct in_addr*) &smf_cfg.amf_addr.ipv4_addr))) +
//":" + std::to_string(smf_cfg.amf_addr.port) +
sp.get()->get_amf_addr() + NAMF_COMMUNICATION_BASE +
"http://" + sp.get()->get_amf_addr() + NAMF_COMMUNICATION_BASE +
smf_cfg.amf_addr.api_version +
fmt::format(
NAMF_COMMUNICATION_N1N2_MESSAGE_TRANSFER_URL,
......@@ -1611,7 +1611,7 @@ void smf_context::handle_pdu_session_create_sm_context_request(
supi_str = sm_context_resp_pending->res.get_supi_prefix() + "-" +
smf_supi_to_string(supi);
std::string url =
sp.get()->get_amf_addr() + NAMF_COMMUNICATION_BASE +
"http://" + sp.get()->get_amf_addr() + NAMF_COMMUNICATION_BASE +
smf_cfg.amf_addr.api_version +
fmt::format(
NAMF_COMMUNICATION_N1N2_MESSAGE_TRANSFER_URL, supi_str.c_str());
......@@ -2807,7 +2807,7 @@ void smf_context::handle_pdu_session_modification_network_requested(
// std::string(inet_ntoa(*((struct in_addr*)
// &smf_cfg.amf_addr.ipv4_addr))) +
//":" + std::to_string(smf_cfg.amf_addr.port) + NAMF_COMMUNICATION_BASE +
sp.get()->get_amf_addr() + NAMF_COMMUNICATION_BASE +
"http://" + sp.get()->get_amf_addr() + NAMF_COMMUNICATION_BASE +
smf_cfg.amf_addr.api_version +
fmt::format(
NAMF_COMMUNICATION_N1N2_MESSAGE_TRANSFER_URL, supi_str.c_str());
......@@ -3276,6 +3276,7 @@ bool dnn_context::remove_pdu_session(const uint32_t pdu_session_id) {
}
return false;
}
//------------------------------------------------------------------------------
size_t dnn_context::get_number_pdu_sessions() const {
std::shared_lock lock(m_context);
......
......@@ -444,7 +444,7 @@ void session_create_sm_context_procedure::handle_itti_msg(
// std::string(inet_ntoa(*((struct in_addr*)
// &smf_cfg.amf_addr.ipv4_addr))) +
//":" + std::to_string(smf_cfg.amf_addr.port) + NAMF_COMMUNICATION_BASE +
sps.get()->get_amf_addr() + NAMF_COMMUNICATION_BASE +
"http://" + sps.get()->get_amf_addr() + NAMF_COMMUNICATION_BASE +
smf_cfg.amf_addr.api_version +
fmt::format(
NAMF_COMMUNICATION_N1N2_MESSAGE_TRANSFER_URL, supi_str.c_str());
......
This diff is collapsed.
......@@ -32,6 +32,8 @@
#include <map>
#include <thread>
#include <boost/thread.hpp>
#include <boost/thread/future.hpp>
#include <curl/curl.h>
#include "3gpp_29.503.h"
#include "smf.h"
......@@ -43,11 +45,21 @@ namespace smf {
class smf_sbi {
private:
CURLM* curl_multi;
std::vector<CURL*> handles;
struct curl_slist* headers;
mutable std::shared_mutex m_curl_handle_promises;
std::map<uint32_t, boost::shared_ptr<boost::promise<uint32_t>>>
curl_handle_promises;
std::thread::id thread_id;
std::thread thread;
public:
smf_sbi();
virtual ~smf_sbi();
smf_sbi(smf_sbi const&) = delete;
void operator=(smf_sbi const&) = delete;
......@@ -134,14 +146,6 @@ class smf_sbi {
void subscribe_upf_status_notify(
std::shared_ptr<itti_n11_subscribe_upf_status_notify> msg);
/*
* Create Curl handle for multi curl
* @param [event_notification&] ev_notif: content of the event notification
* @param [std::string *] data: data
* @return pointer to the created curl
*/
CURL* curl_create_handle(event_notification& ev_notif, std::string* data);
/*
* Get SM subscription data from UDM
* @param [const supi64_t &] supi
......@@ -162,6 +166,103 @@ class smf_sbi {
*
*/
void subscribe_sm_data();
/*
* Create Curl handle for multi curl
* @param [const std::string &] uri: URI of the subscribed NF
* @param [const char* ] data: pointer to the data to be sent
* @param [uint32_t] data_len: len of data to be sent
* @param [std::string &] response_data: response data
* @param [uint32_t* ] promise_id: pointer to the promise id
* @param [const std::string&] method: HTTP method
* @param [bool] is_multipart: use multipart or json format
* @return true if a handle was created successfully, otherwise return false
*/
bool curl_create_handle(
const std::string& uri, const char* data, uint32_t data_len,
std::string& response_data, uint32_t* promise_id,
const std::string& method, bool is_multipart, uint8_t http_version = 1);
/*
* Create Curl handle for multi curl
* @param [const std::string &] uri: URI of the subscribed NF
* @param [const std::string& ] data: data to be sent
* @param [std::string &] response_data: response data
* @param [uint32_t* ] promise_id: pointer to the promise id
* @param [const std::string&] method: HTTP method
* @param [bool] is_multipart: use multipart or json format
* @return true if a handle was created successfully, otherwise return false
*/
bool curl_create_handle(
const std::string& uri, const std::string& data,
std::string& response_data, uint32_t* promise_id,
const std::string& method, uint8_t http_version = 1);
/*
* Create Curl handle for multi curl
* @param [const std::string &] uri: URI of the subscribed NF
* @param [std::string &] response_data: response data
* @param [uint32_t* ] promise_id: pointer to the promise id
* @param [const std::string&] method: HTTP method
* @return true if a handle was created successfully, otherwise return false
*/
bool curl_create_handle(
const std::string& uri, std::string& response_data, uint32_t* promise_id,
const std::string& method, uint8_t http_version = 1);
/*
* Perform curl multi to actually process the available data
* @param [uint64_t ms] ms: current time
* @return void
*/
void perform_curl_multi(uint64_t ms);
/*
* Release all the handles
* @param void
* @return void
*/
void curl_release_handles();
/*
* Wait for the promise ready
* @param [boost::shared_future<uint32_t>&] f: future
* @return future value
*/
uint32_t get_available_response(boost::shared_future<uint32_t>& f);
/*
* Store the promise
* @param [uint32_t] pid: promise id
* @param [boost::shared_ptr<boost::promise<uint32_t>>&] p: promise
* @return void
*/
void add_promise(
uint32_t pid, boost::shared_ptr<boost::promise<uint32_t>>& p);
/*
* Remove the promise
* @param [uint32_t] pid: promise id
* @return void
*/
void remove_promise(uint32_t id);
/*
* Set the value of the promise to make it ready
* @param [uint32_t] pid: promise id
* @param [uint32_t ] http_code: http response code
* @return void
*/
void trigger_process_response(uint32_t pid, uint32_t http_code);
/*
* Generate an unique value for promise id
* @param void
* @return generated promise id
*/
static uint64_t generate_promise_id() {
return util::uint_uid_generator<uint64_t>::get_instance().get_uid();
}
};
} // namespace smf
#endif /* FILE_SMF_SBI_HPP_SEEN */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment