Commit 5764e798 authored by Tien-Thinh Nguyen's avatar Tien-Thinh Nguyen

Fix issue when requresting to establish an existed session

parent 19bd6d87
......@@ -85,6 +85,7 @@ void SMFApiServer::init(size_t thr) {
}
void SMFApiServer::start() {
Logger::smf_api_server().info("HTTP1 server started");
m_httpEndpoint->setHandler(m_router->handler());
m_httpEndpoint->serve();
......
......@@ -49,8 +49,9 @@ using namespace oai::smf_server::model;
void smf_http2_server::start() {
boost::system::error_code ec;
Logger::smf_api_server().info("HTTP2 server started");
//Create SM Context Request
server.handle("/nsmf-pdusession/v2/sm-contexts",
server.handle(NSMF_PDU_SESSION_SM_CONTEXT_CREATE_URL,
[&](const request &request, const response &response) {
request.on_data([&](const uint8_t *data, std::size_t len) {
......@@ -130,7 +131,7 @@ void smf_http2_server::start() {
});
//Update SM Context Request
server.handle("/nsmf-pdusession/v2/sm-contexts/",
server.handle(NSMF_PDU_SESSION_SM_CONTEXT_UPDATE_URL,
[&](const request &request, const response &response) {
request.on_data([&](const uint8_t *data, std::size_t len) {
......
......@@ -76,6 +76,13 @@ typedef struct s_nssai // section 28.4, TS23.003
sST(p.sST),
sD(p.sD) {
}
bool operator==(const struct s_nssai &s) const {
if ((s.sST == this->sST) && (s.sD.compare(this->sD) == 0)) {
return true;
} else {
return false;
}
}
} snssai_t;
......@@ -171,13 +178,15 @@ typedef struct qos_profile_s {
} parameter;
} qos_profile_t;
#define NAMF_COMMUNICATION_N1N2_MESSAGE_TRANSFER_URL "/namf-comm/v2/ue-contexts/{}/n1-n2-messages" //may get from configuration file
#define NUDM_SDM_GET_SM_DATA_URL "/nudm-sdm/v2/{}/sm-data" //may get from configuration file
//URL, N1, N2 (may get from configuration file)
#define NAMF_COMMUNICATION_N1N2_MESSAGE_TRANSFER_URL "/namf-comm/v2/ue-contexts/{}/n1-n2-messages" //context id
#define NUDM_SDM_GET_SM_DATA_URL "/nudm-sdm/v2/{}/sm-data" //ue Id
#define N1_SM_CONTENT_ID "n1SmMsg"
#define N1N2_MESSAGE_CLASS "SM"
#define N2_SM_CONTENT_ID "n2msg"
#define NSMF_CALLBACK_N1N2_MESSAGE_TRANSFER_FAILURE "/nsmf-pdusession/v2/callback/N1N2MsgTxfrFailureNotification/{}" //may get from configuration file
#define NSMF_CALLBACK_N1N2_MESSAGE_TRANSFER_FAILURE "/nsmf-pdusession/v2/callback/N1N2MsgTxfrFailureNotification/{}" //UE Id
#define NSMF_PDU_SESSION_SM_CONTEXT_CREATE_URL "/nsmf-pdusession/v2/sm-contexts"
#define NSMF_PDU_SESSION_SM_CONTEXT_UPDATE_URL "/nsmf-pdusession/v2/sm-contexts/"
//for CURL
#define AMF_CURL_TIMEOUT_MS 100L
......
......@@ -337,7 +337,6 @@ set(NAS_include_files
${SRC_TOP_DIR}/ngap/ies
${SRC_TOP_DIR}/common
)
add_library(NAS ${NAS_src_files} ${NETTLE_LIBRARIES} ${CRYPTO_LIBRARIES})
set(NGAP_include_files
......@@ -375,9 +374,8 @@ IF(STATIC_LINKING)
SET_TARGET_PROPERTIES(smf PROPERTIES LINK_SEARCH_END_STATIC 1)
# asan do not support static linking
SET(ASAN)
ENDIF(STATIC_LINKING)
ENDIF(STATIC_LINKING)
target_link_libraries (smf ${ASAN}
-Wl,--start-group CN_UTILS SMF UDP GTPV2C 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 GTPV2C 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)
\ No newline at end of file
......@@ -46,7 +46,8 @@ itti_mw *itti_inst = nullptr;
async_shell_cmd *async_shell_cmd_inst = nullptr;
smf_app *smf_app_inst = nullptr;
smf_config smf_cfg;
SMFApiServer *smf_api_server_1 = nullptr;
//SMFApiServer *smf_api_server_1 = nullptr;
//smf_http2_server *smf_api_server_2 = nullptr;
void send_heartbeat_to_tasks(const uint32_t sequence);
......@@ -71,12 +72,14 @@ void my_app_signal_handler(int s)
std::cout << "Freeing Allocated memory..." << std::endl;
if (async_shell_cmd_inst) delete async_shell_cmd_inst; async_shell_cmd_inst = nullptr;
std::cout << "Async Shell CMD memory done." << std::endl;
//smf_api_server_1->shutdown();
//if (smf_api_server_1) delete smf_api_server_1; smf_api_server_1 = nullptr;
//if (smf_api_server_2) delete smf_api_server_2; smf_api_server_2 = nullptr;
std::cout << "SMF API Server memory done." << std::endl;
if (itti_inst) delete itti_inst; itti_inst = nullptr;
std::cout << "ITTI memory done." << std::endl;
if (smf_app_inst) delete smf_app_inst; smf_app_inst = nullptr;
std::cout << "SMF APP memory done." << std::endl;
smf_api_server_1->shutdown();
if (smf_api_server_1) delete smf_api_server_1; smf_api_server_1 = nullptr;
std::cout << "Freeing Allocated memory done" << std::endl;
exit(0);
}
......@@ -129,13 +132,14 @@ int main(int argc, char **argv)
Pistache::Address addr(std::string(inet_ntoa (*((struct in_addr *)&smf_cfg.sbi.addr4))) , Pistache::Port(smf_cfg.sbi.port));
SMFApiServer *smf_api_server_1 = new SMFApiServer(addr, smf_app_inst);
smf_api_server_1->init(2);
smf_api_server_1->start();
//std::thread smf_api_manager(&SMFApiServer::start, smf_api_server_1);
//smf_api_server_1->start();
std::thread smf_http1_manager(&SMFApiServer::start, smf_api_server_1);
//SMF NGHTTP API server (HTTP2)
smf_http2_server *smf_api_server_2 = new smf_http2_server(conv::toString(smf_cfg.sbi.addr4), smf_cfg.sbi_http2_port, smf_app_inst);
smf_api_server_2->start();
//std::thread smf_api(&smf_http2_server::start, smf_api_server_2);
//smf_api_server_2->start();
std::thread smf_http2_manager(&smf_http2_server::start, smf_api_server_2);
smf_http1_manager.join();
smf_http2_manager.join();
FILE *fp = NULL;
std::string filename = fmt::format("/tmp/smf_{}.status", getpid());
......
......@@ -277,7 +277,12 @@ void smf_app_task(void*) {
//------------------------------------------------------------------------------
smf_app::smf_app(const std::string &config_file)
:
m_seid2smf_context() {
m_seid2smf_context(),
m_supi2smf_context(),
m_scid2smf_context(),
m_sm_context_create_promises(),
m_sm_context_update_promises(),
m_sm_context_release_promises() {
Logger::smf_app().startup("Starting...");
supi2smf_context = { };
......@@ -719,7 +724,19 @@ void smf_app::handle_pdu_session_create_sm_context_request(
return;
}
//Step 4. create a context for this supi if not existed, otherwise update
//Step 4. Verify the session is already existed
if (is_scid_2_smf_context(supi64, dnn, snssai, pdu_session_id)) {
Logger::smf_app().warn(
"PDU Session already existed (SUPI " SUPI_64_FMT ", DNN %s, NSSAI (sst %d, sd %s), PDU Session ID %d)",
supi64, dnn.c_str(), snssai.sST, snssai.sD.c_str(), pdu_session_id);
//trigger to send reply to AMF
trigger_http_response(
http_status_code_e::HTTP_STATUS_CODE_406_NOT_ACCEPTABLE, smreq->pid,
N11_SESSION_CREATE_SM_CONTEXT_RESPONSE);
return;
}
//Step 5. create a context for this supi if not existed, otherwise update
std::shared_ptr<smf_context> sc = { };
if (is_supi_2_smf_context(supi64)) {
Logger::smf_app().debug("Update SMF context with SUPI " SUPI_64_FMT "",
......@@ -735,7 +752,7 @@ void smf_app::handle_pdu_session_create_sm_context_request(
set_supi_2_smf_context(supi64, sc);
}
//Step 5. Create/update context with dnn information
//Step 6. Create/update context with dnn information
std::shared_ptr<dnn_context> sd = { };
if (!sc.get()->find_dnn_context(snssai, dnn, sd)) {
......@@ -751,7 +768,7 @@ void smf_app::handle_pdu_session_create_sm_context_request(
}
}
//Step 6. retrieve Session Management Subscription data from UDM if not available (step 4, section 4.3.2 3GPP TS 23.502)
//Step 7. retrieve Session Management Subscription data from UDM if not available (step 4, section 4.3.2 3GPP TS 23.502)
std::string dnn_selection_mode = smreq->req.get_dnn_selection_mode();
//if the Session Management Subscription data is not available, get from configuration file or UDM
if (not sc.get()->is_dnn_snssai_subscription_data(dnn, snssai)) {
......@@ -803,7 +820,7 @@ void smf_app::handle_pdu_session_create_sm_context_request(
}
}
// Step 7. generate a SMF context Id and store the corresponding information in a map (SM_Context_ID, (supi, dnn, nssai, pdu_session_id))
// Step 8. generate a SMF context Id and store the corresponding information in a map (SM_Context_ID, (supi, dnn, nssai, pdu_session_id))
scid_t scid = generate_smf_context_ref();
std::shared_ptr<smf_context_ref> scf = std::shared_ptr<smf_context_ref>(
new smf_context_ref());
......@@ -818,7 +835,7 @@ void smf_app::handle_pdu_session_create_sm_context_request(
Logger::smf_app().debug("Generated a SMF Context ID " SCID_FMT " ", scid);
//Step 8. let the context handle the message
//Step 9. Let the context handle the message
sc.get()->handle_pdu_session_create_sm_context_request(smreq);
}
......@@ -1092,6 +1109,21 @@ bool smf_app::is_scid_2_smf_context(const scid_t &scid) const {
return bool { scid2smf_context.count(scid) > 0 };
}
//------------------------------------------------------------------------------
bool smf_app::is_scid_2_smf_context(const supi64_t &supi,
const std::string &dnn,
const snssai_t &snssai,
const pdu_session_id_t &pid) const {
std::shared_lock lock(m_scid2smf_context);
for (auto it : scid2smf_context) {
supi64_t supi64 = smf_supi_to_u64(it.second->supi);
if ((supi64 == supi) and (it.second->dnn.compare(dnn) == 0)
and (it.second->nssai == snssai) and (it.second->pdu_session_id == pid))
return true;
}
return false;
}
//------------------------------------------------------------------------------
bool smf_app::scid_2_smf_context(const scid_t &scid,
std::shared_ptr<smf_context_ref> &scf) const {
......@@ -1376,6 +1408,7 @@ bool smf_app::get_session_management_subscription_data(
void smf_app::add_promise(
uint32_t id,
boost::shared_ptr<boost::promise<pdu_session_create_sm_context_response> > &p) {
std::shared_lock lock(m_sm_context_create_promises);
sm_context_create_promises.emplace(id, p);
}
......@@ -1383,6 +1416,7 @@ void smf_app::add_promise(
void smf_app::add_promise(
uint32_t id,
boost::shared_ptr<boost::promise<pdu_session_update_sm_context_response> > &p) {
std::shared_lock lock(m_sm_context_update_promises);
sm_context_update_promises.emplace(id, p);
}
......@@ -1390,6 +1424,7 @@ void smf_app::add_promise(
void smf_app::add_promise(
uint32_t id,
boost::shared_ptr<boost::promise<pdu_session_release_sm_context_response> > &p) {
std::shared_lock lock(m_sm_context_release_promises);
sm_context_release_promises.emplace(id, p);
}
......@@ -1496,6 +1531,19 @@ void smf_app::trigger_http_response(const uint32_t &http_code,
break;
case N11_SESSION_CREATE_SM_CONTEXT_RESPONSE: {
std::shared_ptr<itti_n11_create_sm_context_response> itti_msg =
std::make_shared<itti_n11_create_sm_context_response>(TASK_SMF_N11,
TASK_SMF_APP,
promise_id);
pdu_session_create_sm_context_response sm_context_response = { };
sm_context_response.set_http_code(http_code);
itti_msg->res = sm_context_response;
int ret = itti_inst->send_msg(itti_msg);
if (RETURNok != ret) {
Logger::smf_app().error(
"Could not send ITTI message %s to task TASK_SMF_APP",
itti_msg->get_msg_name());
}
}
break;
default: {
......
......@@ -119,6 +119,10 @@ class smf_app {
std::map<scid_t, std::shared_ptr<smf_context_ref>> scid2smf_context;
mutable std::shared_mutex m_scid2smf_context;
//Store promise IDs for Create/Update session
mutable std::shared_mutex m_sm_context_create_promises;
mutable std::shared_mutex m_sm_context_update_promises;
mutable std::shared_mutex m_sm_context_release_promises;
std::map<uint32_t,
boost::shared_ptr<boost::promise<pdu_session_create_sm_context_response>>> sm_context_create_promises;
std::map<uint32_t,
......@@ -390,6 +394,18 @@ class smf_app {
*/
bool is_scid_2_smf_context(const scid_t &scid) const;
/*
* Verify whether a SMF Context Reference with a given ID exist
* @param [const supi64_t &] supi64: Supi64
* @param [const std::string &] dnn: DNN
* @param [const snssai_t &] snssai: S-NSSAI
* @param [const pdu_session_id_t &] pid: PDU Session ID
*
* @return bool: True if a SMF Context Reference exist, otherwise return false
*/
bool is_scid_2_smf_context(const supi64_t &supi, const std::string &dnn, const snssai_t &snssai,
const pdu_session_id_t &pid ) const;
/*
* Find SMF Context Reference by its ID
* @param [const scid_t &] scid: SM Context Reference ID
......
......@@ -1176,7 +1176,8 @@ void smf_context::handle_pdu_session_create_sm_context_request(
sm_context_resp->http_version = smreq->http_version;
sm_context_resp->res.set_http_code(http_status_code_e::HTTP_STATUS_CODE_200_OK); //default status code
sm_context_resp->res.set_http_code(
http_status_code_e::HTTP_STATUS_CODE_200_OK); //default status code
sm_context_resp->res.set_supi(supi);
sm_context_resp->res.set_supi_prefix(smreq->req.get_supi_prefix());
sm_context_resp->res.set_cause(REQUEST_ACCEPTED);
......@@ -1220,11 +1221,12 @@ void smf_context::handle_pdu_session_create_sm_context_request(
sd->insert_pdu_session(sp);
} else {
Logger::smf_app().debug("PDN connection is already existed!");
//TODO:
//trigger to send reply to AMF
smf_app_inst->trigger_http_response(
http_status_code_e::HTTP_STATUS_CODE_406_NOT_ACCEPTABLE, smreq->pid,
N11_SESSION_CREATE_SM_CONTEXT_RESPONSE);
}
//pending session??
//TODO: if "Integrity Protection is required", check UE Integrity Protection Maximum Data Rate
//TODO: (Optional) Secondary authentication/authorization
......@@ -1520,7 +1522,8 @@ void smf_context::handle_pdu_session_update_sm_context_request(
std::shared_ptr<itti_n11_update_sm_context_response> sm_context_resp_pending =
std::shared_ptr<itti_n11_update_sm_context_response>(n11_sm_context_resp);
sm_context_resp_pending->res.set_http_code(http_status_code_e::HTTP_STATUS_CODE_200_OK); //default status code
sm_context_resp_pending->res.set_http_code(
http_status_code_e::HTTP_STATUS_CODE_200_OK); //default status code
n11_sm_context_resp->res.set_supi(sm_context_req_msg.get_supi());
n11_sm_context_resp->res.set_supi_prefix(
sm_context_req_msg.get_supi_prefix());
......@@ -2482,7 +2485,8 @@ void smf_context::handle_pdu_session_release_sm_context_request(
std::shared_ptr<itti_n11_release_sm_context_response>(
n11_sm_context_resp);
n11_sm_context_resp->res.set_http_code(http_status_code_e::HTTP_STATUS_CODE_200_OK); //default http response code
n11_sm_context_resp->res.set_http_code(
http_status_code_e::HTTP_STATUS_CODE_200_OK); //default http response code
n11_sm_context_resp->res.set_supi(smreq->req.get_supi());
n11_sm_context_resp->res.set_supi_prefix(smreq->req.get_supi_prefix());
n11_sm_context_resp->res.set_cause(REQUEST_ACCEPTED);
......
......@@ -11,6 +11,9 @@
#define HTTP_V1 1
#define HTTP_V2 2
#define HTTP_CODE_OK 200
#define HTTP_CODE_CREATED 201
/*
* To read content of the response from UDM
*/
......@@ -163,11 +166,14 @@ void create_multipart_related_content(
}
//------------------------------------------------------------------------------
void send_pdu_session_establishment_request(std::string smf_ip_address,
bool send_pdu_session_establishment_request(uint8_t pid,
std::string smf_ip_address,
uint8_t http_version,
std::string port) {
std::cout << "[AMF N11] PDU Session Establishment Request (SM Context Create)"
<< std::endl;
// Response information.
long httpCode = { 0 };
nlohmann::json pdu_session_establishment_request;
//encode PDU Session Establishment Request
......@@ -178,7 +184,7 @@ void send_pdu_session_establishment_request(std::string smf_ip_address,
char *buffer = (char*) calloc(1, buffer_size);
int size = 0;
ENCODE_U8(buffer, 0x2e, size); //ExtendedProtocolDiscriminator
ENCODE_U8(buffer + size, 0x01, size); //PDUSessionIdentity
ENCODE_U8(buffer + size, pid, size); //PDUSessionIdentity
ENCODE_U8(buffer + size, 0x01, size); //ProcedureTransactionIdentity
ENCODE_U8(buffer + size, 0xc1, size); //MessageType - PDU_SESSION_ESTABLISHMENT_REQUEST
ENCODE_U8(buffer + size, 0xff, size); //Integrity Protection Maximum Data Rate
......@@ -206,7 +212,7 @@ void send_pdu_session_establishment_request(std::string smf_ip_address,
pdu_session_establishment_request["dnn"] = "default";
pdu_session_establishment_request["sNssai"]["sst"] = 222;
pdu_session_establishment_request["sNssai"]["sd"] = "0000D4";
pdu_session_establishment_request["pduSessionId"] = 1;
pdu_session_establishment_request["pduSessionId"] = pid;
pdu_session_establishment_request["requestType"] = "INITIAL_REQUEST";
pdu_session_establishment_request["servingNfId"] = "servingNfId";
pdu_session_establishment_request["servingNetwork"]["mcc"] = "234";
......@@ -256,8 +262,6 @@ void send_pdu_session_establishment_request(std::string smf_ip_address,
#endif
}
// Response information.
long httpCode = { 0 };
std::unique_ptr<std::string> httpData(new std::string());
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &callback);
......@@ -281,20 +285,28 @@ void send_pdu_session_establishment_request(std::string smf_ip_address,
<< "[AMF N11] PDU session establishment request, response from SMF "
<< response_data.dump().c_str() << ", Http Code " << httpCode
<< std::endl;
curl_easy_cleanup(curl);
}
curl_global_cleanup();
free(buffer);
if (httpCode == HTTP_CODE_CREATED) {
return true;
} else {
return false;
}
}
//------------------------------------------------------------------------------
void send_pdu_session_update_sm_context_establishment(
std::string smf_ip_address, uint8_t http_version, std::string port) {
bool send_pdu_session_update_sm_context_establishment(
uint8_t context_id, std::string smf_ip_address, uint8_t http_version,
std::string port) {
std::cout << "[AMF N11] PDU Session Establishment Request (SM Context Update)"
<< std::endl;
// Response information.
long httpCode = { 0 };
nlohmann::json pdu_session_update_request;
//encode PDU Session Resource Setup Response Transfer IE
/*
......@@ -330,7 +342,10 @@ void send_pdu_session_update_sm_context_establishment(
url.append(std::string(":"));
url.append(port);
}
url.append(std::string("/nsmf-pdusession/v2/sm-contexts/1/modify"));
url.append(std::string("/nsmf-pdusession/v2/sm-contexts/"));
url.append(std::to_string(context_id));
url.append(std::string("/modify"));
// url.append(std::string("/nsmf-pdusession/v2/sm-contexts/1/modify"));
//Fill the json part
pdu_session_update_request["n2SmInfoType"] = "PDU_RES_SETUP_RSP";
......@@ -381,8 +396,6 @@ void send_pdu_session_update_sm_context_establishment(
#endif
}
// Response information.
long httpCode = { 0 };
std::unique_ptr<std::string> httpData(new std::string());
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &callback);
......@@ -415,6 +428,13 @@ void send_pdu_session_update_sm_context_establishment(
curl_global_cleanup();
free(buffer);
if (httpCode == HTTP_CODE_OK) {
return true;
} else {
return false;
}
}
//------------------------------------------------------------------------------
......@@ -1462,36 +1482,54 @@ int main(int argc, char *argv[]) {
<< std::to_string(http_version) << ", -p " << port.c_str()
<< std::endl;
//PDU Session Establishment procedure
send_pdu_session_establishment_request(smf_ip_address, http_version, port);
usleep(100000);
send_pdu_session_update_sm_context_establishment(smf_ip_address, http_version,
port);
usleep(200000);
//UE-initiated Service Request
send_pdu_session_update_sm_context_ue_service_request(smf_ip_address,
http_version, port);
usleep(200000);
send_pdu_session_update_sm_context_ue_service_request_step2(smf_ip_address,
http_version,
port);
usleep(200000);
//PDU Session Modification
send_pdu_session_modification_request_step1(smf_ip_address, http_version,
port);
usleep(200000);
send_pdu_session_modification_request_step2(smf_ip_address, http_version,
port);
usleep(200000);
send_pdu_session_modification_complete(smf_ip_address, http_version, port);
usleep(200000);
//PDU Session Release procedure
send_pdu_session_release_request(smf_ip_address, http_version, port);
usleep(200000);
send_pdu_session_release_resource_release_ack(smf_ip_address, http_version,
bool cont = false;
/*//Check multiple sessions
for (int i=1; i< 10; i++){
//PDU Session Establishment procedure
if (send_pdu_session_establishment_request(i, smf_ip_address, http_version, port)) {
usleep(100000);
cont = send_pdu_session_update_sm_context_establishment(i, smf_ip_address, http_version,
port);
}
}
*/
if (send_pdu_session_establishment_request(1, smf_ip_address, http_version,
port)) {
usleep(100000);
cont = send_pdu_session_update_sm_context_establishment(1, smf_ip_address,
http_version, port);
}
if (cont) {
usleep(200000);
//UE-initiated Service Request
send_pdu_session_update_sm_context_ue_service_request(smf_ip_address,
http_version, port);
usleep(200000);
send_pdu_session_update_sm_context_ue_service_request_step2(smf_ip_address,
http_version,
port);
usleep(200000);
//PDU Session Modification
send_pdu_session_modification_request_step1(smf_ip_address, http_version,
port);
usleep(200000);
send_pdu_session_release_complete(smf_ip_address, http_version, port);
usleep(200000);
send_pdu_session_modification_request_step2(smf_ip_address, http_version,
port);
usleep(200000);
send_pdu_session_modification_complete(smf_ip_address, http_version, port);
usleep(200000);
//PDU Session Release procedure
send_pdu_session_release_request(smf_ip_address, http_version, port);
usleep(200000);
send_pdu_session_release_resource_release_ack(smf_ip_address, http_version,
port);
usleep(200000);
send_pdu_session_release_complete(smf_ip_address, http_version, port);
}
usleep(200000);
//Release SM context
//send_release_sm_context_request(smf_ip_address, http_version, port);
......
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